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