tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / chart2 / source / model / main / Diagram.cxx
blobc3c4e0be9cc613bdd6e9d4b1db37f689ad17d79f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <Diagram.hxx>
21 #include <AxisHelper.hxx>
22 #include <BaseGFXHelper.hxx>
23 #include <ChartTypeHelper.hxx>
24 #include <ChartTypeManager.hxx>
25 #include <ChartTypeTemplate.hxx>
26 #include <ChartType.hxx>
27 #include <DataSeriesHelper.hxx>
28 #include <PropertyHelper.hxx>
29 #include <RegressionCurveHelper.hxx>
30 #include <RegressionCurveModel.hxx>
31 #include "Wall.hxx"
32 #include <ModifyListenerHelper.hxx>
33 #include <UserDefinedProperties.hxx>
34 #include <ConfigColorScheme.hxx>
35 #include <DiagramHelper.hxx>
36 #include <ThreeDHelper.hxx>
37 #include <CloneHelper.hxx>
38 #include <SceneProperties.hxx>
39 #include <unonames.hxx>
40 #include <BaseCoordinateSystem.hxx>
41 #include <Legend.hxx>
42 #include <Axis.hxx>
43 #include <DataTable.hxx>
44 #include <servicenames_charttypes.hxx>
45 #include <defines.hxx>
47 #include <basegfx/numeric/ftools.hxx>
48 #include <com/sun/star/beans/PropertyAttribute.hpp>
49 #include <com/sun/star/chart2/AxisType.hpp>
50 #include <com/sun/star/chart2/DataPointGeometry3D.hpp>
51 #include <com/sun/star/chart2/StackingDirection.hpp>
52 #include <com/sun/star/chart2/RelativePosition.hpp>
53 #include <com/sun/star/chart2/RelativeSize.hpp>
54 #include <com/sun/star/chart2/PieChartSubType.hpp>
55 #include <com/sun/star/chart/MissingValueTreatment.hpp>
56 #include <com/sun/star/container/NoSuchElementException.hpp>
57 #include <com/sun/star/drawing/ShadeMode.hpp>
58 #include <com/sun/star/uno/XComponentContext.hpp>
59 #include <com/sun/star/util/CloseVetoException.hpp>
61 #include <cppuhelper/supportsservice.hxx>
62 #include <comphelper/diagnose_ex.hxx>
63 #include <o3tl/safeint.hxx>
64 #include <rtl/math.hxx>
65 #include <tools/helpers.hxx>
67 #include <algorithm>
68 #include <utility>
70 using namespace ::com::sun::star;
71 using namespace ::com::sun::star::beans::PropertyAttribute;
72 using namespace ::chart::SceneProperties;
74 using ::com::sun::star::beans::Property;
75 using ::com::sun::star::uno::Sequence;
76 using ::com::sun::star::uno::Reference;
77 using ::com::sun::star::uno::Any;
78 using ::osl::MutexGuard;
80 namespace
83 enum
85 PROP_DIAGRAM_REL_POS,
86 PROP_DIAGRAM_REL_SIZE,
87 PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS,
88 PROP_DIAGRAM_SORT_BY_X_VALUES,
89 PROP_DIAGRAM_CONNECT_BARS,
90 PROP_DIAGRAM_GROUP_BARS_PER_AXIS,
91 PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS,
92 PROP_DIAGRAM_STARTING_ANGLE,
93 PROP_DIAGRAM_RIGHT_ANGLED_AXES,
94 PROP_DIAGRAM_PERSPECTIVE,
95 PROP_DIAGRAM_ROTATION_HORIZONTAL,
96 PROP_DIAGRAM_ROTATION_VERTICAL,
97 PROP_DIAGRAM_MISSING_VALUE_TREATMENT,
98 PROP_DIAGRAM_3DRELATIVEHEIGHT,
99 PROP_DIAGRAM_DATATABLEHBORDER,
100 PROP_DIAGRAM_OF_PIE_TYPE,
101 PROP_DIAGRAM_SPLIT_POS,
102 PROP_DIAGRAM_DATATABLEVBORDER,
103 PROP_DIAGRAM_DATATABLEOUTLINE,
104 PROP_DIAGRAM_EXTERNALDATA
107 void lcl_AddPropertiesToVector(
108 std::vector< Property > & rOutProperties )
110 rOutProperties.emplace_back( "RelativePosition",
111 PROP_DIAGRAM_REL_POS,
112 cppu::UnoType<chart2::RelativePosition>::get(),
113 beans::PropertyAttribute::BOUND
114 | beans::PropertyAttribute::MAYBEVOID );
116 rOutProperties.emplace_back( "RelativeSize",
117 PROP_DIAGRAM_REL_SIZE,
118 cppu::UnoType<chart2::RelativeSize>::get(),
119 beans::PropertyAttribute::BOUND
120 | beans::PropertyAttribute::MAYBEVOID );
122 rOutProperties.emplace_back( "PosSizeExcludeAxes",
123 PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS,
124 cppu::UnoType<bool>::get(),
125 beans::PropertyAttribute::BOUND
126 | beans::PropertyAttribute::MAYBEDEFAULT );
128 rOutProperties.emplace_back( CHART_UNONAME_SORT_BY_XVALUES,
129 PROP_DIAGRAM_SORT_BY_X_VALUES,
130 cppu::UnoType<bool>::get(),
131 beans::PropertyAttribute::BOUND
132 | beans::PropertyAttribute::MAYBEDEFAULT );
134 rOutProperties.emplace_back( "ConnectBars",
135 PROP_DIAGRAM_CONNECT_BARS,
136 cppu::UnoType<bool>::get(),
137 beans::PropertyAttribute::BOUND
138 | beans::PropertyAttribute::MAYBEDEFAULT );
140 rOutProperties.emplace_back( "GroupBarsPerAxis",
141 PROP_DIAGRAM_GROUP_BARS_PER_AXIS,
142 cppu::UnoType<bool>::get(),
143 beans::PropertyAttribute::BOUND
144 | beans::PropertyAttribute::MAYBEDEFAULT );
146 rOutProperties.emplace_back( "IncludeHiddenCells",
147 PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS,
148 cppu::UnoType<bool>::get(),
149 beans::PropertyAttribute::BOUND
150 | beans::PropertyAttribute::MAYBEDEFAULT );
152 rOutProperties.emplace_back( "StartingAngle",
153 PROP_DIAGRAM_STARTING_ANGLE,
154 cppu::UnoType<sal_Int32>::get(),
155 beans::PropertyAttribute::BOUND
156 | beans::PropertyAttribute::MAYBEDEFAULT );
158 rOutProperties.emplace_back( "RightAngledAxes",
159 PROP_DIAGRAM_RIGHT_ANGLED_AXES,
160 cppu::UnoType<bool>::get(),
161 beans::PropertyAttribute::BOUND
162 | beans::PropertyAttribute::MAYBEDEFAULT );
164 rOutProperties.emplace_back( "Perspective",
165 PROP_DIAGRAM_PERSPECTIVE,
166 cppu::UnoType<sal_Int32>::get(),
167 beans::PropertyAttribute::MAYBEVOID );
169 rOutProperties.emplace_back( "RotationHorizontal",
170 PROP_DIAGRAM_ROTATION_HORIZONTAL,
171 cppu::UnoType<sal_Int32>::get(),
172 beans::PropertyAttribute::MAYBEVOID );
174 rOutProperties.emplace_back( "RotationVertical",
175 PROP_DIAGRAM_ROTATION_VERTICAL,
176 cppu::UnoType<sal_Int32>::get(),
177 beans::PropertyAttribute::MAYBEVOID );
179 rOutProperties.emplace_back( "MissingValueTreatment",
180 PROP_DIAGRAM_MISSING_VALUE_TREATMENT,
181 cppu::UnoType<sal_Int32>::get(),
182 beans::PropertyAttribute::BOUND
183 | beans::PropertyAttribute::MAYBEVOID );
184 rOutProperties.emplace_back( "3DRelativeHeight",
185 PROP_DIAGRAM_3DRELATIVEHEIGHT,
186 cppu::UnoType<sal_Int32>::get(),
187 beans::PropertyAttribute::MAYBEVOID );
188 rOutProperties.emplace_back( "SubPieType",
189 PROP_DIAGRAM_OF_PIE_TYPE,
190 cppu::UnoType<chart2::PieChartSubType>::get(),
191 beans::PropertyAttribute::MAYBEVOID );
192 rOutProperties.emplace_back( "SplitPos",
193 PROP_DIAGRAM_SPLIT_POS,
194 cppu::UnoType<sal_Int32>::get(),
195 beans::PropertyAttribute::MAYBEVOID );
196 rOutProperties.emplace_back( "ExternalData",
197 PROP_DIAGRAM_EXTERNALDATA,
198 cppu::UnoType<OUString>::get(),
199 beans::PropertyAttribute::MAYBEVOID );
202 const ::chart::tPropertyValueMap& StaticDiagramDefaults()
204 static ::chart::tPropertyValueMap aStaticDefaults = []()
206 ::chart::tPropertyValueMap aMap;
207 ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS, true );
208 ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_SORT_BY_X_VALUES, false );
209 ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_CONNECT_BARS, false );
210 ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_GROUP_BARS_PER_AXIS, true );
211 ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_INCLUDE_HIDDEN_CELLS, true );
212 ::chart::PropertyHelper::setPropertyValueDefault( aMap, PROP_DIAGRAM_RIGHT_ANGLED_AXES, false );
213 ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_DIAGRAM_STARTING_ANGLE, 90 );
214 ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_DIAGRAM_3DRELATIVEHEIGHT, 100 );
215 ::chart::PropertyHelper::setPropertyValueDefault< chart2::PieChartSubType >( aMap, PROP_DIAGRAM_OF_PIE_TYPE,
216 chart2::PieChartSubType_NONE);
217 ::chart::PropertyHelper::setPropertyValueDefault< sal_Int32 >( aMap, PROP_DIAGRAM_SPLIT_POS, 2 );
218 ::chart::SceneProperties::AddDefaultsToMap( aMap );
219 return aMap;
220 }();
221 return aStaticDefaults;
224 ::cppu::OPropertyArrayHelper& StaticDiagramInfoHelper()
226 static ::cppu::OPropertyArrayHelper aPropHelper = []()
228 std::vector< css::beans::Property > aProperties;
229 lcl_AddPropertiesToVector( aProperties );
230 ::chart::SceneProperties::AddPropertiesToVector( aProperties );
231 ::chart::UserDefinedProperties::AddPropertiesToVector( aProperties );
233 std::sort( aProperties.begin(), aProperties.end(),
234 ::chart::PropertyNameLess() );
236 return ::cppu::OPropertyArrayHelper( aProperties.data(), aProperties.size() );
237 }();
238 return aPropHelper;
241 const uno::Reference< beans::XPropertySetInfo >& StaticDiagramInfo()
243 static const uno::Reference< beans::XPropertySetInfo > xPropertySetInfo(
244 ::cppu::OPropertySetHelper::createPropertySetInfo(StaticDiagramInfoHelper() ) );
245 return xPropertySetInfo;
248 void lcl_CloneCoordinateSystems(
249 const ::chart::Diagram::tCoordinateSystemContainerType & rSource,
250 ::chart::Diagram::tCoordinateSystemContainerType & rDestination )
252 for( rtl::Reference< ::chart::BaseCoordinateSystem > const & i : rSource )
254 auto xClone = i->createClone();
255 ::chart::BaseCoordinateSystem* pClone = dynamic_cast<::chart::BaseCoordinateSystem*>(xClone.get());
256 assert(pClone);
257 rDestination.push_back( pClone );
261 } // anonymous namespace
263 namespace chart
266 Diagram::Diagram( uno::Reference< uno::XComponentContext > xContext ) :
267 m_xContext(std::move( xContext )),
268 m_xModifyEventForwarder( new ModifyEventForwarder() )
270 // Set camera position to a default position (that should be set hard, so
271 // that it will be exported. The property default is a camera looking
272 // straight ono the scene). These defaults have been acquired from the old
273 // chart implementation.
274 setFastPropertyValue_NoBroadcast(
275 PROP_SCENE_CAMERA_GEOMETRY, uno::Any(
276 ThreeDHelper::getDefaultCameraGeometry()));
279 Diagram::Diagram( const Diagram & rOther ) :
280 impl::Diagram_Base(rOther),
281 ::property::OPropertySet( rOther ),
282 m_xContext( rOther.m_xContext ),
283 m_xModifyEventForwarder( new ModifyEventForwarder() )
285 lcl_CloneCoordinateSystems( rOther.m_aCoordSystems, m_aCoordSystems );
286 for (auto & xSystem : m_aCoordSystems)
287 xSystem->addModifyListener(m_xModifyEventForwarder);
289 if ( rOther.m_xWall )
290 m_xWall = new Wall( *rOther.m_xWall );
291 if ( rOther.m_xFloor )
292 m_xFloor = new Wall( *rOther.m_xFloor );
293 m_xTitle.set( CloneHelper::CreateRefClone< chart2::XTitle >()( rOther.m_xTitle ));
294 if (rOther.m_xLegend)
295 m_xLegend = new Legend(*rOther.m_xLegend);
296 if (rOther.m_xDataTable)
297 m_xDataTable = new DataTable(*rOther.m_xDataTable);
299 if ( m_xWall )
300 m_xWall->addModifyListener( m_xModifyEventForwarder );
301 if ( m_xFloor )
302 m_xFloor->addModifyListener( m_xModifyEventForwarder );
303 ModifyListenerHelper::addListener( m_xTitle, m_xModifyEventForwarder );
304 ModifyListenerHelper::addListener( m_xLegend, m_xModifyEventForwarder );
307 Diagram::~Diagram()
311 for (auto & xSystem : m_aCoordSystems)
312 xSystem->removeModifyListener(m_xModifyEventForwarder);
314 if ( m_xWall )
315 m_xWall->removeModifyListener( m_xModifyEventForwarder );
316 if ( m_xFloor )
317 m_xFloor->removeModifyListener( m_xModifyEventForwarder );
318 ModifyListenerHelper::removeListener( m_xTitle, m_xModifyEventForwarder );
319 ModifyListenerHelper::removeListener( m_xLegend, m_xModifyEventForwarder );
321 catch( const uno::Exception & )
323 DBG_UNHANDLED_EXCEPTION("chart2");
327 // ____ XDiagram ____
328 uno::Reference< beans::XPropertySet > SAL_CALL Diagram::getWall()
330 rtl::Reference< Wall > xRet;
331 bool bAddListener = false;
333 MutexGuard aGuard( m_aMutex );
334 if( !m_xWall.is() )
336 m_xWall.set( new Wall() );
337 bAddListener = true;
339 xRet = m_xWall;
341 if(bAddListener)
342 xRet->addModifyListener( m_xModifyEventForwarder );
343 return xRet;
346 uno::Reference< beans::XPropertySet > SAL_CALL Diagram::getFloor()
348 rtl::Reference< Wall > xRet;
349 bool bAddListener = false;
351 MutexGuard aGuard( m_aMutex );
352 if( !m_xFloor.is() )
354 m_xFloor.set( new Wall() );
355 bAddListener = true;
357 xRet = m_xFloor;
359 if(bAddListener)
360 xRet->addModifyListener( m_xModifyEventForwarder );
361 return xRet;
364 uno::Reference< chart2::XLegend > SAL_CALL Diagram::getLegend()
366 MutexGuard aGuard( m_aMutex );
367 return m_xLegend;
370 rtl::Reference< ::chart::Legend > Diagram::getLegend2() const
372 MutexGuard aGuard( m_aMutex );
373 return m_xLegend;
376 void SAL_CALL Diagram::setLegend( const uno::Reference< chart2::XLegend >& xNewLegend )
378 auto pLegend = dynamic_cast<Legend*>(xNewLegend.get());
379 assert(!xNewLegend || pLegend);
380 setLegend(rtl::Reference< Legend >(pLegend));
383 void Diagram::setLegend( const rtl::Reference< Legend >& xNewLegend )
385 rtl::Reference< Legend > xOldLegend;
387 MutexGuard aGuard( m_aMutex );
388 if( m_xLegend == xNewLegend )
389 return;
390 xOldLegend = m_xLegend;
391 m_xLegend = xNewLegend;
393 if( xOldLegend.is())
394 ModifyListenerHelper::removeListener( xOldLegend, m_xModifyEventForwarder );
395 if( xNewLegend.is())
396 ModifyListenerHelper::addListener( xNewLegend, m_xModifyEventForwarder );
397 fireModifyEvent();
400 Reference< chart2::XColorScheme > SAL_CALL Diagram::getDefaultColorScheme()
402 Reference< chart2::XColorScheme > xRet;
404 MutexGuard aGuard( m_aMutex );
405 xRet = m_xColorScheme;
408 if( !xRet.is())
410 xRet.set( createConfigColorScheme( m_xContext ));
411 MutexGuard aGuard( m_aMutex );
412 m_xColorScheme = xRet;
414 return xRet;
417 void SAL_CALL Diagram::setDefaultColorScheme( const Reference< chart2::XColorScheme >& xColorScheme )
420 MutexGuard aGuard( m_aMutex );
421 m_xColorScheme.set( xColorScheme );
423 fireModifyEvent();
426 void SAL_CALL Diagram::setDiagramData(
427 const Reference< chart2::data::XDataSource >& xDataSource,
428 const Sequence< beans::PropertyValue >& aArguments )
430 rtl::Reference< ::chart::ChartTypeManager > xChartTypeManager = new ::chart::ChartTypeManager( m_xContext );
431 Diagram::tTemplateWithServiceName aTemplateAndService = getTemplate( xChartTypeManager );
432 rtl::Reference< ::chart::ChartTypeTemplate > xTemplate( aTemplateAndService.xChartTypeTemplate );
433 if( !xTemplate.is() )
434 xTemplate = xChartTypeManager->createTemplate( u"com.sun.star.chart2.template.Column"_ustr );
435 if(!xTemplate.is())
436 return;
437 xTemplate->changeDiagramData( rtl::Reference< ::chart::Diagram >(this), xDataSource, aArguments );
440 // ____ XTitled ____
441 uno::Reference< chart2::XTitle > SAL_CALL Diagram::getTitleObject()
443 MutexGuard aGuard( m_aMutex );
444 return m_xTitle;
447 void SAL_CALL Diagram::setTitleObject( const uno::Reference< chart2::XTitle >& xNewTitle )
449 Reference< chart2::XTitle > xOldTitle;
451 MutexGuard aGuard( m_aMutex );
452 if( m_xTitle == xNewTitle )
453 return;
454 xOldTitle = m_xTitle;
455 m_xTitle = xNewTitle;
457 if( xOldTitle.is())
458 ModifyListenerHelper::removeListener( xOldTitle, m_xModifyEventForwarder );
459 if( xNewTitle.is())
460 ModifyListenerHelper::addListener( xNewTitle, m_xModifyEventForwarder );
461 fireModifyEvent();
464 // ____ X3DDefaultSetter ____
465 void SAL_CALL Diagram::set3DSettingsToDefault()
467 setPropertyToDefault( u"D3DSceneDistance"_ustr);
468 setPropertyToDefault( u"D3DSceneFocalLength"_ustr);
469 setDefaultRotation();
470 setDefaultIllumination();
473 void SAL_CALL Diagram::setDefaultRotation()
475 bool bPieOrDonut( isPieOrDonutChart() );
476 setDefaultRotation( bPieOrDonut );
479 static ::basegfx::B3DHomMatrix lcl_getCompleteRotationMatrix( Diagram& rDiagram )
481 ::basegfx::B3DHomMatrix aCompleteRotation;
482 double fXAngleRad=0.0;
483 double fYAngleRad=0.0;
484 double fZAngleRad=0.0;
485 rDiagram.getRotationAngle( fXAngleRad, fYAngleRad, fZAngleRad );
486 aCompleteRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
487 return aCompleteRotation;
489 static void lcl_RotateLightSource( Diagram& rDiagram
490 , int nLightSourceDirectionProp
491 , int nLightSourceOnProp
492 , const ::basegfx::B3DHomMatrix& rRotationMatrix )
494 bool bLightOn = false;
495 if( !(rDiagram.getFastPropertyValue( nLightSourceOnProp ) >>= bLightOn) )
496 return;
498 if( bLightOn )
500 drawing::Direction3D aLight;
501 if( rDiagram.getFastPropertyValue( nLightSourceDirectionProp ) >>= aLight )
503 ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aLight ) );
504 aLightVector = rRotationMatrix*aLightVector;
506 rDiagram.setFastPropertyValue( nLightSourceDirectionProp
507 , uno::Any( BaseGFXHelper::B3DVectorToDirection3D( aLightVector ) ) );
512 static void lcl_setLightsForScheme( Diagram& rDiagram, const ThreeDLookScheme& rScheme )
514 if( rScheme == ThreeDLookScheme::ThreeDLookScheme_Unknown)
515 return;
517 // "D3DSceneLightOn2" / UNO_NAME_3D_SCENE_LIGHTON_2
518 rDiagram.setFastPropertyValue( PROP_SCENE_LIGHT_ON_2, uno::Any( true ) );
520 rtl::Reference< ChartType > xChartType( rDiagram.getChartTypeByIndex( 0 ) );
521 uno::Any aADirection( rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple
522 ? ChartTypeHelper::getDefaultSimpleLightDirection(xChartType)
523 : ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) );
525 // "D3DSceneLightDirection2" / UNO_NAME_3D_SCENE_LIGHTDIRECTION_2
526 rDiagram.setFastPropertyValue( PROP_SCENE_LIGHT_DIRECTION_2, aADirection );
527 //rotate light direction when right angled axes are off but supported
529 bool bRightAngledAxes = false;
530 rDiagram.getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bRightAngledAxes; // "RightAngledAxes"
531 if(!bRightAngledAxes)
533 if( ChartTypeHelper::isSupportingRightAngledAxes( xChartType ) )
535 ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( rDiagram ) );
536 BaseGFXHelper::ReduceToRotationMatrix( aRotation );
537 // "D3DSceneLightDirection2", "D3DSceneLightOn2"
538 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_2, PROP_SCENE_LIGHT_ON_2, aRotation );
543 sal_Int32 nColor = ::chart::ChartTypeHelper::getDefaultDirectLightColor(
544 rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple, xChartType);
545 // "D3DSceneLightColor2" / UNO_NAME_3D_SCENE_LIGHTCOLOR_2
546 rDiagram.setFastPropertyValue( PROP_SCENE_LIGHT_COLOR_2, uno::Any( nColor ) );
548 sal_Int32 nAmbientColor = ::chart::ChartTypeHelper::getDefaultAmbientLightColor(
549 rScheme == ThreeDLookScheme::ThreeDLookScheme_Simple, xChartType);
550 // "D3DSceneAmbientColor" / UNO_NAME_3D_SCENE_AMBIENTCOLOR
551 rDiagram.setFastPropertyValue( PROP_SCENE_AMBIENT_COLOR, uno::Any( nAmbientColor ) );
554 void SAL_CALL Diagram::setDefaultIllumination()
556 drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH );
559 // "D3DSceneShadeMode"
560 getFastPropertyValue( PROP_SCENE_SHADE_MODE )>>= aShadeMode;
561 // "D3DSceneLightOn1" / UNO_NAME_3D_SCENE_LIGHTON_1
562 setFastPropertyValue( PROP_SCENE_LIGHT_ON_1, uno::Any( false ) );
563 setFastPropertyValue( PROP_SCENE_LIGHT_ON_3, uno::Any( false ) );
564 setFastPropertyValue( PROP_SCENE_LIGHT_ON_4, uno::Any( false ) );
565 setFastPropertyValue( PROP_SCENE_LIGHT_ON_5, uno::Any( false ) );
566 setFastPropertyValue( PROP_SCENE_LIGHT_ON_6, uno::Any( false ) );
567 setFastPropertyValue( PROP_SCENE_LIGHT_ON_7, uno::Any( false ) );
568 setFastPropertyValue( PROP_SCENE_LIGHT_ON_8, uno::Any( false ) );
570 catch( const uno::Exception & )
572 DBG_UNHANDLED_EXCEPTION("chart2");
575 ThreeDLookScheme aScheme = (aShadeMode == drawing::ShadeMode_FLAT)
576 ? ThreeDLookScheme::ThreeDLookScheme_Simple
577 : ThreeDLookScheme::ThreeDLookScheme_Realistic;
578 lcl_setLightsForScheme( *this, aScheme );
581 // ____ XCoordinateSystemContainer ____
582 void SAL_CALL Diagram::addCoordinateSystem(
583 const uno::Reference< chart2::XCoordinateSystem >& aCoordSys )
585 ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordSys.get());
586 assert(pCoordSys);
588 MutexGuard aGuard( m_aMutex );
589 if( std::find( m_aCoordSystems.begin(), m_aCoordSystems.end(), pCoordSys )
590 != m_aCoordSystems.end())
591 throw lang::IllegalArgumentException(u"coordsys not found"_ustr, static_cast<cppu::OWeakObject*>(this), 1);
593 if( !m_aCoordSystems.empty() )
595 OSL_FAIL( "more than one coordinatesystem is not supported yet by the fileformat" );
596 return;
598 m_aCoordSystems.push_back( pCoordSys );
600 ModifyListenerHelper::addListener( aCoordSys, m_xModifyEventForwarder );
601 fireModifyEvent();
604 void SAL_CALL Diagram::removeCoordinateSystem(
605 const uno::Reference< chart2::XCoordinateSystem >& aCoordSys )
607 ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordSys.get());
608 assert(pCoordSys);
610 MutexGuard aGuard( m_aMutex );
611 auto aIt = std::find( m_aCoordSystems.begin(), m_aCoordSystems.end(), pCoordSys );
612 if( aIt == m_aCoordSystems.end())
613 throw container::NoSuchElementException(
614 u"The given coordinate-system is no element of the container"_ustr,
615 static_cast< uno::XWeak * >( this ));
616 m_aCoordSystems.erase( aIt );
618 ModifyListenerHelper::removeListener( aCoordSys, m_xModifyEventForwarder );
619 fireModifyEvent();
622 uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > SAL_CALL Diagram::getCoordinateSystems()
624 MutexGuard aGuard( m_aMutex );
625 return comphelper::containerToSequence<uno::Reference< chart2::XCoordinateSystem >>( m_aCoordSystems );
628 Diagram::tCoordinateSystemContainerType Diagram::getBaseCoordinateSystems() const
630 MutexGuard aGuard( m_aMutex );
631 return m_aCoordSystems;
634 void SAL_CALL Diagram::setCoordinateSystems(
635 const Sequence< Reference< chart2::XCoordinateSystem > >& aCoordinateSystems )
637 tCoordinateSystemContainerType aNew;
638 tCoordinateSystemContainerType aOld;
639 if( aCoordinateSystems.hasElements() )
641 OSL_ENSURE( aCoordinateSystems.getLength()<=1, "more than one coordinatesystem is not supported yet by the fileformat" );
642 ::chart::BaseCoordinateSystem* pCoordSys = dynamic_cast<::chart::BaseCoordinateSystem*>(aCoordinateSystems[0].get());
643 assert(pCoordSys);
644 aNew.push_back( pCoordSys );
647 MutexGuard aGuard( m_aMutex );
648 std::swap( aOld, m_aCoordSystems );
649 m_aCoordSystems = aNew;
651 for (auto & xSystem : aOld)
652 xSystem->removeModifyListener(m_xModifyEventForwarder);
653 for (auto & xSystem : aNew)
654 xSystem->addModifyListener(m_xModifyEventForwarder);
655 fireModifyEvent();
658 void Diagram::setCoordinateSystems(
659 const std::vector< rtl::Reference< BaseCoordinateSystem > >& aCoordinateSystems )
661 tCoordinateSystemContainerType aNew;
662 tCoordinateSystemContainerType aOld;
663 if( !aCoordinateSystems.empty() )
665 OSL_ENSURE( aCoordinateSystems.size()<=1, "more than one coordinatesystem is not supported yet by the fileformat" );
666 aNew.push_back( aCoordinateSystems[0] );
669 MutexGuard aGuard( m_aMutex );
670 std::swap( aOld, m_aCoordSystems );
671 m_aCoordSystems = aNew;
673 for (auto & xSystem : aOld)
674 xSystem->removeModifyListener(m_xModifyEventForwarder);
675 for (auto & xSystem : aNew)
676 xSystem->addModifyListener(m_xModifyEventForwarder);
677 fireModifyEvent();
680 // ____ XCloneable ____
681 Reference< util::XCloneable > SAL_CALL Diagram::createClone()
683 MutexGuard aGuard( m_aMutex );
684 return Reference< util::XCloneable >( new Diagram( *this ));
687 // ____ XModifyBroadcaster ____
688 void SAL_CALL Diagram::addModifyListener( const Reference< util::XModifyListener >& aListener )
690 m_xModifyEventForwarder->addModifyListener( aListener );
693 void SAL_CALL Diagram::removeModifyListener( const Reference< util::XModifyListener >& aListener )
695 m_xModifyEventForwarder->removeModifyListener( aListener );
698 // ____ XModifyListener ____
699 void SAL_CALL Diagram::modified( const lang::EventObject& aEvent )
701 m_xModifyEventForwarder->modified( aEvent );
704 // ____ XEventListener (base of XModifyListener) ____
705 void SAL_CALL Diagram::disposing( const lang::EventObject& /* Source */ )
707 // nothing
710 // ____ OPropertySet ____
711 void Diagram::firePropertyChangeEvent()
713 fireModifyEvent();
716 void Diagram::fireModifyEvent()
718 m_xModifyEventForwarder->modified( lang::EventObject( static_cast< uno::XWeak* >( this )));
721 // ____ OPropertySet ____
722 void Diagram::GetDefaultValue( sal_Int32 nHandle, uno::Any& rAny ) const
724 const tPropertyValueMap& rStaticDefaults = StaticDiagramDefaults();
725 tPropertyValueMap::const_iterator aFound( rStaticDefaults.find( nHandle ) );
726 if( aFound == rStaticDefaults.end() )
727 rAny.clear();
728 else
729 rAny = (*aFound).second;
732 // ____ OPropertySet ____
733 ::cppu::IPropertyArrayHelper & SAL_CALL Diagram::getInfoHelper()
735 return StaticDiagramInfoHelper();
738 // ____ XPropertySet ____
739 uno::Reference< beans::XPropertySetInfo > SAL_CALL Diagram::getPropertySetInfo()
741 return StaticDiagramInfo();
744 // ____ XFastPropertySet ____
745 void SAL_CALL Diagram::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
747 //special treatment for some 3D properties
748 if( nHandle == PROP_DIAGRAM_PERSPECTIVE )
750 sal_Int32 fPerspective = 20;
751 if( rValue >>=fPerspective )
752 setCameraDistance( ThreeDHelper::PerspectiveToCameraDistance( fPerspective ) );
754 else if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL
755 || nHandle == PROP_DIAGRAM_ROTATION_VERTICAL )
757 sal_Int32 nNewAngleDegree = 0;
758 if( rValue >>=nNewAngleDegree )
760 sal_Int32 nHorizontal, nVertical;
761 getRotation( nHorizontal, nVertical );
762 if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL )
763 nHorizontal = nNewAngleDegree;
764 else
765 nVertical = nNewAngleDegree;
766 setRotation( nHorizontal, nVertical );
769 else
770 ::property::OPropertySet::setFastPropertyValue_NoBroadcast( nHandle, rValue );
773 void SAL_CALL Diagram::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
775 //special treatment for some 3D properties
776 if( nHandle == PROP_DIAGRAM_PERSPECTIVE )
778 sal_Int32 nPerspective = ::basegfx::fround( ThreeDHelper::CameraDistanceToPerspective(
779 const_cast< Diagram* >( this )->getCameraDistance() ) );
780 rValue <<= nPerspective;
782 else if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL
783 || nHandle == PROP_DIAGRAM_ROTATION_VERTICAL )
785 sal_Int32 nHorizontal, nVertical;
786 const_cast< Diagram* >( this )->getRotation( nHorizontal, nVertical );
787 sal_Int32 nAngleDegree = 0;
788 if( nHandle == PROP_DIAGRAM_ROTATION_HORIZONTAL )
789 nAngleDegree = nHorizontal;
790 else
791 nAngleDegree = nVertical;
792 rValue <<= nAngleDegree;
794 else
795 ::property::OPropertySet::getFastPropertyValue( rValue,nHandle );
798 uno::Reference<chart2::XDataTable> SAL_CALL Diagram::getDataTable()
800 MutexGuard aGuard( m_aMutex );
801 return m_xDataTable;
804 rtl::Reference<::chart::DataTable> Diagram::getDataTableRef() const
806 MutexGuard aGuard( m_aMutex );
807 return m_xDataTable;
810 void SAL_CALL Diagram::setDataTable(const uno::Reference<chart2::XDataTable>& xDataTable)
812 auto* pDataTable = dynamic_cast<DataTable*>(xDataTable.get());
813 assert(!xDataTable || pDataTable);
814 setDataTable(rtl::Reference<DataTable>(pDataTable));
817 void Diagram::setDataTable(const rtl::Reference<DataTable>& xNewDataTable)
819 rtl::Reference<DataTable> xOldDataTable;
821 MutexGuard aGuard(m_aMutex);
822 if (m_xDataTable == xNewDataTable)
823 return;
824 xOldDataTable = m_xDataTable;
825 m_xDataTable = xNewDataTable;
827 if (xOldDataTable.is())
828 ModifyListenerHelper::removeListener(xOldDataTable, m_xModifyEventForwarder);
829 if (xNewDataTable.is())
830 ModifyListenerHelper::addListener(xNewDataTable, m_xModifyEventForwarder);
831 fireModifyEvent();
834 using impl::Diagram_Base;
836 IMPLEMENT_FORWARD_XINTERFACE2( Diagram, Diagram_Base, ::property::OPropertySet )
837 IMPLEMENT_FORWARD_XTYPEPROVIDER2( Diagram, Diagram_Base, ::property::OPropertySet )
839 // implement XServiceInfo methods basing upon getSupportedServiceNames_Static
840 OUString SAL_CALL Diagram::getImplementationName()
842 return u"com.sun.star.comp.chart2.Diagram"_ustr;
845 sal_Bool SAL_CALL Diagram::supportsService( const OUString& rServiceName )
847 return cppu::supportsService(this, rServiceName);
850 css::uno::Sequence< OUString > SAL_CALL Diagram::getSupportedServiceNames()
852 return {
853 u"com.sun.star.chart2.Diagram"_ustr,
854 u"com.sun.star.layout.LayoutElement"_ustr,
855 u"com.sun.star.beans.PropertySet"_ustr };
858 DiagramPositioningMode Diagram::getDiagramPositioningMode()
860 DiagramPositioningMode eMode = DiagramPositioningMode::Auto;
861 chart2::RelativePosition aRelPos;
862 chart2::RelativeSize aRelSize;
863 if( (getFastPropertyValue(PROP_DIAGRAM_REL_POS) >>= aRelPos ) &&
864 (getFastPropertyValue(PROP_DIAGRAM_REL_SIZE) >>= aRelSize ) )
866 bool bPosSizeExcludeAxes=false;
867 getFastPropertyValue(PROP_DIAGRAM_POSSIZE_EXCLUDE_LABELS) >>= bPosSizeExcludeAxes;
868 if( bPosSizeExcludeAxes )
869 eMode = DiagramPositioningMode::Excluding;
870 else
871 eMode = DiagramPositioningMode::Including;
873 return eMode;
877 sal_Int32 Diagram::getCorrectedMissingValueTreatment(
878 const rtl::Reference< ChartType >& xChartType )
880 sal_Int32 nResult = css::chart::MissingValueTreatment::LEAVE_GAP;
881 const uno::Sequence < sal_Int32 > aAvailableMissingValueTreatments(
882 ChartTypeHelper::getSupportedMissingValueTreatments( xChartType ) );
884 if( getFastPropertyValue( PROP_DIAGRAM_MISSING_VALUE_TREATMENT ) >>= nResult )
886 //ensure that the set value is supported by this charttype
887 for( sal_Int32 n : aAvailableMissingValueTreatments )
888 if( n == nResult )
889 return nResult; //ok
892 //otherwise use the first supported one
893 if( aAvailableMissingValueTreatments.hasElements() )
895 nResult = aAvailableMissingValueTreatments[0];
896 return nResult;
899 return nResult;
902 void Diagram::setGeometry3D( sal_Int32 nNewGeometry )
904 std::vector< rtl::Reference< DataSeries > > aSeriesVec =
905 getDataSeries();
907 for (auto const& series : aSeriesVec)
909 DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints(
910 series, u"Geometry3D"_ustr, uno::Any( nNewGeometry ));
914 sal_Int32 Diagram::getGeometry3D( bool& rbFound, bool& rbAmbiguous )
916 sal_Int32 nCommonGeom( css::chart2::DataPointGeometry3D::CUBOID );
917 rbFound = false;
918 rbAmbiguous = false;
920 std::vector< rtl::Reference< DataSeries > > aSeriesVec = getDataSeries();
922 if( aSeriesVec.empty())
923 rbAmbiguous = true;
925 for (auto const& series : aSeriesVec)
929 sal_Int32 nGeom = 0;
930 if( series->getPropertyValue( u"Geometry3D"_ustr) >>= nGeom )
932 if( ! rbFound )
934 // first series
935 nCommonGeom = nGeom;
936 rbFound = true;
938 // further series: compare for uniqueness
939 else if( nCommonGeom != nGeom )
941 rbAmbiguous = true;
942 break;
946 catch( const uno::Exception & )
948 DBG_UNHANDLED_EXCEPTION("chart2");
952 return nCommonGeom;
955 bool Diagram::isPieOrDonutChart()
957 rtl::Reference< ChartType > xChartType = getChartTypeByIndex( 0 );
959 if( xChartType .is() )
961 OUString aChartType = xChartType->getChartType();
962 if( aChartType == CHART2_SERVICE_NAME_CHARTTYPE_PIE )
963 return true;
965 return false;
968 bool Diagram::isSupportingFloorAndWall()
970 //pies and donuts currently do not support this because of wrong files from older versions
971 //todo: allow this in future again, if fileversion is available for OLE objects (metastream)
972 //thus the wrong bottom can be removed on import
974 const std::vector< rtl::Reference< ChartType > > aTypes = getChartTypes();
975 for( rtl::Reference< ChartType > const & xType : aTypes )
977 OUString sChartType = xType->getChartType();
978 if( sChartType.match(CHART2_SERVICE_NAME_CHARTTYPE_PIE) )
979 return false;
980 if( sChartType.match(CHART2_SERVICE_NAME_CHARTTYPE_NET) )
981 return false;
982 if( sChartType.match(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET) )
983 return false;
985 return true;
989 * This method implements the logic of checking if a series can be moved
990 * forward/backward. Depending on the "bDoMove" parameter the series will
991 * be moved (bDoMove = true) or the function just will test if the
992 * series can be moved without doing the move (bDoMove = false).
994 * @param xDiagram
995 * Reference to the diagram that contains the series.
997 * @param xGivenDataSeries
998 * Reference to the series that should moved or tested for moving.
1000 * @param bForward
1001 * Direction in which the series should be moved or tested for moving.
1003 * @param bDoMove
1004 * Should this function really move the series (true) or just test if it is
1005 * possible (false).
1008 * @returns
1009 * in case of bDoMove == true
1010 * - True : if the move was done
1011 * - False : the move failed
1012 * in case of bDoMove == false
1013 * - True : the series can be moved
1014 * - False : the series can not be moved
1017 static bool lcl_moveSeriesOrCheckIfMoveIsAllowed(
1018 Diagram& rDiagram,
1019 const rtl::Reference< DataSeries >& xGivenDataSeries,
1020 bool bForward,
1021 bool bDoMove )
1023 bool bMovedOrMoveAllowed = false;
1027 if( !xGivenDataSeries.is() )
1028 return false;
1030 //find position of series.
1031 bool bFound = false;
1032 const std::vector< rtl::Reference< BaseCoordinateSystem > > aCooSysList( rDiagram.getBaseCoordinateSystems() );
1034 for( std::size_t nCS = 0; !bFound && nCS < aCooSysList.size(); ++nCS )
1036 const rtl::Reference< BaseCoordinateSystem > & xCooSys( aCooSysList[nCS] );
1038 //iterate through all chart types in the current coordinate system
1039 std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() );
1040 rtl::Reference< ChartType > xFormerChartType;
1042 for( std::size_t nT = 0; !bFound && nT < aChartTypeList.size(); ++nT )
1044 rtl::Reference< ChartType > xCurrentChartType( aChartTypeList[nT] );
1046 //iterate through all series in this chart type
1048 std::vector< rtl::Reference< DataSeries > > aSeriesList = xCurrentChartType->getDataSeries2();
1050 for( std::size_t nS = 0; !bFound && nS < aSeriesList.size(); ++nS )
1053 // We found the series we are interested in!
1054 if( xGivenDataSeries==aSeriesList[nS] )
1056 std::size_t nOldSeriesIndex = nS;
1057 bFound = true;
1061 sal_Int32 nNewSeriesIndex = nS;
1063 // tdf#34517 Bringing forward means increasing, backwards means decreasing series position
1064 if( !bForward )
1065 nNewSeriesIndex--;
1066 else
1067 nNewSeriesIndex++;
1069 if( nNewSeriesIndex >= 0 && o3tl::make_unsigned(nNewSeriesIndex) < aSeriesList.size() )
1071 //move series in the same charttype
1072 bMovedOrMoveAllowed = true;
1073 if( bDoMove )
1075 aSeriesList[ nOldSeriesIndex ] = aSeriesList[ nNewSeriesIndex ];
1076 aSeriesList[ nNewSeriesIndex ] = xGivenDataSeries;
1077 xCurrentChartType->setDataSeries( aSeriesList );
1080 else if( nNewSeriesIndex<0 )
1082 //exchange series with former charttype
1083 if( xFormerChartType.is() && DiagramHelper::areChartTypesCompatible( xFormerChartType, xCurrentChartType ) )
1085 bMovedOrMoveAllowed = true;
1086 if( bDoMove )
1088 std::vector< rtl::Reference< DataSeries > > aOtherSeriesList = xFormerChartType->getDataSeries2();
1089 sal_Int32 nOtherSeriesIndex = aOtherSeriesList.size()-1;
1090 if( nOtherSeriesIndex >= 0 && o3tl::make_unsigned(nOtherSeriesIndex) < aOtherSeriesList.size() )
1092 rtl::Reference< DataSeries > xExchangeSeries( aOtherSeriesList[nOtherSeriesIndex] );
1093 aOtherSeriesList[nOtherSeriesIndex] = xGivenDataSeries;
1094 xFormerChartType->setDataSeries(aOtherSeriesList);
1096 aSeriesList[nOldSeriesIndex] = std::move(xExchangeSeries);
1097 xCurrentChartType->setDataSeries(aSeriesList);
1102 else if( nT+1 < aChartTypeList.size() )
1104 //exchange series with next charttype
1105 const rtl::Reference< ChartType >& xOtherChartType( aChartTypeList[nT+1] );
1106 if( xOtherChartType.is() && DiagramHelper::areChartTypesCompatible( xOtherChartType, xCurrentChartType ) )
1108 bMovedOrMoveAllowed = true;
1109 if( bDoMove )
1111 std::vector< rtl::Reference< DataSeries > > aOtherSeriesList = xOtherChartType->getDataSeries2();
1112 if( !aOtherSeriesList.empty() )
1114 rtl::Reference<DataSeries> xExchangeSeries(aOtherSeriesList[0]);
1115 aOtherSeriesList[0] = xGivenDataSeries;
1116 xOtherChartType->setDataSeries(aOtherSeriesList);
1118 aSeriesList[nOldSeriesIndex] = std::move(xExchangeSeries);
1119 xCurrentChartType->setDataSeries(aSeriesList);
1125 catch( const util::CloseVetoException& )
1128 catch( const uno::RuntimeException& )
1133 xFormerChartType = std::move(xCurrentChartType);
1137 catch( const util::CloseVetoException& )
1140 catch( const uno::RuntimeException& )
1143 return bMovedOrMoveAllowed;
1146 bool Diagram::isSeriesMoveable(
1147 const rtl::Reference< DataSeries >& xGivenDataSeries,
1148 bool bForward )
1150 const bool bDoMove = false;
1152 bool bIsMoveable = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1153 *this, xGivenDataSeries, bForward, bDoMove );
1155 return bIsMoveable;
1158 bool Diagram::moveSeries( const rtl::Reference< DataSeries >& xGivenDataSeries, bool bForward )
1160 const bool bDoMove = true;
1162 bool bMoved = lcl_moveSeriesOrCheckIfMoveIsAllowed(
1163 *this, xGivenDataSeries, bForward, bDoMove );
1165 return bMoved;
1168 std::vector< rtl::Reference< ChartType > > Diagram::getChartTypes()
1170 std::vector< rtl::Reference< ChartType > > aResult;
1173 for( rtl::Reference< BaseCoordinateSystem > const & coords : getBaseCoordinateSystems() )
1175 const std::vector< rtl::Reference< ChartType > > & aChartTypeSeq( coords->getChartTypes2());
1176 aResult.insert( aResult.end(), aChartTypeSeq.begin(), aChartTypeSeq.end() );
1179 catch( const uno::Exception & )
1181 DBG_UNHANDLED_EXCEPTION("chart2");
1184 return aResult;
1187 rtl::Reference< ChartType > Diagram::getChartTypeByIndex( sal_Int32 nIndex )
1189 rtl::Reference< ChartType > xChartType;
1191 //iterate through all coordinate systems
1192 sal_Int32 nTypesSoFar = 0;
1193 for( rtl::Reference< BaseCoordinateSystem > const & coords : getBaseCoordinateSystems() )
1195 const std::vector< rtl::Reference< ChartType > > & aChartTypeList( coords->getChartTypes2() );
1196 if( nIndex >= 0 && o3tl::make_unsigned(nIndex) < nTypesSoFar + aChartTypeList.size() )
1198 xChartType = aChartTypeList[nIndex - nTypesSoFar];
1199 break;
1201 nTypesSoFar += aChartTypeList.size();
1204 return xChartType;
1207 bool Diagram::isSupportingDateAxis()
1209 return ::chart::ChartTypeHelper::isSupportingDateAxis( getChartTypeByIndex( 0 ), 0 );
1212 static std::vector< rtl::Reference< Axis > > lcl_getAxisHoldingCategoriesFromDiagram(
1213 Diagram& rDiagram )
1215 std::vector< rtl::Reference< Axis > > aRet;
1217 // return first x-axis as fall-back
1218 rtl::Reference< Axis > xFallBack;
1221 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : rDiagram.getBaseCoordinateSystems() )
1223 OSL_ASSERT( xCooSys.is());
1224 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
1226 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
1227 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
1229 rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nN,nI );
1230 OSL_ASSERT( xAxis.is());
1231 if( xAxis.is())
1233 chart2::ScaleData aScaleData = xAxis->getScaleData();
1234 if( aScaleData.Categories.is() || (aScaleData.AxisType == chart2::AxisType::CATEGORY) )
1236 aRet.push_back(xAxis);
1238 if( (nN == 0) && !xFallBack.is())
1239 xFallBack = std::move(xAxis);
1245 catch( const uno::Exception & )
1247 DBG_UNHANDLED_EXCEPTION("chart2" );
1250 if( aRet.empty() )
1251 aRet.push_back(xFallBack);
1253 return aRet;
1256 uno::Reference< chart2::data::XLabeledDataSequence > Diagram::getCategories()
1258 uno::Reference< chart2::data::XLabeledDataSequence > xResult;
1262 std::vector< rtl::Reference< Axis > > aCatAxes(
1263 lcl_getAxisHoldingCategoriesFromDiagram( *this ));
1264 //search for first categories
1265 if (aCatAxes.empty())
1266 return xResult;
1268 const rtl::Reference< Axis >& xCatAxis(aCatAxes[0]);
1269 if( !xCatAxis.is())
1270 return xResult;
1272 chart2::ScaleData aScaleData( xCatAxis->getScaleData());
1273 if( !aScaleData.Categories.is() )
1274 return xResult;
1276 xResult = aScaleData.Categories;
1277 uno::Reference<beans::XPropertySet> xProp(xResult->getValues(), uno::UNO_QUERY );
1278 if( xProp.is() )
1282 xProp->setPropertyValue( u"Role"_ustr, uno::Any( u"categories"_ustr ) );
1284 catch( const uno::Exception & )
1286 DBG_UNHANDLED_EXCEPTION("chart2");
1290 catch( const uno::Exception & )
1292 DBG_UNHANDLED_EXCEPTION("chart2");
1295 return xResult;
1298 void Diagram::setCategories(
1299 const uno::Reference< chart2::data::XLabeledDataSequence >& xCategories,
1300 bool bSetAxisType /* = false */,
1301 bool bCategoryAxis /* = true */ )
1303 std::vector< rtl::Reference< Axis > > aCatAxes(
1304 lcl_getAxisHoldingCategoriesFromDiagram( *this ));
1306 for (const rtl::Reference< Axis >& xCatAxis : aCatAxes)
1308 if( xCatAxis.is())
1310 chart2::ScaleData aScaleData( xCatAxis->getScaleData());
1311 aScaleData.Categories = xCategories;
1312 if( bSetAxisType )
1314 if( bCategoryAxis )
1315 aScaleData.AxisType = chart2::AxisType::CATEGORY;
1316 else if( aScaleData.AxisType == chart2::AxisType::CATEGORY || aScaleData.AxisType == chart2::AxisType::DATE )
1317 aScaleData.AxisType = chart2::AxisType::REALNUMBER;
1319 xCatAxis->setScaleData( aScaleData );
1324 bool Diagram::isCategory()
1328 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() )
1330 for( sal_Int32 nN = xCooSys->getDimension(); nN--; )
1332 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nN);
1333 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
1335 rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( nN,nI );
1336 OSL_ASSERT( xAxis.is());
1337 if( xAxis.is())
1339 chart2::ScaleData aScaleData = xAxis->getScaleData();
1340 if( aScaleData.AxisType == chart2::AxisType::CATEGORY || aScaleData.AxisType == chart2::AxisType::DATE )
1341 return true;
1347 catch( const uno::Exception & )
1349 DBG_UNHANDLED_EXCEPTION("chart2");
1352 return false;
1355 std::vector< std::vector< rtl::Reference< DataSeries > > >
1356 Diagram::getDataSeriesGroups()
1358 std::vector< std::vector< rtl::Reference< DataSeries > > > aResult;
1360 //iterate through all coordinate systems
1361 for( rtl::Reference< BaseCoordinateSystem > const & coords : getBaseCoordinateSystems() )
1363 //iterate through all chart types in the current coordinate system
1364 for( rtl::Reference< ChartType > const & chartType : coords->getChartTypes2() )
1366 aResult.push_back( chartType->getDataSeries2() );
1369 return aResult;
1372 std::vector< rtl::Reference< ::chart::DataSeries > >
1373 Diagram::getDataSeries()
1375 std::vector< rtl::Reference< DataSeries > > aResult;
1378 for( rtl::Reference< BaseCoordinateSystem > const & coords : getBaseCoordinateSystems() )
1380 for( rtl::Reference< ChartType> const & chartType : coords->getChartTypes2() )
1382 const std::vector< rtl::Reference< DataSeries > > aSeriesSeq( chartType->getDataSeries2() );
1383 aResult.insert( aResult.end(), aSeriesSeq.begin(), aSeriesSeq.end() );
1387 catch( const uno::Exception & )
1389 DBG_UNHANDLED_EXCEPTION("chart2");
1392 return aResult;
1395 rtl::Reference< ChartType > Diagram::getChartTypeOfSeries(
1396 const rtl::Reference< DataSeries >& xGivenDataSeries )
1398 if( !xGivenDataSeries.is() )
1399 return nullptr;
1401 //iterate through the model to find the given xSeries
1402 //the found parent indicates the charttype
1404 //iterate through all coordinate systems
1406 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() )
1408 //iterate through all chart types in the current coordinate system
1409 const std::vector< rtl::Reference< ChartType > > & aChartTypeList( xCooSys->getChartTypes2() );
1410 for( rtl::Reference< ChartType > const & xChartType : aChartTypeList )
1412 //iterate through all series in this chart type
1413 for( rtl::Reference< DataSeries > const & dataSeries : xChartType->getDataSeries2() )
1415 if( xGivenDataSeries==dataSeries )
1416 return xChartType;
1420 return nullptr;
1423 rtl::Reference< Axis > Diagram::getAttachedAxis(
1424 const rtl::Reference< DataSeries >& xSeries )
1426 return AxisHelper::getAxis( 1, DiagramHelper::isSeriesAttachedToMainAxis( xSeries ), this );
1429 bool Diagram::attachSeriesToAxis( bool bAttachToMainAxis
1430 , const rtl::Reference< DataSeries >& xDataSeries
1431 , const uno::Reference< uno::XComponentContext > & xContext
1432 , bool bAdaptAxes )
1434 bool bChanged = false;
1436 //set property at axis
1438 sal_Int32 nNewAxisIndex = bAttachToMainAxis ? 0 : 1;
1439 sal_Int32 nOldAxisIndex = DataSeriesHelper::getAttachedAxisIndex(xDataSeries);
1440 rtl::Reference< Axis > xOldAxis = getAttachedAxis( xDataSeries );
1442 if( nOldAxisIndex != nNewAxisIndex )
1446 xDataSeries->setPropertyValue( u"AttachedAxisIndex"_ustr, uno::Any( nNewAxisIndex ) );
1447 bChanged = true;
1449 catch( const uno::Exception & )
1451 DBG_UNHANDLED_EXCEPTION("chart2");
1455 if( bChanged )
1457 rtl::Reference< Axis > xAxis = AxisHelper::getAxis( 1, bAttachToMainAxis, this );
1458 if(!xAxis.is()) //create an axis if necessary
1459 xAxis = AxisHelper::createAxis( 1, bAttachToMainAxis, this, xContext );
1460 if( bAdaptAxes )
1462 AxisHelper::makeAxisVisible( xAxis );
1463 AxisHelper::hideAxisIfNoDataIsAttached( xOldAxis, this );
1467 return bChanged;
1470 void Diagram::replaceCoordinateSystem(
1471 const rtl::Reference< BaseCoordinateSystem > & xCooSysToReplace,
1472 const rtl::Reference< BaseCoordinateSystem > & xReplacement )
1474 // update the coordinate-system container
1477 uno::Reference< chart2::data::XLabeledDataSequence > xCategories = getCategories();
1479 // move chart types of xCooSysToReplace to xReplacement
1480 xReplacement->setChartTypes( xCooSysToReplace->getChartTypes());
1482 removeCoordinateSystem( xCooSysToReplace );
1483 addCoordinateSystem( xReplacement );
1485 if( xCategories.is() )
1486 setCategories( xCategories );
1488 catch( const uno::Exception & )
1490 DBG_UNHANDLED_EXCEPTION("chart2");
1494 sal_Int32 Diagram::getDimension()
1496 // -1: not yet set
1497 sal_Int32 nResult = -1;
1501 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() )
1503 if(xCooSys.is())
1505 nResult = xCooSys->getDimension();
1506 break;
1510 catch( const uno::Exception & )
1512 DBG_UNHANDLED_EXCEPTION("chart2");
1515 return nResult;
1518 void Diagram::setDimension( sal_Int32 nNewDimensionCount )
1520 if( getDimension() == nNewDimensionCount )
1521 return;
1525 bool rbFound = false;
1526 bool rbAmbiguous = true;
1527 StackMode eStackMode = getStackMode( rbFound, rbAmbiguous );
1528 bool bIsSupportingOnlyDeepStackingFor3D=false;
1530 //change all coordinate systems:
1531 auto aCoordSystems = getBaseCoordinateSystems();
1532 for( rtl::Reference<BaseCoordinateSystem> const & xOldCooSys : aCoordSystems )
1534 rtl::Reference< BaseCoordinateSystem > xNewCooSys;
1536 const std::vector< rtl::Reference< ChartType > > aChartTypeList( xOldCooSys->getChartTypes2() );
1537 for( rtl::Reference< ChartType > const & xChartType : aChartTypeList )
1539 bIsSupportingOnlyDeepStackingFor3D = ChartTypeHelper::isSupportingOnlyDeepStackingFor3D( xChartType );
1540 if(!xNewCooSys.is())
1542 xNewCooSys = dynamic_cast<BaseCoordinateSystem*>(xChartType->createCoordinateSystem( nNewDimensionCount ).get());
1543 assert(xNewCooSys);
1544 break;
1546 //@todo make sure that all following charttypes are also capable of the new dimension
1547 //otherwise separate them in a different group
1548 //BM: might be done in replaceCoordinateSystem()
1551 // replace the old coordinate system at all places where it was used
1552 replaceCoordinateSystem( xOldCooSys, xNewCooSys );
1555 //correct stack mode if necessary
1556 if( nNewDimensionCount==3 && eStackMode != StackMode::ZStacked && bIsSupportingOnlyDeepStackingFor3D )
1557 setStackMode( StackMode::ZStacked );
1558 else if( nNewDimensionCount==2 && eStackMode == StackMode::ZStacked )
1559 setStackMode( StackMode::NONE );
1561 catch( const uno::Exception & )
1563 DBG_UNHANDLED_EXCEPTION("chart2");
1567 void Diagram::setStackMode( StackMode eStackMode )
1571 bool bValueFound = false;
1572 bool bIsAmbiguous = false;
1573 StackMode eOldStackMode = getStackMode( bValueFound, bIsAmbiguous );
1575 if( eStackMode == eOldStackMode && !bIsAmbiguous )
1576 return;
1578 chart2::StackingDirection eNewDirection = chart2::StackingDirection_NO_STACKING;
1579 if( eStackMode == StackMode::YStacked || eStackMode == StackMode::YStackedPercent )
1580 eNewDirection = chart2::StackingDirection_Y_STACKING;
1581 else if( eStackMode == StackMode::ZStacked )
1582 eNewDirection = chart2::StackingDirection_Z_STACKING;
1584 uno::Any aNewDirection( eNewDirection );
1586 bool bPercent = false;
1587 if( eStackMode == StackMode::YStackedPercent )
1588 bPercent = true;
1590 //iterate through all coordinate systems
1591 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() )
1593 //set correct percent stacking
1594 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(1);
1595 for(sal_Int32 nI=0; nI<=nMaximumScaleIndex; ++nI)
1597 rtl::Reference< Axis > xAxis = xCooSys->getAxisByDimension2( 1,nI );
1598 if( xAxis.is())
1600 chart2::ScaleData aScaleData = xAxis->getScaleData();
1601 if( (aScaleData.AxisType==chart2::AxisType::PERCENT) != bPercent )
1603 if( bPercent )
1604 aScaleData.AxisType = chart2::AxisType::PERCENT;
1605 else
1606 aScaleData.AxisType = chart2::AxisType::REALNUMBER;
1607 xAxis->setScaleData( aScaleData );
1611 //iterate through all chart types in the current coordinate system
1612 const std::vector< rtl::Reference< ChartType > > & aChartTypeList( xCooSys->getChartTypes2() );
1613 if (aChartTypeList.empty())
1614 continue;
1616 rtl::Reference< ChartType > xChartType( aChartTypeList[0] );
1618 //iterate through all series in this chart type
1619 for( rtl::Reference< DataSeries > const & dataSeries : xChartType->getDataSeries2() )
1621 dataSeries->setPropertyValue( u"StackingDirection"_ustr, aNewDirection );
1625 catch( const uno::Exception & )
1627 DBG_UNHANDLED_EXCEPTION("chart2");
1631 StackMode Diagram::getStackMode( bool& rbFound, bool& rbAmbiguous )
1633 rbFound=false;
1634 rbAmbiguous=false;
1636 StackMode eGlobalStackMode = StackMode::NONE;
1638 //iterate through all coordinate systems
1639 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() )
1641 //iterate through all chart types in the current coordinate system
1642 std::vector< rtl::Reference< ChartType > > aChartTypeList( xCooSys->getChartTypes2() );
1643 for( std::size_t nT = 0; nT < aChartTypeList.size(); ++nT )
1645 const rtl::Reference< ChartType >& xChartType( aChartTypeList[nT] );
1647 StackMode eLocalStackMode = DiagramHelper::getStackModeFromChartType(
1648 xChartType, rbFound, rbAmbiguous, xCooSys );
1650 if( rbFound && eLocalStackMode != eGlobalStackMode && nT>0 )
1652 rbAmbiguous = true;
1653 return eGlobalStackMode;
1656 eGlobalStackMode = eLocalStackMode;
1660 return eGlobalStackMode;
1663 void Diagram::setVertical( bool bVertical /* = true */ )
1667 uno::Any aValue;
1668 aValue <<= bVertical;
1669 for( rtl::Reference< BaseCoordinateSystem > const & xCooSys : getBaseCoordinateSystems() )
1671 bool bChanged = false;
1672 bool bOldSwap = false;
1673 if( !(xCooSys->getPropertyValue(u"SwapXAndYAxis"_ustr) >>= bOldSwap)
1674 || bVertical != bOldSwap )
1675 bChanged = true;
1677 if( bChanged )
1678 xCooSys->setPropertyValue(u"SwapXAndYAxis"_ustr, aValue);
1680 const sal_Int32 nDimensionCount = xCooSys->getDimension();
1681 sal_Int32 nDimIndex = 0;
1682 for (nDimIndex=0; nDimIndex < nDimensionCount; ++nDimIndex)
1684 const sal_Int32 nMaximumScaleIndex = xCooSys->getMaximumAxisIndexByDimension(nDimIndex);
1685 for (sal_Int32 nI = 0; nI <= nMaximumScaleIndex; ++nI)
1687 rtl::Reference<Axis> xAxis = xCooSys->getAxisByDimension2(nDimIndex,nI);
1688 if (!xAxis.is())
1689 continue;
1691 //adapt title rotation only when axis swapping has changed
1692 if (!bChanged)
1693 continue;
1695 Reference< beans::XPropertySet > xTitleProps( xAxis->getTitleObject(), uno::UNO_QUERY );
1696 if (!xTitleProps.is())
1697 continue;
1699 double fAngleDegree = 0.0;
1700 xTitleProps->getPropertyValue(u"TextRotation"_ustr) >>= fAngleDegree;
1701 if (fAngleDegree != 0.0 &&
1702 !rtl::math::approxEqual(fAngleDegree, 90.0))
1703 continue;
1705 double fNewAngleDegree = 0.0;
1706 if( !bVertical && nDimIndex == 1 )
1707 fNewAngleDegree = 90.0;
1708 else if( bVertical && nDimIndex == 0 )
1709 fNewAngleDegree = 90.0;
1711 xTitleProps->setPropertyValue(u"TextRotation"_ustr, uno::Any(fNewAngleDegree));
1716 catch( const uno::Exception & )
1718 DBG_UNHANDLED_EXCEPTION("chart2");
1722 bool Diagram::getVertical( bool& rbFound, bool& rbAmbiguous )
1724 bool bValue = false;
1725 rbFound = false;
1726 rbAmbiguous = false;
1728 for (rtl::Reference<BaseCoordinateSystem> const & coords : getBaseCoordinateSystems())
1730 bool bCurrent = false;
1731 if (coords->getPropertyValue(u"SwapXAndYAxis"_ustr) >>= bCurrent)
1733 if (!rbFound)
1735 bValue = bCurrent;
1736 rbFound = true;
1738 else if (bCurrent != bValue)
1740 // ambiguous -> choose always first found
1741 rbAmbiguous = true;
1745 return bValue;
1748 Diagram::tTemplateWithServiceName
1749 Diagram::getTemplate(
1750 const rtl::Reference< ::chart::ChartTypeManager > & xChartTypeManager )
1752 tTemplateWithServiceName aResult;
1754 if( !xChartTypeManager )
1755 return aResult;
1757 Sequence< OUString > aServiceNames( xChartTypeManager->getAvailableServiceNames());
1758 const sal_Int32 nLength = aServiceNames.getLength();
1760 bool bTemplateFound = false;
1762 for( sal_Int32 i = 0; ! bTemplateFound && i < nLength; ++i )
1766 rtl::Reference< ::chart::ChartTypeTemplate > xTempl =
1767 xChartTypeManager->createTemplate( aServiceNames[ i ] );
1769 if (xTempl.is() && xTempl->matchesTemplate2(this, true))
1771 aResult.xChartTypeTemplate = std::move(xTempl);
1772 aResult.sServiceName = aServiceNames[ i ];
1773 bTemplateFound = true;
1776 catch( const uno::Exception & )
1778 DBG_UNHANDLED_EXCEPTION("chart2");
1782 return aResult;
1785 std::vector< rtl::Reference< RegressionCurveModel > >
1786 Diagram::getAllRegressionCurvesNotMeanValueLine()
1788 std::vector< rtl::Reference< RegressionCurveModel > > aResult;
1789 std::vector< rtl::Reference< DataSeries > > aSeries( getDataSeries());
1790 for (auto const& elem : aSeries)
1792 for( rtl::Reference< RegressionCurveModel > const & curve : elem->getRegressionCurves2() )
1794 if( ! RegressionCurveHelper::isMeanValueLine( curve ))
1795 aResult.push_back( curve );
1799 return aResult;
1802 double Diagram::getCameraDistance()
1804 double fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME;
1808 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1809 getFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY ) >>= aCG;
1810 ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) );
1811 fCameraDistance = aVRP.getLength();
1813 ThreeDHelper::ensureCameraDistanceRange( fCameraDistance );
1815 catch( const uno::Exception & )
1817 DBG_UNHANDLED_EXCEPTION("chart2");
1819 return fCameraDistance;
1822 void Diagram::setCameraDistance(double fCameraDistance )
1826 if( fCameraDistance <= 0 )
1827 fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME;
1829 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1830 getFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY ) >>= aCG;
1831 ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) );
1832 if( ::basegfx::fTools::equalZero( aVRP.getLength() ) )
1833 aVRP = ::basegfx::B3DVector(0,0,1);
1834 aVRP.setLength(fCameraDistance);
1835 aCG.vrp = BaseGFXHelper::B3DVectorToPosition3D( aVRP );
1837 setFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY, uno::Any( aCG ));
1839 catch( const uno::Exception & )
1841 DBG_UNHANDLED_EXCEPTION("chart2");
1845 static bool lcl_isRightAngledAxesSetAndSupported( Diagram& rDiagram )
1847 bool bRightAngledAxes = false;
1848 rDiagram.getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bRightAngledAxes; // "RightAngledAxes"
1849 if(bRightAngledAxes)
1851 if( ChartTypeHelper::isSupportingRightAngledAxes(
1852 rDiagram.getChartTypeByIndex( 0 ) ) )
1854 return true;
1857 return false;
1860 void Diagram::getRotation( sal_Int32& rnHorizontalAngleDegree, sal_Int32& rnVerticalAngleDegree )
1862 double fXAngle, fYAngle, fZAngle;
1863 getRotationAngle( fXAngle, fYAngle, fZAngle );
1865 if( !lcl_isRightAngledAxesSetAndSupported( *this ) )
1867 ThreeDHelper::convertXYZAngleRadToElevationRotationDeg(
1868 rnHorizontalAngleDegree, rnVerticalAngleDegree, fXAngle, fYAngle, fZAngle);
1869 rnVerticalAngleDegree*=-1;
1871 else
1873 rnHorizontalAngleDegree = basegfx::fround(basegfx::rad2deg(fXAngle));
1874 rnVerticalAngleDegree = basegfx::fround(-1.0 * basegfx::rad2deg(fYAngle));
1875 // nZRotation = basegfx::fround(-1.0 * basegfx::rad2deg(fZAngle));
1878 rnHorizontalAngleDegree = NormAngle180(rnHorizontalAngleDegree);
1879 rnVerticalAngleDegree = NormAngle180(rnVerticalAngleDegree);
1882 void Diagram::setRotation( sal_Int32 nHorizontalAngleDegree, sal_Int32 nVerticalYAngleDegree )
1884 //todo: x and y is not equal to horz and vert in case of RightAngledAxes==false
1885 double fXAngle = basegfx::deg2rad(nHorizontalAngleDegree);
1886 double fYAngle = basegfx::deg2rad(-1 * nVerticalYAngleDegree);
1887 double fZAngle = 0.0;
1889 if( !lcl_isRightAngledAxesSetAndSupported( *this ) )
1890 ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
1891 nHorizontalAngleDegree, -1*nVerticalYAngleDegree, fXAngle, fYAngle, fZAngle );
1893 setRotationAngle( fXAngle, fYAngle, fZAngle );
1896 static ::basegfx::B3DHomMatrix lcl_getCameraMatrix( Diagram& rDiagram )
1898 drawing::HomogenMatrix aCameraMatrix;
1900 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1901 rDiagram.getFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY ) >>= aCG; // "D3DCameraGeometry"
1903 ::basegfx::B3DVector aVPN( BaseGFXHelper::Direction3DToB3DVector( aCG.vpn ) );
1904 ::basegfx::B3DVector aVUP( BaseGFXHelper::Direction3DToB3DVector( aCG.vup ) );
1906 //normalize vectors:
1907 aVPN.normalize();
1908 aVUP.normalize();
1910 ::basegfx::B3DVector aCross = ::basegfx::cross( aVUP, aVPN );
1912 //first line is VUP x VPN
1913 aCameraMatrix.Line1.Column1 = aCross[0];
1914 aCameraMatrix.Line1.Column2 = aCross[1];
1915 aCameraMatrix.Line1.Column3 = aCross[2];
1916 aCameraMatrix.Line1.Column4 = 0.0;
1918 //second line is VUP
1919 aCameraMatrix.Line2.Column1 = aVUP[0];
1920 aCameraMatrix.Line2.Column2 = aVUP[1];
1921 aCameraMatrix.Line2.Column3 = aVUP[2];
1922 aCameraMatrix.Line2.Column4 = 0.0;
1924 //third line is VPN
1925 aCameraMatrix.Line3.Column1 = aVPN[0];
1926 aCameraMatrix.Line3.Column2 = aVPN[1];
1927 aCameraMatrix.Line3.Column3 = aVPN[2];
1928 aCameraMatrix.Line3.Column4 = 0.0;
1930 //fourth line is 0 0 0 1
1931 aCameraMatrix.Line4.Column1 = 0.0;
1932 aCameraMatrix.Line4.Column2 = 0.0;
1933 aCameraMatrix.Line4.Column3 = 0.0;
1934 aCameraMatrix.Line4.Column4 = 1.0;
1936 return BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aCameraMatrix );
1939 static double lcl_shiftAngleToIntervalMinusPiToPi( double fAngleRad )
1941 //valid range: ]-Pi,Pi]
1942 while( fAngleRad<=-M_PI )
1943 fAngleRad+=(2*M_PI);
1944 while( fAngleRad>M_PI )
1945 fAngleRad-=(2*M_PI);
1946 return fAngleRad;
1949 void Diagram::getRotationAngle( double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad )
1951 //takes the camera and the transformation matrix into account
1953 rfXAngleRad = rfYAngleRad = rfZAngleRad = 0.0;
1955 //get camera rotation
1956 ::basegfx::B3DHomMatrix aFixCameraRotationMatrix( lcl_getCameraMatrix( *this ) );
1957 BaseGFXHelper::ReduceToRotationMatrix( aFixCameraRotationMatrix );
1959 //get scene rotation
1960 ::basegfx::B3DHomMatrix aSceneRotation;
1962 drawing::HomogenMatrix aHomMatrix;
1963 // "D3DTransformMatrix"
1964 if( getFastPropertyValue( PROP_SCENE_TRANSF_MATRIX ) >>= aHomMatrix )
1966 aSceneRotation = BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHomMatrix );
1967 BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation );
1971 ::basegfx::B3DHomMatrix aResultRotation = aFixCameraRotationMatrix * aSceneRotation;
1972 ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( aResultRotation ) );
1974 rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getX());
1975 rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getY());
1976 rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getZ());
1978 if(rfZAngleRad<-M_PI_2 || rfZAngleRad>M_PI_2)
1980 rfZAngleRad-=M_PI;
1981 rfXAngleRad-=M_PI;
1982 rfYAngleRad=(M_PI-rfYAngleRad);
1984 rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfXAngleRad);
1985 rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfYAngleRad);
1986 rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfZAngleRad);
1990 static ::basegfx::B3DHomMatrix lcl_getInverseRotationMatrix( Diagram& rDiagram )
1992 ::basegfx::B3DHomMatrix aInverseRotation;
1993 double fXAngleRad=0.0;
1994 double fYAngleRad=0.0;
1995 double fZAngleRad=0.0;
1996 rDiagram.getRotationAngle( fXAngleRad, fYAngleRad, fZAngleRad );
1997 aInverseRotation.rotate( 0.0, 0.0, -fZAngleRad );
1998 aInverseRotation.rotate( 0.0, -fYAngleRad, 0.0 );
1999 aInverseRotation.rotate( -fXAngleRad, 0.0, 0.0 );
2000 return aInverseRotation;
2003 static void lcl_rotateLights( const ::basegfx::B3DHomMatrix& rLightRotation, Diagram& rDiagram )
2005 ::basegfx::B3DHomMatrix aLightRotation( rLightRotation );
2006 BaseGFXHelper::ReduceToRotationMatrix( aLightRotation );
2008 // "D3DSceneLightDirection1","D3DSceneLightOn1",
2009 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_1, PROP_SCENE_LIGHT_ON_1, aLightRotation );
2010 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_2, PROP_SCENE_LIGHT_ON_2, aLightRotation );
2011 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_3, PROP_SCENE_LIGHT_ON_3, aLightRotation );
2012 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_4, PROP_SCENE_LIGHT_ON_4, aLightRotation );
2013 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_5, PROP_SCENE_LIGHT_ON_5, aLightRotation );
2014 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_6, PROP_SCENE_LIGHT_ON_6, aLightRotation );
2015 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_7, PROP_SCENE_LIGHT_ON_7, aLightRotation );
2016 lcl_RotateLightSource( rDiagram, PROP_SCENE_LIGHT_DIRECTION_8, PROP_SCENE_LIGHT_ON_8, aLightRotation );
2019 void Diagram::setRotationAngle(
2020 double fXAngleRad, double fYAngleRad, double fZAngleRad )
2022 //the rotation of the camera is not touched but taken into account
2023 //the rotation difference is applied to the transformation matrix
2025 //the light sources will be adapted also
2029 //remind old rotation for adaptation of light directions
2030 ::basegfx::B3DHomMatrix aInverseOldRotation( lcl_getInverseRotationMatrix( *this ) );
2032 ::basegfx::B3DHomMatrix aInverseCameraRotation;
2034 ::basegfx::B3DTuple aR( BaseGFXHelper::GetRotationFromMatrix(
2035 lcl_getCameraMatrix( *this ) ) );
2036 aInverseCameraRotation.rotate( 0.0, 0.0, -aR.getZ() );
2037 aInverseCameraRotation.rotate( 0.0, -aR.getY(), 0.0 );
2038 aInverseCameraRotation.rotate( -aR.getX(), 0.0, 0.0 );
2041 ::basegfx::B3DHomMatrix aCumulatedRotation;
2042 aCumulatedRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
2044 //calculate new scene matrix
2045 ::basegfx::B3DHomMatrix aSceneRotation = aInverseCameraRotation*aCumulatedRotation;
2046 BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation );
2048 //set new rotation to transformation matrix ("D3DTransformMatrix")
2049 setFastPropertyValue(
2050 PROP_SCENE_TRANSF_MATRIX, uno::Any( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation )));
2052 //rotate lights if RightAngledAxes are not set or not supported
2053 bool bRightAngledAxes = false;
2054 getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bRightAngledAxes;
2055 if(!bRightAngledAxes || !ChartTypeHelper::isSupportingRightAngledAxes(
2056 getChartTypeByIndex( 0 ) ) )
2058 ::basegfx::B3DHomMatrix aNewRotation;
2059 aNewRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
2060 lcl_rotateLights( aNewRotation*aInverseOldRotation, *this );
2063 catch( const uno::Exception & )
2065 DBG_UNHANDLED_EXCEPTION("chart2");
2069 static bool lcl_isEqual( const drawing::Direction3D& rA, const drawing::Direction3D& rB )
2071 return ::rtl::math::approxEqual(rA.DirectionX, rB.DirectionX)
2072 && ::rtl::math::approxEqual(rA.DirectionY, rB.DirectionY)
2073 && ::rtl::math::approxEqual(rA.DirectionZ, rB.DirectionZ);
2075 static bool lcl_isSimpleScheme( drawing::ShadeMode aShadeMode
2076 , sal_Int32 nRoundedEdges
2077 , sal_Int32 nObjectLines
2078 , const rtl::Reference< Diagram >& xDiagram )
2080 if(aShadeMode!=drawing::ShadeMode_FLAT)
2081 return false;
2082 if(nRoundedEdges!=0)
2083 return false;
2084 if(nObjectLines==0)
2086 rtl::Reference< ChartType > xChartType( xDiagram->getChartTypeByIndex( 0 ) );
2087 return ChartTypeHelper::noBordersForSimpleScheme( xChartType );
2089 if(nObjectLines!=1)
2090 return false;
2091 return true;
2093 static bool lcl_isRealisticScheme( drawing::ShadeMode aShadeMode
2094 , sal_Int32 nRoundedEdges
2095 , sal_Int32 nObjectLines )
2097 if(aShadeMode!=drawing::ShadeMode_SMOOTH)
2098 return false;
2099 if(nRoundedEdges!=5)
2100 return false;
2101 if(nObjectLines!=0)
2102 return false;
2103 return true;
2105 static bool lcl_isLightScheme( Diagram& rDiagram, bool bRealistic )
2107 bool bIsOn = false;
2108 // "D3DSceneLightOn2" / UNO_NAME_3D_SCENE_LIGHTON_2
2109 rDiagram.getFastPropertyValue( PROP_SCENE_LIGHT_ON_2 ) >>= bIsOn;
2110 if(!bIsOn)
2111 return false;
2113 rtl::Reference< ChartType > xChartType( rDiagram.getChartTypeByIndex( 0 ) );
2115 sal_Int32 nColor = 0;
2116 // "D3DSceneLightColor2" / UNO_NAME_3D_SCENE_LIGHTCOLOR_2
2117 rDiagram.getFastPropertyValue( PROP_SCENE_LIGHT_COLOR_2 ) >>= nColor;
2118 if( nColor != ::chart::ChartTypeHelper::getDefaultDirectLightColor( !bRealistic, xChartType ) )
2119 return false;
2121 sal_Int32 nAmbientColor = 0;
2122 // "D3DSceneAmbientColor" / UNO_NAME_3D_SCENE_AMBIENTCOLOR
2123 rDiagram.getFastPropertyValue( PROP_SCENE_AMBIENT_COLOR ) >>= nAmbientColor;
2124 if( nAmbientColor != ::chart::ChartTypeHelper::getDefaultAmbientLightColor( !bRealistic, xChartType ) )
2125 return false;
2127 drawing::Direction3D aDirection(0,0,0);
2128 // "D3DSceneLightDirection2" / UNO_NAME_3D_SCENE_LIGHTDIRECTION_2
2129 rDiagram.getFastPropertyValue( PROP_SCENE_LIGHT_DIRECTION_2 ) >>= aDirection;
2131 drawing::Direction3D aDefaultDirection( bRealistic
2132 ? ChartTypeHelper::getDefaultRealisticLightDirection(xChartType)
2133 : ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) );
2135 //rotate default light direction when right angled axes are off but supported
2137 bool bRightAngledAxes = false;
2138 rDiagram.getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bRightAngledAxes; // "RightAngledAxes"
2139 if(!bRightAngledAxes)
2141 if( ChartTypeHelper::isSupportingRightAngledAxes(
2142 rDiagram.getChartTypeByIndex( 0 ) ) )
2144 ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( rDiagram ) );
2145 BaseGFXHelper::ReduceToRotationMatrix( aRotation );
2146 ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aDefaultDirection ) );
2147 aLightVector = aRotation*aLightVector;
2148 aDefaultDirection = BaseGFXHelper::B3DVectorToDirection3D( aLightVector );
2153 return lcl_isEqual( aDirection, aDefaultDirection );
2155 static bool lcl_isRealisticLightScheme( Diagram& rDiagram )
2157 return lcl_isLightScheme( rDiagram, true /*bRealistic*/ );
2159 static bool lcl_isSimpleLightScheme( Diagram& rDiagram )
2161 return lcl_isLightScheme( rDiagram, false /*bRealistic*/ );
2164 ThreeDLookScheme Diagram::detectScheme()
2166 ThreeDLookScheme aScheme = ThreeDLookScheme::ThreeDLookScheme_Unknown;
2168 sal_Int32 nRoundedEdges;
2169 sal_Int32 nObjectLines;
2170 ThreeDHelper::getRoundedEdgesAndObjectLines( this, nRoundedEdges, nObjectLines );
2172 //get shade mode and light settings:
2173 drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH );
2176 getFastPropertyValue( PROP_SCENE_SHADE_MODE )>>= aShadeMode; // "D3DSceneShadeMode"
2178 catch( const uno::Exception & )
2180 DBG_UNHANDLED_EXCEPTION("chart2");
2183 if( lcl_isSimpleScheme( aShadeMode, nRoundedEdges, nObjectLines, this ) )
2185 if( lcl_isSimpleLightScheme(*this) )
2186 aScheme = ThreeDLookScheme::ThreeDLookScheme_Simple;
2188 else if( lcl_isRealisticScheme( aShadeMode, nRoundedEdges, nObjectLines ) )
2190 if( lcl_isRealisticLightScheme(*this) )
2191 aScheme = ThreeDLookScheme::ThreeDLookScheme_Realistic;
2194 return aScheme;
2197 static void lcl_setRealisticScheme( drawing::ShadeMode& rShadeMode
2198 , sal_Int32& rnRoundedEdges
2199 , sal_Int32& rnObjectLines )
2201 rShadeMode = drawing::ShadeMode_SMOOTH;
2202 rnRoundedEdges = 5;
2203 rnObjectLines = 0;
2206 static void lcl_setSimpleScheme( drawing::ShadeMode& rShadeMode
2207 , sal_Int32& rnRoundedEdges
2208 , sal_Int32& rnObjectLines
2209 , const rtl::Reference< Diagram >& xDiagram )
2211 rShadeMode = drawing::ShadeMode_FLAT;
2212 rnRoundedEdges = 0;
2214 rtl::Reference< ChartType > xChartType( xDiagram->getChartTypeByIndex( 0 ) );
2215 rnObjectLines = ChartTypeHelper::noBordersForSimpleScheme( xChartType ) ? 0 : 1;
2217 void Diagram::setScheme( ThreeDLookScheme aScheme )
2219 if( aScheme == ThreeDLookScheme::ThreeDLookScheme_Unknown )
2220 return;
2222 drawing::ShadeMode aShadeMode;
2223 sal_Int32 nRoundedEdges;
2224 sal_Int32 nObjectLines;
2226 if( aScheme == ThreeDLookScheme::ThreeDLookScheme_Simple )
2227 lcl_setSimpleScheme(aShadeMode,nRoundedEdges,nObjectLines,this);
2228 else
2229 lcl_setRealisticScheme(aShadeMode,nRoundedEdges,nObjectLines);
2233 ThreeDHelper::setRoundedEdgesAndObjectLines( this, nRoundedEdges, nObjectLines );
2235 drawing::ShadeMode aOldShadeMode;
2236 if( ! (getFastPropertyValue( PROP_SCENE_SHADE_MODE)>>=aOldShadeMode) ||
2237 aOldShadeMode != aShadeMode )
2239 setFastPropertyValue( PROP_SCENE_SHADE_MODE, uno::Any( aShadeMode )); // "D3DSceneShadeMode"
2242 lcl_setLightsForScheme( *this, aScheme );
2244 catch( const uno::Exception & )
2246 DBG_UNHANDLED_EXCEPTION("chart2");
2251 void Diagram::setDefaultRotation( bool bPieOrDonut )
2253 drawing::CameraGeometry aCameraGeo( ThreeDHelper::getDefaultCameraGeometry( bPieOrDonut ) );
2254 // "D3DCameraGeometry"
2255 setFastPropertyValue( PROP_SCENE_CAMERA_GEOMETRY, uno::Any( aCameraGeo ));
2257 ::basegfx::B3DHomMatrix aSceneRotation;
2258 if( bPieOrDonut )
2259 aSceneRotation.rotate( -M_PI/3.0, 0, 0 );
2260 // "D3DTransformMatrix"
2261 setFastPropertyValue( PROP_SCENE_TRANSF_MATRIX,
2262 uno::Any( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation )));
2265 void Diagram::switchRightAngledAxes( bool bRightAngledAxes )
2269 bool bOldRightAngledAxes = false;
2270 getFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES ) >>= bOldRightAngledAxes; // "RightAngledAxes"
2271 if( bOldRightAngledAxes!=bRightAngledAxes)
2273 setFastPropertyValue( PROP_DIAGRAM_RIGHT_ANGLED_AXES, uno::Any( bRightAngledAxes ));
2274 if(bRightAngledAxes)
2276 ::basegfx::B3DHomMatrix aInverseRotation( lcl_getInverseRotationMatrix( *this ) );
2277 lcl_rotateLights( aInverseRotation, *this );
2279 else
2281 ::basegfx::B3DHomMatrix aCompleteRotation( lcl_getCompleteRotationMatrix( *this ) );
2282 lcl_rotateLights( aCompleteRotation, *this );
2286 catch( const uno::Exception & )
2288 DBG_UNHANDLED_EXCEPTION("chart2");
2292 } // namespace chart
2294 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
2295 com_sun_star_comp_chart2_Diagram_get_implementation(css::uno::XComponentContext *context,
2296 css::uno::Sequence<css::uno::Any> const &)
2298 return cppu::acquire(new ::chart::Diagram(context));
2301 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */