1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "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"
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>
54 #if OSL_DEBUG_LEVEL > 1
58 using namespace ::com::sun::star
;
60 using ::com::sun::star::uno::Reference
;
61 using ::com::sun::star::uno::Sequence
;
68 const Reference
< chart2::data::XDataSequence
> & xSeq
)
71 Reference
< beans::XPropertySet
> xProp( xSeq
, uno::UNO_QUERY
);
76 xProp
->getPropertyValue( "Role" ) >>= aResult
;
78 catch( const uno::Exception
& ex
)
80 ASSERT_EXCEPTION( ex
);
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
);
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;
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
126 catch( const uno::Exception
& ex
)
128 ASSERT_EXCEPTION( ex
);
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 )
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());
150 for( sal_Int32 nSeriesIdx
=1; nSeriesIdx
<rSeries
.getLength(); ++nSeriesIdx
)
152 bShared
= lcl_SequenceOfSeriesIsShared( rSeries
[nSeriesIdx
], xValues
);
157 aResult
.push_back( aLSeq
[nIdx
] );
163 sal_Int32
lcl_getValuesRepresentationIndex(
164 const Reference
< chart2::data::XLabeledDataSequence
> & xLSeq
)
166 sal_Int32 nResult
= -1;
169 Reference
< chart2::data::XDataSequence
> xSeq( xLSeq
->getValues());
172 OUString
aRep( xSeq
->getSourceRangeRepresentation());
173 nResult
= aRep
.toInt32();
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())
186 bool operator() ( const Reference
< chart2::data::XLabeledDataSequence
> & xLSeq
)
188 if (!xLSeq
.is() || !xLSeq
->getValues().is())
191 return xLSeq
->getValues()->getSourceRangeRepresentation() == m_aValuesRep
;
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
);
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
;
227 tDataColumn() : m_nIndexInDataSeries( -1 ), m_eCellType( TEXT
), m_nNumberFormatKey( 0 ) {}
230 const uno::Reference
<chart2::XDataSeries
> & xDataSeries
,
231 sal_Int32 nIndexInDataSeries
,
232 const OUString
& aUIRoleName
,
233 const uno::Reference
<chart2::data::XLabeledDataSequence
>& xLabeledDataSequence
,
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
));
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
))
269 DataBrowserModel::~DataBrowserModel()
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
);
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())
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;
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
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
;
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())
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
;
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.
353 Reference
< chart2::data::XDataSource
> xSource( xNewSeries
, uno::UNO_QUERY
);
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());
373 // Insert a new column in the internal data for the new sequence.
374 xDataProvider
->insertSequence( nIndex
- 1 );
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
);
385 Reference
< chart2::data::XDataSequence
> xNewLabelSeq(
386 xDataProvider
->createDataSequenceByRangeRepresentation(
388 OUString::number( nIndex
)));
389 lcl_copyDataSequenceProperties(
390 aLSequences
[nSeqIdx
]->getLabel(), xNewLabelSeq
);
391 aLSequences
[nSeqIdx
]->setLabel( xNewLabelSeq
);
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
));
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())
417 if( !isCategoriesColumn(nAfterColumnIndex
) )
418 nAfterColumnIndex
= getCategoryColumnCount()-1;
420 if(nAfterColumnIndex
<0)
422 OSL_FAIL( "wrong index for category level insertion" );
426 m_apDialogModel
->startControllerLockTimer();
427 ControllerLockGuardUNO
aLockedControllers( Reference
< frame::XModel
>( m_xChartDocument
, uno::UNO_QUERY
) );
428 xDataProvider
->insertComplexCategoryLevel( nAfterColumnIndex
+1 );
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())
441 m_apDialogModel
->startControllerLockTimer();
442 ControllerLockGuardUNO
aLockedControllers( Reference
< frame::XModel
>( m_xChartDocument
, uno::UNO_QUERY
) );
443 xDataProvider
->deleteComplexCategoryLevel( nAtColumnIndex
);
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())
455 if (isCategoriesColumn(nAtColumnIndex
))
457 removeComplexCategoryLevel(nAtColumnIndex
);
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.
477 Reference
<chart2::XDataSeriesContainer
> xSeriesCnt(
478 getHeaderForSeries(xSeries
).m_xChartType
, uno::UNO_QUERY
);
479 if (!xSeriesCnt
.is())
481 // Unexpected happened. Bail out.
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
)
513 xDataProvider
->deleteSequence( *aIt
);
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
);
527 m_apDialogModel
->moveSeries( xSeries
, DialogModel::MOVE_DOWN
);
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
);
539 ControllerLockGuardUNO
aGuard( m_apDialogModel
->getChartModel());
540 if( xDataProvider
.is())
541 xDataProvider
->swapDataPointWithNextOneForAllSequences( nFirstIndex
);
545 void DataBrowserModel::insertDataPointForAllSeries( sal_Int32 nAfterIndex
)
547 Reference
< chart2::XInternalDataProvider
> xDataProvider(
548 m_apDialogModel
->getDataProvider(), uno::UNO_QUERY
);
550 ControllerLockGuardUNO
aGuard( m_apDialogModel
->getChartModel());
551 if( xDataProvider
.is())
552 xDataProvider
->insertDataPointForAllSequences( nAfterIndex
);
556 void DataBrowserModel::removeDataPointForAllSeries( sal_Int32 nAtIndex
)
558 Reference
< chart2::XInternalDataProvider
> xDataProvider(
559 m_apDialogModel
->getDataProvider(), uno::UNO_QUERY
);
561 ControllerLockGuardUNO
aGuard( m_apDialogModel
->getChartModel());
562 if( xDataProvider
.is())
563 xDataProvider
->deleteDataPointForAllSequences( nAtIndex
);
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
)
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
;
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
;
597 double DataBrowserModel::getCellNumber( sal_Int32 nAtColumn
, sal_Int32 nAtRow
)
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
);
610 Sequence
< double > aValues( xData
->getNumericalData());
611 if( nAtRow
< aValues
.getLength())
612 fResult
= aValues
[nAtRow
];
618 uno::Any
DataBrowserModel::getCellAny( sal_Int32 nAtColumn
, sal_Int32 nAtRow
)
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() );
630 Sequence
< uno::Any
> aValues( xData
->getData());
631 if( nAtRow
< aValues
.getLength())
632 aResult
= aValues
[nAtRow
];
638 OUString
DataBrowserModel::getCellText( sal_Int32 nAtColumn
, sal_Int32 nAtRow
)
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
);
650 Sequence
< OUString
> aValues( xData
->getTextualData());
651 if( nAtRow
< aValues
.getLength())
652 aResult
= aValues
[nAtRow
];
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
;
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())
676 ControllerLockGuardUNO
aLockedControllers( Reference
< frame::XModel
>( m_xChartDocument
, uno::UNO_QUERY
) );
681 Reference
< container::XIndexReplace
> xIndexReplace(
682 m_aColumns
[ nIndex
].m_xLabeledDataSequence
->getLabel(), uno::UNO_QUERY_THROW
);
683 xIndexReplace
->replaceByIndex( 0, rValue
);
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
)
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());
736 sal_Int32
nLength( xSeq
->getData().getLength());
737 if( nLength
> 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
;
753 bool DataBrowserModel::isCategoriesColumn( sal_Int32 nColumnIndex
) const
755 if (nColumnIndex
< 0)
758 if (static_cast<size_t>(nColumnIndex
) >= m_aColumns
.size())
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
++;
776 return nLastTextColumnIndex
+1;
779 void DataBrowserModel::updateFromModel()
781 if( !m_xChartDocument
.is())
786 Reference
< chart2::XDiagram
> xDiagram( ChartModelHelper::findDiagram( m_xChartDocument
));
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());
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() )
814 tDataColumn aCategories
;
815 aCategories
.m_xLabeledDataSequence
.set( xCategories
);
816 if( lcl_ShowCategoriesAsDataLabel( xDiagram
))
817 aCategories
.m_aUIRoleName
= DialogModel::GetRoleDataLabel();
819 aCategories
.m_aUIRoleName
= lcl_getUIRoleName( xCategories
);
820 aCategories
.m_eCellType
= TEXTORDATE
;
821 m_aColumns
.push_back( aCategories
);
826 Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt( xDiagram
, uno::UNO_QUERY
);
827 if( !xCooSysCnt
.is())
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
);
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
);
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
);
866 Sequence
< Reference
< chart2::data::XLabeledDataSequence
> > aLSeqs( xSource
->getDataSequences());
867 if( aLSeqs
.getLength() == 0 )
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 );
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(
898 lcl_getUIRoleName( aLSeqs
[nSeqIdx
] ),
901 nSequenceNumberFormatKey
));
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
)
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(
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(
958 /* bPositiveValue = */ true,
960 if( xErrorLSequence
.is())
961 aSequences
.push_back( xErrorLSequence
);
964 StatisticsHelper::getErrorLabeledDataSequenceFromDataSource(
966 /* bPositiveValue = */ false,
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(
978 lcl_getUIRoleName( *aIt
),
982 ++rInOutSequenceIndex
;
986 catch( const uno::Exception
& ex
)
988 ASSERT_EXCEPTION( ex
);
994 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */