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