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 #include "ChartTypeTemplate.hxx"
27 #include "PropertyHelper.hxx"
28 #include "macros.hxx"
29 #include "DataSeriesHelper.hxx"
30 #include "DataInterpreter.hxx"
31 #include "CommonConverters.hxx"
32 #include "ContainerHelper.hxx"
33 #include "ChartTypeHelper.hxx"
34 
35 #include "CartesianCoordinateSystem.hxx"
36 #include "AxisHelper.hxx"
37 #include "LegendHelper.hxx"
38 #include "DiagramHelper.hxx"
39 #include "ChartDebugTrace.hxx"
40 #include "AxisIndexDefines.hxx"
41 #include <cppuhelper/component_context.hxx>
42 #include <com/sun/star/chart/ChartSolidType.hpp>
43 #include <com/sun/star/chart2/AxisType.hpp>
44 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
45 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
46 #include <com/sun/star/chart2/AxisType.hpp>
47 
48 #include <algorithm>
49 #include <iterator>
50 
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::chart2;
53 
54 using ::rtl::OUString;
55 using ::com::sun::star::uno::Sequence;
56 using ::com::sun::star::uno::Reference;
57 using ::com::sun::star::uno::Any;
58 
59 // ======================================================================
60 
61 namespace
62 {
63 
lcl_applyDefaultStyle(const Reference<XDataSeries> & xSeries,sal_Int32 nIndex,const Reference<XDiagram> & xDiagram)64 void lcl_applyDefaultStyle(
65     const Reference< XDataSeries > & xSeries,
66     sal_Int32 nIndex,
67     const Reference< XDiagram > & xDiagram )
68 {
69     // @deprecated: correct default color should be found by view without
70     // setting color as hard attribute
71     if( xSeries.is() && xDiagram.is())
72     {
73         Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY );
74         Reference< chart2::XColorScheme > xColorScheme( xDiagram->getDefaultColorScheme());
75         if( xSeriesProp.is() && xColorScheme.is() )
76             xSeriesProp->setPropertyValue(
77                 C2U("Color"),
78                 uno::makeAny( xColorScheme->getColorByIndex( nIndex )));
79     }
80 }
81 
lcl_ensureCorrectLabelPlacement(const Reference<beans::XPropertySet> & xProp,const uno::Sequence<sal_Int32> & rAvailablePlacements)82 void lcl_ensureCorrectLabelPlacement( const Reference< beans::XPropertySet >& xProp, const uno::Sequence < sal_Int32 >& rAvailablePlacements )
83 {
84     sal_Int32 nLabelPlacement=0;
85     if( xProp.is() && (xProp->getPropertyValue( C2U( "LabelPlacement" ) ) >>= nLabelPlacement) )
86     {
87         bool bValid = false;
88         for( sal_Int32 nN = 0; nN < rAvailablePlacements.getLength(); nN++ )
89         {
90             if( rAvailablePlacements[nN] == nLabelPlacement )
91             {
92                 bValid = true;
93                 break;
94             }
95         }
96         if( !bValid )
97         {
98             uno::Any aNewValue;
99             //otherwise use the first supported one
100             if( rAvailablePlacements.getLength() )
101                 aNewValue <<=rAvailablePlacements[0];
102             xProp->setPropertyValue( C2U("LabelPlacement"), aNewValue );
103         }
104     }
105 }
106 
lcl_resetLabelPlacementIfDefault(const Reference<beans::XPropertySet> & xProp,sal_Int32 nDefaultPlacement)107 void lcl_resetLabelPlacementIfDefault( const Reference< beans::XPropertySet >& xProp, sal_Int32 nDefaultPlacement )
108 {
109 
110     sal_Int32 nLabelPlacement=0;
111     if( xProp.is() && (xProp->getPropertyValue( C2U( "LabelPlacement" ) ) >>= nLabelPlacement) )
112     {
113         if( nDefaultPlacement == nLabelPlacement )
114             xProp->setPropertyValue( C2U("LabelPlacement"), uno::Any() );
115     }
116 }
117 
lcl_ensureCorrectMissingValueTreatment(const Reference<chart2::XDiagram> & xDiagram,const Reference<XChartType> & xChartType)118 void lcl_ensureCorrectMissingValueTreatment( const Reference< chart2::XDiagram >& xDiagram, const Reference< XChartType >& xChartType )
119 {
120     Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
121     if( xDiaProp.is() )
122     {
123         uno::Sequence < sal_Int32 > aAvailableMissingValueTreatment(
124             ::chart::ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) );
125 
126         if( aAvailableMissingValueTreatment.getLength() )
127             xDiaProp->setPropertyValue( C2U( "MissingValueTreatment" ), uno::makeAny( aAvailableMissingValueTreatment[0] ) );
128         else
129             xDiaProp->setPropertyValue( C2U( "MissingValueTreatment" ), uno::Any() );
130     }
131 }
132 
133 } // anonymous namespace
134 
135 namespace chart
136 {
137 
ChartTypeTemplate(Reference<uno::XComponentContext> const & xContext,const::rtl::OUString & rServiceName)138 ChartTypeTemplate::ChartTypeTemplate(
139     Reference< uno::XComponentContext > const & xContext,
140     const ::rtl::OUString & rServiceName ) :
141         m_xContext( xContext ),
142         m_aServiceName( rServiceName )
143 {
144 }
145 
~ChartTypeTemplate()146 ChartTypeTemplate::~ChartTypeTemplate()
147 {}
148 
149 // ____ XChartTypeTemplate ____
createDiagramByDataSource(const uno::Reference<data::XDataSource> & xDataSource,const uno::Sequence<beans::PropertyValue> & aArguments)150 uno::Reference< XDiagram > SAL_CALL ChartTypeTemplate::createDiagramByDataSource(
151     const uno::Reference< data::XDataSource >& xDataSource,
152     const uno::Sequence< beans::PropertyValue >& aArguments )
153     throw (uno::RuntimeException)
154 {
155     Reference< XDiagram > xDia;
156 
157     try
158     {
159         // create diagram
160         xDia.set(
161             GetComponentContext()->getServiceManager()->createInstanceWithContext(
162                 C2U( "com.sun.star.chart2.Diagram" ),
163                 GetComponentContext() ),
164             uno::UNO_QUERY_THROW );
165 
166         // modify diagram
167         Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter());
168         chart2::InterpretedData aData(
169             xInterpreter->interpretDataSource(
170                 xDataSource, aArguments, Sequence< Reference< XDataSeries > >() ));
171 
172         Sequence< Sequence< Reference< XDataSeries > > > aSeries( aData.Series );
173         sal_Int32 i, j, nCount = 0;
174         for( i=0; i<aSeries.getLength(); ++i )
175         {
176             for( j=0; j<aSeries[i].getLength(); ++j, ++nCount )
177                 lcl_applyDefaultStyle( aSeries[i][j], nCount, xDia );
178         }
179 
180         Sequence< Reference< XChartType > > aOldChartTypesSeq;
181         FillDiagram( xDia, aData.Series, aData.Categories, aOldChartTypesSeq, true );
182     }
183     catch( uno::Exception & ex )
184     {
185         ASSERT_EXCEPTION( ex );
186     }
187 
188     return xDia;
189 }
190 
supportsCategories()191 sal_Bool SAL_CALL ChartTypeTemplate::supportsCategories()
192     throw (uno::RuntimeException)
193 {
194     return sal_True;
195 }
196 
changeDiagram(const uno::Reference<XDiagram> & xDiagram)197 void SAL_CALL ChartTypeTemplate::changeDiagram( const uno::Reference< XDiagram >& xDiagram )
198     throw (uno::RuntimeException)
199 {
200     if( ! xDiagram.is())
201         return;
202 
203     try
204     {
205         Sequence< Sequence< Reference< XDataSeries > > > aSeriesSeq(
206             DiagramHelper::getDataSeriesGroups( xDiagram ));
207         Sequence< Reference< XDataSeries > > aFlatSeriesSeq( FlattenSequence( aSeriesSeq ));
208         const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.getLength();
209 
210         // chart-type specific interpretation of existing data series
211         Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter());
212         chart2::InterpretedData aData;
213         aData.Series = aSeriesSeq;
214         aData.Categories = DiagramHelper::getCategoriesFromDiagram( xDiagram );
215 
216         if( xInterpreter->isDataCompatible( aData ) )
217         {
218             aData = xInterpreter->reinterpretDataSeries( aData );
219         }
220         else
221         {
222             Reference< data::XDataSource > xSource( xInterpreter->mergeInterpretedData( aData ));
223             // todo: get a "range-union" from the data provider by calling
224             // OUString aRange = getRangeRepresentationByData( xSource );
225             // xSource.set( getDataByRangeRepresentation( aRange, aParam ));
226             // where aParam == ??
227             Sequence< beans::PropertyValue > aParam;
228             if( aData.Categories.is())
229             {
230                 aParam.realloc( 1 );
231                 aParam[0] = beans::PropertyValue( C2U("HasCategories"), -1, uno::makeAny( true ),
232                                                   beans::PropertyState_DIRECT_VALUE );
233             }
234             aData = xInterpreter->interpretDataSource( xSource, aParam, aFlatSeriesSeq );
235         }
236         aSeriesSeq = aData.Series;
237 
238         sal_Int32 i, j, nIndex = 0;
239         for( i=0; i<aSeriesSeq.getLength(); ++i )
240             for( j=0; j<aSeriesSeq[i].getLength(); ++j, ++nIndex )
241             {
242                 if( nIndex >= nFormerSeriesCount )
243                     lcl_applyDefaultStyle( aSeriesSeq[i][j], nIndex, xDiagram );
244             }
245 
246         // remove charttype groups from all coordinate systems
247             Sequence< Reference< XChartType > > aOldChartTypesSeq(
248                 DiagramHelper::getChartTypesFromDiagram(xDiagram) );
249 
250         Reference< XCoordinateSystemContainer > xCoordSysCnt( xDiagram, uno::UNO_QUERY );
251         OSL_ASSERT( xCoordSysCnt.is());
252         if( xCoordSysCnt.is())
253         {
254             Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
255                 xCoordSysCnt->getCoordinateSystems());
256             for( sal_Int32 nCooSysIdx = 0; nCooSysIdx < aCooSysSeq.getLength(); ++nCooSysIdx )
257             {
258                 Reference< XChartTypeContainer > xContainer( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY );
259                 if( xContainer.is() )
260                     xContainer->setChartTypes( Sequence< Reference< XChartType > >() );
261             }
262         }
263 
264         FillDiagram( xDiagram, aSeriesSeq, aData.Categories, aOldChartTypesSeq, false );
265     }
266     catch( uno::Exception & ex )
267     {
268         ASSERT_EXCEPTION( ex );
269     }
270 }
271 
changeDiagramData(const Reference<chart2::XDiagram> & xDiagram,const Reference<chart2::data::XDataSource> & xDataSource,const Sequence<beans::PropertyValue> & aArguments)272 void SAL_CALL ChartTypeTemplate::changeDiagramData(
273     const Reference< chart2::XDiagram >& xDiagram,
274     const Reference< chart2::data::XDataSource >& xDataSource,
275     const Sequence< beans::PropertyValue >& aArguments )
276     throw (uno::RuntimeException)
277 {
278     if( ! (xDiagram.is() &&
279            xDataSource.is()) )
280         return;
281 
282     try
283     {
284         // interpret new data and re-use existing series
285         Sequence< Reference< XDataSeries > > aFlatSeriesSeq(
286             ::chart::ContainerHelper::ContainerToSequence( DiagramHelper::getDataSeriesFromDiagram( xDiagram )));
287         const sal_Int32 nFormerSeriesCount = aFlatSeriesSeq.getLength();
288         Reference< chart2::XDataInterpreter > xInterpreter( getDataInterpreter());
289         chart2::InterpretedData aData =
290             xInterpreter->interpretDataSource( xDataSource, aArguments, aFlatSeriesSeq );
291 
292         // data series
293         Sequence< Sequence< Reference< XDataSeries > > > aSeriesSeq( aData.Series );
294 
295         sal_Int32 i, j, nIndex = 0;
296         for( i=0; i<aSeriesSeq.getLength(); ++i )
297             for( j=0; j<aSeriesSeq[i].getLength(); ++j, ++nIndex )
298             {
299                 if( nIndex >= nFormerSeriesCount )
300                 {
301                     lcl_applyDefaultStyle( aSeriesSeq[i][j], nIndex, xDiagram );
302                     applyStyle( aSeriesSeq[i][j], i, j, aSeriesSeq[i].getLength() );
303                 }
304             }
305 
306         // categories
307         DiagramHelper::setCategoriesToDiagram( aData.Categories, xDiagram, true, supportsCategories() );
308 
309         Sequence< Reference< XChartType > > aChartTypes(
310             DiagramHelper::getChartTypesFromDiagram( xDiagram ));
311         sal_Int32 nMax = ::std::min( aChartTypes.getLength(), aSeriesSeq.getLength());
312         for( i=0; i<nMax; ++i )
313         {
314             Reference< XDataSeriesContainer > xDSCnt( aChartTypes[i], uno::UNO_QUERY_THROW );
315             xDSCnt->setDataSeries( aSeriesSeq[i] );
316         }
317 #if OSL_DEBUG_LEVEL >= CHART_TRACE_OSL_DEBUG_LEVEL
318     OSL_TRACE( "ChartTypeTemplate::changeDiagramData: Showing Diagram structure" );
319     OSL_TRACE( "---------------------------------------------------------------" );
320     debug::ChartDebugTraceDiagram( xDiagram );
321 #endif
322     }
323     catch( uno::Exception & ex )
324     {
325         ASSERT_EXCEPTION( ex );
326     }
327 }
328 
matchesTemplate(const Reference<chart2::XDiagram> & xDiagram,sal_Bool)329 sal_Bool SAL_CALL ChartTypeTemplate::matchesTemplate(
330     const Reference< chart2::XDiagram >& xDiagram,
331     sal_Bool /* bAdaptProperties */ )
332     throw (uno::RuntimeException)
333 {
334     sal_Bool bResult = sal_False;
335 
336     if( ! xDiagram.is())
337         return bResult;
338 
339     try
340     {
341         Reference< XCoordinateSystemContainer > xCooSysCnt(
342             xDiagram, uno::UNO_QUERY_THROW );
343         Sequence< Reference< XCoordinateSystem > > aCooSysSeq(
344             xCooSysCnt->getCoordinateSystems());
345 
346         // need to have at least one coordinate system
347         bResult = (aCooSysSeq.getLength() > 0);
348         if( bResult )
349         {
350             Sequence< Reference< XChartType > > aFormerlyUsedChartTypes;
351             const OUString aChartTypeToMatch( getChartTypeForNewSeries(aFormerlyUsedChartTypes)->getChartType());
352             const sal_Int32 nDimensionToMatch = getDimension();
353             for( sal_Int32 nCooSysIdx=0; bResult && (nCooSysIdx < aCooSysSeq.getLength()); ++nCooSysIdx )
354             {
355                 // match dimension
356                 bResult = bResult && (aCooSysSeq[nCooSysIdx]->getDimension() == nDimensionToMatch);
357 
358                 Reference< XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
359                 Sequence< Reference< XChartType > > aChartTypeSeq( xCTCnt->getChartTypes());
360                 for( sal_Int32 nCTIdx=0; bResult && (nCTIdx < aChartTypeSeq.getLength()); ++nCTIdx )
361                 {
362                     // match chart type
363                     bResult = bResult && aChartTypeSeq[nCTIdx]->getChartType().equals( aChartTypeToMatch );
364                     bool bFound=false;
365                     bool bAmbiguous=false;
366                     // match stacking mode
367                     bResult = bResult &&
368                         ( DiagramHelper::getStackModeFromChartType(
369                             aChartTypeSeq[nCTIdx], bFound, bAmbiguous,
370                             aCooSysSeq[nCooSysIdx] )
371                           == getStackMode( nCTIdx ) );
372                 }
373             }
374         }
375     }
376     catch( uno::Exception & ex )
377     {
378         ASSERT_EXCEPTION( ex );
379     }
380 
381     return bResult;
382 }
383 
getDataInterpreter()384 Reference< chart2::XDataInterpreter > SAL_CALL ChartTypeTemplate::getDataInterpreter()
385     throw (uno::RuntimeException)
386 {
387     if( ! m_xDataInterpreter.is())
388         m_xDataInterpreter.set( new DataInterpreter( GetComponentContext() ) );
389 
390     return m_xDataInterpreter;
391 }
392 
applyStyle(const Reference<chart2::XDataSeries> & xSeries,::sal_Int32 nChartTypeIndex,::sal_Int32,::sal_Int32)393 void SAL_CALL ChartTypeTemplate::applyStyle(
394     const Reference< chart2::XDataSeries >& xSeries,
395     ::sal_Int32 nChartTypeIndex,
396     ::sal_Int32 /* nSeriesIndex */,
397     ::sal_Int32 /* nSeriesCount */ )
398     throw (uno::RuntimeException)
399 {
400     // sset stacking mode
401     Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY );
402     if( xSeriesProp.is())
403     {
404         try
405         {
406             StackMode eStackMode = getStackMode( nChartTypeIndex );
407             const uno::Any aPropValue = uno::makeAny(
408                 ( (eStackMode == StackMode_Y_STACKED) ||
409                   (eStackMode == StackMode_Y_STACKED_PERCENT) )
410                 ? chart2::StackingDirection_Y_STACKING
411                 : (eStackMode == StackMode_Z_STACKED )
412                 ? chart2::StackingDirection_Z_STACKING
413                 : chart2::StackingDirection_NO_STACKING );
414             xSeriesProp->setPropertyValue( C2U("StackingDirection"), aPropValue );
415 
416             //ensure valid label placement
417             {
418                 uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
419                             getChartTypeForIndex( nChartTypeIndex ), getDimension(), isSwapXAndY(), xSeries ) );
420                 lcl_ensureCorrectLabelPlacement( xSeriesProp, aAvailablePlacements );
421 
422                 uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
423                 if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
424                     for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
425                         lcl_ensureCorrectLabelPlacement( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), aAvailablePlacements );
426             }
427         }
428         catch( const uno::Exception & ex )
429         {
430             ASSERT_EXCEPTION( ex );
431         }
432     }
433 }
434 
applyStyles(const Reference<chart2::XDiagram> & xDiagram)435 void SAL_CALL ChartTypeTemplate::applyStyles( const Reference< chart2::XDiagram >& xDiagram )
436     throw (uno::RuntimeException)
437 {
438     // apply chart-type specific styles, like "symbols on" for example
439     Sequence< Sequence< Reference< XDataSeries > > > aNewSeriesSeq(
440         DiagramHelper::getDataSeriesGroups( xDiagram ));
441     for( sal_Int32 i=0; i<aNewSeriesSeq.getLength(); ++i )
442     {
443         const sal_Int32 nNumSeries = aNewSeriesSeq[i].getLength();
444         for( sal_Int32 j=0; j<nNumSeries; ++j )
445             applyStyle( aNewSeriesSeq[i][j], i, j, nNumSeries );
446     }
447 
448     //ensure valid empty cell handling (for first chart type...)
449     lcl_ensureCorrectMissingValueTreatment( xDiagram, getChartTypeForIndex( 0 ) );
450 }
451 
resetStyles(const Reference<chart2::XDiagram> & xDiagram)452 void SAL_CALL ChartTypeTemplate::resetStyles( const Reference< chart2::XDiagram >& xDiagram )
453     throw (uno::RuntimeException)
454 {
455     // reset number format if we had percent stacking on
456     sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT);
457     if( bPercent )
458     {
459         Sequence< Reference< chart2::XAxis > > aAxisSeq( AxisHelper::getAllAxesOfDiagram( xDiagram ) );
460         for( sal_Int32 i=0; i<aAxisSeq.getLength(); ++i )
461         {
462             if( 1== AxisHelper::getDimensionIndexOfAxis( aAxisSeq[i], xDiagram ) )
463             {
464                 Reference< beans::XPropertySet > xAxisProp( aAxisSeq[i], uno::UNO_QUERY );
465                 if( xAxisProp.is())
466                 {
467                     // set number format to source format
468                     uno::Any aValue( xAxisProp->getPropertyValue(C2U("NumberFormat")));
469                     if( aValue.hasValue())
470                         xAxisProp->setPropertyValue(C2U("NumberFormat"), uno::Any());
471                 }
472             }
473         }
474     }
475 
476     //reset label placement if default
477     {
478         uno::Reference< XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY );
479         if( xCooSysContainer.is() )
480         {
481             uno::Sequence< uno::Reference< XCoordinateSystem > > aCooSysList( xCooSysContainer->getCoordinateSystems() );
482             for( sal_Int32 nCS = 0; nCS < aCooSysList.getLength(); ++nCS )
483             {
484                 uno::Reference< XCoordinateSystem > xCooSys( aCooSysList[nCS] );
485 
486                 //iterate through all chart types in the current coordinate system
487                 uno::Reference< XChartTypeContainer > xChartTypeContainer( xCooSys, uno::UNO_QUERY );
488                 OSL_ASSERT( xChartTypeContainer.is());
489                 if( !xChartTypeContainer.is() )
490                     continue;
491                 uno::Sequence< uno::Reference< XChartType > > aChartTypeList( xChartTypeContainer->getChartTypes() );
492                 for( sal_Int32 nT = 0; nT < aChartTypeList.getLength(); ++nT )
493                 {
494                     uno::Reference< XChartType > xChartType( aChartTypeList[nT] );
495 
496                     //iterate through all series in this chart type
497                     uno::Reference< XDataSeriesContainer > xDataSeriesContainer( xChartType, uno::UNO_QUERY );
498                     OSL_ASSERT( xDataSeriesContainer.is());
499                     if( !xDataSeriesContainer.is() )
500                         continue;
501 
502                     uno::Sequence< uno::Reference< XDataSeries > > aSeriesList( xDataSeriesContainer->getDataSeries() );
503                     for( sal_Int32 nS = 0; nS < aSeriesList.getLength(); ++nS )
504                     {
505                         Reference< XDataSeries > xSeries(aSeriesList[nS]);
506                         Reference< beans::XPropertySet > xSeriesProp( xSeries, uno::UNO_QUERY );
507                         if(!xSeries.is() || !xSeriesProp.is() )
508                             continue;
509 
510                         uno::Sequence < sal_Int32 > aAvailablePlacements( ChartTypeHelper::getSupportedLabelPlacements(
511                             xChartType, getDimension(), isSwapXAndY(), xSeries ) );
512                         if(!aAvailablePlacements.getLength())
513                             continue;
514 
515                         sal_Int32 nDefaultPlacement = aAvailablePlacements[0];
516 
517                         lcl_resetLabelPlacementIfDefault( xSeriesProp, nDefaultPlacement );
518 
519                         uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
520                         if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
521                             for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
522                                 lcl_resetLabelPlacementIfDefault( xSeries->getDataPointByIndex(aAttributedDataPointIndexList[nN]), nDefaultPlacement );
523                     }
524                 }
525             }
526         }
527     }
528 
529     return;
530 }
531 
532 // ____ XServiceName ____
getServiceName()533     ::rtl::OUString SAL_CALL ChartTypeTemplate::getServiceName()
534     throw (uno::RuntimeException)
535 {
536     return m_aServiceName;
537 }
538 
539 // ________________________________________
540 
getDimension() const541 sal_Int32 ChartTypeTemplate::getDimension() const
542 {
543     return 2;
544 }
545 
getStackMode(sal_Int32) const546 StackMode ChartTypeTemplate::getStackMode( sal_Int32 /* nChartTypeIndex */ ) const
547 {
548     return StackMode_NONE;
549 }
550 
isSwapXAndY() const551 bool ChartTypeTemplate::isSwapXAndY() const
552 {
553     return false;
554 }
555 
556 // ________________________________________
557 
createCoordinateSystems(const Reference<chart2::XCoordinateSystemContainer> & xOutCooSysCnt)558 void ChartTypeTemplate::createCoordinateSystems(
559     const Reference< chart2::XCoordinateSystemContainer > & xOutCooSysCnt )
560 {
561     if( ! xOutCooSysCnt.is())
562         return;
563     Sequence< Reference< XChartType > > aFormerlyUsedChartTypes;
564     Reference< XChartType > xChartType( getChartTypeForNewSeries(aFormerlyUsedChartTypes));
565     if( ! xChartType.is())
566         return;
567     Reference< XCoordinateSystem > xCooSys( xChartType->createCoordinateSystem( getDimension()));
568     if( ! xCooSys.is())
569     {
570         // chart type wants no coordinate systems
571         xOutCooSysCnt->setCoordinateSystems( Sequence< Reference< XCoordinateSystem > >());
572         return;
573     }
574     // #i69680# make grid of first y-axis visible (was in the CooSys CTOR before)
575     if( xCooSys->getDimension() >= 2 )
576     {
577         Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1, 0 ));
578         if( xAxis.is())
579             AxisHelper::makeGridVisible( xAxis->getGridProperties() );
580     }
581 
582     Sequence< Reference< XCoordinateSystem > > aCoordinateSystems(
583         xOutCooSysCnt->getCoordinateSystems());
584 
585     if( aCoordinateSystems.getLength())
586     {
587         bool bOk = true;
588         for( sal_Int32 i=0; bOk && i<aCoordinateSystems.getLength(); ++i )
589             bOk = bOk && ( xCooSys->getCoordinateSystemType().equals( aCoordinateSystems[i]->getCoordinateSystemType()) &&
590                            (xCooSys->getDimension() == aCoordinateSystems[i]->getDimension()) );
591         // coordinate systems are ok
592         if( bOk )
593             return;
594         // there are coordinate systems but they do not fit.  So overwrite them.
595     }
596 
597     //copy as much info from former coordinate system as possible:
598     if( aCoordinateSystems.getLength() )
599     {
600         Reference< XCoordinateSystem > xOldCooSys( aCoordinateSystems[0] );
601         sal_Int32 nMaxDimensionCount = std::min( xCooSys->getDimension(), xOldCooSys->getDimension() );
602 
603         for(sal_Int32 nDimensionIndex=0; nDimensionIndex<nMaxDimensionCount; nDimensionIndex++)
604         {
605             const sal_Int32 nMaximumAxisIndex = xOldCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
606             for(sal_Int32 nAxisIndex=0; nAxisIndex<=nMaximumAxisIndex; ++nAxisIndex)
607             {
608                 uno::Reference< XAxis > xAxis( xOldCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex ) );
609                 if( xAxis.is())
610                 {
611                     xCooSys->setAxisByDimension( nDimensionIndex, xAxis, nAxisIndex );
612                 }
613             }
614         }
615     }
616 
617     // set new coordinate systems
618     aCoordinateSystems.realloc( 1 );
619     aCoordinateSystems[0] = xCooSys;
620 
621     xOutCooSysCnt->setCoordinateSystems( aCoordinateSystems );
622 }
623 
adaptScales(const Sequence<Reference<chart2::XCoordinateSystem>> & aCooSysSeq,const Reference<data::XLabeledDataSequence> & xCategories)624 void ChartTypeTemplate::adaptScales(
625     const Sequence< Reference< chart2::XCoordinateSystem > > & aCooSysSeq,
626     const Reference< data::XLabeledDataSequence > & xCategories //@todo: in future there may be more than one sequence of categories (e.g. charttype with categories at x and y axis )
627     )
628 {
629     bool bSupportsCategories( supportsCategories() );
630     for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
631     {
632         try
633         {
634             Reference< XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIdx] );
635             if( !xCooSys.is() )
636                 continue;
637 
638             // attach categories to first axis
639             sal_Int32 nDim( xCooSys->getDimension());
640             if( nDim > 0 )
641             {
642                 const sal_Int32 nDimensionX = 0;
643                 const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionX);
644                 for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI)
645                 {
646                     Reference< XAxis > xAxis( xCooSys->getAxisByDimension(nDimensionX,nI) );
647                     if( xAxis.is())
648                     {
649                         ScaleData aData( xAxis->getScaleData() );
650                         aData.Categories = xCategories;
651                         if(bSupportsCategories)
652                         {
653 
654                             Reference< XChartType > xChartType( getChartTypeForNewSeries(Sequence< Reference< XChartType > >() ));
655                             bool bSupportsDates = ::chart::ChartTypeHelper::isSupportingDateAxis( xChartType, 2, nDimensionX );
656                             if( aData.AxisType != AxisType::CATEGORY && ( aData.AxisType != AxisType::DATE || !bSupportsDates) )
657                             {
658                                 aData.AxisType = AxisType::CATEGORY;
659                                 aData.AutoDateAxis = true;
660                                 AxisHelper::removeExplicitScaling( aData );
661                             }
662                         }
663                         else
664                             aData.AxisType = AxisType::REALNUMBER;
665 
666                         xAxis->setScaleData( aData );
667                     }
668                 }
669             }
670             // set percent stacking mode at second axis
671             if( nDim > 1 )
672             {
673                 const sal_Int32 nMaxIndex = xCooSys->getMaximumAxisIndexByDimension(1);
674                 for(sal_Int32 nI=0; nI<=nMaxIndex; ++nI)
675                 {
676                     Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( 1,nI ));
677                     if( xAxis.is())
678                     {
679                         sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT);
680                         chart2::ScaleData aScaleData = xAxis->getScaleData();
681 
682                         if( bPercent != (aScaleData.AxisType==AxisType::PERCENT) )
683                         {
684                             if( bPercent )
685                                 aScaleData.AxisType = AxisType::PERCENT;
686                             else
687                                 aScaleData.AxisType = AxisType::REALNUMBER;
688                             xAxis->setScaleData( aScaleData );
689                         }
690                     }
691                 }
692             }
693         }
694         catch( const uno::Exception & ex )
695         {
696             ASSERT_EXCEPTION( ex );
697         }
698     }
699 }
700 
adaptDiagram(const Reference<XDiagram> &)701 void ChartTypeTemplate::adaptDiagram( const Reference< XDiagram > & /* xDiagram */ )
702 {
703     return;
704 }
705 
createAxes(const Sequence<Reference<XCoordinateSystem>> & rCoordSys)706 void ChartTypeTemplate::createAxes(
707     const Sequence< Reference< XCoordinateSystem > > & rCoordSys )
708 {
709     //create missing axes
710     if( rCoordSys.getLength() > 0 )
711     {
712         sal_Int32 nCooSysIdx = 0;
713         Reference< XCoordinateSystem > xCooSys( rCoordSys[nCooSysIdx] );
714         if(!xCooSys.is())
715             return;
716 
717         //create main axis in first coordinate system
718         sal_Int32 nDimCount = xCooSys->getDimension();
719         sal_Int32 nDim=0;
720         for( nDim=0; nDim<nDimCount; ++nDim )
721         {
722             sal_Int32 nAxisCount = getAxisCountByDimension( nDim );
723             if( nDim == 1 &&
724                 nAxisCount < 2 && AxisHelper::isSecondaryYAxisNeeded( xCooSys ))
725                 nAxisCount = 2;
726             for( sal_Int32 nAxisIndex = 0; nAxisIndex < nAxisCount; ++nAxisIndex )
727             {
728                 Reference< XAxis > xAxis = AxisHelper::getAxis( nDim, nAxisIndex, xCooSys );
729                 if( !xAxis.is())
730                 {
731                     // create and add axis
732                     xAxis.set( AxisHelper::createAxis(
733                                    nDim, nAxisIndex, xCooSys, GetComponentContext() ));
734                 }
735             }
736         }
737     }
738 }
739 
adaptAxes(const Sequence<Reference<XCoordinateSystem>> & rCoordSys)740 void ChartTypeTemplate::adaptAxes(
741     const Sequence< Reference< XCoordinateSystem > > & rCoordSys )
742 {
743     //adapt properties of exsisting axes and remove superfluous axes
744 
745     if( rCoordSys.getLength() > 0 )
746     {
747         for( sal_Int32 nCooSysIdx=0; nCooSysIdx < rCoordSys.getLength(); ++nCooSysIdx )
748         {
749             Reference< XCoordinateSystem > xCooSys( rCoordSys[nCooSysIdx] );
750             if( !xCooSys.is() )
751                 continue;
752             sal_Int32 nDimCount = xCooSys->getDimension();
753             for( sal_Int32 nDim=0; nDim<nDimCount; ++nDim )
754             {
755                 sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension( nDim );
756                 for( sal_Int32 nAxisIndex=0; nAxisIndex<=nMaxAxisIndex; nAxisIndex++ )
757                 {
758                     Reference< XAxis > xAxis( AxisHelper::getAxis( nDim, nAxisIndex, xCooSys ) );
759                     if( !xAxis.is() )
760                         continue;
761 
762                     if( nAxisIndex == MAIN_AXIS_INDEX || nAxisIndex == SECONDARY_AXIS_INDEX )
763                     {
764                         // adapt scales
765                         sal_Bool bPercent = (getStackMode(0) == StackMode_Y_STACKED_PERCENT);
766                         if( bPercent && nDim == 1 )
767                         {
768                             Reference< beans::XPropertySet > xAxisProp( xAxis, uno::UNO_QUERY );
769                             if( xAxisProp.is())
770                             {
771                                 // set number format to source format
772                                 uno::Any aValue( xAxisProp->getPropertyValue(C2U("NumberFormat")));
773                                 if( aValue.hasValue())
774                                     xAxisProp->setPropertyValue(C2U("NumberFormat"), uno::Any());
775                             }
776                         }
777                     }
778                 }
779             }
780         }
781     }
782 }
783 
getAxisCountByDimension(sal_Int32 nDimension)784 sal_Int32 ChartTypeTemplate::getAxisCountByDimension( sal_Int32 nDimension )
785 {
786     return (nDimension < getDimension()) ? 1 : 0;
787 }
788 
FillDiagram(const Reference<XDiagram> & xDiagram,const Sequence<Sequence<Reference<XDataSeries>>> & aSeriesSeq,Reference<data::XLabeledDataSequence> xCategories,const Sequence<Reference<XChartType>> & aOldChartTypesSeq,bool)789 void ChartTypeTemplate::FillDiagram(
790     const Reference< XDiagram >& xDiagram,
791     const Sequence< Sequence< Reference< XDataSeries > > >& aSeriesSeq,
792     Reference< data::XLabeledDataSequence > xCategories,
793     const Sequence< Reference< XChartType > >& aOldChartTypesSeq,
794     bool /* bCreate */ )
795 {
796     adaptDiagram( xDiagram );
797 
798     try
799     {
800         // create coordinate systems and scales
801         Reference< XCoordinateSystemContainer > xCoordSysCnt( xDiagram, uno::UNO_QUERY_THROW );
802         createCoordinateSystems( xCoordSysCnt );
803         Sequence< Reference< XCoordinateSystem > > aCoordinateSystems( xCoordSysCnt->getCoordinateSystems());
804         createAxes( aCoordinateSystems );
805         adaptAxes( aCoordinateSystems );
806         adaptScales( aCoordinateSystems, xCategories );
807 
808         // chart types
809         createChartTypes( aSeriesSeq, aCoordinateSystems, aOldChartTypesSeq );
810         applyStyles( xDiagram );
811     }
812     catch( const uno::Exception & ex )
813     {
814         ASSERT_EXCEPTION( ex );
815     }
816 
817 #if OSL_DEBUG_LEVEL >= CHART_TRACE_OSL_DEBUG_LEVEL
818     OSL_TRACE( "ChartTypeTemplate::FillDiagram: Showing Diagram structure" );
819     OSL_TRACE( "---------------------------------------------------------" );
820     debug::ChartDebugTraceDiagram( xDiagram );
821 #endif
822 }
823 
createChartTypes(const Sequence<Sequence<Reference<XDataSeries>>> & aSeriesSeq,const Sequence<Reference<XCoordinateSystem>> & rCoordSys,const Sequence<Reference<XChartType>> & aOldChartTypesSeq)824 void ChartTypeTemplate::createChartTypes(
825     const Sequence< Sequence< Reference< XDataSeries > > > & aSeriesSeq,
826     const Sequence< Reference< XCoordinateSystem > > & rCoordSys,
827     const Sequence< Reference< XChartType > >& aOldChartTypesSeq )
828 {
829     if( rCoordSys.getLength() == 0 ||
830         ! rCoordSys[0].is() )
831         return;
832 
833     try
834     {
835         sal_Int32 nCooSysIdx=0;
836         Reference< XChartType > xCT;
837         if( aSeriesSeq.getLength() == 0 )
838         {
839             // we need a new chart type
840             xCT.set( getChartTypeForNewSeries( aOldChartTypesSeq ));
841             Reference< XChartTypeContainer > xCTCnt( rCoordSys[nCooSysIdx], uno::UNO_QUERY_THROW );
842             Sequence< Reference< XChartType > > aCTSeq( xCTCnt->getChartTypes());
843             aCTSeq.realloc( 1 );
844             aCTSeq[0] = xCT;
845             xCTCnt->setChartTypes( aCTSeq );
846         }
847         else
848         {
849             for( sal_Int32 nSeriesIdx=0; nSeriesIdx<aSeriesSeq.getLength(); ++nSeriesIdx )
850             {
851                 if( nSeriesIdx == nCooSysIdx )
852                 {
853                     // we need a new chart type
854                     xCT.set( getChartTypeForNewSeries( aOldChartTypesSeq ));
855                     Reference< XChartTypeContainer > xCTCnt( rCoordSys[nCooSysIdx], uno::UNO_QUERY_THROW );
856                     Sequence< Reference< XChartType > > aCTSeq( xCTCnt->getChartTypes());
857                     if( aCTSeq.getLength())
858                     {
859                         aCTSeq[0] = xCT;
860                         xCTCnt->setChartTypes( aCTSeq );
861                     }
862                     else
863                         xCTCnt->addChartType( xCT );
864 
865                     Reference< chart2::XDataSeriesContainer > xDSCnt( xCT, uno::UNO_QUERY_THROW );
866                     xDSCnt->setDataSeries( aSeriesSeq[nSeriesIdx] );
867                 }
868                 else
869                 {
870                     // reuse existing chart type
871                     OSL_ASSERT( xCT.is());
872                     Reference< chart2::XDataSeriesContainer > xDSCnt( xCT, uno::UNO_QUERY_THROW );
873                     Sequence< Reference< XDataSeries > > aNewSeriesSeq( xDSCnt->getDataSeries());
874                     sal_Int32 nNewStartIndex = aNewSeriesSeq.getLength();
875                     aNewSeriesSeq.realloc( nNewStartIndex + aSeriesSeq[nSeriesIdx].getLength() );
876                     ::std::copy( aSeriesSeq[nSeriesIdx].getConstArray(),
877                                  aSeriesSeq[nSeriesIdx].getConstArray() + aSeriesSeq[nSeriesIdx].getLength(),
878                                  aNewSeriesSeq.getArray() + nNewStartIndex );
879                     xDSCnt->setDataSeries( aNewSeriesSeq );
880                 }
881 
882                 // spread the series over the available coordinate systems
883                 if( rCoordSys.getLength() > (nCooSysIdx + 1) )
884                     ++nCooSysIdx;
885             }
886         }
887     }
888     catch( uno::Exception & ex )
889     {
890         ASSERT_EXCEPTION( ex );
891     }
892 }
893 
copyPropertiesFromOldToNewCoordianteSystem(const Sequence<Reference<XChartType>> & rOldChartTypesSeq,const Reference<XChartType> & xNewChartType)894 void ChartTypeTemplate::copyPropertiesFromOldToNewCoordianteSystem(
895                     const Sequence< Reference< XChartType > > & rOldChartTypesSeq,
896                     const Reference< XChartType > & xNewChartType )
897 {
898     Reference< beans::XPropertySet > xDestination( xNewChartType, uno::UNO_QUERY );
899     if( !xDestination.is() )
900         return;
901 
902     OUString aNewChartType( xNewChartType->getChartType() );
903 
904     Reference< beans::XPropertySet > xSource;
905     sal_Int32 nN=0;
906     for( nN=0; nN<rOldChartTypesSeq.getLength();++nN)
907     {
908         Reference< XChartType > xOldType( rOldChartTypesSeq[nN] );
909         if( xOldType.is() && xOldType->getChartType().equals( aNewChartType ) )
910         {
911             xSource.set( Reference< beans::XPropertySet >(xOldType, uno::UNO_QUERY ) );
912             if( xSource.is() )
913                 break;
914         }
915     }
916     if( xSource.is() )
917         comphelper::copyProperties( xSource, xDestination );
918 }
919 
920 // ________
921 
getSupportedServiceNames_Static()922 Sequence< OUString > ChartTypeTemplate::getSupportedServiceNames_Static()
923 {
924     Sequence< OUString > aServices( 3 );
925     aServices[ 0 ] = C2U( "com.sun.star.chart2.ChartTypeTemplate" );
926     aServices[ 1 ] = C2U( "com.sun.star.layout.LayoutElement" );
927     aServices[ 2 ] = C2U( "com.sun.star.beans.PropertySet" );
928     return aServices;
929 }
930 
GetComponentContext() const931 Reference< uno::XComponentContext > ChartTypeTemplate::GetComponentContext() const
932 {
933     return m_xContext;
934 }
935 
936 // ================================================================================
937 
938 // implement XServiceInfo methods basing upon getSupportedServiceNames_Static
939 APPHELPER_XSERVICEINFO_IMPL( ChartTypeTemplate,
940                              C2U( "com.sun.star.comp.chart.ChartTypeTemplate" ));
941 } //  namespace chart
942