Branch libreoffice-5-0-4
[LibreOffice.git] / chart2 / source / controller / dialogs / DataBrowser.cxx
blob7ad3c383b12f5364893f7a92d9dd8ed5df3f2184
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
31 #include "macros.hxx"
32 #include "NumberFormatterWrapper.hxx"
33 #include "servicenames_charttypes.hxx"
34 #include "ResId.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>
52 #include <algorithm>
53 #include <functional>
55 /* BrowserMode::COLUMNSELECTION : single cells may be selected rather than only
56 entire rows
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
62 (usually blue)
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;
81 namespace
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
95 namespace chart
98 namespace impl
101 class SeriesHeaderEdit : public Edit
103 public:
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 );
111 private:
112 sal_Int32 m_nStartColumn;
113 bool m_bShowWarningBox;
116 SeriesHeaderEdit::SeriesHeaderEdit( vcl::Window * pParent ) :
117 Edit( pParent ),
118 m_nStartColumn( 0 ),
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();
143 class SeriesHeader
145 public:
146 explicit SeriesHeader(vcl::Window * pParent, vcl::Window *pColorParent);
147 ~SeriesHeader();
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; }
167 void Show();
168 void Hide();
170 /** call this before destroying the class. This notifies the listeners to
171 changes of the edit field for the series name.
173 void applyChanges();
175 void SetGetFocusHdl( const Link<>& rLink );
177 void SetEditChangedHdl( const Link<> & rLink );
179 bool HasFocus() const;
181 private:
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,
194 bool bSwapXAndYAxis
197 sal_Int32 m_nStartCol, m_nEndCol;
198 sal_Int32 m_nWidth;
199 Point m_aPos;
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 ),
208 m_nStartCol( 0 ),
209 m_nEndCol( 0 ),
210 m_nWidth( 42 ),
211 m_aPos( 0, 22 ),
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 );
218 Show();
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 )
240 notifyChanges();
244 void SeriesHeader::SetColor( const Color & rCol )
246 m_spColorBar->SetControlBackground( rCol );
249 void SeriesHeader::SetPos( const Point & rPos )
251 m_aPos = rPos;
253 // chart type symbol
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());
270 // color bar
271 aSize.setWidth(1);
272 aSize = m_pDevice->LogicToPixel( aSize, MAP_APPFONT );
273 m_spColorBar->set_margin_left(aSize.Width() + 2);
274 nHeight = 3;
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 )
284 m_nWidth = nWidth;
285 SetPos( m_aPos );
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,
295 bool bSwapXAndYAxis
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()
315 m_spSymbol->Show();
316 m_spSeriesName->Show();
317 m_spColorBar->Show();
320 void SeriesHeader::Hide()
322 m_spSymbol->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)
334 notifyChanges();
335 return 0;
338 IMPL_LINK_NOARG(SeriesHeader, SeriesNameEdited)
340 m_bSeriesNameChangePending = true;
341 return 0;
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,
356 bool bSwapXAndYAxis
359 Image aResult;
360 if( !xChartType.is())
361 return aResult;
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 )
370 if( bSwapXAndYAxis )
371 aResult = Image( SchResId( IMG_TYPE_BAR ) );
372 else
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 ) );
402 return aResult;
405 struct applyChangesFunctor : public ::std::unary_function< ::boost::shared_ptr< SeriesHeader >, void >
407 void operator() ( ::boost::shared_ptr< SeriesHeader > spHeader )
409 spHeader->applyChanges();
413 } // namespace impl
415 namespace
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())
432 if( pOutIndex )
433 *pOutIndex = nIndex;
434 return true;
437 return false;
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()));
448 else
449 nColIdx = lcl_getColumnInData( nCol );
451 return nColIdx;
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 ),
458 m_nSeekRow( 0 ),
459 m_bIsReadOnly( false ),
460 m_bIsDirty( 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() ))
468 double fNan;
469 ::rtl::math::setNan( & fNan );
470 m_aNumberEditField->SetDefaultValue( fNan );
471 m_aNumberEditField->TreatAsNumber( true );
472 RenewTable();
473 SetClean();
476 DataBrowser::~DataBrowser()
478 disposeOnce();
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 ))
511 return true;
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()
537 && ( nColIdx > 0 )
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())
552 return;
554 long nOldRow = GetCurRow();
555 sal_uInt16 nOldColId = GetCurColumnId();
557 bool bLastUpdateMode = GetUpdateMode();
558 SetUpdateMode( false );
560 if( IsModified() )
561 SaveModified();
563 DeactivateCell();
565 RemoveColumns();
566 RowRemoved( 1, GetRowCount() );
568 // for row numbers
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
593 clearHeaders();
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(
611 aIt->m_xDataSeries,
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();
623 SetDirty();
624 SetUpdateMode( bLastUpdateMode );
625 ActivateCell();
626 Invalidate();
629 OUString DataBrowser::GetColString( sal_Int32 nColumnId ) const
631 OSL_ASSERT( m_apDataBrowserModel.get());
632 if( nColumnId > 0 )
633 return OUString( m_apDataBrowserModel->getRoleOfColumn( static_cast< sal_Int32 >( nColumnId ) - 1 ));
634 return OUString();
637 OUString DataBrowser::GetRowString( sal_Int32 nRow )
639 return OUString::number(nRow + 1);
642 OUString DataBrowser::GetCellText( long nRow, sal_uInt16 nColumnId ) const
644 OUString aResult;
646 if( nColumnId == 0 )
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 );
671 OUString aText;
672 double fDouble=0.0;
673 if( aAny>>=aText )
674 aResult = aText;
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
682 // guess work.
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 );
692 else
694 OSL_ASSERT( m_apDataBrowserModel->getCellType( nColIndex, nRow ) == DataBrowserModel::TEXT );
695 aResult = m_apDataBrowserModel->getCellText( nColIndex, nRow );
699 return aResult;
702 double DataBrowser::GetCellNumber( long nRow, sal_uInt16 nColumnId ) const
704 double fResult;
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 );
714 return fResult;
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;
734 Invalidate();
735 DeactivateCell();
738 return bResult;
741 void DataBrowser::SetClean()
743 m_bIsDirty = false;
746 void DataBrowser::SetDirty()
748 if( !m_bLiveUpdate )
749 m_bIsDirty = true;
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 )
767 if( !m_bDataValid )
768 ShowWarningBox();
769 else
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()
788 bool bValid = true;
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;
795 double fDummy = 0.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 ))
804 bValid = false;
808 return bValid;
811 void DataBrowser::CellModified()
813 m_bDataValid = IsDataValid();
814 SetDirty();
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 )
823 if( m_bLiveUpdate )
825 m_xChartDoc.set( xChartDoc );
827 else
829 Reference< util::XCloneable > xCloneable( xChartDoc, uno::UNO_QUERY );
830 if( xCloneable.is())
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() );
842 RenewTable();
844 const sal_Int32 nColCnt = m_apDataBrowserModel->getColumnCount();
845 const sal_Int32 nRowCnt = m_apDataBrowserModel->getMaxRowCount();
846 if( nRowCnt && nColCnt )
848 GoToRow( 0 );
849 GoToColumnId( 1 );
851 SetClean();
854 void DataBrowser::InsertColumn()
856 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
858 if( nColIdx >= 0 &&
859 m_apDataBrowserModel.get())
861 // save changes made to edit-field
862 if( IsModified() )
863 SaveModified();
865 m_apDataBrowserModel->insertDataSeries( nColIdx );
866 RenewTable();
870 void DataBrowser::InsertTextColumn()
872 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
874 if( nColIdx >= 0 &&
875 m_apDataBrowserModel.get())
877 // save changes made to edit-field
878 if( IsModified() )
879 SaveModified();
881 m_apDataBrowserModel->insertComplexCategoryLevel( nColIdx );
882 RenewTable();
886 void DataBrowser::RemoveColumn()
888 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
890 if( nColIdx >= 0 &&
891 m_apDataBrowserModel.get())
893 // save changes made to edit-field
894 if( IsModified() )
895 SaveModified();
897 m_bDataValid = true;
898 m_apDataBrowserModel->removeDataSeriesOrComplexCategoryLevel( nColIdx );
899 RenewTable();
903 void DataBrowser::InsertRow()
905 sal_Int32 nRowIdx = lcl_getRowInData( GetCurRow());
907 if( nRowIdx >= 0 &&
908 m_apDataBrowserModel.get())
910 // save changes made to edit-field
911 if( IsModified() )
912 SaveModified();
914 m_apDataBrowserModel->insertDataPointForAllSeries( nRowIdx );
915 RenewTable();
919 void DataBrowser::RemoveRow()
921 sal_Int32 nRowIdx = lcl_getRowInData( GetCurRow());
923 if( nRowIdx >= 0 &&
924 m_apDataBrowserModel.get())
926 // save changes made to edit-field
927 if( IsModified() )
928 SaveModified();
930 m_bDataValid = true;
931 m_apDataBrowserModel->removeDataPointForAllSeries( nRowIdx );
932 RenewTable();
936 void DataBrowser::SwapColumn()
938 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
940 if( nColIdx >= 0 &&
941 m_apDataBrowserModel.get())
943 // save changes made to edit-field
944 if( IsModified() )
945 SaveModified();
947 m_apDataBrowserModel->swapDataSeries( nColIdx );
949 // keep cursor in swapped column
950 if( GetCurColumnId() < ColCount() - 1 )
952 Dispatch( BROWSER_CURSORRIGHT );
954 RenewTable();
958 void DataBrowser::SwapRow()
960 sal_Int32 nRowIdx = lcl_getRowInData( GetCurRow());
962 if( nRowIdx >= 0 &&
963 m_apDataBrowserModel.get())
965 // save changes made to edit-field
966 if( IsModified() )
967 SaveModified();
969 m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx );
971 // keep cursor in swapped row
972 if( GetCurRow() < GetRowCount() - 1 )
974 Dispatch( BROWSER_CURSORDOWN );
976 RenewTable();
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());
990 aPos.X() += 1;
992 OUString aText = GetCellText( m_nSeekRow, nColumnId );
993 Size TxtSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight());
995 // clipping
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();
1003 if( ! bEnabled )
1004 rDev.SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
1006 // draw the text
1007 rDev.DrawText( aPos, aText );
1009 // reset the color (if necessary)
1010 if( ! bEnabled )
1011 rDev.SetTextColor( aOriginalColor );
1013 if( rDev.IsClipRegion())
1014 rDev.SetClipRegion();
1017 bool DataBrowser::SeekRow( long nRow )
1019 if( ! EditBrowseBox::SeekRow( nRow ))
1020 return false;
1022 if( nRow < 0 )
1023 m_nSeekRow = - 1;
1024 else
1025 m_nSeekRow = nRow;
1027 return true;
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
1038 : 1;
1039 long nBadRow = bForward
1040 ? GetRowCount() - 1
1041 : 0;
1043 if( !m_bDataValid )
1045 const_cast< DataBrowser* >( this )->ShowWarningBox();
1046 return false;
1049 return ( nRow != nBadRow ||
1050 nCol != nBadCol );
1053 ::svt::CellController* DataBrowser::GetController( long nRow, sal_uInt16 nCol )
1055 if( m_bIsReadOnly )
1056 return 0;
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());
1083 else
1084 m_aNumberEditField->SetValue( GetCellNumber( nRow, nCol ) );
1085 OUString aText( m_aNumberEditField->GetText());
1086 m_aNumberEditField->SetSelection( Selection( 0, aText.getLength()));
1088 else
1090 OSL_FAIL( "Invalid Controller" );
1094 bool DataBrowser::CellContainsNumbers( sal_Int32 nRow, sal_uInt16 nCol ) const
1096 if( ! m_apDataBrowserModel.get())
1097 return false;
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())
1105 return 0;
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);
1118 return false;
1121 bool DataBrowser::SaveModified()
1123 if( ! IsModified() )
1124 return true;
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;
1148 else
1150 double fData = m_aNumberEditField->GetValue();
1151 bChangeValid = m_apDataBrowserModel->setCellNumber( nCol, nRow, fData );
1154 break;
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 ) );
1162 if(!bChangeValid)
1163 bChangeValid = m_apDataBrowserModel->setCellAny( nCol, nRow, uno::makeAny( aText ) );
1165 break;
1166 case DataBrowserModel::TEXT:
1168 OUString aText( m_aTextEditField->GetText());
1169 bChangeValid = m_apDataBrowserModel->setCellText( nCol, nRow, aText );
1171 break;
1174 // the first valid change changes this to true
1175 if( bChangeValid )
1177 RowModified( GetCurRow(), GetCurColumnId());
1178 ::svt::CellController* pCtrl = GetController( GetCurRow(), GetCurColumnId());
1179 if( pCtrl )
1180 pCtrl->ClearModified();
1181 SetDirty();
1184 return bChangeValid;
1187 bool DataBrowser::EndEditing()
1189 SaveModified();
1191 // apply changes made to series headers
1192 ::std::for_each( m_aSeriesHeaders.begin(), m_aSeriesHeaders.end(), impl::applyChangesFunctor());
1194 if( m_bDataValid )
1195 return true;
1196 else
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");
1232 clearHeaders();
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(
1249 aIt->m_xDataSeries,
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) )
1282 (*aIt)->Hide();
1283 ++aIt;
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 );
1297 (*aIt)->Show();
1299 if (pWin)
1301 pWin->set_margin_left(nStartPos);
1302 pColorWin->set_margin_left(nStartPos);
1303 pWin = pColorWin = NULL;
1307 else
1308 (*aIt)->Hide();
1309 ++aIt;
1314 IMPL_LINK( DataBrowser, SeriesHeaderGotFocus, impl::SeriesHeaderEdit*, pEdit )
1316 if( pEdit )
1318 pEdit->SetShowWarningBox( !m_bDataValid );
1320 if( !m_bDataValid )
1321 GoToCell( 0, 0 );
1322 else
1324 MakeFieldVisible( GetCurRow(), static_cast< sal_uInt16 >( pEdit->getStartColumn()), true /* bComplete */ );
1325 ActivateCell();
1326 m_aCursorMovedHdlLink.Call( this );
1329 return 0;
1332 IMPL_LINK( DataBrowser, SeriesHeaderChanged, impl::SeriesHeaderEdit*, pEdit )
1334 if( pEdit )
1336 Reference< chart2::XDataSeries > xSeries(
1337 m_apDataBrowserModel->getDataSeriesByColumn( pEdit->getStartColumn() - 1 ));
1338 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
1339 if( xSource.is())
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())));
1357 return 0;
1360 } // namespace chart
1362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */