1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <svl/zforlist.hxx>
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>
31 #include <bitmaps.hlst>
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 <osl/diagnose.h>
40 #include <toolkit/helper/vclunohelper.hxx>
42 #include <com/sun/star/util/XCloneable.hpp>
43 #include <com/sun/star/chart2/XChartDocument.hpp>
44 #include <com/sun/star/chart2/XChartType.hpp>
45 #include <com/sun/star/container/XIndexReplace.hpp>
50 using namespace ::com::sun::star
;
51 using ::com::sun::star::uno::Reference
;
53 using namespace ::svt
;
57 /* BrowserMode::COLUMNSELECTION : single cells may be selected rather than only
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
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
68 const BrowserMode BrowserStdFlags
= BrowserMode::COLUMNSELECTION
|
69 BrowserMode::HLINES
| BrowserMode::VLINES
|
70 BrowserMode::AUTO_HSCROLL
| BrowserMode::AUTO_VSCROLL
|
71 BrowserMode::HIDESELECT
;
73 sal_Int32
lcl_getRowInData( long nRow
)
75 return static_cast< sal_Int32
>( nRow
);
78 sal_Int32
lcl_getColumnInData( sal_uInt16 nCol
)
80 return static_cast< sal_Int32
>( nCol
) - 1;
83 } // anonymous namespace
91 class SeriesHeaderEdit
94 explicit SeriesHeaderEdit(std::unique_ptr
<weld::Entry
> xControl
);
96 void setStartColumn( sal_Int32 nStartColumn
);
97 sal_Int32
getStartColumn() const { return m_nStartColumn
;}
98 void SetShowWarningBox( bool bShowWarning
);
100 OUString
GetText() const { return m_xControl
->get_text(); }
101 void SetText(const OUString
& rText
) { m_xControl
->set_text(rText
); }
103 bool HasFocus() const { return m_xControl
->has_focus(); }
105 void Hide() { m_xControl
->hide(); }
106 void Show() { m_xControl
->show(); }
108 void set_size_request(int nWidth
, int nHeight
) { m_xControl
->set_size_request(nWidth
, nHeight
); }
109 void set_margin_left(int nLeft
) { m_xControl
->set_margin_left(nLeft
); }
111 void SetModifyHdl(const Link
<SeriesHeaderEdit
&,void>& rLink
) { m_aModifyHdl
= rLink
; }
112 void SetGetFocusHdl(const Link
<SeriesHeaderEdit
&,void>& rLink
) { m_aFocusInHdl
= rLink
; }
115 DECL_LINK(NameEdited
, weld::Entry
&, void);
116 DECL_LINK(NameFocusIn
, weld::Widget
&, void);
117 DECL_LINK(MousePressHdl
, const MouseEvent
&, bool);
119 std::unique_ptr
<weld::Entry
> m_xControl
;
120 Link
<SeriesHeaderEdit
&,void> m_aModifyHdl
;
121 Link
<SeriesHeaderEdit
&,void> m_aFocusInHdl
;
122 sal_Int32 m_nStartColumn
;
123 bool m_bShowWarningBox
;
126 SeriesHeaderEdit::SeriesHeaderEdit(std::unique_ptr
<weld::Entry
> xControl
)
127 : m_xControl(std::move(xControl
))
129 , m_bShowWarningBox(false)
131 m_xControl
->set_help_id(HID_SCH_DATA_SERIES_LABEL
);
132 m_xControl
->connect_changed(LINK(this, SeriesHeaderEdit
, NameEdited
));
133 m_xControl
->connect_focus_in(LINK(this, SeriesHeaderEdit
, NameFocusIn
));
134 m_xControl
->connect_mouse_press(LINK(this, SeriesHeaderEdit
, MousePressHdl
));
137 IMPL_LINK_NOARG(SeriesHeaderEdit
, NameEdited
, weld::Entry
&, void)
139 m_aModifyHdl
.Call(*this);
142 IMPL_LINK_NOARG(SeriesHeaderEdit
, NameFocusIn
, weld::Widget
&, void)
144 m_aFocusInHdl
.Call(*this);
147 void SeriesHeaderEdit::setStartColumn( sal_Int32 nStartColumn
)
149 m_nStartColumn
= nStartColumn
;
152 void SeriesHeaderEdit::SetShowWarningBox( bool bShowWarning
)
154 m_bShowWarningBox
= bShowWarning
;
157 IMPL_LINK_NOARG(SeriesHeaderEdit
, MousePressHdl
, const MouseEvent
&, bool)
159 if (m_bShowWarningBox
)
161 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(m_xControl
.get(),
162 VclMessageType::Warning
, VclButtonsType::Ok
,
163 SchResId(STR_INVALID_NUMBER
)));
173 explicit SeriesHeader(weld::Container
* pParent
, weld::Container
* pColorParent
);
176 void SetColor( const Color
& rCol
);
178 void SetWidth( sal_Int32 nWidth
);
179 void SetChartType( const Reference
< chart2::XChartType
> & xChartType
,
180 bool bSwapXAndYAxis
);
181 void SetSeriesName( const OUString
& rName
);
182 void SetRange( sal_Int32 nStartCol
, sal_Int32 nEndCol
);
184 void SetPixelWidth( sal_Int32 nWidth
);
186 sal_Int32
GetStartColumn() const { return m_nStartCol
;}
187 sal_Int32
GetEndColumn() const { return m_nEndCol
;}
189 static const sal_Int32 nSymbolHeight
= 10;
190 static const sal_Int32 nSymbolDistance
= 2;
192 static sal_Int32
GetRelativeAppFontXPosForNameField() { return nSymbolHeight
+ nSymbolDistance
; }
197 /** call this before destroying the class. This notifies the listeners to
198 changes of the edit field for the series name.
202 void SetGetFocusHdl(const Link
<SeriesHeaderEdit
&,void>& rLink
);
204 void SetEditChangedHdl( const Link
<SeriesHeaderEdit
&,void> & rLink
);
206 bool HasFocus() const;
209 Timer m_aUpdateDataTimer
;
211 std::unique_ptr
<weld::Builder
> m_xBuilder1
;
212 std::unique_ptr
<weld::Builder
> m_xBuilder2
;
214 weld::Container
* m_pParent
;
215 weld::Container
* m_pColorParent
;
217 std::unique_ptr
<weld::Container
> m_xContainer1
;
218 std::unique_ptr
<weld::Container
> m_xContainer2
;
219 std::unique_ptr
<weld::Image
> m_spSymbol
;
220 std::unique_ptr
<SeriesHeaderEdit
> m_spSeriesName
;
221 std::unique_ptr
<weld::Image
> m_spColorBar
;
222 VclPtr
< OutputDevice
> m_xDevice
;
223 Link
<SeriesHeaderEdit
&,void> m_aChangeLink
;
226 void notifyChanges();
227 DECL_LINK( ImplUpdateDataHdl
, Timer
*, void );
228 DECL_LINK( SeriesNameEdited
, SeriesHeaderEdit
&, void );
230 static OUString
GetChartTypeImage(
231 const Reference
< chart2::XChartType
> & xChartType
,
235 sal_Int32 m_nStartCol
, m_nEndCol
;
237 bool m_bSeriesNameChangePending
;
240 SeriesHeader::SeriesHeader(weld::Container
* pParent
, weld::Container
* pColorParent
)
241 : m_aUpdateDataTimer("UpdateDataTimer")
242 , m_xBuilder1(Application::CreateBuilder(pParent
, "modules/schart/ui/columnfragment.ui"))
243 , m_xBuilder2(Application::CreateBuilder(pColorParent
, "modules/schart/ui/imagefragment.ui"))
245 , m_pColorParent(pColorParent
)
246 , m_xContainer1(m_xBuilder1
->weld_container("container"))
247 , m_xContainer2(m_xBuilder2
->weld_container("container"))
248 , m_spSymbol(m_xBuilder1
->weld_image("image"))
249 , m_spSeriesName(new SeriesHeaderEdit(m_xBuilder1
->weld_entry("entry")))
250 , m_spColorBar(m_xBuilder2
->weld_image("image"))
251 , m_xDevice(Application::GetDefaultDevice())
255 , m_bSeriesNameChangePending( false )
257 m_aUpdateDataTimer
.SetInvokeHandler(LINK(this, SeriesHeader
, ImplUpdateDataHdl
));
258 m_aUpdateDataTimer
.SetDebugName( "SeriesHeader UpdateDataTimer" );
259 m_aUpdateDataTimer
.SetTimeout(4 * EDIT_UPDATEDATA_TIMEOUT
);
261 m_spSeriesName
->SetModifyHdl(LINK(this, SeriesHeader
, SeriesNameEdited
));
265 SeriesHeader::~SeriesHeader()
267 m_aUpdateDataTimer
.Stop();
268 m_pParent
->move(m_xContainer1
.get(), nullptr);
269 m_pColorParent
->move(m_xContainer2
.get(), nullptr);
272 void SeriesHeader::notifyChanges()
274 m_aChangeLink
.Call(*m_spSeriesName
);
275 m_bSeriesNameChangePending
= false;
278 void SeriesHeader::applyChanges()
280 if( m_bSeriesNameChangePending
)
286 void SeriesHeader::SetColor( const Color
& rCol
)
291 void SeriesHeader::SetPos()
294 Size
aSize( nSymbolHeight
, nSymbolHeight
);
295 aSize
= m_xDevice
->LogicToPixel(aSize
, MapMode(MapUnit::MapAppFont
));
296 m_spSymbol
->set_size_request(aSize
.Width(), aSize
.Height());
298 // series name edit field
299 aSize
.setWidth(nSymbolDistance
);
300 aSize
= m_xDevice
->LogicToPixel(aSize
, MapMode(MapUnit::MapAppFont
));
301 m_spSeriesName
->set_margin_left(aSize
.Width() + 2);
302 aSize
.setWidth( m_nWidth
- nSymbolHeight
- nSymbolDistance
);
303 sal_Int32 nHeight
= 12;
304 aSize
.setHeight( nHeight
);
305 aSize
= m_xDevice
->LogicToPixel(aSize
, MapMode(MapUnit::MapAppFont
));
306 m_spSeriesName
->set_size_request(aSize
.Width(), aSize
.Height());
310 aSize
= m_xDevice
->LogicToPixel(aSize
, MapMode(MapUnit::MapAppFont
));
311 m_spColorBar
->set_margin_left(aSize
.Width() + 2);
313 aSize
.setWidth( m_nWidth
- 1 );
314 aSize
.setHeight( nHeight
);
315 aSize
= m_xDevice
->LogicToPixel(aSize
, MapMode(MapUnit::MapAppFont
));
316 m_spColorBar
->set_size_request(aSize
.Width(), aSize
.Height());
318 auto xVirDev(m_spColorBar
->create_virtual_device());
319 xVirDev
->SetOutputSizePixel(aSize
);
320 xVirDev
->SetFillColor(m_aColor
);
321 xVirDev
->SetLineColor(m_aColor
);
322 xVirDev
->DrawRect(tools::Rectangle(Point(0, 0), aSize
));
323 m_spColorBar
->set_image(xVirDev
.get());
326 void SeriesHeader::SetWidth( sal_Int32 nWidth
)
332 void SeriesHeader::SetPixelWidth( sal_Int32 nWidth
)
334 SetWidth( m_xDevice
->PixelToLogic(Size(nWidth
, 0), MapMode(MapUnit::MapAppFont
)).getWidth());
337 void SeriesHeader::SetChartType(
338 const Reference
< chart2::XChartType
> & xChartType
,
342 m_spSymbol
->set_from_icon_name( GetChartTypeImage( xChartType
, bSwapXAndYAxis
) );
345 void SeriesHeader::SetSeriesName( const OUString
& rName
)
347 m_spSeriesName
->SetText(rName
);
350 void SeriesHeader::SetRange( sal_Int32 nStartCol
, sal_Int32 nEndCol
)
352 m_nStartCol
= nStartCol
;
353 m_nEndCol
= std::max(nEndCol
, nStartCol
);
354 m_spSeriesName
->setStartColumn( nStartCol
);
357 void SeriesHeader::Show()
360 m_spSeriesName
->Show();
361 m_spColorBar
->show();
364 void SeriesHeader::Hide()
367 m_spSeriesName
->Hide();
368 m_spColorBar
->hide();
371 void SeriesHeader::SetEditChangedHdl( const Link
<SeriesHeaderEdit
&,void> & rLink
)
373 m_aChangeLink
= rLink
;
376 IMPL_LINK_NOARG(SeriesHeader
, ImplUpdateDataHdl
, Timer
*, void)
381 IMPL_LINK_NOARG(SeriesHeader
, SeriesNameEdited
, SeriesHeaderEdit
&, void)
383 m_bSeriesNameChangePending
= true;
384 m_aUpdateDataTimer
.Start();
387 void SeriesHeader::SetGetFocusHdl( const Link
<SeriesHeaderEdit
&,void>& rLink
)
389 m_spSeriesName
->SetGetFocusHdl( rLink
);
392 bool SeriesHeader::HasFocus() const
394 return m_spSeriesName
->HasFocus();
397 OUString
SeriesHeader::GetChartTypeImage(
398 const Reference
< chart2::XChartType
> & xChartType
,
403 if( !xChartType
.is())
405 OUString
aChartTypeName( xChartType
->getChartType());
407 if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_AREA
)
409 aResult
= BMP_TYPE_AREA
;
411 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_COLUMN
)
414 aResult
= BMP_TYPE_BAR
;
416 aResult
= BMP_TYPE_COLUMN
;
418 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_LINE
)
420 aResult
= BMP_TYPE_LINE
;
422 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_SCATTER
)
424 aResult
= BMP_TYPE_XY
;
426 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_PIE
)
428 aResult
= BMP_TYPE_PIE
;
430 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_NET
431 || aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET
)
433 aResult
= BMP_TYPE_NET
;
435 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK
)
437 // @todo: correct image for candle-stick type
438 aResult
= BMP_TYPE_STOCK
;
440 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE
)
442 aResult
= BMP_TYPE_BUBBLE
;
453 /** returns false, if no header as the focus.
455 If a header has the focus, true is returned and the index of the header
456 with focus is set at pIndex if pOutIndex is not 0.
458 bool lcl_SeriesHeaderHasFocus(
459 const std::vector
< std::shared_ptr
< ::chart::impl::SeriesHeader
> > & rSeriesHeader
,
460 sal_Int32
* pOutIndex
= nullptr )
462 sal_Int32 nIndex
= 0;
463 for (auto const& elem
: rSeriesHeader
)
476 sal_Int32
lcl_getColumnInDataOrHeader(
477 sal_uInt16 nCol
, const std::vector
< std::shared_ptr
< ::chart::impl::SeriesHeader
> > & rSeriesHeader
)
479 sal_Int32 nColIdx
= 0;
480 bool bHeaderHasFocus( lcl_SeriesHeaderHasFocus( rSeriesHeader
, &nColIdx
));
482 if( bHeaderHasFocus
)
483 nColIdx
= lcl_getColumnInData( static_cast< sal_uInt16
>( rSeriesHeader
[nColIdx
]->GetStartColumn()));
485 nColIdx
= lcl_getColumnInData( nCol
);
490 } // anonymous namespace
492 DataBrowser::DataBrowser(const css::uno::Reference
<css::awt::XWindow
> &rParent
,
493 weld::Container
* pColumns
, weld::Container
* pColors
) :
494 ::svt::EditBrowseBox(VCLUnoHelper::GetWindow(rParent
),
495 EditBrowseBoxFlags::SMART_TAB_TRAVEL
| EditBrowseBoxFlags::HANDLE_COLUMN_TEXT
,
496 WB_BORDER
| WB_TABSTOP
, BrowserStdFlags
),
498 m_bIsReadOnly( false ),
499 m_bDataValid( true ),
500 m_aNumberEditField( VclPtr
<FormattedField
>::Create( & EditBrowseBox::GetDataWindow(), WB_NOBORDER
) ),
501 m_aTextEditField( VclPtr
<Edit
>::Create( & EditBrowseBox::GetDataWindow(), WB_NOBORDER
) ),
502 m_pColumnsWin(pColumns
),
503 m_pColorsWin(pColors
),
504 m_rNumberEditController( new ::svt::FormattedFieldCellController( m_aNumberEditField
.get() )),
505 m_rTextEditController( new ::svt::EditCellController( m_aTextEditField
.get() ))
508 ::rtl::math::setNan( & fNan
);
509 m_aNumberEditField
->SetDefaultValue( fNan
);
510 m_aNumberEditField
->TreatAsNumber( true );
514 DataBrowser::~DataBrowser()
519 void DataBrowser::dispose()
521 m_aSeriesHeaders
.clear();
522 m_aNumberEditField
.disposeAndClear();
523 m_aTextEditField
.disposeAndClear();
524 ::svt::EditBrowseBox::dispose();
527 bool DataBrowser::MayInsertRow() const
529 return ! IsReadOnly()
530 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
));
533 bool DataBrowser::MayInsertColumn() const
535 return ! IsReadOnly();
538 bool DataBrowser::MayDeleteRow() const
540 return ! IsReadOnly()
541 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
))
542 && ( GetCurRow() >= 0 )
543 && ( GetRowCount() > 1 );
546 bool DataBrowser::MayDeleteColumn() const
548 // if a series header has the focus
549 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
))
552 return ! IsReadOnly()
553 && ( GetCurColumnId() > 1 )
554 && ( ColCount() > 2 );
557 bool DataBrowser::MayMoveUpRows() const
559 return ! IsReadOnly()
560 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
))
561 && ( GetCurRow() > 0 )
562 && ( GetCurRow() <= GetRowCount() - 1 );
565 bool DataBrowser::MayMoveDownRows() const
567 return ! IsReadOnly()
568 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
))
569 && ( GetCurRow() >= 0 )
570 && ( GetCurRow() < GetRowCount() - 1 );
573 bool DataBrowser::MayMoveLeftColumns() const
575 // if a series header (except the last one) has the focus
577 sal_Int32
nColIndex(0);
578 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
, &nColIndex
))
579 return (static_cast< sal_uInt32
>( nColIndex
) <= (m_aSeriesHeaders
.size() - 1)) && (static_cast< sal_uInt32
>( nColIndex
) != 0);
582 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
583 return ! IsReadOnly()
585 && ( nColIdx
<= ColCount() - 2 )
586 && m_apDataBrowserModel
.get()
587 && !m_apDataBrowserModel
->isCategoriesColumn( nColIdx
);
590 bool DataBrowser::MayMoveRightColumns() const
592 // if a series header (except the last one) has the focus
594 sal_Int32
nColIndex(0);
595 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
, &nColIndex
))
596 return (static_cast< sal_uInt32
>( nColIndex
) < (m_aSeriesHeaders
.size() - 1));
599 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
600 return ! IsReadOnly()
602 && ( nColIdx
< ColCount()-2 )
603 && m_apDataBrowserModel
.get()
604 && !m_apDataBrowserModel
->isCategoriesColumn( nColIdx
);
607 void DataBrowser::clearHeaders()
609 for( const auto& spHeader
: m_aSeriesHeaders
)
610 spHeader
->applyChanges();
611 m_aSeriesHeaders
.clear();
614 void DataBrowser::RenewTable()
616 if (!m_apDataBrowserModel
)
619 long nOldRow
= GetCurRow();
620 sal_uInt16 nOldColId
= GetCurColumnId();
622 bool bLastUpdateMode
= GetUpdateMode();
623 SetUpdateMode( false );
631 RowRemoved( 1, GetRowCount() );
634 InsertHandleColumn( static_cast< sal_uInt16
>(
635 GetDataWindow().LogicToPixel( Size( 42, 0 )).getWidth() ));
637 OUString
aDefaultSeriesName(SchResId(STR_COLUMN_LABEL
));
638 replaceParamterInString( aDefaultSeriesName
, "%COLUMNNUMBER", OUString::number( 24 ) );
639 sal_Int32 nColumnWidth
= GetDataWindow().GetTextWidth( aDefaultSeriesName
)
640 + GetDataWindow().LogicToPixel(Point(8 + impl::SeriesHeader::GetRelativeAppFontXPosForNameField(), 0), MapMode(MapUnit::MapAppFont
)).X();
641 sal_Int32 nColumnCount
= m_apDataBrowserModel
->getColumnCount();
642 // nRowCount is a member of a base class
643 sal_Int32 nRowCountLocal
= m_apDataBrowserModel
->getMaxRowCount();
644 for( sal_Int32 nColIdx
=1; nColIdx
<=nColumnCount
; ++nColIdx
)
646 InsertDataColumn( static_cast< sal_uInt16
>( nColIdx
), GetColString( nColIdx
), nColumnWidth
);
649 RowInserted( 1, nRowCountLocal
);
650 GoToRow( std::min( nOldRow
, GetRowCount() - 1 ));
651 GoToColumnId( std::min( nOldColId
, static_cast< sal_uInt16
>( ColCount() - 1 )));
653 // fill series headers
655 const DataBrowserModel::tDataHeaderVector
& aHeaders( m_apDataBrowserModel
->getDataHeaders());
656 Link
<impl::SeriesHeaderEdit
&,void> aFocusLink( LINK( this, DataBrowser
, SeriesHeaderGotFocus
));
657 Link
<impl::SeriesHeaderEdit
&,void> aSeriesHeaderChangedLink( LINK( this, DataBrowser
, SeriesHeaderChanged
));
659 for (auto const& elemHeader
: aHeaders
)
661 std::shared_ptr
< impl::SeriesHeader
> spHeader( new impl::SeriesHeader( m_pColumnsWin
, m_pColorsWin
));
662 Reference
< beans::XPropertySet
> xSeriesProp( elemHeader
.m_xDataSeries
, uno::UNO_QUERY
);
663 sal_Int32 nColor
= 0;
664 // @todo: Set "DraftColor", i.e. interpolated colors for gradients, bitmaps, etc.
665 if( xSeriesProp
.is() &&
666 ( xSeriesProp
->getPropertyValue( "Color" ) >>= nColor
))
667 spHeader
->SetColor( Color( nColor
));
668 spHeader
->SetChartType( elemHeader
.m_xChartType
, elemHeader
.m_bSwapXAndYAxis
);
669 spHeader
->SetSeriesName(
670 DataSeriesHelper::getDataSeriesLabel(
671 elemHeader
.m_xDataSeries
,
672 (elemHeader
.m_xChartType
.is() ?
673 elemHeader
.m_xChartType
->getRoleOfSequenceForSeriesLabel() :
674 OUString("values-y"))));
675 // index is 1-based, as 0 is for the column that contains the row-numbers
676 spHeader
->SetRange( elemHeader
.m_nStartColumn
+ 1, elemHeader
.m_nEndColumn
+ 1 );
677 spHeader
->SetGetFocusHdl( aFocusLink
);
678 spHeader
->SetEditChangedHdl( aSeriesHeaderChangedLink
);
679 m_aSeriesHeaders
.push_back( spHeader
);
682 ImplAdjustHeaderControls();
683 SetUpdateMode( bLastUpdateMode
);
688 OUString
DataBrowser::GetColString( sal_Int32 nColumnId
) const
690 OSL_ASSERT(m_apDataBrowserModel
);
692 return m_apDataBrowserModel
->getRoleOfColumn( nColumnId
- 1 );
696 OUString
DataBrowser::GetCellText( long nRow
, sal_uInt16 nColumnId
) const
702 aResult
= OUString::number(static_cast< sal_Int32
>( nRow
) + 1);
704 else if( nRow
>= 0 && m_apDataBrowserModel
.get())
706 sal_Int32 nColIndex
= static_cast< sal_Int32
>( nColumnId
) - 1;
708 if( m_apDataBrowserModel
->getCellType( nColIndex
) == DataBrowserModel::NUMBER
)
710 double fData( m_apDataBrowserModel
->getCellNumber( nColIndex
, nRow
));
713 if( ! ::rtl::math::isNan( fData
) &&
714 m_spNumberFormatterWrapper
.get() )
716 bool bColorChanged
= false;
717 aResult
= m_spNumberFormatterWrapper
->getFormattedString(
718 GetNumberFormatKey( nColumnId
),
719 fData
, nLabelColor
, bColorChanged
);
722 else if( m_apDataBrowserModel
->getCellType( nColIndex
) == DataBrowserModel::TEXTORDATE
)
724 uno::Any aAny
= m_apDataBrowserModel
->getCellAny( nColIndex
, nRow
);
729 else if( aAny
>>=fDouble
)
731 if( ! ::rtl::math::isNan( fDouble
) && m_spNumberFormatterWrapper
.get() )
733 // If a numberformat was available here we could directly
734 // obtain the corresponding edit format in
735 // getDateTimeInputNumberFormat() instead of doing the
737 sal_Int32 nNumberFormat
= DiagramHelper::getDateTimeInputNumberFormat(
738 Reference
< util::XNumberFormatsSupplier
>( m_xChartDoc
, uno::UNO_QUERY
), fDouble
);
740 bool bColorChanged
= false;
741 aResult
= m_spNumberFormatterWrapper
->getFormattedString(
742 nNumberFormat
, fDouble
, nLabelColor
, bColorChanged
);
748 OSL_ASSERT( m_apDataBrowserModel
->getCellType( nColIndex
) == DataBrowserModel::TEXT
);
749 aResult
= m_apDataBrowserModel
->getCellText( nColIndex
, nRow
);
756 double DataBrowser::GetCellNumber( long nRow
, sal_uInt16 nColumnId
) const
759 ::rtl::math::setNan( & fResult
);
761 if(( nColumnId
>= 1 ) && ( nRow
>= 0 ) &&
762 m_apDataBrowserModel
.get())
764 fResult
= m_apDataBrowserModel
->getCellNumber(
765 static_cast< sal_Int32
>( nColumnId
) - 1, nRow
);
771 void DataBrowser::Resize()
773 bool bLastUpdateMode
= GetUpdateMode();
774 SetUpdateMode( false );
776 ::svt::EditBrowseBox::Resize();
777 ImplAdjustHeaderControls();
778 SetUpdateMode( bLastUpdateMode
);
781 void DataBrowser::SetReadOnly( bool bNewState
)
783 if( m_bIsReadOnly
!= bNewState
)
785 m_bIsReadOnly
= bNewState
;
791 void DataBrowser::CursorMoved()
793 EditBrowseBox::CursorMoved();
795 if( GetUpdateMode() )
796 m_aCursorMovedHdlLink
.Call( this );
799 void DataBrowser::MouseButtonDown( const BrowserMouseEvent
& rEvt
)
804 EditBrowseBox::MouseButtonDown( rEvt
);
807 void DataBrowser::ShowWarningBox()
809 std::unique_ptr
<weld::MessageDialog
> xWarn(Application::CreateMessageDialog(GetFrameWeld(),
810 VclMessageType::Warning
, VclButtonsType::Ok
,
811 SchResId(STR_INVALID_NUMBER
)));
815 bool DataBrowser::ShowQueryBox()
817 std::unique_ptr
<weld::MessageDialog
> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
818 VclMessageType::Question
, VclButtonsType::YesNo
,
819 SchResId(STR_DATA_EDITOR_INCORRECT_INPUT
)));
820 return xQueryBox
->run() == RET_YES
;
823 bool DataBrowser::IsDataValid() const
826 const sal_Int32 nCol
= lcl_getColumnInData( GetCurColumnId());
828 if( m_apDataBrowserModel
->getCellType( nCol
) == DataBrowserModel::NUMBER
)
830 sal_uInt32 nDummy
= 0;
832 OUString
aText( m_aNumberEditField
->GetText());
834 if( !aText
.isEmpty() &&
835 m_spNumberFormatterWrapper
.get() &&
836 m_spNumberFormatterWrapper
->getSvNumberFormatter() &&
837 ! m_spNumberFormatterWrapper
->getSvNumberFormatter()->IsNumberFormat(
838 aText
, nDummy
, fDummy
))
847 void DataBrowser::CellModified()
849 m_bDataValid
= IsDataValid();
850 m_aCursorMovedHdlLink
.Call( this );
853 void DataBrowser::SetDataFromModel(
854 const Reference
< chart2::XChartDocument
> & xChartDoc
,
855 const Reference
< uno::XComponentContext
> & xContext
)
857 m_xChartDoc
.set( xChartDoc
);
859 m_apDataBrowserModel
.reset( new DataBrowserModel( m_xChartDoc
, xContext
));
860 m_spNumberFormatterWrapper
.reset(
861 new NumberFormatterWrapper(
862 Reference
< util::XNumberFormatsSupplier
>( m_xChartDoc
, uno::UNO_QUERY
)));
864 m_aNumberEditField
->SetFormatter( m_spNumberFormatterWrapper
->getSvNumberFormatter() );
868 const sal_Int32 nColCnt
= m_apDataBrowserModel
->getColumnCount();
869 const sal_Int32 nRowCnt
= m_apDataBrowserModel
->getMaxRowCount();
870 if( nRowCnt
&& nColCnt
)
877 void DataBrowser::InsertColumn()
879 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
882 m_apDataBrowserModel
.get())
884 // save changes made to edit-field
888 m_apDataBrowserModel
->insertDataSeries( nColIdx
);
893 void DataBrowser::InsertTextColumn()
895 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
898 m_apDataBrowserModel
.get())
900 // save changes made to edit-field
904 m_apDataBrowserModel
->insertComplexCategoryLevel( nColIdx
);
909 void DataBrowser::RemoveColumn()
911 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
914 m_apDataBrowserModel
.get())
916 // save changes made to edit-field
921 m_apDataBrowserModel
->removeDataSeriesOrComplexCategoryLevel( nColIdx
);
926 void DataBrowser::InsertRow()
928 sal_Int32 nRowIdx
= lcl_getRowInData( GetCurRow());
931 m_apDataBrowserModel
.get())
933 // save changes made to edit-field
937 m_apDataBrowserModel
->insertDataPointForAllSeries( nRowIdx
);
942 void DataBrowser::RemoveRow()
944 sal_Int32 nRowIdx
= lcl_getRowInData( GetCurRow());
947 m_apDataBrowserModel
.get())
949 // save changes made to edit-field
954 m_apDataBrowserModel
->removeDataPointForAllSeries( nRowIdx
);
959 void DataBrowser::MoveLeftColumn()
961 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
964 m_apDataBrowserModel
.get())
966 // save changes made to edit-field
970 m_apDataBrowserModel
->swapDataSeries( nColIdx
- 1 );
972 // keep cursor in swapped column
973 if(( 0 < GetCurColumnId() ) && ( GetCurColumnId() <= ColCount() - 1 ))
975 Dispatch( BROWSER_CURSORLEFT
);
981 void DataBrowser::MoveRightColumn()
983 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
986 m_apDataBrowserModel
.get())
988 // save changes made to edit-field
992 m_apDataBrowserModel
->swapDataSeries( nColIdx
);
994 // keep cursor in swapped column
995 if( GetCurColumnId() < ColCount() - 1 )
997 Dispatch( BROWSER_CURSORRIGHT
);
1003 void DataBrowser::MoveUpRow()
1005 sal_Int32 nRowIdx
= lcl_getRowInData( GetCurRow());
1008 m_apDataBrowserModel
.get())
1010 // save changes made to edit-field
1014 m_apDataBrowserModel
->swapDataPointForAllSeries( nRowIdx
- 1 );
1016 // keep cursor in swapped row
1017 if(( 0 < GetCurRow() ) && ( GetCurRow() <= GetRowCount() - 1 ))
1019 Dispatch( BROWSER_CURSORUP
);
1025 void DataBrowser::MoveDownRow()
1027 sal_Int32 nRowIdx
= lcl_getRowInData( GetCurRow());
1030 m_apDataBrowserModel
.get())
1032 // save changes made to edit-field
1036 m_apDataBrowserModel
->swapDataPointForAllSeries( nRowIdx
);
1038 // keep cursor in swapped row
1039 if( GetCurRow() < GetRowCount() - 1 )
1041 Dispatch( BROWSER_CURSORDOWN
);
1047 void DataBrowser::SetCursorMovedHdl( const Link
<DataBrowser
*,void>& rLink
)
1049 m_aCursorMovedHdlLink
= rLink
;
1052 // implementations for ::svt::EditBrowseBox (pure virtual methods)
1053 void DataBrowser::PaintCell(
1054 OutputDevice
& rDev
, const tools::Rectangle
& rRect
, sal_uInt16 nColumnId
) const
1056 Point
aPos( rRect
.TopLeft());
1059 OUString aText
= GetCellText( m_nSeekRow
, nColumnId
);
1060 Size
TxtSize( GetDataWindow().GetTextWidth( aText
), GetDataWindow().GetTextHeight());
1063 if( aPos
.X() < rRect
.Right() || aPos
.X() + TxtSize
.Width() > rRect
.Right() ||
1064 aPos
.Y() < rRect
.Top() || aPos
.Y() + TxtSize
.Height() > rRect
.Bottom())
1065 rDev
.SetClipRegion(vcl::Region(rRect
));
1067 // allow for a disabled control ...
1068 bool bEnabled
= IsEnabled();
1069 Color aOriginalColor
= rDev
.GetTextColor();
1071 rDev
.SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
1074 rDev
.DrawText( aPos
, aText
);
1076 // reset the color (if necessary)
1078 rDev
.SetTextColor( aOriginalColor
);
1080 if( rDev
.IsClipRegion())
1081 rDev
.SetClipRegion();
1084 bool DataBrowser::SeekRow( long nRow
)
1086 if( ! EditBrowseBox::SeekRow( nRow
))
1097 bool DataBrowser::IsTabAllowed( bool bForward
) const
1099 long nRow
= GetCurRow();
1100 long nCol
= GetCurColumnId();
1102 // column 0 is header-column
1103 long nBadCol
= bForward
1104 ? GetColumnCount() - 1
1106 long nBadRow
= bForward
1112 const_cast< DataBrowser
* >( this )->ShowWarningBox();
1116 return ( nRow
!= nBadRow
||
1120 ::svt::CellController
* DataBrowser::GetController( long /*nRow*/, sal_uInt16 nCol
)
1125 if( CellContainsNumbers( nCol
))
1127 m_aNumberEditField
->UseInputStringForFormatting();
1128 m_aNumberEditField
->SetFormatKey( GetNumberFormatKey( nCol
));
1129 return m_rNumberEditController
.get();
1132 return m_rTextEditController
.get();
1135 void DataBrowser::InitController(
1136 ::svt::CellControllerRef
& rController
, long nRow
, sal_uInt16 nCol
)
1138 if( rController
== m_rTextEditController
)
1140 OUString
aText( GetCellText( nRow
, nCol
) );
1141 m_aTextEditField
->SetText( aText
);
1142 m_aTextEditField
->SetSelection( Selection( 0, aText
.getLength() ));
1144 else if( rController
== m_rNumberEditController
)
1146 // treat invalid and empty text as Nan
1147 m_aNumberEditField
->EnableNotANumber( true );
1148 if( ::rtl::math::isNan( GetCellNumber( nRow
, nCol
)))
1149 m_aNumberEditField
->SetTextValue( OUString());
1151 m_aNumberEditField
->SetValue( GetCellNumber( nRow
, nCol
) );
1152 OUString
aText( m_aNumberEditField
->GetText());
1153 m_aNumberEditField
->SetSelection( Selection( 0, aText
.getLength()));
1157 OSL_FAIL( "Invalid Controller" );
1161 bool DataBrowser::CellContainsNumbers( sal_uInt16 nCol
) const
1163 if (!m_apDataBrowserModel
)
1165 return m_apDataBrowserModel
->getCellType( lcl_getColumnInData( nCol
)) == DataBrowserModel::NUMBER
;
1168 sal_uInt32
DataBrowser::GetNumberFormatKey( sal_uInt16 nCol
) const
1170 if (!m_apDataBrowserModel
)
1172 return m_apDataBrowserModel
->getNumberFormatKey( lcl_getColumnInData( nCol
) );
1175 bool DataBrowser::isDateTimeString( const OUString
& aInputString
, double& fOutDateTimeValue
)
1177 sal_uInt32 nNumberFormat
=0;
1178 SvNumberFormatter
* pSvNumberFormatter
= m_spNumberFormatterWrapper
.get() ? m_spNumberFormatterWrapper
->getSvNumberFormatter() : nullptr;
1179 if( !aInputString
.isEmpty() && pSvNumberFormatter
&& pSvNumberFormatter
->IsNumberFormat( aInputString
, nNumberFormat
, fOutDateTimeValue
) )
1181 SvNumFormatType nType
= pSvNumberFormatter
->GetType( nNumberFormat
);
1182 return (nType
& SvNumFormatType::DATE
) || (nType
& SvNumFormatType::TIME
);
1187 bool DataBrowser::SaveModified()
1189 if( ! IsModified() )
1192 bool bChangeValid
= true;
1194 const sal_Int32 nRow
= lcl_getRowInData( GetCurRow());
1195 const sal_Int32 nCol
= lcl_getColumnInData( GetCurColumnId());
1197 OSL_ENSURE( nRow
>= 0 || nCol
>= 0, "This cell should not be modified!" );
1199 SvNumberFormatter
* pSvNumberFormatter
= m_spNumberFormatterWrapper
.get() ? m_spNumberFormatterWrapper
->getSvNumberFormatter() : nullptr;
1200 switch( m_apDataBrowserModel
->getCellType( nCol
))
1202 case DataBrowserModel::NUMBER
:
1204 sal_uInt32 nDummy
= 0;
1205 double fDummy
= 0.0;
1206 OUString
aText( m_aNumberEditField
->GetText());
1207 // an empty string is valid, if no numberformatter exists, all
1208 // values are treated as valid
1209 if( !aText
.isEmpty() && pSvNumberFormatter
&&
1210 ! pSvNumberFormatter
->IsNumberFormat( aText
, nDummy
, fDummy
) )
1212 bChangeValid
= false;
1216 double fData
= m_aNumberEditField
->GetValue();
1217 bChangeValid
= m_apDataBrowserModel
->setCellNumber( nCol
, nRow
, fData
);
1221 case DataBrowserModel::TEXTORDATE
:
1223 OUString
aText( m_aTextEditField
->GetText() );
1224 double fValue
= 0.0;
1225 bChangeValid
= false;
1226 if( isDateTimeString( aText
, fValue
) )
1227 bChangeValid
= m_apDataBrowserModel
->setCellAny( nCol
, nRow
, uno::Any( fValue
) );
1229 bChangeValid
= m_apDataBrowserModel
->setCellAny( nCol
, nRow
, uno::Any( aText
) );
1232 case DataBrowserModel::TEXT
:
1234 OUString
aText( m_aTextEditField
->GetText());
1235 bChangeValid
= m_apDataBrowserModel
->setCellText( nCol
, nRow
, aText
);
1240 // the first valid change changes this to true
1243 RowModified( GetCurRow(), GetCurColumnId());
1244 ::svt::CellController
* pCtrl
= GetController( GetCurRow(), GetCurColumnId());
1246 pCtrl
->ClearModified();
1249 return bChangeValid
;
1252 bool DataBrowser::EndEditing()
1256 // apply changes made to series headers
1257 for( const auto& spHeader
: m_aSeriesHeaders
)
1258 spHeader
->applyChanges();
1263 return ShowQueryBox();
1266 void DataBrowser::ColumnResized( sal_uInt16 nColId
)
1268 bool bLastUpdateMode
= GetUpdateMode();
1269 SetUpdateMode( false );
1271 EditBrowseBox::ColumnResized( nColId
);
1272 ImplAdjustHeaderControls();
1273 SetUpdateMode( bLastUpdateMode
);
1276 void DataBrowser::EndScroll()
1278 bool bLastUpdateMode
= GetUpdateMode();
1279 SetUpdateMode( false );
1281 EditBrowseBox::EndScroll();
1282 RenewSeriesHeaders();
1284 SetUpdateMode( bLastUpdateMode
);
1287 void DataBrowser::RenewSeriesHeaders()
1290 DataBrowserModel::tDataHeaderVector
aHeaders( m_apDataBrowserModel
->getDataHeaders());
1291 Link
<impl::SeriesHeaderEdit
&,void> aFocusLink( LINK( this, DataBrowser
, SeriesHeaderGotFocus
));
1292 Link
<impl::SeriesHeaderEdit
&,void> aSeriesHeaderChangedLink( LINK( this, DataBrowser
, SeriesHeaderChanged
));
1294 for (auto const& elemHeader
: aHeaders
)
1296 std::shared_ptr
< impl::SeriesHeader
> spHeader( new impl::SeriesHeader( m_pColumnsWin
, m_pColorsWin
));
1297 Reference
< beans::XPropertySet
> xSeriesProp(elemHeader
.m_xDataSeries
, uno::UNO_QUERY
);
1298 sal_Int32 nColor
= 0;
1299 if( xSeriesProp
.is() &&
1300 ( xSeriesProp
->getPropertyValue( "Color" ) >>= nColor
))
1301 spHeader
->SetColor( Color( nColor
));
1302 spHeader
->SetChartType( elemHeader
.m_xChartType
, elemHeader
.m_bSwapXAndYAxis
);
1303 spHeader
->SetSeriesName(
1304 DataSeriesHelper::getDataSeriesLabel(
1305 elemHeader
.m_xDataSeries
,
1306 (elemHeader
.m_xChartType
.is() ?
1307 elemHeader
.m_xChartType
->getRoleOfSequenceForSeriesLabel() :
1308 OUString( "values-y"))));
1309 spHeader
->SetRange( elemHeader
.m_nStartColumn
+ 1, elemHeader
.m_nEndColumn
+ 1 );
1310 spHeader
->SetGetFocusHdl( aFocusLink
);
1311 spHeader
->SetEditChangedHdl( aSeriesHeaderChangedLink
);
1312 m_aSeriesHeaders
.push_back( spHeader
);
1315 ImplAdjustHeaderControls();
1318 void DataBrowser::ImplAdjustHeaderControls()
1320 sal_uInt16 nColCount
= GetColumnCount();
1321 sal_uInt32 nCurrentPos
= GetPosPixel().getX();
1322 sal_uInt32 nMaxPos
= nCurrentPos
+ GetOutputSizePixel().getWidth();
1323 sal_uInt32 nStartPos
= nCurrentPos
;
1325 // width of header column
1326 nCurrentPos
+= GetColumnWidth( 0 );
1328 weld::Container
* pWin
= m_pColumnsWin
;
1329 weld::Container
* pColorWin
= m_pColorsWin
;
1330 pWin
->set_margin_left(nCurrentPos
);
1331 pColorWin
->set_margin_left(nCurrentPos
);
1333 tSeriesHeaderContainer::iterator
aIt( m_aSeriesHeaders
.begin());
1334 sal_uInt16 i
= GetFirstVisibleColNumber();
1335 while( (aIt
!= m_aSeriesHeaders
.end()) && ((*aIt
)->GetStartColumn() < i
) )
1340 for( ; i
< nColCount
&& aIt
!= m_aSeriesHeaders
.end(); ++i
)
1342 if( (*aIt
)->GetStartColumn() == i
)
1343 nStartPos
= nCurrentPos
;
1345 nCurrentPos
+= (GetColumnWidth( i
));
1347 if( (*aIt
)->GetEndColumn() == i
)
1349 if( nStartPos
< nMaxPos
)
1351 (*aIt
)->SetPixelWidth( nCurrentPos
- nStartPos
- 3 );
1356 pWin
->set_margin_left(nStartPos
);
1357 pColorWin
->set_margin_left(nStartPos
);
1358 pWin
= pColorWin
= nullptr;
1369 IMPL_LINK( DataBrowser
, SeriesHeaderGotFocus
, impl::SeriesHeaderEdit
&, rEdit
, void )
1371 rEdit
.SetShowWarningBox( !m_bDataValid
);
1377 MakeFieldVisible( GetCurRow(), static_cast< sal_uInt16
>( rEdit
.getStartColumn()) );
1379 m_aCursorMovedHdlLink
.Call( this );
1383 IMPL_LINK( DataBrowser
, SeriesHeaderChanged
, impl::SeriesHeaderEdit
&, rEdit
, void )
1385 Reference
< chart2::XDataSeries
> xSeries(
1386 m_apDataBrowserModel
->getDataSeriesByColumn( rEdit
.getStartColumn() - 1 ));
1387 Reference
< chart2::data::XDataSource
> xSource( xSeries
, uno::UNO_QUERY
);
1390 Reference
< chart2::XChartType
> xChartType(
1391 m_apDataBrowserModel
->getHeaderForSeries( xSeries
).m_xChartType
);
1392 if( xChartType
.is())
1394 Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq(
1395 DataSeriesHelper::getDataSequenceByRole( xSource
, xChartType
->getRoleOfSequenceForSeriesLabel()));
1396 if( xLabeledSeq
.is())
1398 Reference
< container::XIndexReplace
> xIndexReplace( xLabeledSeq
->getLabel(), uno::UNO_QUERY
);
1399 if( xIndexReplace
.is())
1400 xIndexReplace
->replaceByIndex(
1401 0, uno::Any( rEdit
.GetText()));
1407 } // namespace chart
1409 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */