Update ooo320-m1
[ooovba.git] / chart2 / source / controller / dialogs / DataBrowser.cxx
blob6a3fa6ca916264a87f5c388907aecd3af2c661b9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: DataBrowser.cxx,v $
10 * $Revision: 1.9.8.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_chart2.hxx"
34 // header for class SvNumberformat
35 #ifndef _ZFORMAT_HXX
36 #ifndef _ZFORLIST_DECLARE_TABLE
37 #define _ZFORLIST_DECLARE_TABLE
38 #endif
39 #include <svtools/zformat.hxx>
40 #endif
41 // header for SvNumberFormatter
42 #include <svtools/zforlist.hxx>
44 #include "DataBrowser.hxx"
45 #include "DataBrowserModel.hxx"
46 #include "Strings.hrc"
47 #include "ContainerHelper.hxx"
48 #include "DataSeriesHelper.hxx"
49 #include "DiagramHelper.hxx"
50 #include "ChartModelHelper.hxx"
51 #include "chartview/NumberFormatterWrapper.hxx"
52 #include "servicenames_charttypes.hxx"
53 #include "ResId.hxx"
54 #include "Bitmaps.hrc"
55 #include "Bitmaps_HC.hrc"
56 #include "HelpIds.hrc"
58 #include <vcl/fixed.hxx>
59 #include <vcl/image.hxx>
60 #include <vcl/msgbox.hxx>
61 #include <rtl/math.hxx>
63 #include <com/sun/star/util/XCloneable.hpp>
64 #include <com/sun/star/chart2/XChartDocument.hpp>
65 #include <com/sun/star/chart2/XChartType.hpp>
67 #include <com/sun/star/container/XIndexReplace.hpp>
69 #include <algorithm>
70 #include <functional>
72 #define SELECT_IMAGE(name,hc) Image( SchResId( hc ? name ## _HC : name ))
74 /* BROWSER_COLUMNSELECTION : single cells may be selected rather than only
75 entire rows
76 BROWSER_(H|V)LINES : show horizontal or vertical grid-lines
78 BROWSER_AUTO_(H|V)SCROLL : scroll automated horizontally or vertically when
79 cursor is moved beyond the edge of the dialog
80 BROWSER_HIGHLIGHT_NONE : Do not mark the current row with selection color
81 (usually blue)
84 #define BROWSER_STANDARD_FLAGS \
85 BROWSER_COLUMNSELECTION | \
86 BROWSER_HLINES | BROWSER_VLINES | \
87 BROWSER_AUTO_HSCROLL | BROWSER_AUTO_VSCROLL | \
88 BROWSER_HIGHLIGHT_NONE
90 // BROWSER_HIDECURSOR would prevent flickering in edit fields, but navigating
91 // with shift up/down, and entering non-editable cells would be problematic,
92 // e.g. the first cell, or when being in read-only mode
95 using namespace ::com::sun::star;
96 using ::com::sun::star::uno::Sequence;
97 using ::com::sun::star::uno::Reference;
98 using ::rtl::OUString;
100 using namespace ::svt;
102 namespace
104 sal_Int32 lcl_getRowInData( long nRow )
106 return static_cast< sal_Int32 >( nRow );
109 sal_Int32 lcl_getColumnInData( USHORT nCol )
111 return static_cast< sal_Int32 >( nCol ) - 1;
114 } // anonymous namespace
116 // --------------------------------------------------------------------------------
118 namespace chart
121 // ----------------------------------------
122 namespace impl
125 class SeriesHeaderEdit : public Edit
127 public:
128 SeriesHeaderEdit( Window * pParent );
129 virtual ~SeriesHeaderEdit();
130 virtual void MouseButtonDown( const MouseEvent& rMEvt );
132 void setStartColumn( sal_Int32 nStartColumn );
133 sal_Int32 getStartColumn() const;
134 void SetShowWarningBox( bool bShowWarning = true );
136 private:
137 sal_Int32 m_nStartColumn;
138 bool m_bShowWarningBox;
141 SeriesHeaderEdit::SeriesHeaderEdit( Window * pParent ) :
142 Edit( pParent ),
143 m_nStartColumn( 0 ),
144 m_bShowWarningBox( false )
146 SeriesHeaderEdit::~SeriesHeaderEdit()
149 void SeriesHeaderEdit::setStartColumn( sal_Int32 nStartColumn )
151 m_nStartColumn = nStartColumn;
154 sal_Int32 SeriesHeaderEdit::getStartColumn() const
156 return m_nStartColumn;
159 void SeriesHeaderEdit::SetShowWarningBox( bool bShowWarning )
161 m_bShowWarningBox = bShowWarning;
164 void SeriesHeaderEdit::MouseButtonDown( const MouseEvent& rMEvt )
166 Edit::MouseButtonDown( rMEvt );
168 if( m_bShowWarningBox )
169 WarningBox( this, WinBits( WB_OK ),
170 String( SchResId( STR_INVALID_NUMBER ))).Execute();
173 class SeriesHeader
175 public:
176 explicit SeriesHeader( Window * pParent );
178 void SetColor( const Color & rCol );
179 void SetPos( const Point & rPos );
180 void SetWidth( sal_Int32 nWidth );
181 void SetChartType( const Reference< chart2::XChartType > & xChartType,
182 bool bSwapXAndYAxis,
183 bool bIsHighContrast );
184 void SetSeriesName( const String & rName );
185 void SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol );
187 void SetPixelPosX( sal_Int32 nPos );
188 void SetPixelWidth( sal_Int32 nWidth );
190 sal_Int32 GetStartColumn() const;
191 sal_Int32 GetEndColumn() const;
193 void Show();
195 /** call this before destroying the class. This notifies the listeners to
196 changes of the edit field for the series name.
198 void applyChanges();
200 void SetGetFocusHdl( const Link& rLink );
202 void SetEditChangedHdl( const Link & rLink );
204 bool HasFocus() const;
206 private:
207 ::boost::shared_ptr< FixedImage > m_spSymbol;
208 ::boost::shared_ptr< SeriesHeaderEdit > m_spSeriesName;
209 ::boost::shared_ptr< FixedText > m_spColorBar;
210 OutputDevice * m_pDevice;
211 Link m_aChangeLink;
213 void notifyChanges();
214 DECL_LINK( SeriesNameChanged, void * );
215 DECL_LINK( SeriesNameEdited, void * );
217 /// @param bHC </TRUE> for hight-contrast image
218 static Image GetChartTypeImage(
219 const Reference< chart2::XChartType > & xChartType,
220 bool bSwapXAndYAxis,
221 bool bHC );
223 sal_Int32 m_nStartCol, m_nEndCol;
224 sal_Int32 m_nWidth;
225 Point m_aPos;
226 bool m_bSeriesNameChangePending;
229 SeriesHeader::SeriesHeader( Window * pParent ) :
230 m_spSymbol( new FixedImage( pParent, WB_NOBORDER )),
231 m_spSeriesName( new SeriesHeaderEdit( pParent )),
232 m_spColorBar( new FixedText( pParent, WB_NOBORDER )),
233 m_pDevice( pParent ),
234 m_nStartCol( 0 ),
235 m_nEndCol( 0 ),
236 m_nWidth( 42 ),
237 m_aPos( 0, 22 ),
238 m_bSeriesNameChangePending( false )
240 m_spSeriesName->EnableUpdateData( 4 * EDIT_UPDATEDATA_TIMEOUT ); // define is in vcl/edit.hxx
241 m_spSeriesName->SetUpdateDataHdl( LINK( this, SeriesHeader, SeriesNameChanged ));
242 m_spSeriesName->SetModifyHdl( LINK( this, SeriesHeader, SeriesNameEdited ));
243 m_spSeriesName->SetSmartHelpId( SmartId( HID_SCH_DATA_SERIES_LABEL ));
244 Show();
247 void SeriesHeader::notifyChanges()
249 if( m_aChangeLink.IsSet())
250 m_aChangeLink.Call( m_spSeriesName.get());
252 m_bSeriesNameChangePending = false;
255 void SeriesHeader::applyChanges()
257 if( m_bSeriesNameChangePending )
259 notifyChanges();
263 void SeriesHeader::SetColor( const Color & rCol )
265 m_spColorBar->SetControlBackground( rCol );
268 void SeriesHeader::SetPos( const Point & rPos )
270 m_aPos = rPos;
272 // chart type symbol
273 sal_Int32 nHeight = 10;
274 Point aPos( rPos );
275 aPos.setY( aPos.getY() + 2 );
276 Size aSize( nHeight, nHeight );
277 m_spSymbol->SetPosPixel( m_pDevice->LogicToPixel( aPos, MAP_APPFONT ));
278 m_spSymbol->SetSizePixel( m_pDevice->LogicToPixel( aSize, MAP_APPFONT ));
279 aPos.setY( aPos.getY() - 2 );
281 // series name edit field
282 aPos.setX( aPos.getX() + nHeight + 2 );
283 aSize.setWidth( m_nWidth - nHeight - 2 );
284 nHeight = 12;
285 aSize.setHeight( nHeight );
286 m_spSeriesName->SetPosPixel( m_pDevice->LogicToPixel( aPos, MAP_APPFONT ));
287 m_spSeriesName->SetSizePixel( m_pDevice->LogicToPixel( aSize, MAP_APPFONT ));
289 // color bar
290 aPos.setX( rPos.getX() + 1 );
291 aPos.setY( aPos.getY() + nHeight + 2 );
292 nHeight = 3;
293 aSize.setWidth( m_nWidth - 1 );
294 aSize.setHeight( nHeight );
295 m_spColorBar->SetPosPixel( m_pDevice->LogicToPixel( aPos, MAP_APPFONT ));
296 m_spColorBar->SetSizePixel( m_pDevice->LogicToPixel( aSize, MAP_APPFONT ));
299 void SeriesHeader::SetWidth( sal_Int32 nWidth )
301 m_nWidth = nWidth;
302 SetPos( m_aPos );
306 void SeriesHeader::SetPixelPosX( sal_Int32 nPos )
308 Point aPos( m_pDevice->LogicToPixel( m_aPos, MAP_APPFONT ));
309 aPos.setX( nPos );
310 SetPos( m_pDevice->PixelToLogic( aPos, MAP_APPFONT ));
313 void SeriesHeader::SetPixelWidth( sal_Int32 nWidth )
315 SetWidth( m_pDevice->PixelToLogic( Size( nWidth, 0 ), MAP_APPFONT ).getWidth());
318 void SeriesHeader::SetChartType(
319 const Reference< chart2::XChartType > & xChartType,
320 bool bSwapXAndYAxis,
321 bool bIsHighContrast )
323 m_spSymbol->SetImage( GetChartTypeImage( xChartType, bSwapXAndYAxis, bIsHighContrast ));
326 void SeriesHeader::SetSeriesName( const String & rName )
328 m_spSeriesName->SetText( rName );
331 void SeriesHeader::SetRange( sal_Int32 nStartCol, sal_Int32 nEndCol )
333 m_nStartCol = nStartCol;
334 m_nEndCol = (nEndCol > nStartCol) ? nEndCol : nStartCol;
335 m_spSeriesName->setStartColumn( nStartCol );
338 sal_Int32 SeriesHeader::GetStartColumn() const
340 return m_nStartCol;
343 sal_Int32 SeriesHeader::GetEndColumn() const
345 return m_nEndCol;
348 void SeriesHeader::Show()
350 m_spSymbol->Show();
351 m_spSeriesName->Show();
352 m_spColorBar->Show();
355 void SeriesHeader::SetEditChangedHdl( const Link & rLink )
357 m_aChangeLink = rLink;
360 IMPL_LINK( SeriesHeader, SeriesNameChanged, void * , EMPTYARG )
362 notifyChanges();
363 return 0;
366 IMPL_LINK( SeriesHeader, SeriesNameEdited, void * , EMPTYARG )
368 m_bSeriesNameChangePending = true;
369 return 0;
372 void SeriesHeader::SetGetFocusHdl( const Link& rLink )
374 m_spSeriesName->SetGetFocusHdl( rLink );
377 bool SeriesHeader::HasFocus() const
379 return m_spSeriesName->HasFocus();
382 // static
383 Image SeriesHeader::GetChartTypeImage(
384 const Reference< chart2::XChartType > & xChartType,
385 bool bSwapXAndYAxis,
386 bool bHC )
388 Image aResult;
389 if( !xChartType.is())
390 return aResult;
391 OUString aChartTypeName( xChartType->getChartType());
393 if( aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_AREA ))
395 aResult = SELECT_IMAGE( IMG_TYPE_AREA, bHC );
397 else if( aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_COLUMN ))
399 if( bSwapXAndYAxis )
400 aResult = SELECT_IMAGE( IMG_TYPE_BAR, bHC );
401 else
402 aResult = SELECT_IMAGE( IMG_TYPE_COLUMN, bHC );
404 else if( aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_LINE ))
406 aResult = SELECT_IMAGE( IMG_TYPE_LINE, bHC );
408 else if( aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_SCATTER ))
410 aResult = SELECT_IMAGE( IMG_TYPE_XY, bHC );
412 else if( aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_PIE ))
414 aResult = SELECT_IMAGE( IMG_TYPE_PIE, bHC );
416 else if( aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_NET )
417 || aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET ) )
419 aResult = SELECT_IMAGE( IMG_TYPE_NET, bHC );
421 else if( aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK ))
423 // @todo: correct image for candle-stick type
424 aResult = SELECT_IMAGE( IMG_TYPE_STOCK, bHC );
426 else if( aChartTypeName.equals( CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE ))
428 aResult = SELECT_IMAGE( IMG_TYPE_BUBBLE, bHC );
431 return aResult;
434 struct applyChangesFunctor : public ::std::unary_function< ::boost::shared_ptr< SeriesHeader >, void >
436 void operator() ( ::boost::shared_ptr< SeriesHeader > spHeader )
438 spHeader->applyChanges();
442 } // namespace impl
443 // ----------------------------------------
445 namespace
448 /** returns false, if no header as the focus.
450 If a header has the focus, true is returned and the index of the header
451 with focus is set at pIndex if pOutIndex is not 0.
453 bool lcl_SeriesHeaderHasFocus(
454 const ::std::vector< ::boost::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader,
455 sal_Int32 * pOutIndex = 0 )
457 sal_Int32 nIndex = 0;
458 for( ::std::vector< ::boost::shared_ptr< ::chart::impl::SeriesHeader > >::const_iterator aIt( rSeriesHeader.begin());
459 aIt != rSeriesHeader.end(); ++aIt, ++nIndex )
461 if( (*aIt)->HasFocus())
463 if( pOutIndex )
464 *pOutIndex = nIndex;
465 return true;
468 return false;
471 sal_Int32 lcl_getColumnInDataOrHeader(
472 USHORT nCol, const ::std::vector< ::boost::shared_ptr< ::chart::impl::SeriesHeader > > & rSeriesHeader )
474 sal_Int32 nColIdx = 0;
475 bool bHeaderHasFocus( lcl_SeriesHeaderHasFocus( rSeriesHeader, &nColIdx ));
477 if( bHeaderHasFocus )
478 nColIdx = lcl_getColumnInData( static_cast< USHORT >( rSeriesHeader[nColIdx]->GetStartColumn()));
479 else
480 nColIdx = lcl_getColumnInData( nCol );
482 return nColIdx;
485 } // anonymous namespace
488 DataBrowser::DataBrowser( Window* pParent, const ResId& rId, bool bLiveUpdate ) :
489 ::svt::EditBrowseBox( pParent, rId, EBBF_SMART_TAB_TRAVEL | EBBF_HANDLE_COLUMN_TEXT, BROWSER_STANDARD_FLAGS ),
490 m_nSeekRow( 0 ),
491 m_bIsReadOnly( false ),
492 m_bIsDirty( false ),
493 m_bLiveUpdate( bLiveUpdate ),
494 m_bDataValid( true ),
495 m_aNumberEditField( & EditBrowseBox::GetDataWindow(), WB_NOBORDER ),
496 m_aTextEditField( & EditBrowseBox::GetDataWindow(), WB_NOBORDER ),
497 m_rNumberEditController( new ::svt::FormattedFieldCellController( & m_aNumberEditField )),
498 m_rTextEditController( new ::svt::EditCellController( & m_aTextEditField ))
500 double fNan;
501 ::rtl::math::setNan( & fNan );
502 m_aNumberEditField.SetDefaultValue( fNan );
503 m_aNumberEditField.TreatAsNumber( TRUE );
504 RenewTable();
505 SetClean();
508 DataBrowser::~DataBrowser()
512 bool DataBrowser::MayInsertRow() const
514 return ! IsReadOnly()
515 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ));
518 bool DataBrowser::MayInsertColumn() const
520 return ! IsReadOnly();
523 bool DataBrowser::MayDeleteRow() const
525 return ! IsReadOnly()
526 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
527 && ( GetCurRow() >= 0 )
528 && ( GetRowCount() > 1 );
531 bool DataBrowser::MayDeleteColumn() const
533 // if a series header has the focus
534 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
535 return true;
537 return ! IsReadOnly()
538 && ( GetCurColumnId() > 1 )
539 && ( ColCount() > 2 );
542 bool DataBrowser::MaySwapRows() const
544 return ! IsReadOnly()
545 && ( !lcl_SeriesHeaderHasFocus( m_aSeriesHeaders ))
546 && ( GetCurRow() >= 0 )
547 && ( GetCurRow() < GetRowCount() - 1 );
550 bool DataBrowser::MaySwapColumns() const
552 // if a series header (except the last one) has the focus
554 sal_Int32 nColIndex(0);
555 if( lcl_SeriesHeaderHasFocus( m_aSeriesHeaders, &nColIndex ))
556 return (static_cast< sal_uInt32 >( nColIndex ) < (m_aSeriesHeaders.size() - 1));
559 return ! IsReadOnly()
560 && ( GetCurColumnId() > 1 )
561 && ( GetCurColumnId() < ColCount() - 1 );
564 // bool DataBrowser::MaySortRow() const
565 // {
566 // // not implemented
567 // return false;
568 // // return ! IsReadOnly() && ( GetCurRow() >= 0 );
569 // }
571 // bool DataBrowser::MaySortColumn() const
572 // {
573 // // not implemented
574 // return false;
575 // // return ! IsReadOnly() && ( GetCurColumnId() > 1 );
576 // }
578 void DataBrowser::clearHeaders()
580 ::std::for_each( m_aSeriesHeaders.begin(), m_aSeriesHeaders.end(), impl::applyChangesFunctor());
581 m_aSeriesHeaders.clear();
584 void DataBrowser::RenewTable()
586 if( ! m_apDataBrowserModel.get())
587 return;
589 long nOldRow = GetCurRow();
590 USHORT nOldColId = GetCurColumnId();
592 BOOL bLastUpdateMode = GetUpdateMode();
593 SetUpdateMode( FALSE );
595 if( IsModified() )
596 SaveModified();
598 DeactivateCell();
600 RemoveColumns();
601 RowRemoved( 1, GetRowCount() );
603 // for row numbers
604 InsertHandleColumn( static_cast< sal_uInt16 >(
605 GetDataWindow().LogicToPixel( Size( 42, 0 )).getWidth() ));
607 const sal_Int32 nDefaultColumnWidth = 94;
609 sal_Int32 nColumnWidth( GetDataWindow().LogicToPixel( Size( nDefaultColumnWidth, 0 )).getWidth());
610 sal_Int32 nColumnCount = m_apDataBrowserModel->getColumnCount();
611 // nRowCount is a member of a base class
612 sal_Int32 nRowCountLocal = m_apDataBrowserModel->getMaxRowCount();
613 for( sal_Int32 nColIdx=1; nColIdx<=nColumnCount; ++nColIdx )
615 InsertDataColumn( static_cast< sal_uInt16 >( nColIdx ), GetColString( nColIdx ), nColumnWidth );
618 RowInserted( 1, nRowCountLocal );
619 GoToRow( ::std::min( nOldRow, GetRowCount() - 1 ));
620 GoToColumnId( ::std::min( nOldColId, static_cast< USHORT >( ColCount() - 1 )));
622 Window * pWin = this->GetParent();
623 if( !pWin )
624 pWin = this;
626 // fill series headers
627 clearHeaders();
628 const DataBrowserModel::tDataHeaderVector& aHeaders( m_apDataBrowserModel->getDataHeaders());
629 Link aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus ));
630 Link aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged ));
631 bool bIsHighContrast = pWin ? (pWin->GetDisplayBackground().GetColor().IsDark()) : false;
633 for( DataBrowserModel::tDataHeaderVector::const_iterator aIt( aHeaders.begin());
634 aIt != aHeaders.end(); ++aIt )
636 ::boost::shared_ptr< impl::SeriesHeader > spHeader( new impl::SeriesHeader( pWin ));
637 Reference< beans::XPropertySet > xSeriesProp( aIt->m_xDataSeries, uno::UNO_QUERY );
638 sal_Int32 nColor = 0;
639 // @todo: Set "DraftColor", i.e. interpolated colors for gradients, bitmaps, etc.
640 if( xSeriesProp.is() &&
641 ( xSeriesProp->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Color"))) >>= nColor ))
642 spHeader->SetColor( Color( nColor ));
643 spHeader->SetChartType( aIt->m_xChartType, aIt->m_bSwapXAndYAxis, bIsHighContrast );
644 spHeader->SetSeriesName(
645 String( DataSeriesHelper::getDataSeriesLabel(
646 aIt->m_xDataSeries,
647 (aIt->m_xChartType.is() ?
648 aIt->m_xChartType->getRoleOfSequenceForSeriesLabel() :
649 OUString( RTL_CONSTASCII_USTRINGPARAM("values-y"))))));
650 // index is 1-based, as 0 is for the column that contains the row-numbers
651 spHeader->SetRange( aIt->m_nStartColumn + 1, aIt->m_nEndColumn + 1 );
652 spHeader->SetGetFocusHdl( aFocusLink );
653 spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink );
654 m_aSeriesHeaders.push_back( spHeader );
657 ImplAdjustHeaderControls();
658 SetDirty();
659 SetUpdateMode( bLastUpdateMode );
660 ActivateCell();
661 Invalidate();
664 String DataBrowser::GetColString( sal_Int32 nColumnId ) const
666 OSL_ASSERT( m_apDataBrowserModel.get());
667 if( nColumnId > 0 )
668 return String( m_apDataBrowserModel->getRoleOfColumn( static_cast< sal_Int32 >( nColumnId ) - 1 ));
669 return String();
672 String DataBrowser::GetRowString( sal_Int32 nRow ) const
674 return String::CreateFromInt32( nRow + 1 );
677 String DataBrowser::GetCellText( long nRow, USHORT nColumnId ) const
679 String aResult;
681 if( nColumnId == 0 )
683 aResult = GetRowString( static_cast< sal_Int32 >( nRow ));
685 else if( nRow >= 0 &&
686 m_apDataBrowserModel.get())
688 sal_Int32 nColIndex = static_cast< sal_Int32 >( nColumnId ) - 1;
690 if( m_apDataBrowserModel->getCellType( nColIndex, nRow ) == DataBrowserModel::NUMBER )
692 double fData( m_apDataBrowserModel->getCellNumber( nColIndex, nRow ));
693 sal_Int32 nLabelColor;
694 bool bColorChanged = false;
696 if( ! ::rtl::math::isNan( fData ) &&
697 m_spNumberFormatterWrapper.get() )
698 aResult = String( m_spNumberFormatterWrapper->getFormattedString(
699 GetNumberFormatKey( nRow, nColumnId ),
700 fData, nLabelColor, bColorChanged ));
702 else
704 OSL_ASSERT( m_apDataBrowserModel->getCellType( nColIndex, nRow ) == DataBrowserModel::TEXT );
705 aResult = m_apDataBrowserModel->getCellText( nColIndex, nRow );
709 return aResult;
712 double DataBrowser::GetCellNumber( long nRow, USHORT nColumnId ) const
714 double fResult;
715 ::rtl::math::setNan( & fResult );
717 if(( nColumnId >= 1 ) && ( nRow >= 0 ) &&
718 m_apDataBrowserModel.get())
720 fResult = m_apDataBrowserModel->getCellNumber(
721 static_cast< sal_Int32 >( nColumnId ) - 1, nRow );
724 return fResult;
727 void DataBrowser::Resize()
729 BOOL bLastUpdateMode = GetUpdateMode();
730 SetUpdateMode( FALSE );
732 ::svt::EditBrowseBox::Resize();
733 ImplAdjustHeaderControls();
734 SetUpdateMode( bLastUpdateMode );
737 bool DataBrowser::SetReadOnly( bool bNewState )
739 bool bResult = m_bIsReadOnly;
741 if( m_bIsReadOnly != bNewState )
743 m_bIsReadOnly = bNewState;
744 Invalidate();
745 DeactivateCell();
748 return bResult;
751 bool DataBrowser::IsReadOnly() const
753 return m_bIsReadOnly;
757 void DataBrowser::SetClean()
759 m_bIsDirty = false;
762 void DataBrowser::SetDirty()
764 if( !m_bLiveUpdate )
765 m_bIsDirty = true;
768 void DataBrowser::CursorMoved()
770 EditBrowseBox::CursorMoved();
772 if( GetUpdateMode() && m_aCursorMovedHdlLink.IsSet())
773 m_aCursorMovedHdlLink.Call( this );
776 void DataBrowser::SetCellModifiedHdl( const Link& rLink )
778 m_aCellModifiedLink = rLink;
781 void DataBrowser::MouseButtonDown( const BrowserMouseEvent& rEvt )
783 if( !m_bDataValid )
784 ShowWarningBox();
785 else
786 EditBrowseBox::MouseButtonDown( rEvt );
789 void DataBrowser::ShowWarningBox()
791 WarningBox( this, WinBits( WB_OK ),
792 String( SchResId( STR_INVALID_NUMBER ))).Execute();
795 bool DataBrowser::ShowQueryBox()
797 QueryBox* pQueryBox = new QueryBox( this, WB_YES_NO, String( SchResId( STR_DATA_EDITOR_INCORRECT_INPUT )));
799 return ( pQueryBox->Execute() == RET_YES );
802 bool DataBrowser::IsDataValid()
804 bool bValid = true;
805 const sal_Int32 nRow = lcl_getRowInData( GetCurRow());
806 const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId());
808 if( m_apDataBrowserModel->getCellType( nCol, nRow ) == DataBrowserModel::NUMBER )
810 sal_uInt32 nDummy = 0;
811 double fDummy = 0.0;
812 String aText( m_aNumberEditField.GetText());
814 if( aText.Len() > 0 &&
815 m_spNumberFormatterWrapper.get() &&
816 m_spNumberFormatterWrapper->getSvNumberFormatter() &&
817 ! m_spNumberFormatterWrapper->getSvNumberFormatter()->IsNumberFormat(
818 aText, nDummy, fDummy ))
820 bValid = false;
824 return bValid;
827 bool DataBrowser::IsEnableItem()
829 return m_bDataValid;
832 void DataBrowser::CellModified()
834 m_bDataValid = IsDataValid();
835 SetDirty();
836 if( m_aCellModifiedLink.IsSet())
837 m_aCursorMovedHdlLink.Call( this );
840 void DataBrowser::SetDataFromModel(
841 const Reference< chart2::XChartDocument > & xChartDoc,
842 const Reference< uno::XComponentContext > & xContext )
844 if( m_bLiveUpdate )
846 m_xChartDoc.set( xChartDoc );
848 else
850 Reference< util::XCloneable > xCloneable( xChartDoc, uno::UNO_QUERY );
851 if( xCloneable.is())
852 m_xChartDoc.set( xCloneable->createClone(), uno::UNO_QUERY );
855 m_apDataBrowserModel.reset( new DataBrowserModel( m_xChartDoc, xContext ));
856 m_spNumberFormatterWrapper.reset(
857 new NumberFormatterWrapper(
858 Reference< util::XNumberFormatsSupplier >( m_xChartDoc, uno::UNO_QUERY )));
860 RenewTable();
862 const sal_Int32 nColCnt = m_apDataBrowserModel->getColumnCount();
863 const sal_Int32 nRowCnt = m_apDataBrowserModel->getMaxRowCount();
864 if( nRowCnt && nColCnt )
866 GoToRow( 0 );
867 GoToColumnId( 1 );
869 SetClean();
872 void DataBrowser::InsertColumn()
874 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
876 if( nColIdx >= 0 &&
877 m_apDataBrowserModel.get())
879 // save changes made to edit-field
880 if( IsModified() )
881 SaveModified();
883 m_apDataBrowserModel->insertDataSeries( nColIdx );
884 RenewTable();
888 void DataBrowser::RemoveColumn()
890 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
892 if( nColIdx >= 0 &&
893 m_apDataBrowserModel.get())
895 // save changes made to edit-field
896 if( IsModified() )
897 SaveModified();
899 m_bDataValid = true;
900 m_apDataBrowserModel->removeDataSeries( nColIdx );
901 RenewTable();
905 void DataBrowser::InsertRow()
907 sal_Int32 nRowIdx = lcl_getRowInData( GetCurRow());
909 if( nRowIdx >= 0 &&
910 m_apDataBrowserModel.get())
912 // save changes made to edit-field
913 if( IsModified() )
914 SaveModified();
916 m_apDataBrowserModel->insertDataPointForAllSeries( nRowIdx );
917 RenewTable();
921 void DataBrowser::RemoveRow()
923 sal_Int32 nRowIdx = lcl_getRowInData( GetCurRow());
925 if( nRowIdx >= 0 &&
926 m_apDataBrowserModel.get())
928 // save changes made to edit-field
929 if( IsModified() )
930 SaveModified();
932 m_bDataValid = true;
933 m_apDataBrowserModel->removeDataPointForAllSeries( nRowIdx );
934 RenewTable();
938 void DataBrowser::SwapColumn()
940 sal_Int32 nColIdx = lcl_getColumnInDataOrHeader( GetCurColumnId(), m_aSeriesHeaders );
942 if( nColIdx >= 0 &&
943 m_apDataBrowserModel.get())
945 // save changes made to edit-field
946 if( IsModified() )
947 SaveModified();
949 m_apDataBrowserModel->swapDataSeries( nColIdx );
951 // keep cursor in swapped column
952 if( GetCurColumnId() < ColCount() - 1 )
954 Dispatch( BROWSER_CURSORRIGHT );
956 RenewTable();
960 void DataBrowser::SwapRow()
962 sal_Int32 nRowIdx = lcl_getRowInData( GetCurRow());
964 if( nRowIdx >= 0 &&
965 m_apDataBrowserModel.get())
967 // save changes made to edit-field
968 if( IsModified() )
969 SaveModified();
971 m_apDataBrowserModel->swapDataPointForAllSeries( nRowIdx );
973 // keep cursor in swapped row
974 if( GetCurRow() < GetRowCount() - 1 )
976 Dispatch( BROWSER_CURSORDOWN );
978 RenewTable();
982 void DataBrowser::SetCursorMovedHdl( const Link& rLink )
984 m_aCursorMovedHdlLink = rLink;
987 // implementations for ::svt::EditBrowseBox (pure virtual methods)
988 void DataBrowser::PaintCell(
989 OutputDevice& rDev, const Rectangle& rRect, sal_uInt16 nColumnId ) const
991 Point aPos( rRect.TopLeft());
992 aPos.X() += 1;
994 String aText = GetCellText( m_nSeekRow, nColumnId );
995 Size TxtSize( GetDataWindow().GetTextWidth( aText ), GetDataWindow().GetTextHeight());
997 // clipping
998 if( aPos.X() < rRect.Right() || aPos.X() + TxtSize.Width() > rRect.Right() ||
999 aPos.Y() < rRect.Top() || aPos.Y() + TxtSize.Height() > rRect.Bottom())
1000 rDev.SetClipRegion( rRect );
1002 // allow for a disabled control ...
1003 sal_Bool bEnabled = IsEnabled();
1004 Color aOriginalColor = rDev.GetTextColor();
1005 if( ! bEnabled )
1006 rDev.SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
1008 // TEST
1009 // if( nColumnId == 1 )
1010 // // categories
1011 // rDev.SetFillColor( Color( 0xff, 0xff, 0xff ));
1012 // else if( nColumnId == 2 )
1013 // // x-values
1014 // rDev.SetFillColor( Color( 0xf0, 0xf0, 0xff ));
1015 // else
1016 // // y-values
1017 // rDev.SetFillColor( Color( 0xff, 0xff, 0xf0 ));
1019 // rDev.DrawRect( rRect );
1021 // draw the text
1022 rDev.DrawText( aPos, aText );
1024 // reset the color (if necessary)
1025 if( ! bEnabled )
1026 rDev.SetTextColor( aOriginalColor );
1028 if( rDev.IsClipRegion())
1029 rDev.SetClipRegion();
1032 sal_Bool DataBrowser::SeekRow( long nRow )
1034 if( ! EditBrowseBox::SeekRow( nRow ))
1035 return sal_False;
1037 if( nRow < 0 )
1038 m_nSeekRow = - 1;
1039 else
1040 m_nSeekRow = nRow;
1042 return sal_True;
1045 sal_Bool DataBrowser::IsTabAllowed( sal_Bool bForward ) const
1047 long nRow = GetCurRow();
1048 long nCol = GetCurColumnId();
1050 // column 0 is header-column
1051 long nBadCol = bForward
1052 ? GetColumnCount() - 1
1053 : 1;
1054 long nBadRow = bForward
1055 ? GetRowCount() - 1
1056 : 0;
1058 if( !m_bDataValid )
1060 const_cast< DataBrowser* >( this )->ShowWarningBox();
1061 return sal_False;
1064 return ( nRow != nBadRow ||
1065 nCol != nBadCol );
1068 ::svt::CellController* DataBrowser::GetController( long nRow, sal_uInt16 nCol )
1070 if( m_bIsReadOnly )
1071 return 0;
1073 if( CellContainsNumbers( nRow, nCol ))
1075 m_aNumberEditField.UseInputStringForFormatting();
1076 m_aNumberEditField.SetFormatKey( GetNumberFormatKey( nRow, nCol ));
1077 return m_rNumberEditController;
1080 return m_rTextEditController;
1083 void DataBrowser::InitController(
1084 ::svt::CellControllerRef& rController, long nRow, sal_uInt16 nCol )
1086 if( rController == m_rTextEditController )
1088 String aText( GetCellText( nRow, nCol ) );
1089 m_aTextEditField.SetText( aText );
1090 m_aTextEditField.SetSelection( Selection( 0, aText.Len() ));
1092 else if( rController == m_rNumberEditController )
1094 // treat invalid and empty text as Nan
1095 m_aNumberEditField.EnableNotANumber( true );
1096 if( ::rtl::math::isNan( GetCellNumber( nRow, nCol )))
1097 m_aNumberEditField.SetTextValue( String());
1098 else
1099 m_aNumberEditField.SetValue( GetCellNumber( nRow, nCol ) );
1100 String aText( m_aNumberEditField.GetText());
1101 m_aNumberEditField.SetSelection( Selection( 0, aText.Len()));
1103 else
1105 DBG_ERROR( "Invalid Controller" );
1109 bool DataBrowser::CellContainsNumbers( sal_Int32 nRow, sal_uInt16 nCol ) const
1111 if( ! m_apDataBrowserModel.get())
1112 return false;
1113 return (m_apDataBrowserModel->getCellType( lcl_getColumnInData( nCol ), lcl_getRowInData( nRow )) ==
1114 DataBrowserModel::NUMBER);
1117 sal_uInt32 DataBrowser::GetNumberFormatKey( sal_Int32 nRow, sal_uInt16 nCol ) const
1119 if( ! m_apDataBrowserModel.get())
1120 return 0;
1121 return m_apDataBrowserModel->getNumberFormatKey( lcl_getColumnInData( nCol ), lcl_getRowInData( nRow ));
1124 sal_Bool DataBrowser::SaveModified()
1126 if( ! IsModified() )
1127 return sal_True;
1129 sal_Bool bChangeValid = sal_True;
1131 const sal_Int32 nRow = lcl_getRowInData( GetCurRow());
1132 const sal_Int32 nCol = lcl_getColumnInData( GetCurColumnId());
1134 DBG_ASSERT( nRow >= 0 || nCol >= 0, "This cell should not be modified!" );
1136 switch( m_apDataBrowserModel->getCellType( nCol, nRow ))
1138 case DataBrowserModel::NUMBER:
1140 sal_uInt32 nDummy = 0;
1141 double fDummy = 0.0;
1142 String aText( m_aNumberEditField.GetText());
1143 // an empty string is valid, if no numberformatter exists, all
1144 // values are treated as valid
1145 if( aText.Len() > 0 &&
1146 m_spNumberFormatterWrapper.get() &&
1147 m_spNumberFormatterWrapper->getSvNumberFormatter() &&
1148 ! m_spNumberFormatterWrapper->getSvNumberFormatter()->IsNumberFormat(
1149 aText, nDummy, fDummy ))
1151 bChangeValid = sal_False;
1153 else
1155 double fData = m_aNumberEditField.GetValue();
1156 bChangeValid = m_apDataBrowserModel->setCellNumber( nCol, nRow, fData );
1159 break;
1160 case DataBrowserModel::TEXT:
1162 OUString aText( m_aTextEditField.GetText());
1163 bChangeValid = m_apDataBrowserModel->setCellText( nCol, nRow, aText );
1165 break;
1168 // the first valid change changes this to true
1169 if( bChangeValid )
1171 RowModified( GetCurRow(), GetCurColumnId());
1172 ::svt::CellController* pCtrl = GetController( GetCurRow(), GetCurColumnId());
1173 if( pCtrl )
1174 pCtrl->ClearModified();
1175 SetDirty();
1178 return bChangeValid;
1181 bool DataBrowser::EndEditing()
1183 if( IsModified())
1184 SaveModified();
1186 // apply changes made to series headers
1187 ::std::for_each( m_aSeriesHeaders.begin(), m_aSeriesHeaders.end(), impl::applyChangesFunctor());
1189 if( m_bDataValid )
1190 return true;
1191 else
1192 return ShowQueryBox();
1195 sal_Int16 DataBrowser::GetFirstVisibleColumNumber() const
1197 return GetFirstVisibleColNumber();
1200 void DataBrowser::ColumnResized( USHORT nColId )
1202 BOOL bLastUpdateMode = GetUpdateMode();
1203 SetUpdateMode( FALSE );
1205 EditBrowseBox::ColumnResized( nColId );
1206 ImplAdjustHeaderControls();
1207 SetUpdateMode( bLastUpdateMode );
1210 // virtual void MouseMove( const MouseEvent& rEvt );
1212 void DataBrowser::EndScroll()
1214 BOOL bLastUpdateMode = GetUpdateMode();
1215 SetUpdateMode( FALSE );
1217 EditBrowseBox::EndScroll();
1218 RenewSeriesHeaders();
1220 SetUpdateMode( bLastUpdateMode );
1223 void DataBrowser::RenewSeriesHeaders()
1225 Window * pWin = this->GetParent();
1226 if( !pWin )
1227 pWin = this;
1229 clearHeaders();
1230 DataBrowserModel::tDataHeaderVector aHeaders( m_apDataBrowserModel->getDataHeaders());
1231 Link aFocusLink( LINK( this, DataBrowser, SeriesHeaderGotFocus ));
1232 Link aSeriesHeaderChangedLink( LINK( this, DataBrowser, SeriesHeaderChanged ));
1233 bool bIsHighContrast = pWin ? (pWin->GetDisplayBackground().GetColor().IsDark()) : false;
1235 for( DataBrowserModel::tDataHeaderVector::const_iterator aIt( aHeaders.begin());
1236 aIt != aHeaders.end(); ++aIt )
1238 ::boost::shared_ptr< impl::SeriesHeader > spHeader( new impl::SeriesHeader( pWin ));
1239 Reference< beans::XPropertySet > xSeriesProp( aIt->m_xDataSeries, uno::UNO_QUERY );
1240 sal_Int32 nColor = 0;
1241 if( xSeriesProp.is() &&
1242 ( xSeriesProp->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("Color"))) >>= nColor ))
1243 spHeader->SetColor( Color( nColor ));
1244 spHeader->SetChartType( aIt->m_xChartType, aIt->m_bSwapXAndYAxis, bIsHighContrast );
1245 spHeader->SetSeriesName(
1246 String( DataSeriesHelper::getDataSeriesLabel(
1247 aIt->m_xDataSeries,
1248 (aIt->m_xChartType.is() ?
1249 aIt->m_xChartType->getRoleOfSequenceForSeriesLabel() :
1250 OUString( RTL_CONSTASCII_USTRINGPARAM("values-y"))))));
1251 spHeader->SetRange( aIt->m_nStartColumn + 1, aIt->m_nEndColumn + 1 );
1252 spHeader->SetGetFocusHdl( aFocusLink );
1253 spHeader->SetEditChangedHdl( aSeriesHeaderChangedLink );
1254 m_aSeriesHeaders.push_back( spHeader );
1257 ImplAdjustHeaderControls();
1260 void DataBrowser::ImplAdjustHeaderControls()
1262 sal_uInt16 nColCount = this->GetColumnCount();
1263 sal_uInt32 nCurrentPos = this->GetPosPixel().getX();
1264 sal_uInt32 nMaxPos = nCurrentPos + this->GetOutputSizePixel().getWidth();
1265 sal_uInt32 nStartPos = nCurrentPos;
1267 // width of header column
1268 nCurrentPos += this->GetColumnWidth( 0 );
1269 tSeriesHeaderContainer::iterator aIt( m_aSeriesHeaders.begin());
1270 sal_uInt16 i = this->GetFirstVisibleColumNumber();
1271 while( (aIt != m_aSeriesHeaders.end()) && ((*aIt)->GetStartColumn() < i) )
1272 ++aIt;
1273 for( ; i < nColCount && aIt != m_aSeriesHeaders.end(); ++i )
1275 if( (*aIt)->GetStartColumn() == i )
1276 nStartPos = nCurrentPos;
1278 nCurrentPos += (this->GetColumnWidth( i ));
1280 if( (*aIt)->GetEndColumn() == i )
1282 if( nStartPos < nMaxPos )
1284 (*aIt)->SetPixelPosX( nStartPos + 2 );
1285 (*aIt)->SetPixelWidth( nCurrentPos - nStartPos - 3 );
1287 else
1288 // do not hide, to get focus events. Move outside the dialog for "hiding"
1289 (*aIt)->SetPixelPosX( nMaxPos + 42 );
1290 ++aIt;
1295 IMPL_LINK( DataBrowser, SeriesHeaderGotFocus, impl::SeriesHeaderEdit*, pEdit )
1297 if( pEdit )
1299 pEdit->SetShowWarningBox( !m_bDataValid );
1301 if( !m_bDataValid )
1302 GoToCell( 0, 0 );
1303 else
1305 //DeactivateCell();
1306 MakeFieldVisible( GetCurRow(), static_cast< sal_uInt16 >( pEdit->getStartColumn()), true /* bComplete */ );
1307 ActivateCell();
1308 m_aCursorMovedHdlLink.Call( this );
1311 return 0;
1314 IMPL_LINK( DataBrowser, SeriesHeaderChanged, impl::SeriesHeaderEdit*, pEdit )
1316 if( pEdit )
1318 Reference< chart2::XDataSeries > xSeries(
1319 m_apDataBrowserModel->getDataSeriesByColumn( pEdit->getStartColumn() - 1 ));
1320 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
1321 if( xSource.is())
1323 Reference< chart2::XChartType > xChartType(
1324 m_apDataBrowserModel->getHeaderForSeries( xSeries ).m_xChartType );
1325 if( xChartType.is())
1327 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
1328 DataSeriesHelper::getDataSequenceByRole( xSource, xChartType->getRoleOfSequenceForSeriesLabel()));
1329 if( xLabeledSeq.is())
1331 Reference< container::XIndexReplace > xIndexReplace( xLabeledSeq->getLabel(), uno::UNO_QUERY );
1332 if( xIndexReplace.is())
1333 xIndexReplace->replaceByIndex(
1334 0, uno::makeAny( OUString( pEdit->GetText())));
1339 return 0;
1342 sal_Int32 DataBrowser::GetTotalWidth() const
1344 ULONG nWidth = 0;
1345 for ( USHORT nCol = 0; nCol < ColCount(); ++nCol )
1346 nWidth += GetColumnWidth( nCol );
1347 return static_cast< sal_Int32 >( nWidth );
1350 } // namespace chart