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