1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
30 
31 #include "DialogModel.hxx"
32 #include "RangeSelectionHelper.hxx"
33 #include "PropertyHelper.hxx"
34 #include "DataSeriesHelper.hxx"
35 #include "DataSourceHelper.hxx"
36 #include "DiagramHelper.hxx"
37 #include "macros.hxx"
38 #include "Strings.hrc"
39 #include "ResId.hxx"
40 #include "ContainerHelper.hxx"
41 #include "CommonFunctors.hxx"
42 #include "ControllerLockGuard.hxx"
43 #include "ChartTypeHelper.hxx"
44 #include "ThreeDHelper.hxx"
45 
46 #include <com/sun/star/util/XCloneable.hpp>
47 #include <com/sun/star/chart2/AxisType.hpp>
48 #include <com/sun/star/chart2/XTitled.hpp>
49 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
50 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
51 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
52 #include <com/sun/star/chart2/data/XDataSink.hpp>
53 
54 #include <tools/string.hxx>
55 
56 #include <utility>
57 #include <algorithm>
58 #include <iterator>
59 #include <functional>
60 #include <numeric>
61 
62 using namespace ::com::sun::star;
63 using namespace ::com::sun::star::chart2;
64 using namespace ::chart::ContainerHelper;
65 
66 using ::com::sun::star::uno::Reference;
67 using ::com::sun::star::uno::Sequence;
68 using ::rtl::OUString;
69 
70 // ----------------------------------------
71 
72 namespace
73 {
74 const OUString lcl_aLabelRole( RTL_CONSTASCII_USTRINGPARAM( "label" ));
75 
76 struct lcl_ChartTypeToSeriesCnt : ::std::unary_function<
77         Reference< XChartType >, Reference< XDataSeriesContainer > >
78 {
79     Reference< XDataSeriesContainer > operator() (
80         const Reference< XChartType > & xChartType )
81     {
82         return Reference< XDataSeriesContainer >::query( xChartType );
83     }
84 };
85 
86 OUString lcl_ConvertRole( const OUString & rRoleString, bool bFromInternalToUI )
87 {
88     OUString aResult( rRoleString );
89 
90     typedef ::std::map< OUString, OUString > tTranslationMap;
91     static tTranslationMap aTranslationMap;
92 
93     if( aTranslationMap.size() == 0 )
94     {
95         aTranslationMap[ C2U( "categories" ) ] =   OUString( String( ::chart::SchResId( STR_DATA_ROLE_CATEGORIES )));
96         aTranslationMap[ C2U( "error-bars-x" ) ] = OUString( String( ::chart::SchResId( STR_DATA_ROLE_X_ERROR )));
97         aTranslationMap[ C2U( "error-bars-x-positive" ) ] = OUString( String( ::chart::SchResId( STR_DATA_ROLE_X_ERROR_POSITIVE )));
98         aTranslationMap[ C2U( "error-bars-x-negative" ) ] = OUString( String( ::chart::SchResId( STR_DATA_ROLE_X_ERROR_NEGATIVE )));
99         aTranslationMap[ C2U( "error-bars-y" ) ] = OUString( String( ::chart::SchResId( STR_DATA_ROLE_Y_ERROR )));
100         aTranslationMap[ C2U( "error-bars-y-positive" ) ] = OUString( String( ::chart::SchResId( STR_DATA_ROLE_Y_ERROR_POSITIVE )));
101         aTranslationMap[ C2U( "error-bars-y-negative" ) ] = OUString( String( ::chart::SchResId( STR_DATA_ROLE_Y_ERROR_NEGATIVE )));
102         aTranslationMap[ C2U( "label" ) ] =        OUString( String( ::chart::SchResId( STR_DATA_ROLE_LABEL )));
103         aTranslationMap[ C2U( "values-first" ) ] = OUString( String( ::chart::SchResId( STR_DATA_ROLE_FIRST )));
104         aTranslationMap[ C2U( "values-last" ) ] =  OUString( String( ::chart::SchResId( STR_DATA_ROLE_LAST )));
105         aTranslationMap[ C2U( "values-max" ) ] =   OUString( String( ::chart::SchResId( STR_DATA_ROLE_MAX )));
106         aTranslationMap[ C2U( "values-min" ) ] =   OUString( String( ::chart::SchResId( STR_DATA_ROLE_MIN )));
107         aTranslationMap[ C2U( "values-x" ) ] =     OUString( String( ::chart::SchResId( STR_DATA_ROLE_X )));
108         aTranslationMap[ C2U( "values-y" ) ] =     OUString( String( ::chart::SchResId( STR_DATA_ROLE_Y )));
109         aTranslationMap[ C2U( "values-size" ) ] =  OUString( String( ::chart::SchResId( STR_DATA_ROLE_SIZE )));
110     }
111 
112     if( bFromInternalToUI )
113     {
114         tTranslationMap::const_iterator aIt( aTranslationMap.find( rRoleString ));
115         if( aIt != aTranslationMap.end())
116         {
117             aResult = (*aIt).second;
118         }
119     }
120     else
121     {
122         tTranslationMap::const_iterator aIt(
123             ::std::find_if( aTranslationMap.begin(), aTranslationMap.end(),
124                             ::std::compose1( ::std::bind2nd(
125                                                  ::std::equal_to< tTranslationMap::mapped_type >(),
126                                                  rRoleString ),
127                                              ::std::select2nd< tTranslationMap::value_type >())));
128 
129         if( aIt != aTranslationMap.end())
130             aResult = (*aIt).first;
131     }
132 
133     return aResult;
134 }
135 
136 typedef ::std::map< ::rtl::OUString, sal_Int32 > lcl_tRoleIndexMap;
137 
138 void lcl_createRoleIndexMap( lcl_tRoleIndexMap & rOutMap )
139 {
140     rOutMap.clear();
141     sal_Int32 nIndex = 0;
142 
143     rOutMap[ C2U( "label" ) ] =                 ++nIndex;
144     rOutMap[ C2U( "categories" ) ] =            ++nIndex;
145     rOutMap[ C2U( "values-x" ) ] =              ++nIndex;
146     rOutMap[ C2U( "values-y" ) ] =              ++nIndex;
147     rOutMap[ C2U( "error-bars-x" ) ] =          ++nIndex;
148     rOutMap[ C2U( "error-bars-x-positive" ) ] = ++nIndex;
149     rOutMap[ C2U( "error-bars-x-negative" ) ] = ++nIndex;
150     rOutMap[ C2U( "error-bars-y" ) ] =          ++nIndex;
151     rOutMap[ C2U( "error-bars-y-positive" ) ] = ++nIndex;
152     rOutMap[ C2U( "error-bars-y-negative" ) ] = ++nIndex;
153     rOutMap[ C2U( "values-first" ) ] =          ++nIndex;
154     rOutMap[ C2U( "values-min" ) ] =            ++nIndex;
155     rOutMap[ C2U( "values-max" ) ] =            ++nIndex;
156     rOutMap[ C2U( "values-last" ) ] =           ++nIndex;
157     rOutMap[ C2U( "values-size" ) ] =           ++nIndex;
158 }
159 
160 struct lcl_DataSeriesContainerAppend : public
161     ::std::iterator< ::std::output_iterator_tag, Reference< XDataSeriesContainer > >
162 {
163     typedef ::std::vector< ::chart::DialogModel::tSeriesWithChartTypeByName > tContainerType;
164 
165     explicit lcl_DataSeriesContainerAppend( tContainerType & rCnt )
166             : m_rDestCnt( rCnt )
167     {}
168 
169     lcl_DataSeriesContainerAppend & operator= ( const value_type & xVal )
170     {
171         try
172         {
173             if( xVal.is())
174             {
175                 Sequence< Reference< XDataSeries > > aSeq( xVal->getDataSeries());
176                 OUString aRole( RTL_CONSTASCII_USTRINGPARAM("values-y"));
177                 Reference< XChartType > xCT( xVal, uno::UNO_QUERY );
178                 if( xCT.is())
179                     aRole = xCT->getRoleOfSequenceForSeriesLabel();
180                 for( sal_Int32 nI = 0; nI < aSeq.getLength(); ++ nI )
181                 {
182                     m_rDestCnt.push_back(
183                         ::chart::DialogModel::tSeriesWithChartTypeByName(
184                             ::chart::DataSeriesHelper::getDataSeriesLabel( aSeq[nI], aRole ),
185                             ::std::make_pair( aSeq[nI], xCT )));
186                 }
187             }
188         }
189         catch( uno::Exception & ex )
190         {
191             ASSERT_EXCEPTION( ex );
192         }
193         return *this;
194     }
195 
196     lcl_DataSeriesContainerAppend & operator* ()     { return *this; }
197     lcl_DataSeriesContainerAppend & operator++ ()    { return *this; }
198     lcl_DataSeriesContainerAppend & operator++ (int) { return *this; }
199 
200 private:
201     tContainerType & m_rDestCnt;
202 };
203 
204 struct lcl_RolesWithRangeAppend : public
205     ::std::iterator< ::std::output_iterator_tag, Reference< data::XLabeledDataSequence > >
206 {
207     typedef ::chart::DialogModel::tRolesWithRanges tContainerType;
208 
209     explicit lcl_RolesWithRangeAppend( tContainerType & rCnt,
210                                        const ::rtl::OUString & aLabelRole )
211             : m_rDestCnt( rCnt ),
212               m_aRoleForLabelSeq( aLabelRole )
213     {}
214 
215     lcl_RolesWithRangeAppend & operator= ( const value_type & xVal )
216     {
217         try
218         {
219             if( xVal.is())
220             {
221                 // data sequence
222                 Reference< data::XDataSequence > xSeq( xVal->getValues());
223                 if( xSeq.is())
224                 {
225                     OUString aRole;
226                     Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY_THROW );
227                     if( xProp->getPropertyValue( C2U("Role")) >>= aRole )
228                     {
229                         m_rDestCnt.insert(
230                             tContainerType::value_type(
231                                 aRole, xSeq->getSourceRangeRepresentation()));
232                         // label
233                         if( aRole.equals( m_aRoleForLabelSeq ))
234                         {
235                             Reference< data::XDataSequence > xLabelSeq( xVal->getLabel());
236                             if( xLabelSeq.is())
237                             {
238                                 m_rDestCnt.insert(
239                                     tContainerType::value_type(
240                                         lcl_aLabelRole, xLabelSeq->getSourceRangeRepresentation()));
241                             }
242                         }
243                     }
244                 }
245             }
246         }
247         catch( uno::Exception & ex )
248         {
249             ASSERT_EXCEPTION( ex );
250         }
251         return *this;
252     }
253 
254     lcl_RolesWithRangeAppend & operator* ()     { return *this; }
255     lcl_RolesWithRangeAppend & operator++ ()    { return *this; }
256     lcl_RolesWithRangeAppend & operator++ (int) { return *this; }
257 
258 private:
259     tContainerType & m_rDestCnt;
260     OUString m_aRoleForLabelSeq;
261 };
262 
263 void lcl_SetSequenceRole(
264     const Reference< data::XDataSequence > & xSeq,
265     const OUString & rRole )
266 {
267     Reference< beans::XPropertySet > xProp( xSeq, uno::UNO_QUERY );
268     if( xProp.is())
269         xProp->setPropertyValue( C2U("Role"), uno::makeAny( rRole ));
270 }
271 
272 Reference< XDataSeries > lcl_CreateNewSeries(
273     const Reference< uno::XComponentContext > & xContext,
274     const Reference< XChartType > & xChartType,
275     sal_Int32 nNewSeriesIndex,
276     sal_Int32 nTotalNumberOfSeriesInCTGroup,
277     const Reference< XDiagram > & xDiagram,
278     const Reference< XChartTypeTemplate > & xTemplate,
279     bool bCreateDataCachedSequences )
280 {
281     // create plain series
282     Reference< XDataSeries > xResult(
283         xContext->getServiceManager()->createInstanceWithContext(
284             C2U( "com.sun.star.chart2.DataSeries" ),
285             xContext ), uno::UNO_QUERY );
286     if( xTemplate.is())
287     {
288         Reference< beans::XPropertySet > xResultProp( xResult, uno::UNO_QUERY );
289         if( xResultProp.is())
290         {
291             // @deprecated: correct default color should be found by view
292             // without setting it as hard attribute
293             Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme());
294             if( xColorScheme.is())
295                 xResultProp->setPropertyValue(
296                     C2U("Color"), uno::makeAny( xColorScheme->getColorByIndex( nNewSeriesIndex )));
297         }
298         sal_Int32 nGroupIndex=0;
299         if( xChartType.is())
300         {
301             Sequence< Reference< XChartType > > aCTs(
302                 ::chart::DiagramHelper::getChartTypesFromDiagram( xDiagram ));
303             for( ; nGroupIndex<aCTs.getLength(); ++nGroupIndex)
304                 if( aCTs[nGroupIndex] == xChartType )
305                     break;
306             if( nGroupIndex == aCTs.getLength())
307                 nGroupIndex = 0;
308         }
309         xTemplate->applyStyle( xResult, nGroupIndex, nNewSeriesIndex, nTotalNumberOfSeriesInCTGroup );
310     }
311 
312     if( bCreateDataCachedSequences )
313     {
314         // set chart type specific roles
315         Reference< data::XDataSink > xSink( xResult, uno::UNO_QUERY );
316         if( xChartType.is() && xSink.is())
317         {
318             ::std::vector< Reference< data::XLabeledDataSequence > > aNewSequences;
319             const OUString aRoleOfSeqForSeriesLabel = xChartType->getRoleOfSequenceForSeriesLabel();
320             const OUString aLabel( String( ::chart::SchResId( STR_DATA_UNNAMED_SERIES )));
321             const Sequence< OUString > aRoles( xChartType->getSupportedMandatoryRoles());
322             const Sequence< OUString > aOptRoles( xChartType->getSupportedOptionalRoles());
323             sal_Int32 nI = 0;
324 
325             for(nI=0; nI<aRoles.getLength(); ++nI)
326             {
327                 if( aRoles[nI].equals( lcl_aLabelRole ))
328                     continue;
329                 Reference< data::XDataSequence > xSeq( ::chart::DataSourceHelper::createCachedDataSequence() );
330                 lcl_SetSequenceRole( xSeq, aRoles[nI] );
331                 // assert that aRoleOfSeqForSeriesLabel is part of the mandatory roles
332                 if( aRoles[nI].equals( aRoleOfSeqForSeriesLabel ))
333                 {
334                     Reference< data::XDataSequence > xLabel( ::chart::DataSourceHelper::createCachedDataSequence( aLabel ));
335                     lcl_SetSequenceRole( xLabel, lcl_aLabelRole );
336                     aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq, xLabel ));
337                 }
338                 else
339                     aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq ));
340             }
341 
342             for(nI=0; nI<aOptRoles.getLength(); ++nI)
343             {
344                 if( aOptRoles[nI].equals( lcl_aLabelRole ))
345                     continue;
346                 Reference< data::XDataSequence > xSeq( ::chart::DataSourceHelper::createCachedDataSequence());
347                 lcl_SetSequenceRole( xSeq, aOptRoles[nI] );
348                 aNewSequences.push_back( ::chart::DataSourceHelper::createLabeledDataSequence( xSeq ));
349             }
350 
351             xSink->setData( ContainerToSequence( aNewSequences ));
352         }
353     }
354 
355     return xResult;
356 }
357 
358 struct lcl_addSeriesNumber : public ::std::binary_function<
359         sal_Int32, Reference< XDataSeriesContainer >, sal_Int32 >
360 {
361     sal_Int32 operator() ( sal_Int32 nCurrentNumber, const Reference< XDataSeriesContainer > & xCnt ) const
362     {
363         if( xCnt.is())
364             return nCurrentNumber + (xCnt->getDataSeries().getLength());
365         return nCurrentNumber;
366     }
367 };
368 
369 } // anonymous namespace
370 
371 // ----------------------------------------
372 
373 
374 namespace chart
375 {
376 
377 DialogModel::DialogModel(
378     const Reference< XChartDocument > & xChartDocument,
379     const Reference< uno::XComponentContext > & xContext ) :
380         m_xChartDocument( xChartDocument ),
381         m_xContext( xContext ),
382         m_aTimerTriggeredControllerLock( uno::Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) )
383 {
384 }
385 
386 DialogModel::~DialogModel()
387 {}
388 
389 void DialogModel::setTemplate(
390     const Reference< XChartTypeTemplate > & xTemplate )
391 {
392     m_xTemplate = xTemplate;
393 }
394 
395 ::boost::shared_ptr< RangeSelectionHelper >
396     DialogModel::getRangeSelectionHelper() const
397 {
398     if( ! m_spRangeSelectionHelper.get())
399         m_spRangeSelectionHelper.reset(
400             new RangeSelectionHelper( m_xChartDocument ));
401 
402     return m_spRangeSelectionHelper;
403 }
404 
405 Reference< frame::XModel > DialogModel::getChartModel() const
406 {
407     Reference< frame::XModel > xResult( m_xChartDocument, uno::UNO_QUERY );
408     return xResult;
409 }
410 
411 Reference< data::XDataProvider > DialogModel::getDataProvider() const
412 {
413     Reference< data::XDataProvider > xResult;
414     if( m_xChartDocument.is())
415         xResult.set( m_xChartDocument->getDataProvider());
416     return xResult;
417 }
418 
419 ::std::vector< Reference< XDataSeriesContainer > >
420     DialogModel::getAllDataSeriesContainers() const
421 {
422     ::std::vector< Reference< XDataSeriesContainer > > aResult;
423 
424     try
425     {
426         Reference< XDiagram > xDiagram;
427         if( m_xChartDocument.is())
428             xDiagram.set( m_xChartDocument->getFirstDiagram());
429         if( xDiagram.is())
430         {
431             Reference< XCoordinateSystemContainer > xCooSysCnt(
432                 xDiagram, uno::UNO_QUERY_THROW );
433             Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
434                 xCooSysCnt->getCoordinateSystems());
435             for( sal_Int32 i=0; i<aCooSysSeq.getLength(); ++i )
436             {
437                 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[i], uno::UNO_QUERY_THROW );
438                 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
439                 ::std::transform(
440                     aChartTypeSeq.getConstArray(), aChartTypeSeq.getConstArray() + aChartTypeSeq.getLength(),
441                     ::std::back_inserter( aResult ),
442                     lcl_ChartTypeToSeriesCnt() );
443             }
444         }
445     }
446     catch( uno::Exception & ex )
447     {
448         ASSERT_EXCEPTION( ex );
449     }
450 
451     return aResult;
452 }
453 
454 ::std::vector< DialogModel::tSeriesWithChartTypeByName >
455     DialogModel::getAllDataSeriesWithLabel() const
456 {
457     ::std::vector< tSeriesWithChartTypeByName > aResult;
458     ::std::vector< Reference< XDataSeriesContainer > > aContainers(
459         getAllDataSeriesContainers());
460 
461     ::std::copy( aContainers.begin(), aContainers.end(),
462                  lcl_DataSeriesContainerAppend( aResult ));
463     return aResult;
464 }
465 
466 DialogModel::tRolesWithRanges DialogModel::getRolesWithRanges(
467     const Reference< XDataSeries > & xSeries,
468     const ::rtl::OUString & aRoleOfSequenceForLabel,
469     const Reference< chart2::XChartType > & xChartType ) const
470 {
471     DialogModel::tRolesWithRanges aResult;
472     try
473     {
474         Reference< data::XDataSource > xSource( xSeries, uno::UNO_QUERY_THROW );
475         const Sequence< Reference< data::XLabeledDataSequence > > aSeq( xSource->getDataSequences());
476         ::std::copy( aSeq.getConstArray(), aSeq.getConstArray() + aSeq.getLength(),
477                      lcl_RolesWithRangeAppend( aResult, aRoleOfSequenceForLabel ));
478         if( xChartType.is())
479         {
480             // add missing mandatory roles
481             Sequence< OUString > aRoles( xChartType->getSupportedMandatoryRoles());
482             OUString aEmptyString;
483             sal_Int32 nI = 0;
484             for( nI=0; nI < aRoles.getLength(); ++nI )
485             {
486                 if( aResult.find( aRoles[nI] ) == aResult.end() )
487                     aResult.insert( DialogModel::tRolesWithRanges::value_type( aRoles[nI], aEmptyString ));
488             }
489 
490             // add missing optional roles
491             aRoles = xChartType->getSupportedOptionalRoles();
492             for( nI=0; nI < aRoles.getLength(); ++nI )
493             {
494                 if( aResult.find( aRoles[nI] ) == aResult.end() )
495                     aResult.insert( DialogModel::tRolesWithRanges::value_type( aRoles[nI], aEmptyString ));
496             }
497         }
498     }
499     catch( uno::Exception & ex )
500     {
501         ASSERT_EXCEPTION( ex );
502     }
503     return aResult;
504 }
505 
506 void DialogModel::moveSeries(
507     const Reference< XDataSeries > & xSeries,
508     eMoveDirection eDirection )
509 {
510     m_aTimerTriggeredControllerLock.startTimer();
511     ControllerLockGuard aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) );
512 
513     Reference< XDiagram > xDiagram( m_xChartDocument->getFirstDiagram());
514     DiagramHelper::moveSeries( xDiagram, xSeries, eDirection==MOVE_UP );
515 }
516 
517 Reference< chart2::XDataSeries > DialogModel::insertSeriesAfter(
518     const Reference< XDataSeries > & xSeries,
519     const Reference< XChartType > & xChartType,
520     bool bCreateDataCachedSequences /* = false */ )
521 {
522     m_aTimerTriggeredControllerLock.startTimer();
523     ControllerLockGuard aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) );
524     Reference< XDataSeries > xNewSeries;
525 
526     try
527     {
528         Reference< chart2::XDiagram > xDiagram( m_xChartDocument->getFirstDiagram() );
529         ThreeDLookScheme e3DScheme = ThreeDHelper::detectScheme( xDiagram );
530 
531         sal_Int32 nSeriesInChartType = 0;
532         const sal_Int32 nTotalSeries = countSeries();
533         if( xChartType.is())
534         {
535             Reference< XDataSeriesContainer > xCnt( xChartType, uno::UNO_QUERY_THROW );
536             nSeriesInChartType = xCnt->getDataSeries().getLength();
537         }
538 
539         // create new series
540         xNewSeries.set(
541             lcl_CreateNewSeries(
542                 m_xContext,
543                 xChartType,
544                 nTotalSeries, // new series' index
545                 nSeriesInChartType,
546                 xDiagram,
547                 m_xTemplate,
548                 bCreateDataCachedSequences ));
549 
550         // add new series to container
551         if( xNewSeries.is())
552         {
553             Reference< XDataSeriesContainer > xSeriesCnt( xChartType, uno::UNO_QUERY_THROW );
554             ::std::vector< Reference< XDataSeries > > aSeries(
555                 SequenceToVector( xSeriesCnt->getDataSeries()));
556             ::std::vector< Reference< XDataSeries > >::iterator aIt =
557                   ::std::find( aSeries.begin(), aSeries.end(), xSeries );
558             if( aIt == aSeries.end())
559                 // if we have no series we insert at the first position.
560                 aIt = aSeries.begin();
561             else
562                 // vector::insert inserts before, so we have to advance
563                 ++aIt;
564             aSeries.insert( aIt, xNewSeries );
565             xSeriesCnt->setDataSeries( ContainerToSequence( aSeries ));
566         }
567 
568         ThreeDHelper::setScheme( xDiagram, e3DScheme );
569     }
570     catch( uno::Exception & ex )
571     {
572         ASSERT_EXCEPTION( ex );
573     }
574     return xNewSeries;
575 }
576 
577 void DialogModel::deleteSeries(
578     const Reference< XDataSeries > & xSeries,
579     const Reference< XChartType > & xChartType )
580 {
581     m_aTimerTriggeredControllerLock.startTimer();
582     ControllerLockGuard aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) );
583 
584     DataSeriesHelper::deleteSeries( xSeries, xChartType );
585 }
586 
587 Reference< data::XLabeledDataSequence > DialogModel::getCategories() const
588 {
589     Reference< data::XLabeledDataSequence > xResult;
590     try
591     {
592         if( m_xChartDocument.is())
593         {
594             Reference< chart2::XDiagram > xDiagram( m_xChartDocument->getFirstDiagram());
595             xResult.set( DiagramHelper::getCategoriesFromDiagram( xDiagram ));
596         }
597     }
598     catch( uno::Exception & ex )
599     {
600         ASSERT_EXCEPTION( ex );
601     }
602     return xResult;
603 }
604 
605 void DialogModel::setCategories( const Reference< chart2::data::XLabeledDataSequence > & xCategories )
606 {
607     if( m_xChartDocument.is())
608     {
609         Reference< chart2::XDiagram > xDiagram( m_xChartDocument->getFirstDiagram());
610         if( xDiagram.is())
611         {
612             // categories
613             bool bSupportsCategories = true;
614 
615             Reference< XChartType > xFirstChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
616             if( xFirstChartType.is() )
617             {
618                 sal_Int32 nAxisType = ChartTypeHelper::getAxisType( xFirstChartType, 0 ); // x-axis
619                 bSupportsCategories = (nAxisType == AxisType::CATEGORY);
620             }
621             DiagramHelper::setCategoriesToDiagram( xCategories, xDiagram, true, bSupportsCategories );
622         }
623     }
624 }
625 
626 OUString DialogModel::getCategoriesRange() const
627 {
628     Reference< data::XLabeledDataSequence > xLSeq( getCategories());
629     OUString aRange;
630     if( xLSeq.is())
631     {
632         Reference< data::XDataSequence > xSeq( xLSeq->getValues());
633         if( xSeq.is())
634             aRange = xSeq->getSourceRangeRepresentation();
635     }
636     return aRange;
637 }
638 
639 bool DialogModel::isCategoryDiagram() const
640 {
641     bool bRet = false;
642     if( m_xChartDocument.is())
643         bRet = DiagramHelper::isCategoryDiagram( m_xChartDocument->getFirstDiagram() );
644     return bRet;
645 }
646 
647 void DialogModel::detectArguments(
648     OUString & rOutRangeString,
649     bool & rOutUseColumns,
650     bool & rOutFirstCellAsLabel,
651     bool & rOutHasCategories ) const
652 {
653     try
654     {
655         uno::Sequence< sal_Int32 > aSequenceMapping;//todo YYYX
656 
657         // Note: unused data is currently not supported in being passed to detectRangeSegmentation
658         if( m_xChartDocument.is())
659             DataSourceHelper::detectRangeSegmentation(
660                 Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY_THROW ),
661                 rOutRangeString, aSequenceMapping, rOutUseColumns, rOutFirstCellAsLabel, rOutHasCategories );
662     }
663     catch( uno::Exception & ex )
664     {
665         ASSERT_EXCEPTION( ex );
666     }
667 }
668 
669 bool DialogModel::allArgumentsForRectRangeDetected() const
670 {
671     return DataSourceHelper::allArgumentsForRectRangeDetected( m_xChartDocument );
672 }
673 
674 void DialogModel::startControllerLockTimer()
675 {
676     m_aTimerTriggeredControllerLock.startTimer();
677 }
678 
679 bool DialogModel::setData(
680     const Sequence< beans::PropertyValue > & rArguments )
681 {
682     m_aTimerTriggeredControllerLock.startTimer();
683     ControllerLockGuard aLockedControllers( Reference< frame::XModel >( m_xChartDocument, uno::UNO_QUERY ) );
684 
685     Reference< data::XDataProvider > xDataProvider( getDataProvider());
686     if( ! xDataProvider.is() ||
687         ! m_xTemplate.is() )
688     {
689         OSL_ENSURE( false, "Model objects missing" );
690         return false;
691     }
692 
693     try
694     {
695         Reference< chart2::data::XDataSource > xDataSource(
696             xDataProvider->createDataSource( rArguments ) );
697 
698         Reference< chart2::XDataInterpreter > xInterpreter(
699             m_xTemplate->getDataInterpreter());
700         if( xInterpreter.is())
701         {
702             Reference< chart2::XDiagram > xDiagram( m_xChartDocument->getFirstDiagram() );
703             ThreeDLookScheme e3DScheme = ThreeDHelper::detectScheme( xDiagram );
704 
705             ::std::vector< Reference< XDataSeries > > aSeriesToReUse(
706                 DiagramHelper::getDataSeriesFromDiagram( xDiagram ));
707             applyInterpretedData(
708                 xInterpreter->interpretDataSource(
709                     xDataSource, rArguments,
710                     ContainerToSequence( aSeriesToReUse )),
711                 aSeriesToReUse,
712                 true /* bSetStyles */);
713 
714             ThreeDHelper::setScheme( xDiagram, e3DScheme );
715         }
716     }
717     catch( uno::Exception & ex )
718     {
719         ASSERT_EXCEPTION( ex );
720         return false;
721     }
722 
723     return true;
724 }
725 
726 OUString DialogModel::ConvertRoleFromInternalToUI( const OUString & rRoleString )
727 {
728     return lcl_ConvertRole( rRoleString, true );
729 }
730 
731 OUString DialogModel::GetRoleDataLabel()
732 {
733     return OUString( String( ::chart::SchResId( STR_OBJECT_DATALABELS )));
734 }
735 
736 sal_Int32 DialogModel::GetRoleIndexForSorting( const ::rtl::OUString & rInternalRoleString )
737 {
738     static lcl_tRoleIndexMap aRoleIndexMap;
739 
740     if( aRoleIndexMap.empty())
741         lcl_createRoleIndexMap( aRoleIndexMap );
742 
743     lcl_tRoleIndexMap::const_iterator aIt( aRoleIndexMap.find( rInternalRoleString ));
744     if( aIt != aRoleIndexMap.end())
745         return aIt->second;
746 
747     return 0;
748 }
749 
750 // private methods
751 
752 void DialogModel::applyInterpretedData(
753     const InterpretedData & rNewData,
754     const ::std::vector< Reference< XDataSeries > > & rSeriesToReUse,
755     bool bSetStyles )
756 {
757     if( ! m_xChartDocument.is())
758         return;
759 
760     m_aTimerTriggeredControllerLock.startTimer();
761     Reference< XDiagram > xDiagram( m_xChartDocument->getFirstDiagram());
762     if( xDiagram.is())
763     {
764         // styles
765         if( bSetStyles && m_xTemplate.is() )
766         {
767             sal_Int32 nGroup = 0;
768             sal_Int32 nSeriesCounter = 0;
769             sal_Int32 nNewSeriesIndex = static_cast< sal_Int32 >( rSeriesToReUse.size());
770             const sal_Int32 nOuterSize=rNewData.Series.getLength();
771 
772             for(; nGroup < nOuterSize; ++nGroup)
773             {
774                 Sequence< Reference< XDataSeries > > aSeries( rNewData.Series[ nGroup ] );
775                 const sal_Int32 nSeriesInGroup = aSeries.getLength();
776                 for( sal_Int32 nSeries=0; nSeries<nSeriesInGroup; ++nSeries, ++nSeriesCounter )
777                 {
778                     if( ::std::find( rSeriesToReUse.begin(), rSeriesToReUse.end(), aSeries[nSeries] )
779                         == rSeriesToReUse.end())
780                     {
781                         Reference< beans::XPropertySet > xSeriesProp( aSeries[nSeries], uno::UNO_QUERY );
782                         if( xSeriesProp.is())
783                         {
784                             // @deprecated: correct default color should be found by view
785                             // without setting it as hard attribute
786                             Reference< XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme());
787                             if( xColorScheme.is())
788                                 xSeriesProp->setPropertyValue(
789                                     C2U("Color"), uno::makeAny( xColorScheme->getColorByIndex( nSeriesCounter )));
790                         }
791                         m_xTemplate->applyStyle( aSeries[nSeries], nGroup, nNewSeriesIndex++, nSeriesInGroup );
792                     }
793                 }
794             }
795         }
796 
797         // data series
798         ::std::vector< Reference< XDataSeriesContainer > > aSeriesCnt( getAllDataSeriesContainers());
799         ::std::vector< Sequence< Reference< XDataSeries > > > aNewSeries(
800             SequenceToVector( rNewData.Series ));
801 
802         OSL_ASSERT( aSeriesCnt.size() == aNewSeries.size());
803 
804         ::std::vector< Sequence< Reference< XDataSeries > > >::const_iterator aSrcIt( aNewSeries.begin());
805         ::std::vector< Reference< XDataSeriesContainer > >::iterator aDestIt( aSeriesCnt.begin());
806         for(; aSrcIt != aNewSeries.end() && aDestIt != aSeriesCnt.end();
807             ++aSrcIt, ++aDestIt )
808         {
809             try
810             {
811                 OSL_ASSERT( (*aDestIt).is());
812                 (*aDestIt)->setDataSeries( *aSrcIt );
813             }
814             catch( uno::Exception & ex )
815             {
816                 ASSERT_EXCEPTION( ex );
817             }
818         }
819 
820         DialogModel::setCategories(rNewData.Categories);
821     }
822 }
823 
824 sal_Int32 DialogModel::countSeries() const
825 {
826     ::std::vector< Reference< XDataSeriesContainer > > aCnt( getAllDataSeriesContainers());
827     return ::std::accumulate( aCnt.begin(), aCnt.end(), 0, lcl_addSeriesNumber());
828 }
829 
830 } //  namespace chart
831