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