1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <svl/zforlist.hxx>
21
22 #include "DataBrowser.hxx"
23 #include "DataBrowserModel.hxx"
24 #include <strings.hrc>
25 #include <DataSeriesHelper.hxx>
26 #include <DiagramHelper.hxx>
27 #include <CommonConverters.hxx>
28 #include <NumberFormatterWrapper.hxx>
29 #include <servicenames_charttypes.hxx>
30 #include <ResId.hxx>
31 #include <bitmaps.hlst>
32 #include <helpids.h>
33
34 #include <vcl/weld.hxx>
35 #include <vcl/settings.hxx>
36 #include <vcl/svapp.hxx>
37 #include <vcl/virdev.hxx>
38 #include <rtl/math.hxx>
39 #include <o3tl/safeint.hxx>
40 #include <osl/diagnose.h>
41 #include <toolkit/helper/vclunohelper.hxx>
42
43 #include <com/sun/star/chart2/XChartDocument.hpp>
44 #include <com/sun/star/chart2/XChartType.hpp>
45 #include <com/sun/star/container/XIndexReplace.hpp>
46
47 #include <algorithm>
48
49
50 using namespace ::com::sun::star;
51 using ::com::sun::star::uno::Reference;
52
53 using namespace ::svt;
54
55 namespace
56 {
57 /* BrowserMode::COLUMNSELECTION : single cells may be selected rather than only
58 entire rows
59 BrowserMode::(H|V)LINES : show horizontal or vertical grid-lines
60 BrowserMode::AUTO_(H|V)SCROLL : scroll automated horizontally or vertically when
61 cursor is moved beyond the edge of the dialog
62 BrowserMode::HIDESELECT : Do not mark the current row with selection color
63 (usually blue)
64 ! BrowserMode::HIDECURSOR would prevent flickering in edit fields, but navigating
65 with shift up/down, and entering non-editable cells would be problematic,
66 e.g. the first cell, or when being in read-only mode
67 */
68 const BrowserMode BrowserStdFlags = BrowserMode::COLUMNSELECTION |
69 BrowserMode::HLINES | BrowserMode::VLINES |
70 BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL |
71 BrowserMode::HIDESELECT;
72
lcl_getColumnInData(sal_uInt16 nCol)73 sal_Int32 lcl_getColumnInData( sal_uInt16 nCol )
74 {
75 return static_cast< sal_Int32 >( nCol ) - 1;
76 }
77
78 } // anonymous namespace
79
80 namespace chart
81 {
82
83 namespace impl
84 {
85
86 class SeriesHeaderEdit
87 {
88 public:
89 explicit SeriesHeaderEdit(std::unique_ptr<weld::Entry> xControl);
90
91 void setStartColumn( sal_Int32 nStartColumn );
getStartColumn() const92 sal_Int32 getStartColumn() const { return m_nStartColumn;}
93 void SetShowWarningBox( bool bShowWarning );
94
GetText() const95 OUString GetText() const { return m_xControl->get_text(); }
SetText(const OUString & rText)96 void SetText(const OUString& rText) { m_xControl->set_text(rText); }
97
HasFocus() const98 bool HasFocus() const { return m_xControl->has_focus(); }
99
set_size_request(int nWidth,int nHeight)100 void set_size_request(int nWidth, int nHeight) { m_xControl->set_size_request(nWidth, nHeight); }
set_margin_start(int nLeft)101 void set_margin_start(int nLeft) { m_xControl->set_margin_start(nLeft); }
102
SetModifyHdl(const Link<SeriesHeaderEdit &,void> & rLink)103 void SetModifyHdl(const Link<SeriesHeaderEdit&,void>& rLink) { m_aModifyHdl = rLink; }
SetGetFocusHdl(const Link<SeriesHeaderEdit &,void> & rLink)104 void SetGetFocusHdl(const Link<SeriesHeaderEdit&,void>& rLink) { m_aFocusInHdl = rLink; }
105
106 private:
107 DECL_LINK(NameEdited, weld::Entry&, void);
108 DECL_LINK(NameFocusIn, weld::Widget&, void);
109 DECL_LINK(MousePressHdl, const MouseEvent&, bool);
110
111 std::unique_ptr<weld::Entry> m_xControl;
112 Link<SeriesHeaderEdit&,void> m_aModifyHdl;
113 Link<SeriesHeaderEdit&,void> m_aFocusInHdl;
114 sal_Int32 m_nStartColumn;
115 bool m_bShowWarningBox;
116 };
117
SeriesHeaderEdit(std::unique_ptr<weld::Entry> xControl)118 SeriesHeaderEdit::SeriesHeaderEdit(std::unique_ptr<weld::Entry> xControl)
119 : m_xControl(std::move(xControl))
120 , m_nStartColumn(0)
121 , m_bShowWarningBox(false)
122 {
123 m_xControl->set_help_id(HID_SCH_DATA_SERIES_LABEL);
124 m_xControl->connect_changed(LINK(this, SeriesHeaderEdit, NameEdited));
125 m_xControl->connect_focus_in(LINK(this, SeriesHeaderEdit, NameFocusIn));
126 m_xControl->connect_mouse_press(LINK(this, SeriesHeaderEdit, MousePressHdl));
127 }
128
IMPL_LINK_NOARG(SeriesHeaderEdit,NameEdited,weld::Entry &,void)129 IMPL_LINK_NOARG(SeriesHeaderEdit, NameEdited, weld::Entry&, void)
130 {
131 m_aModifyHdl.Call(*this);
132 }
133
IMPL_LINK_NOARG(SeriesHeaderEdit,NameFocusIn,weld::Widget &,void)134 IMPL_LINK_NOARG(SeriesHeaderEdit, NameFocusIn, weld::Widget&, void)
135 {
136 m_aFocusInHdl.Call(*this);
137 }
138
setStartColumn(sal_Int32 nStartColumn)139 void SeriesHeaderEdit::setStartColumn( sal_Int32 nStartColumn )
140 {
141 m_nStartColumn = nStartColumn;
142 }
143
SetShowWarningBox(bool bShowWarning)144 void SeriesHeaderEdit::SetShowWarningBox( bool bShowWarning )
145 {
146 m_bShowWarningBox = bShowWarning;
147 }
148
IMPL_LINK_NOARG(SeriesHeaderEdit,MousePressHdl,const MouseEvent &,bool)149 IMPL_LINK_NOARG(SeriesHeaderEdit, MousePressHdl, const MouseEvent&, bool)
150 {
151 if (m_bShowWarningBox)
152 {
153 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xControl.get(),
154 VclMessageType::Warning, VclButtonsType::Ok,
155 SchResId(STR_INVALID_NUMBER)));
156 xWarn->run();
157 }
158
159 return false;
160 }
161
162 class SeriesHeader
163 {
164 public:
165 explicit SeriesHeader(weld::Container* pParent, weld::Container* pColorParent);
166 ~SeriesHeader();
167
168 void SetColor( const Color & rCol );
169 void SetPos();
170 void SetWidth( sal_Int32 nWidth );
171 void SetChartType( const Reference< chart2::XChartType > & xChartType,
172 bool bSwapXAndYAxis );
173 void SetSeriesName( const OUString & rName );
174 void SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol );
175
176 void SetPixelWidth( sal_Int32 nWidth );
177
GetStartColumn() const178 sal_Int32 GetStartColumn() const { return m_nStartCol;}
GetEndColumn() const179 sal_Int32 GetEndColumn() const { return m_nEndCol;}
180
181 static const sal_Int32 nSymbolHeight = 10;
182 static const sal_Int32 nSymbolDistance = 2;
183
GetRelativeAppFontXPosForNameField()184 static sal_Int32 GetRelativeAppFontXPosForNameField() { return nSymbolHeight + nSymbolDistance; }
185
186 void Show();
187 void Hide();
188
189 /** call this before destroying the class. This notifies the listeners to
190 changes of the edit field for the series name.
191 */
192 void applyChanges();
193
194 void SetGetFocusHdl(const Link<SeriesHeaderEdit&,void>& rLink);
195
196 void SetEditChangedHdl( const Link<SeriesHeaderEdit&,void> & rLink );
197
198 bool HasFocus() const;
199
200 private:
201 Timer m_aUpdateDataTimer;
202
203 std::unique_ptr<weld::Builder> m_xBuilder1;
204 std::unique_ptr<weld::Builder> m_xBuilder2;
205
206 weld::Container* m_pParent;
207 weld::Container* m_pColorParent;
208
209 std::unique_ptr<weld::Container> m_xContainer1;
210 std::unique_ptr<weld::Container> m_xContainer2;
211 std::unique_ptr<weld::Image> m_spSymbol;
212 std::unique_ptr<SeriesHeaderEdit> m_spSeriesName;
213 std::unique_ptr<weld::Image> m_spColorBar;
214 VclPtr< OutputDevice> m_xDevice;
215 Link<SeriesHeaderEdit&,void> m_aChangeLink;
216 Color m_aColor;
217
218 void notifyChanges();
219 DECL_LINK( ImplUpdateDataHdl, Timer*, void );
220 DECL_LINK( SeriesNameEdited, SeriesHeaderEdit&, void );
221
222 static OUString GetChartTypeImage(
223 const Reference< chart2::XChartType > & xChartType,
224 bool bSwapXAndYAxis
225 );
226
227 sal_Int32 m_nStartCol, m_nEndCol;
228 sal_Int32 m_nWidth;
229 bool m_bSeriesNameChangePending;
230 };
231
SeriesHeader(weld::Container * pParent,weld::Container * pColorParent)232 SeriesHeader::SeriesHeader(weld::Container* pParent, weld::Container* pColorParent)
233 : m_aUpdateDataTimer("UpdateDataTimer")
234 , m_xBuilder1(Application::CreateBuilder(pParent, "modules/schart/ui/columnfragment.ui"))
235 , m_xBuilder2(Application::CreateBuilder(pColorParent, "modules/schart/ui/imagefragment.ui"))
236 , m_pParent(pParent)
237 , m_pColorParent(pColorParent)
238 , m_xContainer1(m_xBuilder1->weld_container("container"))
239 , m_xContainer2(m_xBuilder2->weld_container("container"))
240 , m_spSymbol(m_xBuilder1->weld_image("image"))
241 , m_spSeriesName(new SeriesHeaderEdit(m_xBuilder1->weld_entry("entry")))
242 , m_spColorBar(m_xBuilder2->weld_image("image"))
243 , m_xDevice(Application::GetDefaultDevice())
244 , m_nStartCol( 0 )
245 , m_nEndCol( 0 )
246 , m_nWidth( 42 )
247 , m_bSeriesNameChangePending( false )
248 {
249 m_aUpdateDataTimer.SetInvokeHandler(LINK(this, SeriesHeader, ImplUpdateDataHdl));
250 m_aUpdateDataTimer.SetDebugName( "SeriesHeader UpdateDataTimer" );
251 m_aUpdateDataTimer.SetTimeout(4 * EDIT_UPDATEDATA_TIMEOUT);
252
253 m_spSeriesName->SetModifyHdl(LINK(this, SeriesHeader, SeriesNameEdited));
254 Show();
255 }
256
~SeriesHeader()257 SeriesHeader::~SeriesHeader()
258 {
259 m_aUpdateDataTimer.Stop();
260 m_pParent->move(m_xContainer1.get(), nullptr);
261 m_pColorParent->move(m_xContainer2.get(), nullptr);
262 }
263
notifyChanges()264 void SeriesHeader::notifyChanges()
265 {
266 m_aChangeLink.Call(*m_spSeriesName);
267 m_bSeriesNameChangePending = false;
268 }
269
applyChanges()270 void SeriesHeader::applyChanges()
271 {
272 if( m_bSeriesNameChangePending )
273 {
274 notifyChanges();
275 }
276 }
277
SetColor(const Color & rCol)278 void SeriesHeader::SetColor( const Color & rCol )
279 {
280 m_aColor = rCol;
281 }
282
SetPos()283 void SeriesHeader::SetPos()
284 {
285 // chart type symbol
286 Size aSize( nSymbolHeight, nSymbolHeight );
287 aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont));
288 m_spSymbol->set_size_request(aSize.Width(), aSize.Height());
289
290 // series name edit field
291 m_spSeriesName->set_margin_start(2);
292
293 aSize.setWidth(nSymbolHeight);
294 aSize.setHeight(12);
295 aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont));
296 aSize.setWidth(m_nWidth - aSize.Width() - 2);
297 m_spSeriesName->set_size_request(aSize.Width(), aSize.Height());
298
299 // color bar
300 aSize.setHeight(3);
301 aSize = m_xDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont));
302 aSize.setWidth(m_nWidth);
303 m_spColorBar->set_size_request(aSize.Width(), aSize.Height());
304
305 ScopedVclPtr<VirtualDevice> xVirDev(m_spColorBar->create_virtual_device());
306 xVirDev->SetOutputSizePixel(aSize);
307 xVirDev->SetFillColor(m_aColor);
308 xVirDev->SetLineColor(m_aColor);
309 xVirDev->DrawRect(tools::Rectangle(Point(0, 0), aSize));
310 m_spColorBar->set_image(xVirDev.get());
311 }
312
SetWidth(sal_Int32 nWidth)313 void SeriesHeader::SetWidth( sal_Int32 nWidth )
314 {
315 m_nWidth = nWidth;
316 SetPos();
317 }
318
SetPixelWidth(sal_Int32 nWidth)319 void SeriesHeader::SetPixelWidth( sal_Int32 nWidth )
320 {
321 SetWidth(nWidth);
322 }
323
SetChartType(const Reference<chart2::XChartType> & xChartType,bool bSwapXAndYAxis)324 void SeriesHeader::SetChartType(
325 const Reference< chart2::XChartType > & xChartType,
326 bool bSwapXAndYAxis
327 )
328 {
329 m_spSymbol->set_from_icon_name( GetChartTypeImage( xChartType, bSwapXAndYAxis ) );
330 }
331
SetSeriesName(const OUString & rName)332 void SeriesHeader::SetSeriesName( const OUString & rName )
333 {
334 m_spSeriesName->SetText(rName);
335 }
336
SetRange(sal_Int32 nStartCol,sal_Int32 nEndCol)337 void SeriesHeader::SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol )
338 {
339 m_nStartCol = nStartCol;
340 m_nEndCol = std::max(nEndCol, nStartCol);
341 m_spSeriesName->setStartColumn( nStartCol );
342 }
343
Show()344 void SeriesHeader::Show()
345 {
346 m_xContainer1->show();
347 m_xContainer2->show();
348 }
349
Hide()350 void SeriesHeader::Hide()
351 {
352 m_xContainer1->hide();
353 m_xContainer2->hide();
354 }
355
SetEditChangedHdl(const Link<SeriesHeaderEdit &,void> & rLink)356 void SeriesHeader::SetEditChangedHdl( const Link<SeriesHeaderEdit&,void> & rLink )
357 {
358 m_aChangeLink = rLink;
359 }
360
IMPL_LINK_NOARG(SeriesHeader,ImplUpdateDataHdl,Timer *,void)361 IMPL_LINK_NOARG(SeriesHeader, ImplUpdateDataHdl, Timer*, void)
362 {
363 notifyChanges();
364 }
365
IMPL_LINK_NOARG(SeriesHeader,SeriesNameEdited,SeriesHeaderEdit &,void)366 IMPL_LINK_NOARG(SeriesHeader, SeriesNameEdited, SeriesHeaderEdit&, void)
367 {
368 m_bSeriesNameChangePending = true;
369 m_aUpdateDataTimer.Start();
370 }
371
SetGetFocusHdl(const Link<SeriesHeaderEdit &,void> & rLink)372 void SeriesHeader::SetGetFocusHdl( const Link<SeriesHeaderEdit&,void>& rLink )
373 {
374 m_spSeriesName->SetGetFocusHdl( rLink );
375 }
376
HasFocus() const377 bool SeriesHeader::HasFocus() const
378 {
379 return m_spSeriesName->HasFocus();
380 }
381
GetChartTypeImage(const Reference<chart2::XChartType> & xChartType,bool bSwapXAndYAxis)382 OUString SeriesHeader::GetChartTypeImage(
383 const Reference< chart2::XChartType > & xChartType,
384 bool bSwapXAndYAxis
385 )
386 {
387 OUString aResult;
388 if( !xChartType.is())
389 return aResult;
390 OUString aChartTypeName( xChartType->getChartType());
391
392 if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_AREA )
393 {
394 aResult = BMP_TYPE_AREA;
395 }
396 else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_COLUMN )
397 {
398 if( bSwapXAndYAxis )
399 aResult = BMP_TYPE_BAR;
400 else
401 aResult = BMP_TYPE_COLUMN;
402 }
403 else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_LINE )
404 {
405 aResult = BMP_TYPE_LINE;
406 }
407 else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_SCATTER )
408 {
409 aResult = BMP_TYPE_XY;
410 }
411 else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_PIE )
412 {
413 aResult = BMP_TYPE_PIE;
414 }
415 else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_NET
416 || aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET )
417 {
418 aResult = BMP_TYPE_NET;
419 }
420 else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK )
421 {
422 // @todo: correct image for candle-stick type
423 aResult = BMP_TYPE_STOCK;
424 }
425 else if( aChartTypeName == CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE )
426 {
427 aResult = BMP_TYPE_BUBBLE;
428 }
429
430 return aResult;
431 }
432
433 } // namespace impl
434
435 namespace
436 {
437
438 /** returns false, if no header as the focus.
439
440 If a header has the focus, true is returned and the index of the header
441 with focus is set at pIndex if pOutIndex is not 0.
442 */
lcl_SeriesHeaderHasFocus(const std::vector<std::shared_ptr<::chart::impl::SeriesHeader>> & rSeriesHeader,sal_Int32 * pOutIndex=nullptr)443 bool lcl_SeriesHeaderHasFocus(
444 const std::vector< std::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader,
445 sal_Int32 * pOutIndex = nullptr )
446 {
447 sal_Int32 nIndex = 0;
448 for (auto const& elem : rSeriesHeader)
449 {
450 if(elem->HasFocus())
451 {
452 if( pOutIndex )
453 *pOutIndex = nIndex;
454 return true;
455 }
456 ++nIndex;
457 }
458 return false;
459 }
460
lcl_getColumnInDataOrHeader(sal_uInt16 nCol,const std::vector<std::shared_ptr<::chart::impl::SeriesHeader>> & rSeriesHeader)461 sal_Int32 lcl_getColumnInDataOrHeader(
462 sal_uInt16 nCol, const std::vector< std::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader )
463 {
464 sal_Int32 nColIdx = 0;
465 bool bHeaderHasFocus( lcl_SeriesHeaderHasFocus( rSeriesHeader, &nColIdx ));
466
467 if( bHeaderHasFocus )
468 nColIdx = lcl_getColumnInData( static_cast< sal_uInt16 >( rSeriesHeader[nColIdx]->GetStartColumn()));
469 else
470 nColIdx = lcl_getColumnInData( nCol );
471
472 return nColIdx;
473 }
474
475 } // anonymous namespace
476
DataBrowser(const css::uno::Reference<css::awt::XWindow> & rParent,weld::Container * pColumns,weld::Container * pColors)477 DataBrowser::DataBrowser(const css::uno::Reference<css::awt::XWindow> &rParent,
478 weld::Container* pColumns, weld::Container* pColors) :
479 ::svt::EditBrowseBox(VCLUnoHelper::GetWindow(rParent),
480 EditBrowseBoxFlags::SMART_TAB_TRAVEL | EditBrowseBoxFlags::HANDLE_COLUMN_TEXT,
481 WB_BORDER | WB_TABSTOP, BrowserStdFlags ),
482 m_nSeekRow( 0 ),
483 m_bIsReadOnly( false ),
484 m_bDataValid( true ),
485 m_aNumberEditField(VclPtr<FormattedControl>::Create(&EditBrowseBox::GetDataWindow(), false)),
486 m_aTextEditField(VclPtr<EditControl>::Create(&EditBrowseBox::GetDataWindow())),
487 m_pColumnsWin(pColumns),
488 m_pColorsWin(pColors),
489 m_rNumberEditController( new ::svt::FormattedFieldCellController( m_aNumberEditField.get() )),
490 m_rTextEditController( new ::svt::EditCellController( m_aTextEditField.get() ))
491 {
492 double fNan;
493 ::rtl::math::setNan( & fNan );
494 Formatter& rFormatter = m_aNumberEditField->get_formatter();
495 rFormatter.SetDefaultValue( fNan );
496 rFormatter.TreatAsNumber( true );
497 RenewTable();
498 }
499
~DataBrowser()500 DataBrowser::~DataBrowser()
501 {
502 disposeOnce();
503 }
504
dispose()505 void DataBrowser::dispose()
506 {
507 m_aSeriesHeaders.clear();
508 m_aNumberEditField.disposeAndClear();
509 m_aTextEditField.disposeAndClear();
510 ::svt::EditBrowseBox::dispose();
511 }
512
MayInsertRow() const513 bool DataBrowser::MayInsertRow() const
514 {
515 return ! IsReadOnly()
516 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ));
517 }
518
MayInsertColumn() const519 bool DataBrowser::MayInsertColumn() const
520 {
521 return ! IsReadOnly();
522 }
523
MayDeleteRow() const524 bool DataBrowser::MayDeleteRow() const
525 {
526 return ! IsReadOnly()
527 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
528 && ( GetCurRow() >= 0 )
529 && ( GetRowCount() > 1 );
530 }
531
MayDeleteColumn() const532 bool DataBrowser::MayDeleteColumn() const
533 {
534 // if a series header has the focus
535 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
536 return true;
537
538 return ! IsReadOnly()
539 && ( GetCurColumnId() > 1 )
540 && ( ColCount() > 2 );
541 }
542
MayMoveUpRows() const543 bool DataBrowser::MayMoveUpRows() const
544 {
545 return ! IsReadOnly()
546 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
547 && ( GetCurRow() > 0 )
548 && ( GetCurRow() <= GetRowCount() - 1 );
549 }
550
MayMoveDownRows() const551 bool DataBrowser::MayMoveDownRows() const
552 {
553 return ! IsReadOnly()
554 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
555 && ( GetCurRow() >= 0 )
556 && ( GetCurRow() < GetRowCount() - 1 );
557 }
558
MayMoveLeftColumns() const559 bool DataBrowser::MayMoveLeftColumns() const
560 {
561 // if a series header (except the last one) has the focus
562 {
563 sal_Int32 nColIndex(0);
564 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex ))
565 return (o3tl::make_unsigned( nColIndex ) <= (m_aSeriesHeaders.size() - 1)) && (static_cast< sal_uInt32 >( nColIndex ) != 0);
566 }
567
568 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
569 return ! IsReadOnly()
570 && ( nColIdx > 1 )
571 && ( nColIdx <= ColCount() - 2 )
572 && m_apDataBrowserModel
573 && !m_apDataBrowserModel->isCategoriesColumn( nColIdx );
574 }
575
MayMoveRightColumns() const576 bool DataBrowser::MayMoveRightColumns() const
577 {
578 // if a series header (except the last one) has the focus
579 {
580 sal_Int32 nColIndex(0);
581 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex ))
582 return (o3tl::make_unsigned( nColIndex ) < (m_aSeriesHeaders.size() - 1));
583 }
584
585 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
586 return ! IsReadOnly()
587 && ( nColIdx > 0 )
588 && ( nColIdx < ColCount()-2 )
589 && m_apDataBrowserModel
590 && !m_apDataBrowserModel->isCategoriesColumn( nColIdx );
591 }
592
clearHeaders()593 void DataBrowser::clearHeaders()
594 {
595 for( const auto& spHeader : m_aSeriesHeaders )
596 spHeader->applyChanges();
597 m_aSeriesHeaders.clear();
598 }
599
RenewTable()600 void DataBrowser::RenewTable()
601 {
602 if (!m_apDataBrowserModel)
603 return;
604
605 sal_Int32 nOldRow = GetCurRow();
606 sal_uInt16 nOldColId = GetCurColumnId();
607
608 bool bLastUpdateMode = GetUpdateMode();
609 SetUpdateMode( false );
610
611 if( IsModified() )
612 SaveModified();
613
614 DeactivateCell();
615
616 RemoveColumns();
617 RowRemoved( 1, GetRowCount() );
618
619 // for row numbers
620 InsertHandleColumn( static_cast< sal_uInt16 >(
621 GetDataWindow().LogicToPixel( Size( 42, 0 )).getWidth() ));
622
623 OUString aDefaultSeriesName(SchResId(STR_COLUMN_LABEL));
624 replaceParamterInString( aDefaultSeriesName, "%COLUMNNUMBER", OUString::number( 24 ) );
625 sal_Int32 nColumnWidth = GetDataWindow().GetTextWidth( aDefaultSeriesName )
626 + GetDataWindow().LogicToPixel(Point(8 + impl::SeriesHeader::GetRelativeAppFontXPosForNameField(), 0), MapMode(MapUnit::MapAppFont)).X();
627 sal_Int32 nColumnCount = m_apDataBrowserModel->getColumnCount();
628 // nRowCount is a member of a base class
629 sal_Int32 nRowCountLocal = m_apDataBrowserModel->getMaxRowCount();
630 for( sal_Int32 nColIdx=1; nColIdx<=nColumnCount; ++nColIdx )
631 {
632 InsertDataColumn( static_cast< sal_uInt16 >( nColIdx ), GetColString( nColIdx ), nColumnWidth );
633 }
634
635 RowInserted( 1, nRowCountLocal );
636 GoToRow( std::min( nOldRow, GetRowCount() - 1 ));
637 GoToColumnId( std::min( nOldColId, static_cast< sal_uInt16 >( ColCount() - 1 )));
638
639 // fill series headers
640 clearHeaders();
641 const DataBrowserModel::tDataHeaderVector& aHeaders( m_apDataBrowserModel->getDataHeaders());
642 Link<impl::SeriesHeaderEdit&,void> aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus ));
643 Link<impl::SeriesHeaderEdit&,void> aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged ));
644
645 for (auto const& elemHeader : aHeaders)
646 {
647 auto spHeader = std::make_shared<impl::SeriesHeader>( m_pColumnsWin, m_pColorsWin );
648 Reference< beans::XPropertySet > xSeriesProp( elemHeader.m_xDataSeries, uno::UNO_QUERY );
649 Color nColor;
650 // @todo: Set "DraftColor", i.e. interpolated colors for gradients, bitmaps, etc.
651 if( xSeriesProp.is() &&
652 ( xSeriesProp->getPropertyValue( "Color" ) >>= nColor ))
653 spHeader->SetColor( nColor );
654 spHeader->SetChartType( elemHeader.m_xChartType, elemHeader.m_bSwapXAndYAxis );
655 spHeader->SetSeriesName(
656 DataSeriesHelper::getDataSeriesLabel(
657 elemHeader.m_xDataSeries,
658 (elemHeader.m_xChartType.is() ?
659 elemHeader.m_xChartType->getRoleOfSequenceForSeriesLabel() :
660 OUString("values-y"))));
661 // index is 1-based, as 0 is for the column that contains the row-numbers
662 spHeader->SetRange( elemHeader.m_nStartColumn + 1, elemHeader.m_nEndColumn + 1 );
663 spHeader->SetGetFocusHdl( aFocusLink );
664 spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink );
665 m_aSeriesHeaders.push_back( spHeader );
666 }
667
668 ImplAdjustHeaderControls();
669 SetUpdateMode( bLastUpdateMode );
670 ActivateCell();
671 Invalidate();
672 }
673
GetColString(sal_Int32 nColumnId) const674 OUString DataBrowser::GetColString( sal_Int32 nColumnId ) const
675 {
676 OSL_ASSERT(m_apDataBrowserModel);
677 if( nColumnId > 0 )
678 return m_apDataBrowserModel->getRoleOfColumn( nColumnId - 1 );
679 return OUString();
680 }
681
GetCellText(sal_Int32 nRow,sal_uInt16 nColumnId) const682 OUString DataBrowser::GetCellText( sal_Int32 nRow, sal_uInt16 nColumnId ) const
683 {
684 OUString aResult;
685
686 if( nColumnId == 0 )
687 {
688 aResult = OUString::number(nRow + 1);
689 }
690 else if( nRow >= 0 && m_apDataBrowserModel)
691 {
692 sal_Int32 nColIndex = static_cast< sal_Int32 >( nColumnId ) - 1;
693
694 if( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::NUMBER )
695 {
696 double fData( m_apDataBrowserModel->getCellNumber( nColIndex, nRow ));
697
698 if( ! std::isnan( fData ) &&
699 m_spNumberFormatterWrapper )
700 {
701 bool bColorChanged = false;
702 Color nLabelColor;
703 aResult = m_spNumberFormatterWrapper->getFormattedString(
704 GetNumberFormatKey( nColumnId ),
705 fData, nLabelColor, bColorChanged );
706 }
707 }
708 else if( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::TEXTORDATE )
709 {
710 uno::Any aAny = m_apDataBrowserModel->getCellAny( nColIndex, nRow );
711 OUString aText;
712 double fDouble=0.0;
713 if( aAny>>=aText )
714 aResult = aText;
715 else if( aAny>>=fDouble )
716 {
717 if( ! std::isnan( fDouble ) && m_spNumberFormatterWrapper )
718 {
719 // If a numberformat was available here we could directly
720 // obtain the corresponding edit format in
721 // getDateTimeInputNumberFormat() instead of doing the
722 // guess work.
723 sal_Int32 nNumberFormat = DiagramHelper::getDateTimeInputNumberFormat(
724 Reference< util::XNumberFormatsSupplier >( m_xChartDoc, uno::UNO_QUERY), fDouble );
725 Color nLabelColor;
726 bool bColorChanged = false;
727 aResult = m_spNumberFormatterWrapper->getFormattedString(
728 nNumberFormat, fDouble, nLabelColor, bColorChanged );
729 }
730 }
731 }
732 else
733 {
734 OSL_ASSERT( m_apDataBrowserModel->getCellType( nColIndex ) == DataBrowserModel::TEXT );
735 aResult = m_apDataBrowserModel->getCellText( nColIndex, nRow );
736 }
737 }
738
739 return aResult;
740 }
741
GetCellNumber(sal_Int32 nRow,sal_uInt16 nColumnId) const742 double DataBrowser::GetCellNumber( sal_Int32 nRow, sal_uInt16 nColumnId ) const
743 {
744 double fResult;
745 ::rtl::math::setNan( & fResult );
746
747 if(( nColumnId >= 1 ) && ( nRow >= 0 ) && m_apDataBrowserModel)
748 {
749 fResult = m_apDataBrowserModel->getCellNumber(
750 static_cast< sal_Int32 >( nColumnId ) - 1, nRow );
751 }
752
753 return fResult;
754 }
755
Resize()756 void DataBrowser::Resize()
757 {
758 bool bLastUpdateMode = GetUpdateMode();
759 SetUpdateMode( false );
760
761 ::svt::EditBrowseBox::Resize();
762 ImplAdjustHeaderControls();
763 SetUpdateMode( bLastUpdateMode );
764 }
765
SetReadOnly(bool bNewState)766 void DataBrowser::SetReadOnly( bool bNewState )
767 {
768 if( m_bIsReadOnly != bNewState )
769 {
770 m_bIsReadOnly = bNewState;
771 Invalidate();
772 DeactivateCell();
773 }
774 }
775
CursorMoved()776 void DataBrowser::CursorMoved()
777 {
778 EditBrowseBox::CursorMoved();
779
780 if( GetUpdateMode() )
781 m_aCursorMovedHdlLink.Call( this );
782 }
783
MouseButtonDown(const BrowserMouseEvent & rEvt)784 void DataBrowser::MouseButtonDown( const BrowserMouseEvent& rEvt )
785 {
786 if( !m_bDataValid )
787 ShowWarningBox();
788 else
789 EditBrowseBox::MouseButtonDown( rEvt );
790 }
791
ShowWarningBox()792 void DataBrowser::ShowWarningBox()
793 {
794 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
795 VclMessageType::Warning, VclButtonsType::Ok,
796 SchResId(STR_INVALID_NUMBER)));
797 xWarn->run();
798 }
799
ShowQueryBox()800 bool DataBrowser::ShowQueryBox()
801 {
802 std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
803 VclMessageType::Question, VclButtonsType::YesNo,
804 SchResId(STR_DATA_EDITOR_INCORRECT_INPUT)));
805 return xQueryBox->run() == RET_YES;
806 }
807
IsDataValid() const808 bool DataBrowser::IsDataValid() const
809 {
810 bool bValid = true;
811 const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId());
812
813 if( m_apDataBrowserModel->getCellType( nCol ) == DataBrowserModel::NUMBER )
814 {
815 sal_uInt32 nDummy = 0;
816 double fDummy = 0.0;
817 OUString aText(m_aNumberEditField->get_widget().get_text());
818
819 if( !aText.isEmpty() &&
820 m_spNumberFormatterWrapper &&
821 m_spNumberFormatterWrapper->getSvNumberFormatter() &&
822 ! m_spNumberFormatterWrapper->getSvNumberFormatter()->IsNumberFormat(
823 aText, nDummy, fDummy ))
824 {
825 bValid = false;
826 }
827 }
828
829 return bValid;
830 }
831
CellModified()832 void DataBrowser::CellModified()
833 {
834 m_bDataValid = IsDataValid();
835 m_aCursorMovedHdlLink.Call( this );
836 }
837
SetDataFromModel(const Reference<chart2::XChartDocument> & xChartDoc,const Reference<uno::XComponentContext> & xContext)838 void DataBrowser::SetDataFromModel(
839 const Reference< chart2::XChartDocument > & xChartDoc,
840 const Reference< uno::XComponentContext > & xContext )
841 {
842 m_xChartDoc.set( xChartDoc );
843
844 m_apDataBrowserModel.reset( new DataBrowserModel( m_xChartDoc, xContext ));
845 m_spNumberFormatterWrapper =
846 std::make_shared<NumberFormatterWrapper>(
847 Reference< util::XNumberFormatsSupplier >( m_xChartDoc, uno::UNO_QUERY ));
848
849 Formatter& rFormatter = m_aNumberEditField->get_formatter();
850 rFormatter.SetFormatter( m_spNumberFormatterWrapper->getSvNumberFormatter() );
851
852 RenewTable();
853
854 const sal_Int32 nColCnt = m_apDataBrowserModel->getColumnCount();
855 const sal_Int32 nRowCnt = m_apDataBrowserModel->getMaxRowCount();
856 if( nRowCnt && nColCnt )
857 {
858 GoToRow( 0 );
859 GoToColumnId( 1 );
860 }
861 }
862
InsertColumn()863 void DataBrowser::InsertColumn()
864 {
865 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
866
867 if( nColIdx >= 0 && m_apDataBrowserModel)
868 {
869 // save changes made to edit-field
870 if( IsModified() )
871 SaveModified();
872
873 m_apDataBrowserModel->insertDataSeries( nColIdx );
874 RenewTable();
875 }
876 }
877
InsertTextColumn()878 void DataBrowser::InsertTextColumn()
879 {
880 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
881
882 if( nColIdx >= 0 && m_apDataBrowserModel)
883 {
884 // save changes made to edit-field
885 if( IsModified() )
886 SaveModified();
887
888 m_apDataBrowserModel->insertComplexCategoryLevel( nColIdx );
889 RenewTable();
890 }
891 }
892
RemoveColumn()893 void DataBrowser::RemoveColumn()
894 {
895 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
896
897 if( nColIdx >= 0 && m_apDataBrowserModel)
898 {
899 // save changes made to edit-field
900 if( IsModified() )
901 SaveModified();
902
903 m_bDataValid = true;
904 m_apDataBrowserModel->removeDataSeriesOrComplexCategoryLevel( nColIdx );
905 RenewTable();
906 }
907 }
908
InsertRow()909 void DataBrowser::InsertRow()
910 {
911 sal_Int32 nRowIdx = GetCurRow();
912
913 if( nRowIdx >= 0 && m_apDataBrowserModel)
914 {
915 // save changes made to edit-field
916 if( IsModified() )
917 SaveModified();
918
919 m_apDataBrowserModel->insertDataPointForAllSeries( nRowIdx );
920 RenewTable();
921 }
922 }
923
RemoveRow()924 void DataBrowser::RemoveRow()
925 {
926 sal_Int32 nRowIdx = GetCurRow();
927
928 if( nRowIdx >= 0 && m_apDataBrowserModel)
929 {
930 // save changes made to edit-field
931 if( IsModified() )
932 SaveModified();
933
934 m_bDataValid = true;
935 m_apDataBrowserModel->removeDataPointForAllSeries( nRowIdx );
936 RenewTable();
937 }
938 }
939
MoveLeftColumn()940 void DataBrowser::MoveLeftColumn()
941 {
942 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
943
944 if( !(nColIdx > 0 && m_apDataBrowserModel))
945 return;
946
947 // save changes made to edit-field
948 if( IsModified() )
949 SaveModified();
950
951 m_apDataBrowserModel->swapDataSeries( nColIdx - 1 );
952
953 // keep cursor in swapped column
954 if(( 0 < GetCurColumnId() ) && ( GetCurColumnId() <= ColCount() - 1 ))
955 {
956 Dispatch( BROWSER_CURSORLEFT );
957 }
958 RenewTable();
959 }
960
MoveRightColumn()961 void DataBrowser::MoveRightColumn()
962 {
963 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
964
965 if( !(nColIdx >= 0 && m_apDataBrowserModel))
966 return;
967
968 // save changes made to edit-field
969 if( IsModified() )
970 SaveModified();
971
972 m_apDataBrowserModel->swapDataSeries( nColIdx );
973
974 // keep cursor in swapped column
975 if( GetCurColumnId() < ColCount() - 1 )
976 {
977 Dispatch( BROWSER_CURSORRIGHT );
978 }
979 RenewTable();
980 }
981
MoveUpRow()982 void DataBrowser::MoveUpRow()
983 {
984 sal_Int32 nRowIdx = GetCurRow();
985
986 if( !(nRowIdx > 0 && m_apDataBrowserModel))
987 return;
988
989 // save changes made to edit-field
990 if( IsModified() )
991 SaveModified();
992
993 m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx - 1 );
994
995 // keep cursor in swapped row
996 if(( 0 < GetCurRow() ) && ( GetCurRow() <= GetRowCount() - 1 ))
997 {
998 Dispatch( BROWSER_CURSORUP );
999 }
1000 RenewTable();
1001 }
1002
MoveDownRow()1003 void DataBrowser::MoveDownRow()
1004 {
1005 sal_Int32 nRowIdx = GetCurRow();
1006
1007 if( !(nRowIdx >= 0 && m_apDataBrowserModel))
1008 return;
1009
1010 // save changes made to edit-field
1011 if( IsModified() )
1012 SaveModified();
1013
1014 m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx );
1015
1016 // keep cursor in swapped row
1017 if( GetCurRow() < GetRowCount() - 1 )
1018 {
1019 Dispatch( BROWSER_CURSORDOWN );
1020 }
1021 RenewTable();
1022 }
1023
SetCursorMovedHdl(const Link<DataBrowser *,void> & rLink)1024 void DataBrowser::SetCursorMovedHdl( const Link<DataBrowser*,void>& rLink )
1025 {
1026 m_aCursorMovedHdlLink = rLink;
1027 }
1028
1029 // implementations for ::svt::EditBrowseBox (pure virtual methods)
PaintCell(OutputDevice & rDev,const tools::Rectangle & rRect,sal_uInt16 nColumnId) const1030 void DataBrowser::PaintCell(
1031 OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColumnId ) const
1032 {
1033 Point aPos( rRect.TopLeft());
1034 aPos.AdjustX(1 );
1035
1036 OUString aText = GetCellText( m_nSeekRow, nColumnId );
1037 Size TxtSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight());
1038
1039 // clipping
1040 if( aPos.X() < rRect.Right() || aPos.X() + TxtSize.Width() > rRect.Right() ||
1041 aPos.Y() < rRect.Top() || aPos.Y() + TxtSize.Height() > rRect.Bottom())
1042 rDev.SetClipRegion(vcl::Region(rRect));
1043
1044 // allow for a disabled control ...
1045 bool bEnabled = IsEnabled();
1046 Color aOriginalColor = rDev.GetTextColor();
1047 if( ! bEnabled )
1048 rDev.SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
1049
1050 // draw the text
1051 rDev.DrawText( aPos, aText );
1052
1053 // reset the color (if necessary)
1054 if( ! bEnabled )
1055 rDev.SetTextColor( aOriginalColor );
1056
1057 if( rDev.IsClipRegion())
1058 rDev.SetClipRegion();
1059 }
1060
SeekRow(sal_Int32 nRow)1061 bool DataBrowser::SeekRow( sal_Int32 nRow )
1062 {
1063 if( ! EditBrowseBox::SeekRow( nRow ))
1064 return false;
1065
1066 if( nRow < 0 )
1067 m_nSeekRow = - 1;
1068 else
1069 m_nSeekRow = nRow;
1070
1071 return true;
1072 }
1073
IsTabAllowed(bool bForward) const1074 bool DataBrowser::IsTabAllowed( bool bForward ) const
1075 {
1076 sal_Int32 nRow = GetCurRow();
1077 sal_Int32 nCol = GetCurColumnId();
1078
1079 // column 0 is header-column
1080 sal_Int32 nBadCol = bForward
1081 ? GetColumnCount() - 1
1082 : 1;
1083 sal_Int32 nBadRow = bForward
1084 ? GetRowCount() - 1
1085 : 0;
1086
1087 if( !m_bDataValid )
1088 {
1089 const_cast< DataBrowser* >( this )->ShowWarningBox();
1090 return false;
1091 }
1092
1093 return ( nRow != nBadRow ||
1094 nCol != nBadCol );
1095 }
1096
GetController(sal_Int32,sal_uInt16 nCol)1097 ::svt::CellController* DataBrowser::GetController( sal_Int32 /*nRow*/, sal_uInt16 nCol )
1098 {
1099 if( m_bIsReadOnly )
1100 return nullptr;
1101
1102 if( CellContainsNumbers( nCol ))
1103 {
1104 Formatter& rFormatter = m_aNumberEditField->get_formatter();
1105 rFormatter.UseInputStringForFormatting();
1106 rFormatter.SetFormatKey( GetNumberFormatKey( nCol ));
1107 return m_rNumberEditController.get();
1108 }
1109
1110 return m_rTextEditController.get();
1111 }
1112
InitController(::svt::CellControllerRef & rController,sal_Int32 nRow,sal_uInt16 nCol)1113 void DataBrowser::InitController(
1114 ::svt::CellControllerRef& rController, sal_Int32 nRow, sal_uInt16 nCol )
1115 {
1116 if( rController == m_rTextEditController )
1117 {
1118 OUString aText( GetCellText( nRow, nCol ) );
1119 weld::Entry& rEntry = m_aTextEditField->get_widget();
1120 rEntry.set_text(aText);
1121 rEntry.select_region(0, -1);
1122 }
1123 else if( rController == m_rNumberEditController )
1124 {
1125 // treat invalid and empty text as Nan
1126 Formatter& rFormatter = m_aNumberEditField->get_formatter();
1127 rFormatter.EnableNotANumber( true );
1128 if( std::isnan( GetCellNumber( nRow, nCol )))
1129 rFormatter.SetTextValue( OUString());
1130 else
1131 rFormatter.SetValue( GetCellNumber( nRow, nCol ) );
1132 weld::Entry& rEntry = m_aNumberEditField->get_widget();
1133 rEntry.select_region(0, -1);
1134 }
1135 else
1136 {
1137 OSL_FAIL( "Invalid Controller" );
1138 }
1139 }
1140
CellContainsNumbers(sal_uInt16 nCol) const1141 bool DataBrowser::CellContainsNumbers( sal_uInt16 nCol ) const
1142 {
1143 if (!m_apDataBrowserModel)
1144 return false;
1145 return m_apDataBrowserModel->getCellType( lcl_getColumnInData( nCol )) == DataBrowserModel::NUMBER;
1146 }
1147
GetNumberFormatKey(sal_uInt16 nCol) const1148 sal_uInt32 DataBrowser::GetNumberFormatKey( sal_uInt16 nCol ) const
1149 {
1150 if (!m_apDataBrowserModel)
1151 return 0;
1152 return m_apDataBrowserModel->getNumberFormatKey( lcl_getColumnInData( nCol ) );
1153 }
1154
isDateTimeString(const OUString & aInputString,double & fOutDateTimeValue)1155 bool DataBrowser::isDateTimeString( const OUString& aInputString, double& fOutDateTimeValue )
1156 {
1157 sal_uInt32 nNumberFormat=0;
1158 SvNumberFormatter* pSvNumberFormatter = m_spNumberFormatterWrapper ? m_spNumberFormatterWrapper->getSvNumberFormatter() : nullptr;
1159 if( !aInputString.isEmpty() && pSvNumberFormatter && pSvNumberFormatter->IsNumberFormat( aInputString, nNumberFormat, fOutDateTimeValue ) )
1160 {
1161 SvNumFormatType nType = pSvNumberFormatter->GetType( nNumberFormat);
1162 return (nType & SvNumFormatType::DATE) || (nType & SvNumFormatType::TIME);
1163 }
1164 return false;
1165 }
1166
SaveModified()1167 bool DataBrowser::SaveModified()
1168 {
1169 if( ! IsModified() )
1170 return true;
1171
1172 bool bChangeValid = true;
1173
1174 const sal_Int32 nRow = GetCurRow();
1175 const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId());
1176
1177 OSL_ENSURE( nRow >= 0 || nCol >= 0, "This cell should not be modified!" );
1178
1179 SvNumberFormatter* pSvNumberFormatter = m_spNumberFormatterWrapper ? m_spNumberFormatterWrapper->getSvNumberFormatter() : nullptr;
1180 switch( m_apDataBrowserModel->getCellType( nCol ))
1181 {
1182 case DataBrowserModel::NUMBER:
1183 {
1184 sal_uInt32 nDummy = 0;
1185 double fDummy = 0.0;
1186 OUString aText(m_aNumberEditField->get_widget().get_text());
1187 // an empty string is valid, if no numberformatter exists, all
1188 // values are treated as valid
1189 if( !aText.isEmpty() && pSvNumberFormatter &&
1190 ! pSvNumberFormatter->IsNumberFormat( aText, nDummy, fDummy ) )
1191 {
1192 bChangeValid = false;
1193 }
1194 else
1195 {
1196 Formatter& rFormatter = m_aNumberEditField->get_formatter();
1197 double fData = rFormatter.GetValue();
1198 bChangeValid = m_apDataBrowserModel->setCellNumber( nCol, nRow, fData );
1199 }
1200 }
1201 break;
1202 case DataBrowserModel::TEXTORDATE:
1203 {
1204 weld::Entry& rEntry = m_aTextEditField->get_widget();
1205 OUString aText(rEntry.get_text());
1206 double fValue = 0.0;
1207 bChangeValid = false;
1208 if( isDateTimeString( aText, fValue ) )
1209 bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::Any( fValue ) );
1210 if(!bChangeValid)
1211 bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::Any( aText ) );
1212 }
1213 break;
1214 case DataBrowserModel::TEXT:
1215 {
1216 weld::Entry& rEntry = m_aTextEditField->get_widget();
1217 OUString aText(rEntry.get_text());
1218 bChangeValid = m_apDataBrowserModel->setCellText( nCol, nRow, aText );
1219 }
1220 break;
1221 }
1222
1223 // the first valid change changes this to true
1224 if( bChangeValid )
1225 {
1226 RowModified( GetCurRow(), GetCurColumnId());
1227 ::svt::CellController* pCtrl = GetController( GetCurRow(), GetCurColumnId());
1228 if( pCtrl )
1229 pCtrl->SaveValue();
1230 }
1231
1232 return bChangeValid;
1233 }
1234
EndEditing()1235 bool DataBrowser::EndEditing()
1236 {
1237 SaveModified();
1238
1239 // apply changes made to series headers
1240 for( const auto& spHeader : m_aSeriesHeaders )
1241 spHeader->applyChanges();
1242
1243 if( m_bDataValid )
1244 return true;
1245 else
1246 return ShowQueryBox();
1247 }
1248
ColumnResized(sal_uInt16 nColId)1249 void DataBrowser::ColumnResized( sal_uInt16 nColId )
1250 {
1251 bool bLastUpdateMode = GetUpdateMode();
1252 SetUpdateMode( false );
1253
1254 EditBrowseBox::ColumnResized( nColId );
1255 ImplAdjustHeaderControls();
1256 SetUpdateMode( bLastUpdateMode );
1257 }
1258
EndScroll()1259 void DataBrowser::EndScroll()
1260 {
1261 bool bLastUpdateMode = GetUpdateMode();
1262 SetUpdateMode( false );
1263
1264 EditBrowseBox::EndScroll();
1265 RenewSeriesHeaders();
1266
1267 SetUpdateMode( bLastUpdateMode );
1268 }
1269
RenewSeriesHeaders()1270 void DataBrowser::RenewSeriesHeaders()
1271 {
1272 clearHeaders();
1273 DataBrowserModel::tDataHeaderVector aHeaders( m_apDataBrowserModel->getDataHeaders());
1274 Link<impl::SeriesHeaderEdit&,void> aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus ));
1275 Link<impl::SeriesHeaderEdit&,void> aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged ));
1276
1277 for (auto const& elemHeader : aHeaders)
1278 {
1279 auto spHeader = std::make_shared<impl::SeriesHeader>( m_pColumnsWin, m_pColorsWin );
1280 Reference< beans::XPropertySet > xSeriesProp(elemHeader.m_xDataSeries, uno::UNO_QUERY);
1281 Color nColor;
1282 if( xSeriesProp.is() &&
1283 ( xSeriesProp->getPropertyValue( "Color" ) >>= nColor ))
1284 spHeader->SetColor( nColor );
1285 spHeader->SetChartType( elemHeader.m_xChartType, elemHeader.m_bSwapXAndYAxis );
1286 spHeader->SetSeriesName(
1287 DataSeriesHelper::getDataSeriesLabel(
1288 elemHeader.m_xDataSeries,
1289 (elemHeader.m_xChartType.is() ?
1290 elemHeader.m_xChartType->getRoleOfSequenceForSeriesLabel() :
1291 OUString( "values-y"))));
1292 spHeader->SetRange( elemHeader.m_nStartColumn + 1, elemHeader.m_nEndColumn + 1 );
1293 spHeader->SetGetFocusHdl( aFocusLink );
1294 spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink );
1295 m_aSeriesHeaders.push_back( spHeader );
1296 }
1297
1298 ImplAdjustHeaderControls();
1299 }
1300
ImplAdjustHeaderControls()1301 void DataBrowser::ImplAdjustHeaderControls()
1302 {
1303 sal_uInt16 nColCount = GetColumnCount();
1304 sal_uInt32 nCurrentPos = GetPosPixel().getX();
1305 sal_uInt32 nMaxPos = nCurrentPos + GetOutputSizePixel().getWidth();
1306 sal_uInt32 nStartPos = nCurrentPos;
1307
1308 // width of header column
1309 nCurrentPos += GetColumnWidth( 0 );
1310
1311 weld::Container* pWin = m_pColumnsWin;
1312 weld::Container* pColorWin = m_pColorsWin;
1313 pWin->set_margin_start(nCurrentPos);
1314 pColorWin->set_margin_start(nCurrentPos);
1315
1316 tSeriesHeaderContainer::iterator aIt( m_aSeriesHeaders.begin());
1317 sal_uInt16 i = GetFirstVisibleColNumber();
1318 while( (aIt != m_aSeriesHeaders.end()) && ((*aIt)->GetStartColumn() < i) )
1319 {
1320 (*aIt)->Hide();
1321 ++aIt;
1322 }
1323 for( ; i < nColCount && aIt != m_aSeriesHeaders.end(); ++i )
1324 {
1325 if( (*aIt)->GetStartColumn() == i )
1326 nStartPos = nCurrentPos;
1327
1328 nCurrentPos += (GetColumnWidth( i ));
1329
1330 if( (*aIt)->GetEndColumn() == i )
1331 {
1332 if( nStartPos < nMaxPos )
1333 {
1334 (*aIt)->SetPixelWidth( nCurrentPos - nStartPos );
1335 (*aIt)->Show();
1336
1337 if (pWin)
1338 {
1339 pWin->set_margin_start(nStartPos);
1340 pColorWin->set_margin_start(nStartPos);
1341 pWin = pColorWin = nullptr;
1342 }
1343
1344 }
1345 else
1346 (*aIt)->Hide();
1347 ++aIt;
1348 }
1349 }
1350 }
1351
IMPL_LINK(DataBrowser,SeriesHeaderGotFocus,impl::SeriesHeaderEdit &,rEdit,void)1352 IMPL_LINK( DataBrowser, SeriesHeaderGotFocus, impl::SeriesHeaderEdit&, rEdit, void )
1353 {
1354 rEdit.SetShowWarningBox( !m_bDataValid );
1355
1356 if( !m_bDataValid )
1357 GoToCell( 0, 0 );
1358 else
1359 {
1360 MakeFieldVisible( GetCurRow(), static_cast< sal_uInt16 >( rEdit.getStartColumn()) );
1361 ActivateCell();
1362 m_aCursorMovedHdlLink.Call( this );
1363 }
1364 }
1365
IMPL_LINK(DataBrowser,SeriesHeaderChanged,impl::SeriesHeaderEdit &,rEdit,void)1366 IMPL_LINK( DataBrowser, SeriesHeaderChanged, impl::SeriesHeaderEdit&, rEdit, void )
1367 {
1368 Reference< chart2::XDataSeries > xSeries(
1369 m_apDataBrowserModel->getDataSeriesByColumn( rEdit.getStartColumn() - 1 ));
1370 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
1371 if( !xSource.is())
1372 return;
1373
1374 Reference< chart2::XChartType > xChartType(
1375 m_apDataBrowserModel->getHeaderForSeries( xSeries ).m_xChartType );
1376 if( xChartType.is())
1377 {
1378 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
1379 DataSeriesHelper::getDataSequenceByRole( xSource, xChartType->getRoleOfSequenceForSeriesLabel()));
1380 if( xLabeledSeq.is())
1381 {
1382 Reference< container::XIndexReplace > xIndexReplace( xLabeledSeq->getLabel(), uno::UNO_QUERY );
1383 if( xIndexReplace.is())
1384 xIndexReplace->replaceByIndex(
1385 0, uno::Any( rEdit.GetText()));
1386 }
1387 }
1388 }
1389
1390 } // namespace chart
1391
1392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1393