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/zformat.hxx>
21 #include <svl/zforlist.hxx>
23 #include "DataBrowser.hxx"
24 #include "DataBrowserModel.hxx"
25 #include "Strings.hrc"
26 #include "ContainerHelper.hxx"
27 #include "DataSeriesHelper.hxx"
28 #include "DiagramHelper.hxx"
29 #include "ChartModelHelper.hxx"
30 #include "CommonConverters.hxx"
32 #include "NumberFormatterWrapper.hxx"
33 #include "servicenames_charttypes.hxx"
35 #include "Bitmaps.hrc"
36 #include "HelpIds.hrc"
38 #include <vcl/fixed.hxx>
39 #include <vcl/image.hxx>
40 #include <vcl/layout.hxx>
41 #include <vcl/msgbox.hxx>
42 #include <vcl/settings.hxx>
43 #include <rtl/math.hxx>
45 #include <com/sun/star/util/XCloneable.hpp>
46 #include <com/sun/star/chart2/XChartDocument.hpp>
47 #include <com/sun/star/chart2/XChartType.hpp>
49 #include <com/sun/star/container/XIndexReplace.hpp>
50 #include <com/sun/star/util/XNumberFormats.hpp>
55 /* BrowserMode::COLUMNSELECTION : single cells may be selected rather than only
57 BROWSER_(H|V)LINES : show horizontal or vertical grid-lines
59 BROWSER_AUTO_(H|V)SCROLL : scroll automated horizontally or vertically when
60 cursor is moved beyond the edge of the dialog
61 BrowserMode::HIDESELECT : Do not mark the current row with selection color
65 #define BROWSER_STANDARD_FLAGS \
66 BrowserMode::COLUMNSELECTION | \
67 BrowserMode::HLINES | BrowserMode::VLINES | \
68 BrowserMode::AUTO_HSCROLL | BrowserMode::AUTO_VSCROLL | \
69 BrowserMode::HIDESELECT
71 // BrowserMode::HIDECURSOR would prevent flickering in edit fields, but navigating
72 // with shift up/down, and entering non-editable cells would be problematic,
73 // e.g. the first cell, or when being in read-only mode
75 using namespace ::com::sun::star
;
76 using ::com::sun::star::uno::Sequence
;
77 using ::com::sun::star::uno::Reference
;
79 using namespace ::svt
;
83 sal_Int32
lcl_getRowInData( long nRow
)
85 return static_cast< sal_Int32
>( nRow
);
88 sal_Int32
lcl_getColumnInData( sal_uInt16 nCol
)
90 return static_cast< sal_Int32
>( nCol
) - 1;
93 } // anonymous namespace
101 class SeriesHeaderEdit
: public Edit
104 SeriesHeaderEdit( vcl::Window
* pParent
);
105 virtual void MouseButtonDown( const MouseEvent
& rMEvt
) SAL_OVERRIDE
;
107 void setStartColumn( sal_Int32 nStartColumn
);
108 sal_Int32
getStartColumn() const { return m_nStartColumn
;}
109 void SetShowWarningBox( bool bShowWarning
= true );
112 sal_Int32 m_nStartColumn
;
113 bool m_bShowWarningBox
;
116 SeriesHeaderEdit::SeriesHeaderEdit( vcl::Window
* pParent
) :
119 m_bShowWarningBox( false )
121 SetHelpId(HID_SCH_DATA_SERIES_LABEL
);
124 void SeriesHeaderEdit::setStartColumn( sal_Int32 nStartColumn
)
126 m_nStartColumn
= nStartColumn
;
129 void SeriesHeaderEdit::SetShowWarningBox( bool bShowWarning
)
131 m_bShowWarningBox
= bShowWarning
;
134 void SeriesHeaderEdit::MouseButtonDown( const MouseEvent
& rMEvt
)
136 Edit::MouseButtonDown( rMEvt
);
138 if( m_bShowWarningBox
)
139 ScopedVclPtr
<WarningBox
>::Create(this, WinBits( WB_OK
),
140 SCH_RESSTR(STR_INVALID_NUMBER
))->Execute();
146 explicit SeriesHeader(vcl::Window
* pParent
, vcl::Window
*pColorParent
);
149 void SetColor( const Color
& rCol
);
150 void SetPos( const Point
& rPos
);
151 void SetWidth( sal_Int32 nWidth
);
152 void SetChartType( const Reference
< chart2::XChartType
> & xChartType
,
153 bool bSwapXAndYAxis
);
154 void SetSeriesName( const OUString
& rName
);
155 void SetRange( sal_Int32 nStartCol
, sal_Int32 nEndCol
);
157 void SetPixelWidth( sal_Int32 nWidth
);
159 sal_Int32
GetStartColumn() const { return m_nStartCol
;}
160 sal_Int32
GetEndColumn() const { return m_nEndCol
;}
162 static const sal_Int32 nSymbolHeight
= 10;
163 static const sal_Int32 nSymbolDistance
= 2;
165 static sal_Int32
GetRelativeAppFontXPosForNameField() { return nSymbolHeight
+ nSymbolDistance
; }
170 /** call this before destroying the class. This notifies the listeners to
171 changes of the edit field for the series name.
175 void SetGetFocusHdl( const Link
<>& rLink
);
177 void SetEditChangedHdl( const Link
<> & rLink
);
179 bool HasFocus() const;
182 VclPtr
< FixedImage
> m_spSymbol
;
183 VclPtr
< SeriesHeaderEdit
> m_spSeriesName
;
184 VclPtr
< FixedText
> m_spColorBar
;
185 VclPtr
< OutputDevice
> m_pDevice
;
186 Link
<> m_aChangeLink
;
188 void notifyChanges();
189 DECL_LINK( SeriesNameChanged
, void * );
190 DECL_LINK( SeriesNameEdited
, void * );
192 static Image
GetChartTypeImage(
193 const Reference
< chart2::XChartType
> & xChartType
,
197 sal_Int32 m_nStartCol
, m_nEndCol
;
200 bool m_bSeriesNameChangePending
;
203 SeriesHeader::SeriesHeader( vcl::Window
* pParent
, vcl::Window
*pColorParent
) :
204 m_spSymbol( VclPtr
<FixedImage
>::Create( pParent
, WB_NOBORDER
)),
205 m_spSeriesName( VclPtr
<SeriesHeaderEdit
>::Create( pParent
)),
206 m_spColorBar( VclPtr
<FixedText
>::Create( pColorParent
, WB_NOBORDER
)),
207 m_pDevice( pParent
),
212 m_bSeriesNameChangePending( false )
214 m_spSeriesName
->EnableUpdateData( 4 * EDIT_UPDATEDATA_TIMEOUT
); // define is in vcl/edit.hxx
215 m_spSeriesName
->SetUpdateDataHdl( LINK( this, SeriesHeader
, SeriesNameChanged
));
216 m_spSeriesName
->SetModifyHdl( LINK( this, SeriesHeader
, SeriesNameEdited
));
217 m_spSeriesName
->SetHelpId( HID_SCH_DATA_SERIES_LABEL
);
221 SeriesHeader::~SeriesHeader()
223 m_spSymbol
.disposeAndClear();
224 m_spSeriesName
.disposeAndClear();
225 m_spColorBar
.disposeAndClear();
228 void SeriesHeader::notifyChanges()
230 if( m_aChangeLink
.IsSet())
231 m_aChangeLink
.Call( m_spSeriesName
.get());
233 m_bSeriesNameChangePending
= false;
236 void SeriesHeader::applyChanges()
238 if( m_bSeriesNameChangePending
)
244 void SeriesHeader::SetColor( const Color
& rCol
)
246 m_spColorBar
->SetControlBackground( rCol
);
249 void SeriesHeader::SetPos( const Point
& rPos
)
254 Size
aSize( nSymbolHeight
, nSymbolHeight
);
255 aSize
= m_pDevice
->LogicToPixel( aSize
, MAP_APPFONT
);
256 m_spSymbol
->set_width_request(aSize
.Width());
257 m_spSymbol
->set_height_request(aSize
.Height());
259 // series name edit field
260 aSize
.setWidth(nSymbolDistance
);
261 aSize
= m_pDevice
->LogicToPixel( aSize
, MAP_APPFONT
);
262 m_spSeriesName
->set_margin_left(aSize
.Width() + 2);
263 aSize
.setWidth( m_nWidth
- nSymbolHeight
- nSymbolDistance
);
264 sal_Int32 nHeight
= 12;
265 aSize
.setHeight( nHeight
);
266 aSize
= m_pDevice
->LogicToPixel( aSize
, MAP_APPFONT
);
267 m_spSeriesName
->set_width_request(aSize
.Width());
268 m_spSeriesName
->set_height_request(aSize
.Height());
272 aSize
= m_pDevice
->LogicToPixel( aSize
, MAP_APPFONT
);
273 m_spColorBar
->set_margin_left(aSize
.Width() + 2);
275 aSize
.setWidth( m_nWidth
- 1 );
276 aSize
.setHeight( nHeight
);
277 aSize
= m_pDevice
->LogicToPixel( aSize
, MAP_APPFONT
);
278 m_spColorBar
->set_width_request(aSize
.Width());
279 m_spColorBar
->set_height_request(aSize
.Height());
282 void SeriesHeader::SetWidth( sal_Int32 nWidth
)
288 void SeriesHeader::SetPixelWidth( sal_Int32 nWidth
)
290 SetWidth( m_pDevice
->PixelToLogic( Size( nWidth
, 0 ), MAP_APPFONT
).getWidth());
293 void SeriesHeader::SetChartType(
294 const Reference
< chart2::XChartType
> & xChartType
,
298 m_spSymbol
->SetImage( GetChartTypeImage( xChartType
, bSwapXAndYAxis
) );
301 void SeriesHeader::SetSeriesName( const OUString
& rName
)
303 m_spSeriesName
->SetText( rName
);
306 void SeriesHeader::SetRange( sal_Int32 nStartCol
, sal_Int32 nEndCol
)
308 m_nStartCol
= nStartCol
;
309 m_nEndCol
= (nEndCol
> nStartCol
) ? nEndCol
: nStartCol
;
310 m_spSeriesName
->setStartColumn( nStartCol
);
313 void SeriesHeader::Show()
316 m_spSeriesName
->Show();
317 m_spColorBar
->Show();
320 void SeriesHeader::Hide()
323 m_spSeriesName
->Hide();
324 m_spColorBar
->Hide();
327 void SeriesHeader::SetEditChangedHdl( const Link
<> & rLink
)
329 m_aChangeLink
= rLink
;
332 IMPL_LINK_NOARG(SeriesHeader
, SeriesNameChanged
)
338 IMPL_LINK_NOARG(SeriesHeader
, SeriesNameEdited
)
340 m_bSeriesNameChangePending
= true;
344 void SeriesHeader::SetGetFocusHdl( const Link
<>& rLink
)
346 m_spSeriesName
->SetGetFocusHdl( rLink
);
349 bool SeriesHeader::HasFocus() const
351 return m_spSeriesName
->HasFocus();
354 Image
SeriesHeader::GetChartTypeImage(
355 const Reference
< chart2::XChartType
> & xChartType
,
360 if( !xChartType
.is())
362 OUString
aChartTypeName( xChartType
->getChartType());
364 if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_AREA
)
366 aResult
= Image( SchResId( IMG_TYPE_AREA
) );
368 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_COLUMN
)
371 aResult
= Image( SchResId( IMG_TYPE_BAR
) );
373 aResult
= Image( SchResId( IMG_TYPE_COLUMN
) );
375 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_LINE
)
377 aResult
= Image( SchResId( IMG_TYPE_LINE
) );
379 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_SCATTER
)
381 aResult
= Image( SchResId( IMG_TYPE_XY
) );
383 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_PIE
)
385 aResult
= Image( SchResId( IMG_TYPE_PIE
) );
387 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_NET
388 || aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET
)
390 aResult
= Image( SchResId( IMG_TYPE_NET
) );
392 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK
)
394 // @todo: correct image for candle-stick type
395 aResult
= Image( SchResId( IMG_TYPE_STOCK
) );
397 else if( aChartTypeName
== CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE
)
399 aResult
= Image( SchResId( IMG_TYPE_BUBBLE
) );
405 struct applyChangesFunctor
: public ::std::unary_function
< ::boost::shared_ptr
< SeriesHeader
>, void >
407 void operator() ( ::boost::shared_ptr
< SeriesHeader
> spHeader
)
409 spHeader
->applyChanges();
418 /** returns false, if no header as the focus.
420 If a header has the focus, true is returned and the index of the header
421 with focus is set at pIndex if pOutIndex is not 0.
423 bool lcl_SeriesHeaderHasFocus(
424 const ::std::vector
< ::boost::shared_ptr
< ::chart::impl::SeriesHeader
> > & rSeriesHeader
,
425 sal_Int32
* pOutIndex
= 0 )
427 sal_Int32 nIndex
= 0;
428 for( auto aIt
= rSeriesHeader
.begin(); aIt
!= rSeriesHeader
.end(); ++aIt
, ++nIndex
)
430 if( (*aIt
)->HasFocus())
440 sal_Int32
lcl_getColumnInDataOrHeader(
441 sal_uInt16 nCol
, const ::std::vector
< ::boost::shared_ptr
< ::chart::impl::SeriesHeader
> > & rSeriesHeader
)
443 sal_Int32 nColIdx
= 0;
444 bool bHeaderHasFocus( lcl_SeriesHeaderHasFocus( rSeriesHeader
, &nColIdx
));
446 if( bHeaderHasFocus
)
447 nColIdx
= lcl_getColumnInData( static_cast< sal_uInt16
>( rSeriesHeader
[nColIdx
]->GetStartColumn()));
449 nColIdx
= lcl_getColumnInData( nCol
);
454 } // anonymous namespace
456 DataBrowser::DataBrowser( vcl::Window
* pParent
, WinBits nStyle
, bool bLiveUpdate
) :
457 ::svt::EditBrowseBox( pParent
, EditBrowseBoxFlags::SMART_TAB_TRAVEL
| EditBrowseBoxFlags::HANDLE_COLUMN_TEXT
, nStyle
, BROWSER_STANDARD_FLAGS
),
459 m_bIsReadOnly( false ),
461 m_bLiveUpdate( bLiveUpdate
),
462 m_bDataValid( true ),
463 m_aNumberEditField( VclPtr
<FormattedField
>::Create( & EditBrowseBox::GetDataWindow(), WB_NOBORDER
) ),
464 m_aTextEditField( VclPtr
<Edit
>::Create( & EditBrowseBox::GetDataWindow(), WB_NOBORDER
) ),
465 m_rNumberEditController( new ::svt::FormattedFieldCellController( m_aNumberEditField
.get() )),
466 m_rTextEditController( new ::svt::EditCellController( m_aTextEditField
.get() ))
469 ::rtl::math::setNan( & fNan
);
470 m_aNumberEditField
->SetDefaultValue( fNan
);
471 m_aNumberEditField
->TreatAsNumber( true );
476 DataBrowser::~DataBrowser()
481 void DataBrowser::dispose()
483 m_aNumberEditField
.disposeAndClear();
484 m_aTextEditField
.disposeAndClear();
485 ::svt::EditBrowseBox::dispose();
488 bool DataBrowser::MayInsertRow() const
490 return ! IsReadOnly()
491 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
));
494 bool DataBrowser::MayInsertColumn() const
496 return ! IsReadOnly();
499 bool DataBrowser::MayDeleteRow() const
501 return ! IsReadOnly()
502 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
))
503 && ( GetCurRow() >= 0 )
504 && ( GetRowCount() > 1 );
507 bool DataBrowser::MayDeleteColumn() const
509 // if a series header has the focus
510 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
))
513 return ! IsReadOnly()
514 && ( GetCurColumnId() > 1 )
515 && ( ColCount() > 2 );
518 bool DataBrowser::MaySwapRows() const
520 return ! IsReadOnly()
521 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
))
522 && ( GetCurRow() >= 0 )
523 && ( GetCurRow() < GetRowCount() - 1 );
526 bool DataBrowser::MaySwapColumns() const
528 // if a series header (except the last one) has the focus
530 sal_Int32
nColIndex(0);
531 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders
, &nColIndex
))
532 return (static_cast< sal_uInt32
>( nColIndex
) < (m_aSeriesHeaders
.size() - 1));
535 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
536 return ! IsReadOnly()
538 && ( nColIdx
< ColCount()-2 )
539 && m_apDataBrowserModel
.get()
540 && !m_apDataBrowserModel
->isCategoriesColumn( nColIdx
);
543 void DataBrowser::clearHeaders()
545 ::std::for_each( m_aSeriesHeaders
.begin(), m_aSeriesHeaders
.end(), impl::applyChangesFunctor());
546 m_aSeriesHeaders
.clear();
549 void DataBrowser::RenewTable()
551 if( ! m_apDataBrowserModel
.get())
554 long nOldRow
= GetCurRow();
555 sal_uInt16 nOldColId
= GetCurColumnId();
557 bool bLastUpdateMode
= GetUpdateMode();
558 SetUpdateMode( false );
566 RowRemoved( 1, GetRowCount() );
569 InsertHandleColumn( static_cast< sal_uInt16
>(
570 GetDataWindow().LogicToPixel( Size( 42, 0 )).getWidth() ));
572 OUString
aDefaultSeriesName(SCH_RESSTR(STR_COLUMN_LABEL
));
573 replaceParamterInString( aDefaultSeriesName
, "%COLUMNNUMBER", OUString::number( 24 ) );
574 sal_Int32 nColumnWidth
= GetDataWindow().GetTextWidth( aDefaultSeriesName
)
575 + GetDataWindow().LogicToPixel( Point( 4 + impl::SeriesHeader::GetRelativeAppFontXPosForNameField(), 0 ), MAP_APPFONT
).X();
576 sal_Int32 nColumnCount
= m_apDataBrowserModel
->getColumnCount();
577 // nRowCount is a member of a base class
578 sal_Int32 nRowCountLocal
= m_apDataBrowserModel
->getMaxRowCount();
579 for( sal_Int32 nColIdx
=1; nColIdx
<=nColumnCount
; ++nColIdx
)
581 InsertDataColumn( static_cast< sal_uInt16
>( nColIdx
), GetColString( nColIdx
), nColumnWidth
);
584 RowInserted( 1, nRowCountLocal
);
585 GoToRow( ::std::min( nOldRow
, GetRowCount() - 1 ));
586 GoToColumnId( ::std::min( nOldColId
, static_cast< sal_uInt16
>( ColCount() - 1 )));
588 Dialog
* pDialog
= GetParentDialog();
589 vcl::Window
* pWin
= pDialog
->get
<VclContainer
>("columns");
590 vcl::Window
* pColorWin
= pDialog
->get
<VclContainer
>("colorcolumns");
592 // fill series headers
594 const DataBrowserModel::tDataHeaderVector
& aHeaders( m_apDataBrowserModel
->getDataHeaders());
595 Link
<> aFocusLink( LINK( this, DataBrowser
, SeriesHeaderGotFocus
));
596 Link
<> aSeriesHeaderChangedLink( LINK( this, DataBrowser
, SeriesHeaderChanged
));
598 for( DataBrowserModel::tDataHeaderVector::const_iterator
aIt( aHeaders
.begin());
599 aIt
!= aHeaders
.end(); ++aIt
)
601 ::boost::shared_ptr
< impl::SeriesHeader
> spHeader( new impl::SeriesHeader( pWin
, pColorWin
));
602 Reference
< beans::XPropertySet
> xSeriesProp( aIt
->m_xDataSeries
, uno::UNO_QUERY
);
603 sal_Int32 nColor
= 0;
604 // @todo: Set "DraftColor", i.e. interpolated colors for gradients, bitmaps, etc.
605 if( xSeriesProp
.is() &&
606 ( xSeriesProp
->getPropertyValue( "Color" ) >>= nColor
))
607 spHeader
->SetColor( Color( nColor
));
608 spHeader
->SetChartType( aIt
->m_xChartType
, aIt
->m_bSwapXAndYAxis
);
609 spHeader
->SetSeriesName(
610 OUString( DataSeriesHelper::getDataSeriesLabel(
612 (aIt
->m_xChartType
.is() ?
613 aIt
->m_xChartType
->getRoleOfSequenceForSeriesLabel() :
614 OUString("values-y")))));
615 // index is 1-based, as 0 is for the column that contains the row-numbers
616 spHeader
->SetRange( aIt
->m_nStartColumn
+ 1, aIt
->m_nEndColumn
+ 1 );
617 spHeader
->SetGetFocusHdl( aFocusLink
);
618 spHeader
->SetEditChangedHdl( aSeriesHeaderChangedLink
);
619 m_aSeriesHeaders
.push_back( spHeader
);
622 ImplAdjustHeaderControls();
624 SetUpdateMode( bLastUpdateMode
);
629 OUString
DataBrowser::GetColString( sal_Int32 nColumnId
) const
631 OSL_ASSERT( m_apDataBrowserModel
.get());
633 return OUString( m_apDataBrowserModel
->getRoleOfColumn( static_cast< sal_Int32
>( nColumnId
) - 1 ));
637 OUString
DataBrowser::GetRowString( sal_Int32 nRow
)
639 return OUString::number(nRow
+ 1);
642 OUString
DataBrowser::GetCellText( long nRow
, sal_uInt16 nColumnId
) const
648 aResult
= GetRowString( static_cast< sal_Int32
>( nRow
));
650 else if( nRow
>= 0 && m_apDataBrowserModel
.get())
652 sal_Int32 nColIndex
= static_cast< sal_Int32
>( nColumnId
) - 1;
654 if( m_apDataBrowserModel
->getCellType( nColIndex
, nRow
) == DataBrowserModel::NUMBER
)
656 double fData( m_apDataBrowserModel
->getCellNumber( nColIndex
, nRow
));
657 sal_Int32 nLabelColor
;
659 if( ! ::rtl::math::isNan( fData
) &&
660 m_spNumberFormatterWrapper
.get() )
662 bool bColorChanged
= false;
663 aResult
= m_spNumberFormatterWrapper
->getFormattedString(
664 GetNumberFormatKey( nRow
, nColumnId
),
665 fData
, nLabelColor
, bColorChanged
);
668 else if( m_apDataBrowserModel
->getCellType( nColIndex
, nRow
) == DataBrowserModel::TEXTORDATE
)
670 uno::Any aAny
= m_apDataBrowserModel
->getCellAny( nColIndex
, nRow
);
675 else if( aAny
>>=fDouble
)
677 if( ! ::rtl::math::isNan( fDouble
) && m_spNumberFormatterWrapper
.get() )
679 // If a numberformat was available here we could directly
680 // obtain the corresponding edit format in
681 // getDateTimeInputNumberFormat() instead of doing the
683 sal_Int32 nNumberFormat
= DiagramHelper::getDateTimeInputNumberFormat(
684 Reference
< util::XNumberFormatsSupplier
>( m_xChartDoc
, uno::UNO_QUERY
), fDouble
);
685 sal_Int32 nLabelColor
;
686 bool bColorChanged
= false;
687 aResult
= m_spNumberFormatterWrapper
->getFormattedString(
688 nNumberFormat
, fDouble
, nLabelColor
, bColorChanged
);
694 OSL_ASSERT( m_apDataBrowserModel
->getCellType( nColIndex
, nRow
) == DataBrowserModel::TEXT
);
695 aResult
= m_apDataBrowserModel
->getCellText( nColIndex
, nRow
);
702 double DataBrowser::GetCellNumber( long nRow
, sal_uInt16 nColumnId
) const
705 ::rtl::math::setNan( & fResult
);
707 if(( nColumnId
>= 1 ) && ( nRow
>= 0 ) &&
708 m_apDataBrowserModel
.get())
710 fResult
= m_apDataBrowserModel
->getCellNumber(
711 static_cast< sal_Int32
>( nColumnId
) - 1, nRow
);
717 void DataBrowser::Resize()
719 bool bLastUpdateMode
= GetUpdateMode();
720 SetUpdateMode( false );
722 ::svt::EditBrowseBox::Resize();
723 ImplAdjustHeaderControls();
724 SetUpdateMode( bLastUpdateMode
);
727 bool DataBrowser::SetReadOnly( bool bNewState
)
729 bool bResult
= m_bIsReadOnly
;
731 if( m_bIsReadOnly
!= bNewState
)
733 m_bIsReadOnly
= bNewState
;
741 void DataBrowser::SetClean()
746 void DataBrowser::SetDirty()
752 void DataBrowser::CursorMoved()
754 EditBrowseBox::CursorMoved();
756 if( GetUpdateMode() && m_aCursorMovedHdlLink
.IsSet())
757 m_aCursorMovedHdlLink
.Call( this );
760 void DataBrowser::SetCellModifiedHdl( const Link
<>& rLink
)
762 m_aCellModifiedLink
= rLink
;
765 void DataBrowser::MouseButtonDown( const BrowserMouseEvent
& rEvt
)
770 EditBrowseBox::MouseButtonDown( rEvt
);
773 void DataBrowser::ShowWarningBox()
775 ScopedVclPtr
<WarningBox
>::Create(this, WinBits( WB_OK
),
776 SCH_RESSTR(STR_INVALID_NUMBER
))->Execute();
779 bool DataBrowser::ShowQueryBox()
781 ScopedVclPtrInstance
<QueryBox
> pQueryBox(this, WB_YES_NO
, SCH_RESSTR(STR_DATA_EDITOR_INCORRECT_INPUT
));
783 return pQueryBox
->Execute() == RET_YES
;
786 bool DataBrowser::IsDataValid()
789 const sal_Int32 nRow
= lcl_getRowInData( GetCurRow());
790 const sal_Int32 nCol
= lcl_getColumnInData( GetCurColumnId());
792 if( m_apDataBrowserModel
->getCellType( nCol
, nRow
) == DataBrowserModel::NUMBER
)
794 sal_uInt32 nDummy
= 0;
796 OUString
aText( m_aNumberEditField
->GetText());
798 if( !aText
.isEmpty() &&
799 m_spNumberFormatterWrapper
.get() &&
800 m_spNumberFormatterWrapper
->getSvNumberFormatter() &&
801 ! m_spNumberFormatterWrapper
->getSvNumberFormatter()->IsNumberFormat(
802 aText
, nDummy
, fDummy
))
811 void DataBrowser::CellModified()
813 m_bDataValid
= IsDataValid();
815 if( m_aCellModifiedLink
.IsSet())
816 m_aCursorMovedHdlLink
.Call( this );
819 void DataBrowser::SetDataFromModel(
820 const Reference
< chart2::XChartDocument
> & xChartDoc
,
821 const Reference
< uno::XComponentContext
> & xContext
)
825 m_xChartDoc
.set( xChartDoc
);
829 Reference
< util::XCloneable
> xCloneable( xChartDoc
, uno::UNO_QUERY
);
831 m_xChartDoc
.set( xCloneable
->createClone(), uno::UNO_QUERY
);
834 m_apDataBrowserModel
.reset( new DataBrowserModel( m_xChartDoc
, xContext
));
835 m_spNumberFormatterWrapper
.reset(
836 new NumberFormatterWrapper(
837 Reference
< util::XNumberFormatsSupplier
>( m_xChartDoc
, uno::UNO_QUERY
)));
839 if( m_spNumberFormatterWrapper
.get() )
840 m_aNumberEditField
->SetFormatter( m_spNumberFormatterWrapper
->getSvNumberFormatter() );
844 const sal_Int32 nColCnt
= m_apDataBrowserModel
->getColumnCount();
845 const sal_Int32 nRowCnt
= m_apDataBrowserModel
->getMaxRowCount();
846 if( nRowCnt
&& nColCnt
)
854 void DataBrowser::InsertColumn()
856 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
859 m_apDataBrowserModel
.get())
861 // save changes made to edit-field
865 m_apDataBrowserModel
->insertDataSeries( nColIdx
);
870 void DataBrowser::InsertTextColumn()
872 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
875 m_apDataBrowserModel
.get())
877 // save changes made to edit-field
881 m_apDataBrowserModel
->insertComplexCategoryLevel( nColIdx
);
886 void DataBrowser::RemoveColumn()
888 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
891 m_apDataBrowserModel
.get())
893 // save changes made to edit-field
898 m_apDataBrowserModel
->removeDataSeriesOrComplexCategoryLevel( nColIdx
);
903 void DataBrowser::InsertRow()
905 sal_Int32 nRowIdx
= lcl_getRowInData( GetCurRow());
908 m_apDataBrowserModel
.get())
910 // save changes made to edit-field
914 m_apDataBrowserModel
->insertDataPointForAllSeries( nRowIdx
);
919 void DataBrowser::RemoveRow()
921 sal_Int32 nRowIdx
= lcl_getRowInData( GetCurRow());
924 m_apDataBrowserModel
.get())
926 // save changes made to edit-field
931 m_apDataBrowserModel
->removeDataPointForAllSeries( nRowIdx
);
936 void DataBrowser::SwapColumn()
938 sal_Int32 nColIdx
= lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders
);
941 m_apDataBrowserModel
.get())
943 // save changes made to edit-field
947 m_apDataBrowserModel
->swapDataSeries( nColIdx
);
949 // keep cursor in swapped column
950 if( GetCurColumnId() < ColCount() - 1 )
952 Dispatch( BROWSER_CURSORRIGHT
);
958 void DataBrowser::SwapRow()
960 sal_Int32 nRowIdx
= lcl_getRowInData( GetCurRow());
963 m_apDataBrowserModel
.get())
965 // save changes made to edit-field
969 m_apDataBrowserModel
->swapDataPointForAllSeries( nRowIdx
);
971 // keep cursor in swapped row
972 if( GetCurRow() < GetRowCount() - 1 )
974 Dispatch( BROWSER_CURSORDOWN
);
980 void DataBrowser::SetCursorMovedHdl( const Link
<>& rLink
)
982 m_aCursorMovedHdlLink
= rLink
;
985 // implementations for ::svt::EditBrowseBox (pure virtual methods)
986 void DataBrowser::PaintCell(
987 OutputDevice
& rDev
, const Rectangle
& rRect
, sal_uInt16 nColumnId
) const
989 Point
aPos( rRect
.TopLeft());
992 OUString aText
= GetCellText( m_nSeekRow
, nColumnId
);
993 Size
TxtSize( GetDataWindow().GetTextWidth( aText
), GetDataWindow().GetTextHeight());
996 if( aPos
.X() < rRect
.Right() || aPos
.X() + TxtSize
.Width() > rRect
.Right() ||
997 aPos
.Y() < rRect
.Top() || aPos
.Y() + TxtSize
.Height() > rRect
.Bottom())
998 rDev
.SetClipRegion(vcl::Region(rRect
));
1000 // allow for a disabled control ...
1001 bool bEnabled
= IsEnabled();
1002 Color aOriginalColor
= rDev
.GetTextColor();
1004 rDev
.SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
1007 rDev
.DrawText( aPos
, aText
);
1009 // reset the color (if necessary)
1011 rDev
.SetTextColor( aOriginalColor
);
1013 if( rDev
.IsClipRegion())
1014 rDev
.SetClipRegion();
1017 bool DataBrowser::SeekRow( long nRow
)
1019 if( ! EditBrowseBox::SeekRow( nRow
))
1030 bool DataBrowser::IsTabAllowed( bool bForward
) const
1032 long nRow
= GetCurRow();
1033 long nCol
= GetCurColumnId();
1035 // column 0 is header-column
1036 long nBadCol
= bForward
1037 ? GetColumnCount() - 1
1039 long nBadRow
= bForward
1045 const_cast< DataBrowser
* >( this )->ShowWarningBox();
1049 return ( nRow
!= nBadRow
||
1053 ::svt::CellController
* DataBrowser::GetController( long nRow
, sal_uInt16 nCol
)
1058 if( CellContainsNumbers( nRow
, nCol
))
1060 m_aNumberEditField
->UseInputStringForFormatting();
1061 m_aNumberEditField
->SetFormatKey( GetNumberFormatKey( nRow
, nCol
));
1062 return m_rNumberEditController
;
1065 return m_rTextEditController
;
1068 void DataBrowser::InitController(
1069 ::svt::CellControllerRef
& rController
, long nRow
, sal_uInt16 nCol
)
1071 if( rController
== m_rTextEditController
)
1073 OUString
aText( GetCellText( nRow
, nCol
) );
1074 m_aTextEditField
->SetText( aText
);
1075 m_aTextEditField
->SetSelection( Selection( 0, aText
.getLength() ));
1077 else if( rController
== m_rNumberEditController
)
1079 // treat invalid and empty text as Nan
1080 m_aNumberEditField
->EnableNotANumber( true );
1081 if( ::rtl::math::isNan( GetCellNumber( nRow
, nCol
)))
1082 m_aNumberEditField
->SetTextValue( OUString());
1084 m_aNumberEditField
->SetValue( GetCellNumber( nRow
, nCol
) );
1085 OUString
aText( m_aNumberEditField
->GetText());
1086 m_aNumberEditField
->SetSelection( Selection( 0, aText
.getLength()));
1090 OSL_FAIL( "Invalid Controller" );
1094 bool DataBrowser::CellContainsNumbers( sal_Int32 nRow
, sal_uInt16 nCol
) const
1096 if( ! m_apDataBrowserModel
.get())
1098 return (m_apDataBrowserModel
->getCellType( lcl_getColumnInData( nCol
), lcl_getRowInData( nRow
)) ==
1099 DataBrowserModel::NUMBER
);
1102 sal_uInt32
DataBrowser::GetNumberFormatKey( sal_Int32 nRow
, sal_uInt16 nCol
) const
1104 if( ! m_apDataBrowserModel
.get())
1106 return m_apDataBrowserModel
->getNumberFormatKey( lcl_getColumnInData( nCol
), lcl_getRowInData( nRow
));
1109 bool DataBrowser::isDateTimeString( const OUString
& aInputString
, double& fOutDateTimeValue
)
1111 sal_uInt32 nNumberFormat
=0;
1112 SvNumberFormatter
* pSvNumberFormatter
= m_spNumberFormatterWrapper
.get() ? m_spNumberFormatterWrapper
->getSvNumberFormatter() : 0;
1113 if( !aInputString
.isEmpty() && pSvNumberFormatter
&& pSvNumberFormatter
->IsNumberFormat( aInputString
, nNumberFormat
, fOutDateTimeValue
) )
1115 short nType
= pSvNumberFormatter
->GetType( nNumberFormat
);
1116 return (nType
& util::NumberFormat::DATE
) || (nType
& util::NumberFormat::TIME
);
1121 bool DataBrowser::SaveModified()
1123 if( ! IsModified() )
1126 bool bChangeValid
= true;
1128 const sal_Int32 nRow
= lcl_getRowInData( GetCurRow());
1129 const sal_Int32 nCol
= lcl_getColumnInData( GetCurColumnId());
1131 OSL_ENSURE( nRow
>= 0 || nCol
>= 0, "This cell should not be modified!" );
1133 SvNumberFormatter
* pSvNumberFormatter
= m_spNumberFormatterWrapper
.get() ? m_spNumberFormatterWrapper
->getSvNumberFormatter() : 0;
1134 switch( m_apDataBrowserModel
->getCellType( nCol
, nRow
))
1136 case DataBrowserModel::NUMBER
:
1138 sal_uInt32 nDummy
= 0;
1139 double fDummy
= 0.0;
1140 OUString
aText( m_aNumberEditField
->GetText());
1141 // an empty string is valid, if no numberformatter exists, all
1142 // values are treated as valid
1143 if( !aText
.isEmpty() && pSvNumberFormatter
&&
1144 ! pSvNumberFormatter
->IsNumberFormat( aText
, nDummy
, fDummy
) )
1146 bChangeValid
= false;
1150 double fData
= m_aNumberEditField
->GetValue();
1151 bChangeValid
= m_apDataBrowserModel
->setCellNumber( nCol
, nRow
, fData
);
1155 case DataBrowserModel::TEXTORDATE
:
1157 OUString
aText( m_aTextEditField
->GetText() );
1158 double fValue
= 0.0;
1159 bChangeValid
= false;
1160 if( isDateTimeString( aText
, fValue
) )
1161 bChangeValid
= m_apDataBrowserModel
->setCellAny( nCol
, nRow
, uno::makeAny( fValue
) );
1163 bChangeValid
= m_apDataBrowserModel
->setCellAny( nCol
, nRow
, uno::makeAny( aText
) );
1166 case DataBrowserModel::TEXT
:
1168 OUString
aText( m_aTextEditField
->GetText());
1169 bChangeValid
= m_apDataBrowserModel
->setCellText( nCol
, nRow
, aText
);
1174 // the first valid change changes this to true
1177 RowModified( GetCurRow(), GetCurColumnId());
1178 ::svt::CellController
* pCtrl
= GetController( GetCurRow(), GetCurColumnId());
1180 pCtrl
->ClearModified();
1184 return bChangeValid
;
1187 bool DataBrowser::EndEditing()
1191 // apply changes made to series headers
1192 ::std::for_each( m_aSeriesHeaders
.begin(), m_aSeriesHeaders
.end(), impl::applyChangesFunctor());
1197 return ShowQueryBox();
1200 sal_Int16
DataBrowser::GetFirstVisibleColumNumber() const
1202 return GetFirstVisibleColNumber();
1205 void DataBrowser::ColumnResized( sal_uInt16 nColId
)
1207 bool bLastUpdateMode
= GetUpdateMode();
1208 SetUpdateMode( false );
1210 EditBrowseBox::ColumnResized( nColId
);
1211 ImplAdjustHeaderControls();
1212 SetUpdateMode( bLastUpdateMode
);
1215 void DataBrowser::EndScroll()
1217 bool bLastUpdateMode
= GetUpdateMode();
1218 SetUpdateMode( false );
1220 EditBrowseBox::EndScroll();
1221 RenewSeriesHeaders();
1223 SetUpdateMode( bLastUpdateMode
);
1226 void DataBrowser::RenewSeriesHeaders()
1228 Dialog
* pDialog
= GetParentDialog();
1229 vcl::Window
* pWin
= pDialog
->get
<VclContainer
>("columns");
1230 vcl::Window
* pColorWin
= pDialog
->get
<VclContainer
>("colorcolumns");
1233 DataBrowserModel::tDataHeaderVector
aHeaders( m_apDataBrowserModel
->getDataHeaders());
1234 Link
<> aFocusLink( LINK( this, DataBrowser
, SeriesHeaderGotFocus
));
1235 Link
<> aSeriesHeaderChangedLink( LINK( this, DataBrowser
, SeriesHeaderChanged
));
1237 for( DataBrowserModel::tDataHeaderVector::const_iterator
aIt( aHeaders
.begin());
1238 aIt
!= aHeaders
.end(); ++aIt
)
1240 ::boost::shared_ptr
< impl::SeriesHeader
> spHeader( new impl::SeriesHeader( pWin
, pColorWin
));
1241 Reference
< beans::XPropertySet
> xSeriesProp( aIt
->m_xDataSeries
, uno::UNO_QUERY
);
1242 sal_Int32 nColor
= 0;
1243 if( xSeriesProp
.is() &&
1244 ( xSeriesProp
->getPropertyValue( "Color" ) >>= nColor
))
1245 spHeader
->SetColor( Color( nColor
));
1246 spHeader
->SetChartType( aIt
->m_xChartType
, aIt
->m_bSwapXAndYAxis
);
1247 spHeader
->SetSeriesName(
1248 DataSeriesHelper::getDataSeriesLabel(
1250 (aIt
->m_xChartType
.is() ?
1251 aIt
->m_xChartType
->getRoleOfSequenceForSeriesLabel() :
1252 OUString( "values-y"))));
1253 spHeader
->SetRange( aIt
->m_nStartColumn
+ 1, aIt
->m_nEndColumn
+ 1 );
1254 spHeader
->SetGetFocusHdl( aFocusLink
);
1255 spHeader
->SetEditChangedHdl( aSeriesHeaderChangedLink
);
1256 m_aSeriesHeaders
.push_back( spHeader
);
1259 ImplAdjustHeaderControls();
1262 void DataBrowser::ImplAdjustHeaderControls()
1264 sal_uInt16 nColCount
= this->GetColumnCount();
1265 sal_uInt32 nCurrentPos
= this->GetPosPixel().getX();
1266 sal_uInt32 nMaxPos
= nCurrentPos
+ this->GetOutputSizePixel().getWidth();
1267 sal_uInt32 nStartPos
= nCurrentPos
;
1269 // width of header column
1270 nCurrentPos
+= this->GetColumnWidth( 0 );
1272 Dialog
* pDialog
= GetParentDialog();
1273 vcl::Window
* pWin
= pDialog
->get
<VclContainer
>("columns");
1274 vcl::Window
* pColorWin
= pDialog
->get
<VclContainer
>("colorcolumns");
1275 pWin
->set_margin_left(nCurrentPos
);
1276 pColorWin
->set_margin_left(nCurrentPos
);
1278 tSeriesHeaderContainer::iterator
aIt( m_aSeriesHeaders
.begin());
1279 sal_uInt16 i
= this->GetFirstVisibleColumNumber();
1280 while( (aIt
!= m_aSeriesHeaders
.end()) && ((*aIt
)->GetStartColumn() < i
) )
1285 for( ; i
< nColCount
&& aIt
!= m_aSeriesHeaders
.end(); ++i
)
1287 if( (*aIt
)->GetStartColumn() == i
)
1288 nStartPos
= nCurrentPos
;
1290 nCurrentPos
+= (this->GetColumnWidth( i
));
1292 if( (*aIt
)->GetEndColumn() == i
)
1294 if( nStartPos
< nMaxPos
)
1296 (*aIt
)->SetPixelWidth( nCurrentPos
- nStartPos
- 3 );
1301 pWin
->set_margin_left(nStartPos
);
1302 pColorWin
->set_margin_left(nStartPos
);
1303 pWin
= pColorWin
= NULL
;
1314 IMPL_LINK( DataBrowser
, SeriesHeaderGotFocus
, impl::SeriesHeaderEdit
*, pEdit
)
1318 pEdit
->SetShowWarningBox( !m_bDataValid
);
1324 MakeFieldVisible( GetCurRow(), static_cast< sal_uInt16
>( pEdit
->getStartColumn()), true /* bComplete */ );
1326 m_aCursorMovedHdlLink
.Call( this );
1332 IMPL_LINK( DataBrowser
, SeriesHeaderChanged
, impl::SeriesHeaderEdit
*, pEdit
)
1336 Reference
< chart2::XDataSeries
> xSeries(
1337 m_apDataBrowserModel
->getDataSeriesByColumn( pEdit
->getStartColumn() - 1 ));
1338 Reference
< chart2::data::XDataSource
> xSource( xSeries
, uno::UNO_QUERY
);
1341 Reference
< chart2::XChartType
> xChartType(
1342 m_apDataBrowserModel
->getHeaderForSeries( xSeries
).m_xChartType
);
1343 if( xChartType
.is())
1345 Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq(
1346 DataSeriesHelper::getDataSequenceByRole( xSource
, xChartType
->getRoleOfSequenceForSeriesLabel()));
1347 if( xLabeledSeq
.is())
1349 Reference
< container::XIndexReplace
> xIndexReplace( xLabeledSeq
->getLabel(), uno::UNO_QUERY
);
1350 if( xIndexReplace
.is())
1351 xIndexReplace
->replaceByIndex(
1352 0, uno::makeAny( OUString( pEdit
->GetText())));
1360 } // namespace chart
1362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */