fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / chart2 / source / controller / dialogs / DataBrowserModel.cxx
blobe63151e6ee0352f1f975929a1efd4bf2aca746a1
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 "DataBrowserModel.hxx"
21 #include "DialogModel.hxx"
22 #include "ChartModelHelper.hxx"
23 #include "DiagramHelper.hxx"
24 #include "DataSeriesHelper.hxx"
25 #include "PropertyHelper.hxx"
26 #include "ControllerLockGuard.hxx"
27 #include "macros.hxx"
28 #include "StatisticsHelper.hxx"
29 #include "ContainerHelper.hxx"
30 #include "ChartTypeHelper.hxx"
31 #include "chartview/ExplicitValueProvider.hxx"
32 #include "ExplicitCategoriesProvider.hxx"
34 #include "ChartModel.hxx"
35 #include <unonames.hxx>
37 #include <com/sun/star/container/XIndexReplace.hpp>
38 #include <com/sun/star/chart2/XAxis.hpp>
39 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
40 #include <com/sun/star/chart2/XInternalDataProvider.hpp>
41 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
42 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
43 #include <com/sun/star/chart2/data/XDataSource.hpp>
44 #include <com/sun/star/chart2/data/XDataSink.hpp>
45 #include <com/sun/star/chart2/data/XLabeledDataSequence.hpp>
46 #include <com/sun/star/chart2/data/XNumericalDataSequence.hpp>
47 #include <com/sun/star/chart2/data/XTextualDataSequence.hpp>
48 #include <com/sun/star/util/XModifiable.hpp>
50 #include <rtl/math.hxx>
52 #include <algorithm>
54 #if OSL_DEBUG_LEVEL > 1
55 #include <cstdio>
56 #endif
58 using namespace ::com::sun::star;
60 using ::com::sun::star::uno::Reference;
61 using ::com::sun::star::uno::Sequence;
63 namespace chart {
65 namespace {
67 OUString lcl_getRole(
68 const Reference< chart2::data::XDataSequence > & xSeq )
70 OUString aResult;
71 Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY );
72 if( xProp.is())
74 try
76 xProp->getPropertyValue( "Role" ) >>= aResult;
78 catch( const uno::Exception & ex )
80 ASSERT_EXCEPTION( ex );
83 return aResult;
86 OUString lcl_getUIRoleName(
87 const Reference< chart2::data::XLabeledDataSequence > & xLSeq )
89 OUString aResult = DataSeriesHelper::getRole(xLSeq);
90 if( !aResult.isEmpty())
91 aResult = DialogModel::ConvertRoleFromInternalToUI(aResult);
92 return aResult;
95 void lcl_copyDataSequenceProperties(
96 const Reference< chart2::data::XDataSequence > & xOldSequence,
97 const Reference< chart2::data::XDataSequence > & xNewSequence )
99 Reference< beans::XPropertySet > xOldSeqProp( xOldSequence, uno::UNO_QUERY );
100 Reference< beans::XPropertySet > xNewSeqProp( xNewSequence, uno::UNO_QUERY );
101 comphelper::copyProperties( xOldSeqProp, xNewSeqProp );
104 bool lcl_SequenceOfSeriesIsShared(
105 const Reference< chart2::XDataSeries > & xSeries,
106 const Reference< chart2::data::XDataSequence > & xValues )
108 bool bResult = false;
109 if( !xValues.is())
110 return bResult;
113 OUString aValuesRole( lcl_getRole( xValues ));
114 OUString aValuesRep( xValues->getSourceRangeRepresentation());
115 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY_THROW );
116 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSeq( xSource->getDataSequences());
117 for( sal_Int32 i=0; i<aLSeq.getLength(); ++i )
118 if (aLSeq[i].is() && DataSeriesHelper::getRole(aLSeq[i]).equals(aValuesRole))
120 // getValues().is(), because lcl_getRole checked that already
121 bResult = (aValuesRep == aLSeq[i]->getValues()->getSourceRangeRepresentation());
122 // assumption: a role appears only once in a series
123 break;
126 catch( const uno::Exception & ex )
128 ASSERT_EXCEPTION( ex );
130 return bResult;
133 typedef ::std::vector< Reference< chart2::data::XLabeledDataSequence > > lcl_tSharedSeqVec;
135 lcl_tSharedSeqVec lcl_getSharedSequences( const Sequence< Reference< chart2::XDataSeries > > & rSeries )
137 // @todo: if only some series share a sequence, those have to be duplicated
138 // and made unshared for all series
139 lcl_tSharedSeqVec aResult;
140 // if we have only one series, we don't want any shared sequences
141 if( rSeries.getLength() <= 1 )
142 return aResult;
144 Reference< chart2::data::XDataSource > xSource( rSeries[0], uno::UNO_QUERY );
145 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSeq( xSource->getDataSequences());
146 for( sal_Int32 nIdx=0; nIdx<aLSeq.getLength(); ++nIdx )
148 Reference< chart2::data::XDataSequence > xValues( aLSeq[nIdx]->getValues());
149 bool bShared = true;
150 for( sal_Int32 nSeriesIdx=1; nSeriesIdx<rSeries.getLength(); ++nSeriesIdx )
152 bShared = lcl_SequenceOfSeriesIsShared( rSeries[nSeriesIdx], xValues );
153 if( !bShared )
154 break;
156 if( bShared )
157 aResult.push_back( aLSeq[nIdx] );
160 return aResult;
163 sal_Int32 lcl_getValuesRepresentationIndex(
164 const Reference< chart2::data::XLabeledDataSequence > & xLSeq )
166 sal_Int32 nResult = -1;
167 if( xLSeq.is())
169 Reference< chart2::data::XDataSequence > xSeq( xLSeq->getValues());
170 if( xSeq.is())
172 OUString aRep( xSeq->getSourceRangeRepresentation());
173 nResult = aRep.toInt32();
176 return nResult;
179 struct lcl_RepresentationsOfLSeqMatch : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool >
181 lcl_RepresentationsOfLSeqMatch( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) :
182 m_aValuesRep( xLSeq.is() ?
183 (xLSeq->getValues().is() ? xLSeq->getValues()->getSourceRangeRepresentation() : OUString())
184 : OUString() )
186 bool operator() ( const Reference< chart2::data::XLabeledDataSequence > & xLSeq )
188 if (!xLSeq.is() || !xLSeq->getValues().is())
189 return false;
191 return xLSeq->getValues()->getSourceRangeRepresentation() == m_aValuesRep;
193 private:
194 OUString m_aValuesRep;
197 struct lcl_RolesOfLSeqMatch : public ::std::unary_function< Reference< chart2::data::XLabeledDataSequence >, bool >
199 lcl_RolesOfLSeqMatch( const Reference< chart2::data::XLabeledDataSequence > & xLSeq ) :
200 m_aRole(DataSeriesHelper::getRole(xLSeq)) {}
202 bool operator() ( const Reference< chart2::data::XLabeledDataSequence > & xLSeq )
204 return DataSeriesHelper::getRole(xLSeq).equals(m_aRole);
206 private:
207 OUString m_aRole;
210 bool lcl_ShowCategoriesAsDataLabel( const Reference< chart2::XDiagram > & xDiagram )
212 return !DiagramHelper::isCategoryDiagram(xDiagram);
215 } // anonymous namespace
217 struct DataBrowserModel::tDataColumn
219 uno::Reference<chart2::XDataSeries> m_xDataSeries;
220 sal_Int32 m_nIndexInDataSeries;
221 OUString m_aUIRoleName;
222 uno::Reference<chart2::data::XLabeledDataSequence> m_xLabeledDataSequence;
223 eCellType m_eCellType;
224 sal_Int32 m_nNumberFormatKey;
226 // default CTOR
227 tDataColumn() : m_nIndexInDataSeries( -1 ), m_eCellType( TEXT ), m_nNumberFormatKey( 0 ) {}
228 // "full" CTOR
229 tDataColumn(
230 const uno::Reference<chart2::XDataSeries> & xDataSeries,
231 sal_Int32 nIndexInDataSeries,
232 const OUString& aUIRoleName,
233 const uno::Reference<chart2::data::XLabeledDataSequence>& xLabeledDataSequence,
234 eCellType aCellType,
235 sal_Int32 nNumberFormatKey ) :
236 m_xDataSeries( xDataSeries ),
237 m_nIndexInDataSeries( nIndexInDataSeries ),
238 m_aUIRoleName( aUIRoleName ),
239 m_xLabeledDataSequence( xLabeledDataSequence ),
240 m_eCellType( aCellType ),
241 m_nNumberFormatKey( nNumberFormatKey )
245 struct DataBrowserModel::implColumnLess : public ::std::binary_function<
246 DataBrowserModel::tDataColumn, DataBrowserModel::tDataColumn, bool >
248 bool operator() ( const first_argument_type & rLeft, const second_argument_type & rRight )
250 if( rLeft.m_xLabeledDataSequence.is() && rRight.m_xLabeledDataSequence.is())
252 return DialogModel::GetRoleIndexForSorting(DataSeriesHelper::getRole(rLeft.m_xLabeledDataSequence)) <
253 DialogModel::GetRoleIndexForSorting(DataSeriesHelper::getRole(rRight.m_xLabeledDataSequence));
255 return true;
259 DataBrowserModel::DataBrowserModel(
260 const Reference< chart2::XChartDocument > & xChartDoc,
261 const Reference< uno::XComponentContext > & xContext ) :
262 m_xChartDocument( xChartDoc ),
263 m_xContext( xContext ),
264 m_apDialogModel( new DialogModel( xChartDoc, xContext ))
266 updateFromModel();
269 DataBrowserModel::~DataBrowserModel()
272 namespace
274 struct lcl_DataSeriesOfHeaderMatches : public ::std::unary_function< ::chart::DataBrowserModel::tDataHeader, bool >
276 lcl_DataSeriesOfHeaderMatches(
277 const Reference< chart2::XDataSeries > & xSeriesToCompareWith ) :
278 m_xSeries( xSeriesToCompareWith )
280 bool operator() ( const ::chart::DataBrowserModel::tDataHeader & rHeader )
282 return (m_xSeries == rHeader.m_xDataSeries);
284 private:
285 Reference< chart2::XDataSeries > m_xSeries;
289 void DataBrowserModel::insertDataSeries( sal_Int32 nAfterColumnIndex )
291 OSL_ASSERT( m_apDialogModel.get());
292 Reference< chart2::XInternalDataProvider > xDataProvider(
293 m_apDialogModel->getDataProvider(), uno::UNO_QUERY );
295 if (!xDataProvider.is())
296 return;
298 if( isCategoriesColumn(nAfterColumnIndex) )
299 // Move to the last category column.
300 nAfterColumnIndex = getCategoryColumnCount()-1;
302 sal_Int32 nStartCol = 0;
303 Reference<chart2::XDiagram> xDiagram = ChartModelHelper::findDiagram(m_xChartDocument);
304 Reference<chart2::XChartType> xChartType;
305 Reference<chart2::XDataSeries> xSeries;
306 if (static_cast<size_t>(nAfterColumnIndex) < m_aColumns.size())
307 // Get the data series at specific column position (if available).
308 xSeries.set( m_aColumns[nAfterColumnIndex].m_xDataSeries );
310 sal_Int32 nSeriesNumberFormat = 0;
311 if( xSeries.is())
313 // Use the chart type of the currently selected data series.
314 xChartType.set( DiagramHelper::getChartTypeOfSeries( xDiagram, xSeries ));
316 // Find the corresponding header and determine the last column of this
317 // data series.
318 tDataHeaderVector::const_iterator aIt(
319 ::std::find_if( m_aHeaders.begin(), m_aHeaders.end(),
320 lcl_DataSeriesOfHeaderMatches( xSeries )));
321 if( aIt != m_aHeaders.end())
322 nStartCol = aIt->m_nEndColumn;
324 // Get the number format too.
325 Reference< beans::XPropertySet > xSeriesProps( xSeries, uno::UNO_QUERY );
326 if( xSeriesProps.is() )
327 xSeriesProps->getPropertyValue(CHART_UNONAME_NUMFMT) >>= nSeriesNumberFormat;
329 else
331 // No data series at specified column position. Use the first chart type.
332 xChartType.set( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ));
333 nStartCol = nAfterColumnIndex;
336 if (!xChartType.is())
337 return;
339 // Get shared sequences of current series. Normally multiple data series
340 // only share "values-x" sequences. (TODO: simplify this logic).
341 Reference< chart2::XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY );
342 lcl_tSharedSeqVec aSharedSequences;
343 if( xSeriesCnt.is())
344 aSharedSequences = lcl_getSharedSequences( xSeriesCnt->getDataSeries());
346 Reference<chart2::XDataSeries> xNewSeries =
347 m_apDialogModel->insertSeriesAfter(xSeries, xChartType, true);
349 if (!xNewSeries.is())
350 // Failed to insert new data series to the model. Bail out.
351 return;
353 Reference< chart2::data::XDataSource > xSource( xNewSeries, uno::UNO_QUERY );
354 if (xSource.is())
356 Sequence<Reference<chart2::data::XLabeledDataSequence> > aLSequences = xSource->getDataSequences();
357 sal_Int32 nSeqIdx = 0;
358 sal_Int32 nSeqSize = aLSequences.getLength();
359 for (sal_Int32 nIndex = nStartCol; nSeqIdx < nSeqSize; ++nSeqIdx)
361 lcl_tSharedSeqVec::const_iterator aSharedIt(
362 ::std::find_if( aSharedSequences.begin(), aSharedSequences.end(),
363 lcl_RolesOfLSeqMatch( aLSequences[nSeqIdx] )));
365 if( aSharedIt != aSharedSequences.end())
367 // Shared sequence. Most likely "values-x" sequence. Copy it from existing sequence.
368 aLSequences[nSeqIdx]->setValues( (*aSharedIt)->getValues());
369 aLSequences[nSeqIdx]->setLabel( (*aSharedIt)->getLabel());
371 else
373 // Insert a new column in the internal data for the new sequence.
374 xDataProvider->insertSequence( nIndex - 1 );
376 // values
377 Reference< chart2::data::XDataSequence > xNewSeq(
378 xDataProvider->createDataSequenceByRangeRepresentation(
379 OUString::number( nIndex )));
380 lcl_copyDataSequenceProperties(
381 aLSequences[nSeqIdx]->getValues(), xNewSeq );
382 aLSequences[nSeqIdx]->setValues( xNewSeq );
384 // labels
385 Reference< chart2::data::XDataSequence > xNewLabelSeq(
386 xDataProvider->createDataSequenceByRangeRepresentation(
387 "label " +
388 OUString::number( nIndex )));
389 lcl_copyDataSequenceProperties(
390 aLSequences[nSeqIdx]->getLabel(), xNewLabelSeq );
391 aLSequences[nSeqIdx]->setLabel( xNewLabelSeq );
392 ++nIndex;
397 if( nSeriesNumberFormat != 0 )
399 //give the new series the same number format as the former series especially for bubble charts thus the bubble size values can be edited with same format immediately
400 Reference< beans::XPropertySet > xNewSeriesProps( xNewSeries, uno::UNO_QUERY );
401 if( xNewSeriesProps.is() )
402 xNewSeriesProps->setPropertyValue(CHART_UNONAME_NUMFMT , uno::makeAny(nSeriesNumberFormat));
405 updateFromModel();
408 void DataBrowserModel::insertComplexCategoryLevel( sal_Int32 nAfterColumnIndex )
410 //create a new text column for complex categories
412 OSL_ASSERT( m_apDialogModel.get());
413 Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY );
414 if (!xDataProvider.is())
415 return;
417 if( !isCategoriesColumn(nAfterColumnIndex) )
418 nAfterColumnIndex = getCategoryColumnCount()-1;
420 if(nAfterColumnIndex<0)
422 OSL_FAIL( "wrong index for category level insertion" );
423 return;
426 m_apDialogModel->startControllerLockTimer();
427 ControllerLockGuardUNO aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) );
428 xDataProvider->insertComplexCategoryLevel( nAfterColumnIndex+1 );
429 updateFromModel();
432 void DataBrowserModel::removeComplexCategoryLevel( sal_Int32 nAtColumnIndex )
434 //delete a category column if there is more than one level (in case of a single column we do not get here)
435 OSL_ENSURE(nAtColumnIndex>0, "wrong index for categories deletion" );
437 Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY );
438 if (!xDataProvider.is())
439 return;
441 m_apDialogModel->startControllerLockTimer();
442 ControllerLockGuardUNO aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) );
443 xDataProvider->deleteComplexCategoryLevel( nAtColumnIndex );
445 updateFromModel();
448 void DataBrowserModel::removeDataSeriesOrComplexCategoryLevel( sal_Int32 nAtColumnIndex )
450 OSL_ASSERT( m_apDialogModel.get());
451 if (nAtColumnIndex < 0 || static_cast<size_t>(nAtColumnIndex) >= m_aColumns.size())
452 // Out of bound.
453 return;
455 if (isCategoriesColumn(nAtColumnIndex))
457 removeComplexCategoryLevel(nAtColumnIndex);
458 return;
461 const Reference<chart2::XDataSeries>& xSeries = m_aColumns[nAtColumnIndex].m_xDataSeries;
463 m_apDialogModel->deleteSeries(xSeries, getHeaderForSeries(xSeries).m_xChartType);
465 //delete sequences from internal data provider that are not used anymore
466 //but do not delete sequences that are still in use by the remaining series
468 Reference< chart2::XInternalDataProvider > xDataProvider( m_apDialogModel->getDataProvider(), uno::UNO_QUERY );
469 Reference< chart2::data::XDataSource > xSourceOfDeleted( xSeries, uno::UNO_QUERY );
470 if (!xDataProvider.is() || !xSourceOfDeleted.is())
472 // Something went wrong. Bail out.
473 updateFromModel();
474 return;
477 Reference<chart2::XDataSeriesContainer> xSeriesCnt(
478 getHeaderForSeries(xSeries).m_xChartType, uno::UNO_QUERY);
479 if (!xSeriesCnt.is())
481 // Unexpected happened. Bail out.
482 updateFromModel();
483 return;
486 // Collect all the remaining data sequences in the same chart type. The
487 // deleted data series is already gone by this point.
488 std::vector<Reference<chart2::data::XLabeledDataSequence> > aAllDataSeqs =
489 DataSeriesHelper::getAllDataSequences(xSeriesCnt->getDataSeries());
491 // Check if the sequences to be deleted are still referenced by any of
492 // the other data series. If not, mark them for deletion.
493 std::vector<sal_Int32> aSequenceIndexesToDelete;
494 Sequence<Reference<chart2::data::XLabeledDataSequence> > aSequencesOfDeleted = xSourceOfDeleted->getDataSequences();
495 for (sal_Int32 i = 0; i < aSequencesOfDeleted.getLength(); ++i)
497 std::vector<Reference<chart2::data::XLabeledDataSequence> >::const_iterator aHitIt(
498 ::std::find_if( aAllDataSeqs.begin(), aAllDataSeqs.end(),
499 lcl_RepresentationsOfLSeqMatch( aSequencesOfDeleted[i] )));
500 // if not used by the remaining series this sequence can be deleted
501 if( aHitIt == aAllDataSeqs.end() )
502 aSequenceIndexesToDelete.push_back( lcl_getValuesRepresentationIndex( aSequencesOfDeleted[i] ) );
505 // delete unnecessary sequences of the internal data
506 // iterate using greatest index first, so that deletion does not
507 // shift other sequences that will be deleted later
508 ::std::sort( aSequenceIndexesToDelete.begin(), aSequenceIndexesToDelete.end());
509 for( ::std::vector< sal_Int32 >::reverse_iterator aIt(
510 aSequenceIndexesToDelete.rbegin()); aIt != aSequenceIndexesToDelete.rend(); ++aIt )
512 if( *aIt != -1 )
513 xDataProvider->deleteSequence( *aIt );
516 updateFromModel();
519 void DataBrowserModel::swapDataSeries( sal_Int32 nFirstColumnIndex )
521 OSL_ASSERT( m_apDialogModel.get());
522 if( static_cast< tDataColumnVector::size_type >( nFirstColumnIndex ) < m_aColumns.size() - 1 )
524 Reference< chart2::XDataSeries > xSeries( m_aColumns[nFirstColumnIndex].m_xDataSeries );
525 if( xSeries.is())
527 m_apDialogModel->moveSeries( xSeries, DialogModel::MOVE_DOWN );
528 updateFromModel();
533 void DataBrowserModel::swapDataPointForAllSeries( sal_Int32 nFirstIndex )
535 OSL_ASSERT( m_apDialogModel.get());
536 Reference< chart2::XInternalDataProvider > xDataProvider(
537 m_apDialogModel->getDataProvider(), uno::UNO_QUERY );
538 // lockControllers
539 ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel());
540 if( xDataProvider.is())
541 xDataProvider->swapDataPointWithNextOneForAllSequences( nFirstIndex );
542 // unlockControllers
545 void DataBrowserModel::insertDataPointForAllSeries( sal_Int32 nAfterIndex )
547 Reference< chart2::XInternalDataProvider > xDataProvider(
548 m_apDialogModel->getDataProvider(), uno::UNO_QUERY );
549 // lockControllers
550 ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel());
551 if( xDataProvider.is())
552 xDataProvider->insertDataPointForAllSequences( nAfterIndex );
553 // unlockControllers
556 void DataBrowserModel::removeDataPointForAllSeries( sal_Int32 nAtIndex )
558 Reference< chart2::XInternalDataProvider > xDataProvider(
559 m_apDialogModel->getDataProvider(), uno::UNO_QUERY );
560 // lockControllers
561 ControllerLockGuardUNO aGuard( m_apDialogModel->getChartModel());
562 if( xDataProvider.is())
563 xDataProvider->deleteDataPointForAllSequences( nAtIndex );
564 // unlockControllers
567 DataBrowserModel::tDataHeader DataBrowserModel::getHeaderForSeries(
568 const Reference< chart2::XDataSeries > & xSeries ) const
570 for( tDataHeaderVector::const_iterator aIt( m_aHeaders.begin());
571 aIt != m_aHeaders.end(); ++aIt )
573 if( aIt->m_xDataSeries == xSeries )
574 return (*aIt);
576 return tDataHeader();
579 Reference< chart2::XDataSeries >
580 DataBrowserModel::getDataSeriesByColumn( sal_Int32 nColumn ) const
582 tDataColumnVector::size_type nIndex( nColumn );
583 if( nIndex < m_aColumns.size())
584 return m_aColumns[nIndex].m_xDataSeries;
585 return 0;
588 DataBrowserModel::eCellType DataBrowserModel::getCellType( sal_Int32 nAtColumn, sal_Int32 /* nAtRow */ ) const
590 eCellType eResult = TEXT;
591 tDataColumnVector::size_type nIndex( nAtColumn );
592 if( nIndex < m_aColumns.size())
593 eResult = m_aColumns[nIndex].m_eCellType;
594 return eResult;
597 double DataBrowserModel::getCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow )
599 double fResult;
600 ::rtl::math::setNan( & fResult );
602 tDataColumnVector::size_type nIndex( nAtColumn );
603 if( nIndex < m_aColumns.size() &&
604 m_aColumns[ nIndex ].m_xLabeledDataSequence.is())
606 Reference< chart2::data::XNumericalDataSequence > xData(
607 m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY );
608 if( xData.is())
610 Sequence< double > aValues( xData->getNumericalData());
611 if( nAtRow < aValues.getLength())
612 fResult = aValues[nAtRow];
615 return fResult;
618 uno::Any DataBrowserModel::getCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow )
620 uno::Any aResult;
622 tDataColumnVector::size_type nIndex( nAtColumn );
623 if( nIndex < m_aColumns.size() &&
624 m_aColumns[ nIndex ].m_xLabeledDataSequence.is())
626 Reference< chart2::data::XDataSequence > xData(
627 m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues() );
628 if( xData.is() )
630 Sequence< uno::Any > aValues( xData->getData());
631 if( nAtRow < aValues.getLength())
632 aResult = aValues[nAtRow];
635 return aResult;
638 OUString DataBrowserModel::getCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow )
640 OUString aResult;
642 tDataColumnVector::size_type nIndex( nAtColumn );
643 if( nIndex < m_aColumns.size() &&
644 m_aColumns[ nIndex ].m_xLabeledDataSequence.is())
646 Reference< chart2::data::XTextualDataSequence > xData(
647 m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY );
648 if( xData.is())
650 Sequence< OUString > aValues( xData->getTextualData());
651 if( nAtRow < aValues.getLength())
652 aResult = aValues[nAtRow];
655 return aResult;
658 sal_uInt32 DataBrowserModel::getNumberFormatKey( sal_Int32 nAtColumn, sal_Int32 /* nAtRow */ )
660 tDataColumnVector::size_type nIndex( nAtColumn );
661 if( nIndex < m_aColumns.size())
662 return m_aColumns[ nIndex ].m_nNumberFormatKey;
663 return 0;
666 bool DataBrowserModel::setCellAny( sal_Int32 nAtColumn, sal_Int32 nAtRow, const uno::Any & rValue )
668 bool bResult = false;
669 tDataColumnVector::size_type nIndex( nAtColumn );
670 if( nIndex < m_aColumns.size() &&
671 m_aColumns[ nIndex ].m_xLabeledDataSequence.is())
673 bResult = true;
676 ControllerLockGuardUNO aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) );
678 // label
679 if( nAtRow == -1 )
681 Reference< container::XIndexReplace > xIndexReplace(
682 m_aColumns[ nIndex ].m_xLabeledDataSequence->getLabel(), uno::UNO_QUERY_THROW );
683 xIndexReplace->replaceByIndex( 0, rValue );
685 else
687 Reference< container::XIndexReplace > xIndexReplace(
688 m_aColumns[ nIndex ].m_xLabeledDataSequence->getValues(), uno::UNO_QUERY_THROW );
689 xIndexReplace->replaceByIndex( nAtRow, rValue );
692 m_apDialogModel->startControllerLockTimer();
693 //notify change directly to the model (this is necessary here as sequences for complex categories not known directly to the chart model so they do not notify their changes) (for complex categories see issue #i82971#)
694 Reference< util::XModifiable > xModifiable( m_xChartDocument, uno::UNO_QUERY );
695 if( xModifiable.is() )
696 xModifiable->setModified(true);
698 catch( const uno::Exception & ex )
700 (void)(ex);
701 bResult = false;
704 return bResult;
707 bool DataBrowserModel::setCellNumber( sal_Int32 nAtColumn, sal_Int32 nAtRow, double fValue )
709 return (getCellType( nAtColumn, nAtRow ) == NUMBER) &&
710 setCellAny( nAtColumn, nAtRow, uno::makeAny( fValue ));
713 bool DataBrowserModel::setCellText( sal_Int32 nAtColumn, sal_Int32 nAtRow, const OUString & rText )
715 return (getCellType( nAtColumn, nAtRow ) == TEXT) &&
716 setCellAny( nAtColumn, nAtRow, uno::makeAny( rText ));
719 sal_Int32 DataBrowserModel::getColumnCount() const
721 return static_cast< sal_Int32 >( m_aColumns.size());
724 sal_Int32 DataBrowserModel::getMaxRowCount() const
726 sal_Int32 nResult = 0;
727 tDataColumnVector::const_iterator aIt( m_aColumns.begin());
728 for( ; aIt != m_aColumns.end(); ++aIt )
730 if( aIt->m_xLabeledDataSequence.is())
732 Reference< chart2::data::XDataSequence > xSeq(
733 aIt->m_xLabeledDataSequence->getValues());
734 if( !xSeq.is())
735 continue;
736 sal_Int32 nLength( xSeq->getData().getLength());
737 if( nLength > nResult )
738 nResult = nLength;
742 return nResult;
745 OUString DataBrowserModel::getRoleOfColumn( sal_Int32 nColumnIndex ) const
747 if( nColumnIndex != -1 &&
748 static_cast< sal_uInt32 >( nColumnIndex ) < m_aColumns.size())
749 return m_aColumns[ nColumnIndex ].m_aUIRoleName;
750 return OUString();
753 bool DataBrowserModel::isCategoriesColumn( sal_Int32 nColumnIndex ) const
755 if (nColumnIndex < 0)
756 return false;
758 if (static_cast<size_t>(nColumnIndex) >= m_aColumns.size())
759 return false;
761 // A column is a category when it doesn't have an associated data series.
762 return !m_aColumns[nColumnIndex].m_xDataSeries.is();
765 sal_Int32 DataBrowserModel::getCategoryColumnCount()
767 sal_Int32 nLastTextColumnIndex = -1;
768 tDataColumnVector::const_iterator aIt = m_aColumns.begin();
769 for( ; aIt != m_aColumns.end(); ++aIt )
771 if( !aIt->m_xDataSeries.is() )
772 nLastTextColumnIndex++;
773 else
774 break;
776 return nLastTextColumnIndex+1;
779 void DataBrowserModel::updateFromModel()
781 if( !m_xChartDocument.is())
782 return;
783 m_aColumns.clear();
784 m_aHeaders.clear();
786 Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram( m_xChartDocument ));
787 if( !xDiagram.is())
788 return;
790 // set template at DialogModel
791 uno::Reference< lang::XMultiServiceFactory > xFact( m_xChartDocument->getChartTypeManager(), uno::UNO_QUERY );
792 DiagramHelper::tTemplateWithServiceName aTemplateAndService =
793 DiagramHelper::getTemplateForDiagram( xDiagram, xFact );
794 if( aTemplateAndService.first.is())
795 m_apDialogModel->setTemplate( aTemplateAndService.first );
797 sal_Int32 nHeaderStart = 0;
798 sal_Int32 nHeaderEnd = 0;
800 Reference< frame::XModel > xChartModel( m_xChartDocument, uno::UNO_QUERY );
801 ChartModel* pModel = dynamic_cast<ChartModel*>(xChartModel.get());
802 if (!pModel)
803 return;
804 ExplicitCategoriesProvider aExplicitCategoriesProvider( ChartModelHelper::getFirstCoordinateSystem(xChartModel), *pModel );
806 const Sequence< Reference< chart2::data::XLabeledDataSequence> >& rSplitCategoriesList( aExplicitCategoriesProvider.getSplitCategoriesList() );
807 sal_Int32 nLevelCount = rSplitCategoriesList.getLength();
808 for( sal_Int32 nL = 0; nL<nLevelCount; nL++ )
810 Reference< chart2::data::XLabeledDataSequence > xCategories( rSplitCategoriesList[nL] );
811 if( !xCategories.is() )
812 continue;
814 tDataColumn aCategories;
815 aCategories.m_xLabeledDataSequence.set( xCategories );
816 if( lcl_ShowCategoriesAsDataLabel( xDiagram ))
817 aCategories.m_aUIRoleName = DialogModel::GetRoleDataLabel();
818 else
819 aCategories.m_aUIRoleName = lcl_getUIRoleName( xCategories );
820 aCategories.m_eCellType = TEXTORDATE;
821 m_aColumns.push_back( aCategories );
822 ++nHeaderStart;
826 Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY );
827 if( !xCooSysCnt.is())
828 return;
829 Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
830 for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
832 Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
833 Sequence< Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes());
834 sal_Int32 nXAxisNumberFormat = DataSeriesHelper::getNumberFormatKeyFromAxis( 0, aCooSysSeq[nCooSysIdx], 0, 0 );
836 for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx )
838 Reference< chart2::XDataSeriesContainer > xSeriesCnt( aChartTypes[nCTIdx], uno::UNO_QUERY );
839 if( xSeriesCnt.is())
841 OUString aRoleForDataLabelNumberFormat = ChartTypeHelper::getRoleOfSequenceForDataLabelNumberFormatDetection( aChartTypes[nCTIdx] );
843 Sequence< Reference< chart2::XDataSeries > > aSeries( xSeriesCnt->getDataSeries());
844 lcl_tSharedSeqVec aSharedSequences( lcl_getSharedSequences( aSeries ));
845 for( lcl_tSharedSeqVec::const_iterator aIt( aSharedSequences.begin());
846 aIt != aSharedSequences.end(); ++aIt )
848 tDataColumn aSharedSequence;
849 aSharedSequence.m_xLabeledDataSequence = *aIt;
850 aSharedSequence.m_aUIRoleName = lcl_getUIRoleName( *aIt );
851 aSharedSequence.m_eCellType = NUMBER;
852 // as the sequences are shared it should be ok to take the first series
853 // @todo: dimension index 0 for x-values used here. This is just a guess.
854 // Also, the axis index is 0, as there is usually only one x-axis
855 aSharedSequence.m_nNumberFormatKey = nXAxisNumberFormat;
856 m_aColumns.push_back( aSharedSequence );
857 ++nHeaderStart;
859 for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeries.getLength(); ++nSeriesIdx )
861 tDataColumnVector::size_type nStartColIndex = m_aColumns.size();
862 Reference< chart2::XDataSeries > xSeries( aSeries[nSeriesIdx] );
863 Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
864 if( xSource.is())
866 Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSeqs( xSource->getDataSequences());
867 if( aLSeqs.getLength() == 0 )
868 continue;
869 nHeaderEnd = nHeaderStart;
871 // @todo: dimension index 1 for y-values used here. This is just a guess
872 sal_Int32 nYAxisNumberFormatKey =
873 DataSeriesHelper::getNumberFormatKeyFromAxis(
874 aSeries[nSeriesIdx], aCooSysSeq[nCooSysIdx], 1 );
876 sal_Int32 nSeqIdx=0;
877 for( ; nSeqIdx<aLSeqs.getLength(); ++nSeqIdx )
879 sal_Int32 nSequenceNumberFormatKey = nYAxisNumberFormatKey;
880 OUString aRole = DataSeriesHelper::getRole(aLSeqs[nSeqIdx]);
882 if( aRole.equals( aRoleForDataLabelNumberFormat ) )
884 nSequenceNumberFormatKey = ExplicitValueProvider::getExplicitNumberFormatKeyForDataLabel(
885 Reference< beans::XPropertySet >( xSeries, uno::UNO_QUERY ), xSeries, -1, xDiagram );
887 else if( aRole == "values-x" )
888 nSequenceNumberFormatKey = nXAxisNumberFormat;
890 if( ::std::find_if( aSharedSequences.begin(), aSharedSequences.end(),
891 lcl_RepresentationsOfLSeqMatch( aLSeqs[nSeqIdx] )) == aSharedSequences.end())
893 // no shared sequence
894 m_aColumns.push_back(
895 tDataColumn(
896 aSeries[nSeriesIdx],
897 nSeqIdx,
898 lcl_getUIRoleName( aLSeqs[nSeqIdx] ),
899 aLSeqs[nSeqIdx],
900 NUMBER,
901 nSequenceNumberFormatKey ));
902 ++nHeaderEnd;
904 // else skip
906 bool bSwapXAndYAxis = false;
909 Reference< beans::XPropertySet > xProp( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY );
910 xProp->getPropertyValue( "SwapXAndYAxis" ) >>= bSwapXAndYAxis;
912 catch( const beans::UnknownPropertyException & ex )
914 (void)ex;
917 // add ranges for error bars if present for a series
918 if( StatisticsHelper::usesErrorBarRanges( aSeries[nSeriesIdx], /* bYError = */ true ))
919 addErrorBarRanges( aSeries[nSeriesIdx], nYAxisNumberFormatKey, nSeqIdx, nHeaderEnd, true );
921 if( StatisticsHelper::usesErrorBarRanges( aSeries[nSeriesIdx], /* bYError = */ false ))
922 addErrorBarRanges( aSeries[nSeriesIdx], nYAxisNumberFormatKey, nSeqIdx, nHeaderEnd, false );
924 m_aHeaders.push_back(
925 tDataHeader(
926 aSeries[nSeriesIdx],
927 aChartTypes[nCTIdx],
928 bSwapXAndYAxis,
929 nHeaderStart,
930 nHeaderEnd - 1 ));
932 nHeaderStart = nHeaderEnd;
934 ::std::sort( m_aColumns.begin() + nStartColIndex, m_aColumns.end(), implColumnLess() );
942 void DataBrowserModel::addErrorBarRanges(
943 const Reference< chart2::XDataSeries > & xDataSeries,
944 sal_Int32 nNumberFormatKey,
945 sal_Int32 & rInOutSequenceIndex,
946 sal_Int32 & rInOutHeaderEnd, bool bYError )
950 ::std::vector< Reference< chart2::data::XLabeledDataSequence > > aSequences;
952 Reference< chart2::data::XDataSource > xErrorSource(
953 StatisticsHelper::getErrorBars( xDataSeries, bYError ), uno::UNO_QUERY );
955 Reference< chart2::data::XLabeledDataSequence > xErrorLSequence(
956 StatisticsHelper::getErrorLabeledDataSequenceFromDataSource(
957 xErrorSource,
958 /* bPositiveValue = */ true,
959 bYError ));
960 if( xErrorLSequence.is())
961 aSequences.push_back( xErrorLSequence );
963 xErrorLSequence.set(
964 StatisticsHelper::getErrorLabeledDataSequenceFromDataSource(
965 xErrorSource,
966 /* bPositiveValue = */ false,
967 bYError ));
968 if( xErrorLSequence.is())
969 aSequences.push_back( xErrorLSequence );
971 for( ::std::vector< Reference< chart2::data::XLabeledDataSequence > >::const_iterator aIt( aSequences.begin());
972 aIt != aSequences.end(); ++aIt )
974 m_aColumns.push_back(
975 tDataColumn(
976 xDataSeries,
977 rInOutSequenceIndex,
978 lcl_getUIRoleName( *aIt ),
979 *aIt,
980 NUMBER,
981 nNumberFormatKey ));
982 ++rInOutSequenceIndex;
983 ++rInOutHeaderEnd;
986 catch( const uno::Exception & ex )
988 ASSERT_EXCEPTION( ex );
992 } // namespace chart
994 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */