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