1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include "SchXMLPlotAreaContext.hxx"
21 #include <SchXMLImport.hxx>
22 #include "SchXMLAxisContext.hxx"
23 #include "SchXMLSeries2Context.hxx"
24 #include "SchXMLTools.hxx"
25 
26 #include <comphelper/processfactory.hxx>
27 #include <sal/log.hxx>
28 #include <tools/diagnose_ex.h>
29 #include <xmloff/xmlnamespace.hxx>
30 #include <xmloff/namespacemap.hxx>
31 #include <xmloff/xmluconv.hxx>
32 #include <xmloff/prstylei.hxx>
33 #include <xmloff/xmlstyle.hxx>
34 #include <oox/helper/containerhelper.hxx>
35 
36 #include <com/sun/star/awt/Point.hpp>
37 #include <com/sun/star/awt/Size.hpp>
38 #include <com/sun/star/chart/ErrorBarStyle.hpp>
39 #include <com/sun/star/chart/X3DDisplay.hpp>
40 #include <com/sun/star/chart/XStatisticDisplay.hpp>
41 #include <com/sun/star/chart/XDiagramPositioning.hpp>
42 #include <com/sun/star/chart/XChartDocument.hpp>
43 #include <com/sun/star/chart2/XChartDocument.hpp>
44 #include <com/sun/star/chart2/data/XDataSink.hpp>
45 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
46 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
47 #include <com/sun/star/drawing/CameraGeometry.hpp>
48 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
49 #include <com/sun/star/lang/XServiceInfo.hpp>
50 #include <com/sun/star/xml/sax/XAttributeList.hpp>
51 
52 using namespace com::sun::star;
53 using namespace ::xmloff::token;
54 
55 using com::sun::star::uno::Reference;
56 
57 namespace
58 {
59 
60 struct lcl_AxisHasCategories
61 {
operator ()__anon361f00960111::lcl_AxisHasCategories62     bool operator() ( const SchXMLAxis & rAxis )
63     {
64         return rAxis.bHasCategories;
65     }
66 };
67 
lcl_ConvertRange(const OUString & rRange,const uno::Reference<chart2::XChartDocument> & xDoc)68 OUString lcl_ConvertRange( const OUString & rRange, const uno::Reference< chart2::XChartDocument > & xDoc )
69 {
70     OUString aResult = rRange;
71     if(!xDoc.is())
72         return aResult;
73     uno::Reference< chart2::data::XRangeXMLConversion > xConversion(
74         xDoc->getDataProvider(), uno::UNO_QUERY );
75     if( xConversion.is())
76         aResult = xConversion->convertRangeFromXML( rRange );
77     return aResult;
78 }
79 
80 } // anonymous namespace
81 
SchXML3DSceneAttributesHelper(SvXMLImport & rImporter)82 SchXML3DSceneAttributesHelper::SchXML3DSceneAttributesHelper( SvXMLImport& rImporter )
83     : SdXML3DSceneAttributesHelper( rImporter )
84 {
85 }
86 
getCameraDefaultFromDiagram(const uno::Reference<chart::XDiagram> & xDiagram)87 void SchXML3DSceneAttributesHelper::getCameraDefaultFromDiagram( const uno::Reference< chart::XDiagram >& xDiagram )
88 {
89     //different defaults for camera geometry necessary to workaround wrong behaviour in old chart
90     //in future make this version dependent if we have versioning (metastream) for ole objects
91 
92     try
93     {
94         uno::Reference< beans::XPropertySet > xProp( xDiagram, uno::UNO_QUERY );
95         if( xProp.is() )
96         {
97             drawing::CameraGeometry aCamGeo;
98             xProp->getPropertyValue("D3DCameraGeometry") >>= aCamGeo;
99             maVRP.setX( aCamGeo.vrp.PositionX );
100             maVRP.setY( aCamGeo.vrp.PositionY );
101             maVRP.setZ( aCamGeo.vrp.PositionZ );
102             maVPN.setX( aCamGeo.vpn.DirectionX );
103             maVPN.setY( aCamGeo.vpn.DirectionY );
104             maVPN.setZ( aCamGeo.vpn.DirectionZ );
105             maVUP.setX( aCamGeo.vup.DirectionX );
106             maVUP.setY( aCamGeo.vup.DirectionY );
107             maVUP.setZ( aCamGeo.vup.DirectionZ );
108         }
109     }
110     catch( const uno::Exception & )
111     {
112         TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property NumberOfLines");
113     }
114 }
115 
~SchXML3DSceneAttributesHelper()116 SchXML3DSceneAttributesHelper::~SchXML3DSceneAttributesHelper()
117 {
118 }
119 
SchXMLPlotAreaContext(SchXMLImportHelper & rImpHelper,SvXMLImport & rImport,const OUString & rXLinkHRefAttributeToIndicateDataProvider,OUString & rCategoriesAddress,OUString & rChartAddress,bool & rbHasRangeAtPlotArea,bool & rAllRangeAddressesAvailable,bool & rColHasLabels,bool & rRowHasLabels,chart::ChartDataRowSource & rDataRowSource,SeriesDefaultsAndStyles & rSeriesDefaultsAndStyles,const OUString & aChartTypeServiceName,tSchXMLLSequencesPerIndex & rLSequencesPerIndex,const awt::Size & rChartSize)120 SchXMLPlotAreaContext::SchXMLPlotAreaContext(
121     SchXMLImportHelper& rImpHelper,
122     SvXMLImport& rImport,
123     const OUString& rXLinkHRefAttributeToIndicateDataProvider,
124     OUString& rCategoriesAddress,
125     OUString& rChartAddress,
126     bool & rbHasRangeAtPlotArea,
127     bool & rAllRangeAddressesAvailable,
128     bool & rColHasLabels,
129     bool & rRowHasLabels,
130     chart::ChartDataRowSource & rDataRowSource,
131     SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles,
132     const OUString& aChartTypeServiceName,
133     tSchXMLLSequencesPerIndex & rLSequencesPerIndex,
134     const awt::Size & rChartSize ) :
135         SvXMLImportContext( rImport ),
136         mrImportHelper( rImpHelper ),
137         mrCategoriesAddress( rCategoriesAddress ),
138         mrSeriesDefaultsAndStyles( rSeriesDefaultsAndStyles ),
139         mnNumOfLinesProp( 0 ),
140         mbStockHasVolume( false ),
141         mnSeries( 0 ),
142         m_aGlobalSeriesImportInfo( rAllRangeAddressesAvailable ),
143         maSceneImportHelper( rImport ),
144         m_aOuterPositioning( rImport ),
145         m_aInnerPositioning( rImport ),
146         mbPercentStacked(false),
147         m_bAxisPositionAttributeImported(false),
148         m_rXLinkHRefAttributeToIndicateDataProvider(rXLinkHRefAttributeToIndicateDataProvider),
149         mrChartAddress( rChartAddress ),
150         m_rbHasRangeAtPlotArea( rbHasRangeAtPlotArea ),
151         mrColHasLabels( rColHasLabels ),
152         mrRowHasLabels( rRowHasLabels ),
153         mrDataRowSource( rDataRowSource ),
154         maChartTypeServiceName( aChartTypeServiceName ),
155         mrLSequencesPerIndex( rLSequencesPerIndex ),
156         mbGlobalChartTypeUsedBySeries( false ),
157         maChartSize( rChartSize )
158 {
159     m_rbHasRangeAtPlotArea = false;
160 
161     // get Diagram
162     uno::Reference< chart::XChartDocument > xDoc = rImpHelper.GetChartDocument();
163     if( xDoc.is())
164     {
165         mxDiagram = xDoc->getDiagram();
166         mxNewDoc.set( xDoc, uno::UNO_QUERY );
167 
168         maSceneImportHelper.getCameraDefaultFromDiagram( mxDiagram );
169     }
170     SAL_WARN_IF( !mxDiagram.is(),"xmloff.chart", "Couldn't get XDiagram" );
171 
172     // turn off all axes initially
173     uno::Any aFalseBool;
174     aFalseBool <<= false;
175 
176     uno::Reference< lang::XServiceInfo > xInfo( mxDiagram, uno::UNO_QUERY );
177     uno::Reference< beans::XPropertySet > xProp( mxDiagram, uno::UNO_QUERY );
178     if( !xInfo.is() || !xProp.is() )
179         return;
180 
181     try
182     {
183         xProp->setPropertyValue("HasXAxis", aFalseBool );
184         xProp->setPropertyValue("HasXAxisGrid", aFalseBool );
185         xProp->setPropertyValue("HasXAxisDescription", aFalseBool );
186         xProp->setPropertyValue("HasSecondaryXAxis", aFalseBool );
187         xProp->setPropertyValue("HasSecondaryXAxisDescription", aFalseBool );
188 
189         xProp->setPropertyValue("HasYAxis", aFalseBool );
190         xProp->setPropertyValue("HasYAxisGrid", aFalseBool );
191         xProp->setPropertyValue("HasYAxisDescription", aFalseBool );
192         xProp->setPropertyValue("HasSecondaryYAxis", aFalseBool );
193         xProp->setPropertyValue("HasSecondaryYAxisDescription", aFalseBool );
194 
195         xProp->setPropertyValue("HasZAxis", aFalseBool );
196         xProp->setPropertyValue("HasZAxisDescription", aFalseBool );
197 
198         xProp->setPropertyValue("DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) );
199     }
200     catch( const beans::UnknownPropertyException & )
201     {
202         SAL_WARN("xmloff.chart", "Property required by service not supported" );
203     }
204 }
205 
~SchXMLPlotAreaContext()206 SchXMLPlotAreaContext::~SchXMLPlotAreaContext()
207 {}
208 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)209 void SchXMLPlotAreaContext::startFastElement (sal_Int32 /*nElement*/,
210         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
211 {
212     // parse attributes
213     uno::Reference< chart2::XChartDocument > xNewDoc( GetImport().GetModel(), uno::UNO_QUERY );
214 
215     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
216     {
217         switch( aIter.getToken() )
218         {
219             case XML_ELEMENT(SVG, XML_X):
220             case XML_ELEMENT(SVG_COMPAT, XML_X):
221             case XML_ELEMENT(SVG, XML_Y):
222             case XML_ELEMENT(SVG_COMPAT, XML_Y):
223             case XML_ELEMENT(SVG, XML_WIDTH):
224             case XML_ELEMENT(SVG_COMPAT, XML_WIDTH):
225             case XML_ELEMENT(SVG, XML_HEIGHT):
226             case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT):
227                 m_aOuterPositioning.readPositioningAttribute( aIter.getToken(), aIter.toView() );
228                 break;
229             case XML_ELEMENT(CHART, XML_STYLE_NAME):
230                 msAutoStyleName = aIter.toString();
231                 break;
232             case XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS):
233                 mrChartAddress = lcl_ConvertRange( aIter.toString(), xNewDoc );
234                 // indicator for getting data from the outside
235                 m_rbHasRangeAtPlotArea = true;
236                 break;
237             case XML_ELEMENT(CHART, XML_DATA_SOURCE_HAS_LABELS):
238                 {
239                     if( IsXMLToken(aIter, XML_BOTH) )
240                         mrColHasLabels = mrRowHasLabels = true;
241                     else if( IsXMLToken(aIter, XML_ROW) )
242                         mrRowHasLabels = true;
243                     else if( IsXMLToken(aIter, XML_COLUMN) )
244                         mrColHasLabels = true;
245                 }
246                 break;
247             case XML_ELEMENT(DR3D, XML_TRANSFORM):
248             case XML_ELEMENT(DR3D, XML_VRP):
249             case XML_ELEMENT(DR3D, XML_VPN):
250             case XML_ELEMENT(DR3D, XML_VUP):
251             case XML_ELEMENT(DR3D, XML_PROJECTION):
252             case XML_ELEMENT(DR3D, XML_DISTANCE):
253             case XML_ELEMENT(DR3D, XML_FOCAL_LENGTH):
254             case XML_ELEMENT(DR3D, XML_SHADOW_SLANT):
255             case XML_ELEMENT(DR3D, XML_SHADE_MODE):
256             case XML_ELEMENT(DR3D, XML_AMBIENT_COLOR):
257             case XML_ELEMENT(DR3D, XML_LIGHTING_MODE):
258                 maSceneImportHelper.processSceneAttribute( aIter );
259                 break;
260             default:
261                 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
262         }
263     }
264 
265     if( ! mxNewDoc.is())
266     {
267         uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
268         if( xDocProp.is())
269         {
270             try
271             {
272                 xDocProp->setPropertyValue("DataSourceLabelsInFirstColumn", uno::Any(mrColHasLabels) );
273                 xDocProp->setPropertyValue("DataSourceLabelsInFirstRow", uno::Any(mrRowHasLabels) );
274             }
275             catch( const beans::UnknownPropertyException & )
276             {
277                 SAL_WARN("xmloff.chart", "Properties missing" );
278             }
279         }
280     }
281 
282     // set properties
283     uno::Reference< beans::XPropertySet > xProp( mxDiagram, uno::UNO_QUERY );
284     if( !msAutoStyleName.isEmpty())
285     {
286         if( xProp.is())
287         {
288             const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
289             if( pStylesCtxt )
290             {
291                 const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
292                     SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName );
293 
294                 XMLPropStyleContext* pPropStyleContext =
295                     const_cast< XMLPropStyleContext * >(
296                         dynamic_cast< const XMLPropStyleContext * >( pStyle ) );
297                 if( pPropStyleContext )
298                 {
299                     pPropStyleContext->FillPropertySet( xProp );
300 
301                     // get the data row source that was set without having data
302                     xProp->getPropertyValue("DataRowSource")
303                         >>= mrDataRowSource;
304 
305                     //lines on/off
306                     //this old property is not supported fully anymore with the new chart, so we need to get the information a little bit different from similar properties
307                     mrSeriesDefaultsAndStyles.maLinesOnProperty = SchXMLTools::getPropertyFromContext(
308                         u"Lines", pPropStyleContext, pStylesCtxt );
309 
310                     //handle automatic position and size
311                     m_aOuterPositioning.readAutomaticPositioningProperties( pPropStyleContext, pStylesCtxt );
312 
313                     //correct default starting angle for old 3D pies
314                     if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan3_0( GetImport().GetModel() ) )
315                     {
316                         bool bIs3d = false;
317                         if( xProp.is() && ( xProp->getPropertyValue("Dim3D") >>= bIs3d ) &&
318                             bIs3d )
319                         {
320                             if( maChartTypeServiceName == "com.sun.star.chart2.PieChartType" || maChartTypeServiceName == "com.sun.star.chart2.DonutChartType" )
321                             {
322                                 OUString aPropName( "StartingAngle" );
323                                 uno::Any aAStartingAngle( SchXMLTools::getPropertyFromContext( aPropName, pPropStyleContext, pStylesCtxt ) );
324                                 if( !aAStartingAngle.hasValue() )
325                                     xProp->setPropertyValue( aPropName, uno::makeAny(sal_Int32(0)) ) ;
326                             }
327                         }
328                     }
329                 }
330             }
331         }
332     }
333 
334     //remember default values for dataseries
335     if(xProp.is())
336     {
337     try
338     {
339         mrSeriesDefaultsAndStyles.maSymbolTypeDefault = xProp->getPropertyValue("SymbolType");
340         mrSeriesDefaultsAndStyles.maDataCaptionDefault = xProp->getPropertyValue("DataCaption");
341 
342         mrSeriesDefaultsAndStyles.maMeanValueDefault = xProp->getPropertyValue("MeanValue");
343         mrSeriesDefaultsAndStyles.maRegressionCurvesDefault = xProp->getPropertyValue("RegressionCurves");
344 
345         bool bStacked = false;
346         mrSeriesDefaultsAndStyles.maStackedDefault = xProp->getPropertyValue("Stacked");
347         mrSeriesDefaultsAndStyles.maStackedDefault >>= bStacked;
348         mrSeriesDefaultsAndStyles.maPercentDefault = xProp->getPropertyValue("Percent");
349         mrSeriesDefaultsAndStyles.maPercentDefault >>= mbPercentStacked;
350         mrSeriesDefaultsAndStyles.maStackedBarsConnectedDefault = xProp->getPropertyValue("StackedBarsConnected");
351 
352         // deep
353         uno::Any aDeepProperty( xProp->getPropertyValue("Deep"));
354         // #124488# old versions store a 3d area and 3D line deep chart with Deep==false => workaround for this
355         if( ! (bStacked || mbPercentStacked ))
356         {
357             if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) )
358             {
359                 bool bIs3d = false;
360                 if( ( xProp->getPropertyValue("Dim3D") >>= bIs3d ) &&
361                     bIs3d )
362                 {
363                     if( maChartTypeServiceName == "com.sun.star.chart2.AreaChartType" || maChartTypeServiceName == "com.sun.star.chart2.LineChartType" )
364                     {
365                         aDeepProperty <<= true;
366                     }
367                 }
368             }
369         }
370         mrSeriesDefaultsAndStyles.maDeepDefault = aDeepProperty;
371 
372         xProp->getPropertyValue("NumberOfLines") >>= mnNumOfLinesProp;
373         xProp->getPropertyValue("Volume") >>= mbStockHasVolume;
374     }
375     catch( const uno::Exception & )
376     {
377         TOOLS_INFO_EXCEPTION("xmloff.chart", "PlotAreaContext:EndElement(): Exception caught");
378     }
379     } // if
380 
381     bool bCreateInternalDataProvider = false;
382     if( m_rXLinkHRefAttributeToIndicateDataProvider == "." ) //data comes from the chart itself
383         bCreateInternalDataProvider = true;
384     else if( m_rXLinkHRefAttributeToIndicateDataProvider == ".." ) //data comes from the parent application
385         bCreateInternalDataProvider = false;
386     else if( !m_rXLinkHRefAttributeToIndicateDataProvider.isEmpty() ) //not supported so far to get the data by sibling objects -> fall back to chart itself
387         bCreateInternalDataProvider = true;
388     else if( !m_rbHasRangeAtPlotArea )
389         bCreateInternalDataProvider = true;
390 
391     if( bCreateInternalDataProvider && mxNewDoc.is() )
392     {
393         // we have no complete range => we have own data, so switch the data
394         // provider to internal. Clone is not necessary, as we don't have any
395         // data yet.
396         mxNewDoc->createInternalDataProvider( false /* bCloneExistingData */ );
397         if( xProp.is() && mrDataRowSource!=chart::ChartDataRowSource_COLUMNS )
398             xProp->setPropertyValue("DataRowSource", uno::makeAny(mrDataRowSource) );
399     }
400 }
401 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)402 css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLPlotAreaContext::createFastChildContext(
403     sal_Int32 nElement,
404     const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
405 {
406     SvXMLImportContext* pContext = nullptr;
407 
408     switch(nElement)
409     {
410         case XML_ELEMENT(CHART_EXT, XML_COORDINATE_REGION):
411         case XML_ELEMENT(CHART, XML_COORDINATE_REGION):
412         {
413             pContext = new SchXMLCoordinateRegionContext( GetImport(), m_aInnerPositioning );
414         }
415         break;
416 
417         case XML_ELEMENT(CHART, XML_AXIS):
418         {
419             bool bAddMissingXAxisForNetCharts = false;
420             bool bAdaptWrongPercentScaleValues = false;
421             if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) )
422             {
423                 //correct errors from older versions
424 
425                 // for NetCharts there were no xAxis exported to older files
426                 // so we need to add the x axis here for those old NetChart files
427                 if ( maChartTypeServiceName == "com.sun.star.chart2.NetChartType" )
428                     bAddMissingXAxisForNetCharts = true;
429 
430                 //Issue 59288
431                 if( mbPercentStacked )
432                     bAdaptWrongPercentScaleValues = true;
433             }
434 
435             bool bAdaptXAxisOrientationForOld2DBarCharts = false;
436             if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_4( GetImport().GetModel() ) )
437             {
438                 //issue74660
439                 if ( maChartTypeServiceName == "com.sun.star.chart2.ColumnChartType" )
440                     bAdaptXAxisOrientationForOld2DBarCharts = true;
441             }
442 
443             pContext = new SchXMLAxisContext( mrImportHelper, GetImport(), mxDiagram, maAxes, mrCategoriesAddress,
444                                               bAddMissingXAxisForNetCharts, bAdaptWrongPercentScaleValues, bAdaptXAxisOrientationForOld2DBarCharts, m_bAxisPositionAttributeImported );
445         }
446         break;
447 
448         case XML_ELEMENT(CHART, XML_SERIES):
449             {
450                 if( mxNewDoc.is())
451                 {
452                     pContext = new SchXMLSeries2Context(
453                         mrImportHelper, GetImport(),
454                         mxNewDoc, maAxes,
455                         mrSeriesDefaultsAndStyles.maSeriesStyleVector,
456                         mrSeriesDefaultsAndStyles.maRegressionStyleVector,
457                         mnSeries,
458                         mbStockHasVolume,
459                         m_aGlobalSeriesImportInfo,
460                         maChartTypeServiceName,
461                         mrLSequencesPerIndex,
462                         mbGlobalChartTypeUsedBySeries, maChartSize );
463                 }
464                 mnSeries++;
465             }
466             break;
467 
468         case XML_ELEMENT(CHART, XML_WALL):
469             pContext = new SchXMLWallFloorContext( mrImportHelper, GetImport(), mxDiagram,
470                                                    SchXMLWallFloorContext::CONTEXT_TYPE_WALL );
471             break;
472         case XML_ELEMENT(CHART, XML_FLOOR):
473             pContext = new SchXMLWallFloorContext( mrImportHelper, GetImport(), mxDiagram,
474                                                    SchXMLWallFloorContext::CONTEXT_TYPE_FLOOR );
475             break;
476 
477         case XML_ELEMENT(DR3D, XML_LIGHT):
478             pContext = maSceneImportHelper.create3DLightContext( xAttrList );
479             break;
480 
481         // elements for stock charts
482         case XML_ELEMENT(CHART, XML_STOCK_GAIN_MARKER):
483             pContext = new SchXMLStockContext( mrImportHelper, GetImport(), mxDiagram,
484                                                SchXMLStockContext::CONTEXT_TYPE_GAIN );
485             break;
486         case XML_ELEMENT(CHART, XML_STOCK_LOSS_MARKER):
487             pContext = new SchXMLStockContext( mrImportHelper, GetImport(), mxDiagram,
488                                                SchXMLStockContext::CONTEXT_TYPE_LOSS );
489             break;
490         case XML_ELEMENT(CHART, XML_STOCK_RANGE_LINE):
491             pContext = new SchXMLStockContext( mrImportHelper, GetImport(), mxDiagram,
492                                                SchXMLStockContext::CONTEXT_TYPE_RANGE );
493             break;
494         default:
495             XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
496     }
497 
498     return pContext;
499 }
500 
endFastElement(sal_Int32)501 void SchXMLPlotAreaContext::endFastElement(sal_Int32 )
502 {
503     // set categories
504     if( !mrCategoriesAddress.isEmpty() && mxNewDoc.is())
505     {
506         uno::Reference< chart2::data::XDataProvider > xDataProvider(
507             mxNewDoc->getDataProvider()  );
508         // @todo: correct coordinate system index
509         sal_Int32 nDimension( 0 );
510         ::std::vector< SchXMLAxis >::const_iterator aIt(
511             ::std::find_if( maAxes.begin(), maAxes.end(), lcl_AxisHasCategories()));
512         if( aIt != maAxes.end())
513             nDimension = static_cast< sal_Int32 >( (*aIt).eDimension );
514         SchXMLTools::CreateCategories(
515             xDataProvider, mxNewDoc, mrCategoriesAddress,
516             0 /* nCooSysIndex */,
517             nDimension, &mrLSequencesPerIndex );
518     }
519 
520     uno::Reference< beans::XPropertySet > xDiaProp( mxDiagram, uno::UNO_QUERY );
521     if( xDiaProp.is())
522     {
523         bool bIsThreeDim = false;
524         uno::Any aAny = xDiaProp->getPropertyValue("Dim3D");
525         aAny >>= bIsThreeDim;
526 
527         // set 3d scene attributes
528         if( bIsThreeDim )
529         {
530             // set scene attributes at diagram
531             maSceneImportHelper.setSceneAttributes( xDiaProp );
532         }
533 
534         // set correct number of lines at series
535         if( ! m_aGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && mnNumOfLinesProp > 0 && maChartTypeServiceName == "com.sun.star.chart2.ColumnChartType" )
536         {
537             try
538             {
539                 xDiaProp->setPropertyValue("NumberOfLines",
540                                             uno::makeAny( mnNumOfLinesProp ));
541             }
542             catch( const uno::Exception & )
543             {
544                 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property NumberOfLines");
545             }
546         }
547 
548         // #i32366# stock has volume
549         if( mxDiagram->getDiagramType() == "com.sun.star.chart.StockDiagram" &&
550             mbStockHasVolume )
551         {
552             try
553             {
554                 xDiaProp->setPropertyValue("Volume",
555                                             uno::makeAny( true ));
556             }
557             catch( const uno::Exception & )
558             {
559                 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught for property Volume");
560             }
561         }
562     }
563 
564     // set changed size and position after properties (esp. 3d)
565 
566     uno::Reference< chart::XDiagramPositioning > xDiaPos( mxDiagram, uno::UNO_QUERY );
567     if( xDiaPos.is())
568     {
569         if( !m_aOuterPositioning.isAutomatic() )
570         {
571             if( m_aInnerPositioning.hasPosSize() )
572                 xDiaPos->setDiagramPositionExcludingAxes( m_aInnerPositioning.getRectangle() );
573             else if( m_aOuterPositioning.hasPosSize() )
574             {
575                 if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan3_3( GetImport().GetModel() ) ) //old version of OOo did write a wrong rectangle for the diagram size
576                     xDiaPos->setDiagramPositionIncludingAxesAndAxisTitles( m_aOuterPositioning.getRectangle() );
577                 else
578                     xDiaPos->setDiagramPositionIncludingAxes( m_aOuterPositioning.getRectangle() );
579             }
580         }
581     }
582 
583     SchXMLAxisContext::CorrectAxisPositions( uno::Reference< chart2::XChartDocument >( mrImportHelper.GetChartDocument(), uno::UNO_QUERY ), maChartTypeServiceName, GetImport().GetODFVersion(), m_bAxisPositionAttributeImported );
584 }
585 
SchXMLDataLabelSpanContext(SvXMLImport & rImport,::std::vector<OUString> & rLabels)586 SchXMLDataLabelSpanContext::SchXMLDataLabelSpanContext( SvXMLImport& rImport, ::std::vector<OUString>& rLabels):
587     SvXMLImportContext( rImport ),
588     mrLabels(rLabels)
589 {
590 }
591 
characters(const OUString & rChars)592 void SchXMLDataLabelSpanContext::characters(const OUString& rChars)
593 {
594     maCharBuffer.append(rChars);
595 }
596 
endFastElement(sal_Int32)597 void SchXMLDataLabelSpanContext::endFastElement(sal_Int32 )
598 {
599     mrLabels.push_back(maCharBuffer.makeStringAndClear());
600 }
601 
SchXMLDataLabelParaContext(SvXMLImport & rImport,::std::vector<OUString> & rLabels)602 SchXMLDataLabelParaContext::SchXMLDataLabelParaContext( SvXMLImport& rImport, ::std::vector<OUString>& rLabels):
603     SvXMLImportContext( rImport ),
604     mrLabels(rLabels)
605 {
606 }
607 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> &)608 css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLDataLabelParaContext::createFastChildContext(
609     sal_Int32 nElement,
610     const css::uno::Reference< css::xml::sax::XFastAttributeList >&  )
611 {
612     if ( nElement == XML_ELEMENT(TEXT, XML_SPAN) )
613         return new SchXMLDataLabelSpanContext(GetImport(), mrLabels);
614     else
615         XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
616     return nullptr;
617 }
618 
SchXMLDataLabelContext(SvXMLImport & rImport,::std::vector<OUString> & rLabels,DataRowPointStyle & rDataLabelStyle)619 SchXMLDataLabelContext::SchXMLDataLabelContext(SvXMLImport& rImport,
620                                                ::std::vector<OUString>& rLabels,
621                                                DataRowPointStyle& rDataLabelStyle)
622     : SvXMLImportContext(rImport)
623     , mrLabels(rLabels)
624     , mrDataLabelStyle(rDataLabelStyle)
625 {
626 }
627 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> &)628 css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLDataLabelContext::createFastChildContext(
629     sal_Int32 nElement,
630     const css::uno::Reference< css::xml::sax::XFastAttributeList >&  )
631 {
632     if ( nElement == XML_ELEMENT(TEXT, XML_P) )
633         return new SchXMLDataLabelParaContext(GetImport(), mrLabels);
634     else
635         XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
636     return nullptr;
637 }
638 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)639 void SchXMLDataLabelContext::startFastElement(
640     sal_Int32 /*nElement*/,
641     const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
642 {
643     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
644     {
645         switch(aIter.getToken())
646         {
647             case XML_ELEMENT(SVG, XML_X):
648             case XML_ELEMENT(SVG_COMPAT, XML_X):
649             {
650                 sal_Int32 nResultValue;
651                 GetImport().GetMM100UnitConverter().convertMeasureToCore(nResultValue, aIter.toView());
652                 mrDataLabelStyle.mo_nLabelAbsolutePosX = nResultValue;
653                 break;
654             }
655             case XML_ELEMENT(SVG, XML_Y):
656             case XML_ELEMENT(SVG_COMPAT, XML_Y):
657             {
658                 sal_Int32 nResultValue;
659                 GetImport().GetMM100UnitConverter().convertMeasureToCore(nResultValue, aIter.toView());
660                 mrDataLabelStyle.mo_nLabelAbsolutePosY = nResultValue;
661                 break;
662             }
663             case XML_ELEMENT(CHART, XML_STYLE_NAME):
664                 mrDataLabelStyle.msStyleName = aIter.toString();
665                 break;
666             default:
667                 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
668         }
669     }
670 }
671 
672 
SchXMLDataPointContext(SvXMLImport & rImport,::std::vector<DataRowPointStyle> & rStyleVector,const css::uno::Reference<css::chart2::XDataSeries> & xSeries,sal_Int32 & rIndex,bool bSymbolSizeForSeriesIsMissingInFile)673 SchXMLDataPointContext::SchXMLDataPointContext(  SvXMLImport& rImport,
674                                                  ::std::vector< DataRowPointStyle >& rStyleVector,
675                                                  const css::uno::Reference< css::chart2::XDataSeries >& xSeries,
676                                                  sal_Int32& rIndex,
677                                                  bool bSymbolSizeForSeriesIsMissingInFile ) :
678         SvXMLImportContext( rImport ),
679         mrStyleVector( rStyleVector ),
680         mrIndex( rIndex ),
681         mDataPoint(DataRowPointStyle::DATA_POINT, xSeries, rIndex, 1, OUString{}),
682         mDataLabel(DataRowPointStyle::DATA_LABEL_POINT, xSeries, rIndex, 1, OUString{})
683 {
684     mDataPoint.mbSymbolSizeForSeriesIsMissingInFile = bSymbolSizeForSeriesIsMissingInFile;
685 }
686 
createFastChildContext(sal_Int32 nElement,const css::uno::Reference<css::xml::sax::XFastAttributeList> &)687 css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLDataPointContext::createFastChildContext(
688     sal_Int32 nElement,
689     const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
690 {
691     SvXMLImportContext* pContext = nullptr;
692     switch(nElement)
693     {
694         case XML_ELEMENT(CHART, XML_DATA_LABEL):
695             mbHasLabelParagraph = true;
696             pContext = new SchXMLDataLabelContext(GetImport(), mDataPoint.mCustomLabels,
697                                                   mDataLabel);
698             break;
699         default:
700             XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
701     }
702     return pContext;
703 }
704 
~SchXMLDataPointContext()705 SchXMLDataPointContext::~SchXMLDataPointContext()
706 {
707 }
708 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)709 void SchXMLDataPointContext::startFastElement (sal_Int32 /*Element*/,
710         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
711 {
712     OUString sAutoStyleName;
713     sal_Int32 nRepeat = 1;
714     OUString sCustomLabelField;
715 
716     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
717     {
718         switch (aIter.getToken())
719         {
720             case XML_ELEMENT(CHART, XML_STYLE_NAME):
721             {
722                 sAutoStyleName = aIter.toString();
723                 mDataPoint.msStyleName = sAutoStyleName;
724                 mDataLabel.msStyleNameOfParent = sAutoStyleName;
725                 break;
726             }
727             case XML_ELEMENT(CHART, XML_REPEATED):
728             {
729                 nRepeat = aIter.toInt32();
730                 mDataPoint.m_nPointRepeat = nRepeat;
731                 mDataLabel.m_nPointRepeat = nRepeat;
732                 break;
733             }
734             // Deprecated. New documents use the chart:data-label element
735             // instead in order to store custom label text.
736             case XML_ELEMENT(LO_EXT, XML_CUSTOM_LABEL_FIELD):
737              if (!mbHasLabelParagraph)
738                 {
739                     sCustomLabelField = aIter.toString();
740                     mDataPoint.mCustomLabels.push_back(sCustomLabelField);
741                 }
742                 break;
743             case XML_ELEMENT(LO_EXT, XML_HIDE_LEGEND):
744             {
745                 bool bHideLegend = aIter.toBoolean();
746                 if (bHideLegend)
747                 {
748                     uno::Sequence<sal_Int32> deletedLegendEntriesSeq;
749                     Reference<beans::XPropertySet> xSeriesProp(mDataPoint.m_xSeries, uno::UNO_QUERY);
750                     xSeriesProp->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntriesSeq;
751                     std::vector<sal_Int32> deletedLegendEntries;
752                     for (auto& deletedLegendEntry : deletedLegendEntriesSeq)
753                     {
754                         deletedLegendEntries.push_back(deletedLegendEntry);
755                     }
756                     deletedLegendEntries.push_back(mDataPoint.m_nPointIndex);
757                     xSeriesProp->setPropertyValue("DeletedLegendEntries", uno::makeAny(::oox::ContainerHelper::vectorToSequence(deletedLegendEntries)));
758                 }
759                 break;
760             }
761             case XML_ELEMENT(LO_EXT, XML_CUSTOM_LABEL_POS_X):
762             {
763                 mDataPoint.mCustomLabelPos[0] = aIter.toDouble();
764                 break;
765             }
766             case XML_ELEMENT(LO_EXT, XML_CUSTOM_LABEL_POS_Y):
767             {
768                 mDataPoint.mCustomLabelPos[1] = aIter.toDouble();
769                 break;
770             }
771             default:
772                 XMLOFF_WARN_UNKNOWN("xmloff", aIter);
773         }
774     }
775 
776     mrIndex += nRepeat;
777 }
778 
endFastElement(sal_Int32)779 void SchXMLDataPointContext::endFastElement(sal_Int32 )
780 {
781     if(!mDataPoint.msStyleName.isEmpty() || mDataPoint.mCustomLabels.size() > 0)
782     {
783         mrStyleVector.push_back(mDataPoint);
784     }
785     if (!mDataLabel.msStyleName.isEmpty() || mDataLabel.mo_nLabelAbsolutePosX.has_value()
786         || mDataLabel.mo_nLabelAbsolutePosY.has_value())
787     {
788         mrStyleVector.push_back(mDataLabel);
789     }
790 }
791 
SchXMLPositionAttributesHelper(SvXMLImport & rImporter)792 SchXMLPositionAttributesHelper::SchXMLPositionAttributesHelper( SvXMLImport& rImporter )
793     : m_rImport( rImporter )
794     , m_aPosition(0,0)
795     , m_aSize(0,0)
796     , m_bHasSizeWidth( false )
797     , m_bHasSizeHeight( false )
798     , m_bHasPositionX( false )
799     , m_bHasPositionY( false )
800     , m_bAutoSize( false )
801     , m_bAutoPosition( false )
802 {
803 }
804 
~SchXMLPositionAttributesHelper()805 SchXMLPositionAttributesHelper::~SchXMLPositionAttributesHelper()
806 {
807 }
808 
hasPosSize() const809 bool SchXMLPositionAttributesHelper::hasPosSize() const
810 {
811     return (m_bHasPositionX && m_bHasPositionY) && (m_bHasSizeWidth && m_bHasSizeHeight);
812 }
813 
isAutomatic() const814 bool SchXMLPositionAttributesHelper::isAutomatic() const
815 {
816     return m_bAutoSize || m_bAutoPosition;
817 }
818 
readPositioningAttribute(sal_Int32 nAttributeToken,std::string_view rValue)819 void SchXMLPositionAttributesHelper::readPositioningAttribute( sal_Int32 nAttributeToken, std::string_view rValue )
820 {
821     if( !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_SVG) && !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_SVG_COMPAT) )
822         return;
823 
824     switch (nAttributeToken & TOKEN_MASK)
825     {
826         case XML_X:
827         {
828             m_rImport.GetMM100UnitConverter().convertMeasureToCore(
829                     m_aPosition.X, rValue );
830             m_bHasPositionX = true;
831             break;
832         }
833         case XML_Y:
834         {
835             m_rImport.GetMM100UnitConverter().convertMeasureToCore(
836                     m_aPosition.Y, rValue );
837             m_bHasPositionY = true;
838             break;
839         }
840         case XML_WIDTH:
841         {
842             m_rImport.GetMM100UnitConverter().convertMeasureToCore(
843                     m_aSize.Width, rValue );
844             m_bHasSizeWidth = true;
845             break;
846         }
847         case XML_HEIGHT:
848         {
849             m_rImport.GetMM100UnitConverter().convertMeasureToCore(
850                     m_aSize.Height, rValue );
851             m_bHasSizeHeight = true;
852             break;
853         }
854         default:
855             XMLOFF_WARN_UNKNOWN_ATTR("xmloff", nAttributeToken, OUString::fromUtf8(rValue));
856     }
857 }
858 
readAutomaticPositioningProperties(XMLPropStyleContext const * pPropStyleContext,const SvXMLStylesContext * pStylesCtxt)859 void SchXMLPositionAttributesHelper::readAutomaticPositioningProperties( XMLPropStyleContext const * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
860 {
861     if( pPropStyleContext && pStylesCtxt )
862     {
863         //handle automatic position and size
864         SchXMLTools::getPropertyFromContext(
865             u"AutomaticSize", pPropStyleContext, pStylesCtxt ) >>= m_bAutoSize;
866         SchXMLTools::getPropertyFromContext(
867             u"AutomaticPosition", pPropStyleContext, pStylesCtxt ) >>= m_bAutoPosition;
868     }
869 }
870 
SchXMLCoordinateRegionContext(SvXMLImport & rImport,SchXMLPositionAttributesHelper & rPositioning)871 SchXMLCoordinateRegionContext::SchXMLCoordinateRegionContext(
872           SvXMLImport& rImport
873         , SchXMLPositionAttributesHelper& rPositioning )
874         : SvXMLImportContext( rImport )
875         , m_rPositioning( rPositioning )
876 {
877 }
878 
~SchXMLCoordinateRegionContext()879 SchXMLCoordinateRegionContext::~SchXMLCoordinateRegionContext()
880 {
881 }
882 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)883 void SchXMLCoordinateRegionContext::startFastElement (sal_Int32 /*Element*/,
884         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
885 {
886     // parse attributes
887     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
888         m_rPositioning.readPositioningAttribute( aIter.getToken(), aIter.toView() );
889 }
890 
SchXMLWallFloorContext(SchXMLImportHelper & rImpHelper,SvXMLImport & rImport,uno::Reference<chart::XDiagram> const & xDiagram,ContextType eContextType)891 SchXMLWallFloorContext::SchXMLWallFloorContext(
892     SchXMLImportHelper& rImpHelper,
893     SvXMLImport& rImport,
894     uno::Reference< chart::XDiagram > const & xDiagram,
895     ContextType eContextType ) :
896         SvXMLImportContext( rImport ),
897         mrImportHelper( rImpHelper ),
898         mxWallFloorSupplier( xDiagram, uno::UNO_QUERY ),
899         meContextType( eContextType )
900 {
901 }
902 
~SchXMLWallFloorContext()903 SchXMLWallFloorContext::~SchXMLWallFloorContext()
904 {
905 }
906 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)907 void SchXMLWallFloorContext::startFastElement (sal_Int32 /*Element*/,
908         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
909 {
910     if( !mxWallFloorSupplier.is())
911         return;
912 
913     OUString sAutoStyleName;
914 
915     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
916     {
917         if( aIter.getToken() == XML_ELEMENT(CHART, XML_STYLE_NAME) )
918             sAutoStyleName = aIter.toString();
919         else
920             XMLOFF_WARN_UNKNOWN("xmloff", aIter);
921     }
922 
923     // set properties
924     uno::Reference< beans::XPropertySet > xProp = ( meContextType == CONTEXT_TYPE_WALL )
925                                                  ? mxWallFloorSupplier->getWall()
926                                                  : mxWallFloorSupplier->getFloor();
927 
928     if (!sAutoStyleName.isEmpty())
929         mrImportHelper.FillAutoStyle(sAutoStyleName, xProp);
930 }
931 
SchXMLStockContext(SchXMLImportHelper & rImpHelper,SvXMLImport & rImport,uno::Reference<chart::XDiagram> const & xDiagram,ContextType eContextType)932 SchXMLStockContext::SchXMLStockContext(
933     SchXMLImportHelper& rImpHelper,
934     SvXMLImport& rImport,
935     uno::Reference< chart::XDiagram > const & xDiagram,
936     ContextType eContextType ) :
937         SvXMLImportContext( rImport ),
938         mrImportHelper( rImpHelper ),
939         mxStockPropProvider( xDiagram, uno::UNO_QUERY ),
940         meContextType( eContextType )
941 {
942 }
943 
~SchXMLStockContext()944 SchXMLStockContext::~SchXMLStockContext()
945 {
946 }
947 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)948 void SchXMLStockContext::startFastElement (sal_Int32 /*Element*/,
949         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
950 {
951     if( !mxStockPropProvider.is())
952         return;
953 
954     OUString sAutoStyleName;
955 
956     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
957     {
958         if( aIter.getToken() == XML_ELEMENT(CHART, XML_STYLE_NAME) )
959             sAutoStyleName = aIter.toString();
960         else
961             XMLOFF_WARN_UNKNOWN("xmloff", aIter);
962     }
963 
964     if( sAutoStyleName.isEmpty())
965         return;
966 
967     // set properties
968     uno::Reference< beans::XPropertySet > xProp;
969     switch( meContextType )
970     {
971         case CONTEXT_TYPE_GAIN:
972             xProp = mxStockPropProvider->getUpBar();
973             break;
974         case CONTEXT_TYPE_LOSS:
975             xProp = mxStockPropProvider->getDownBar();
976             break;
977         case CONTEXT_TYPE_RANGE:
978             xProp = mxStockPropProvider->getMinMaxLine();
979             break;
980     }
981 
982     mrImportHelper.FillAutoStyle(sAutoStyleName, xProp);
983 }
984 
lcl_setErrorBarSequence(const uno::Reference<chart2::XChartDocument> & xDoc,const uno::Reference<beans::XPropertySet> & xBarProp,const OUString & aXMLRange,bool bPositiveValue,bool bYError,tSchXMLLSequencesPerIndex & rSequences)985 static void lcl_setErrorBarSequence ( const uno::Reference< chart2::XChartDocument > &xDoc,
986                                const uno::Reference< beans::XPropertySet > &xBarProp,
987                                const OUString &aXMLRange,
988                                bool bPositiveValue, bool bYError,
989                                tSchXMLLSequencesPerIndex& rSequences)
990 {
991     uno::Reference< css::chart2::data::XDataProvider > xDataProvider(xDoc->getDataProvider());
992     uno::Reference< css::chart2::data::XDataSource > xDataSource( xBarProp, uno::UNO_QUERY );
993     uno::Reference< css::chart2::data::XDataSink > xDataSink( xDataSource, uno::UNO_QUERY );
994 
995     assert( xDataSink.is() && xDataSource.is() && xDataProvider.is() );
996 
997     OUString aRange(lcl_ConvertRange(aXMLRange,xDoc));
998 
999     uno::Reference< chart2::data::XDataSequence > xNewSequence(
1000         xDataProvider->createDataSequenceByRangeRepresentation( aRange ));
1001 
1002     if( !xNewSequence.is())
1003         return;
1004 
1005     SchXMLTools::setXMLRangePropertyAtDataSequence(xNewSequence,aXMLRange);
1006 
1007     OUStringBuffer aRoleBuffer("error-bars-");
1008     if( bYError )
1009         aRoleBuffer.append( 'y' );
1010     else
1011         aRoleBuffer.append( 'x');
1012 
1013     aRoleBuffer.append( '-' );
1014 
1015     if( bPositiveValue )
1016         aRoleBuffer = aRoleBuffer.append( "positive" );
1017     else
1018         aRoleBuffer = aRoleBuffer.append( "negative" );
1019 
1020     OUString aRole = aRoleBuffer.makeStringAndClear();
1021 
1022     Reference< beans::XPropertySet > xSeqProp( xNewSequence, uno::UNO_QUERY );
1023 
1024     xSeqProp->setPropertyValue("Role", uno::makeAny( aRole ));
1025 
1026     Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext();
1027 
1028     Reference< chart2::data::XLabeledDataSequence > xLabelSeq( chart2::data::LabeledDataSequence::create(xContext),
1029         uno::UNO_QUERY_THROW );
1030 
1031     rSequences.emplace( tSchXMLIndexWithPart( -2, SCH_XML_PART_ERROR_BARS ), xLabelSeq );
1032 
1033     xLabelSeq->setValues( xNewSequence );
1034 
1035     uno::Sequence< Reference< chart2::data::XLabeledDataSequence > > aSequences(
1036         xDataSource->getDataSequences());
1037 
1038     aSequences.realloc( aSequences.getLength() + 1 );
1039     aSequences[ aSequences.getLength() - 1 ] = xLabelSeq;
1040     xDataSink->setData( aSequences );
1041 
1042 }
1043 
SchXMLStatisticsObjectContext(SchXMLImportHelper & rImpHelper,SvXMLImport & rImport,const OUString & rSeriesStyleName,::std::vector<DataRowPointStyle> & rStyleVector,const css::uno::Reference<css::chart2::XDataSeries> & xSeries,ContextType eContextType,tSchXMLLSequencesPerIndex & rLSequencesPerIndex)1044 SchXMLStatisticsObjectContext::SchXMLStatisticsObjectContext(
1045     SchXMLImportHelper& rImpHelper,
1046     SvXMLImport& rImport,
1047     const OUString &rSeriesStyleName,
1048     ::std::vector< DataRowPointStyle >& rStyleVector,
1049     const css::uno::Reference< css::chart2::XDataSeries >& xSeries,
1050     ContextType eContextType,
1051     tSchXMLLSequencesPerIndex & rLSequencesPerIndex) :
1052 
1053         SvXMLImportContext( rImport ),
1054         mrImportHelper( rImpHelper ),
1055         mrStyleVector( rStyleVector ),
1056         m_xSeries( xSeries ),
1057         meContextType( eContextType ),
1058         maSeriesStyleName( rSeriesStyleName),
1059         mrLSequencesPerIndex(rLSequencesPerIndex)
1060 {}
1061 
~SchXMLStatisticsObjectContext()1062 SchXMLStatisticsObjectContext::~SchXMLStatisticsObjectContext()
1063 {
1064 }
1065 
1066 namespace {
1067 
SetErrorBarStyleProperties(const OUString & rStyleName,const uno::Reference<beans::XPropertySet> & xBarProp,SchXMLImportHelper const & rImportHelper)1068 void SetErrorBarStyleProperties( const OUString& rStyleName, const uno::Reference< beans::XPropertySet >& xBarProp,
1069                                  SchXMLImportHelper const & rImportHelper )
1070 {
1071     const SvXMLStylesContext* pStylesCtxt = rImportHelper.GetAutoStylesContext();
1072     const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(),
1073             rStyleName);
1074 
1075     XMLPropStyleContext &rSeriesStyleContext =
1076         const_cast< XMLPropStyleContext& >( dynamic_cast< const XMLPropStyleContext& >( *pStyle ));
1077 
1078     rSeriesStyleContext.FillPropertySet( xBarProp );
1079 }
1080 
SetErrorBarPropertiesFromStyleName(const OUString & aStyleName,const uno::Reference<beans::XPropertySet> & xBarProp,SchXMLImportHelper const & rImportHelper,OUString & aPosRange,OUString & aNegRange)1081 void SetErrorBarPropertiesFromStyleName( const OUString& aStyleName, const uno::Reference< beans::XPropertySet>& xBarProp,
1082                                          SchXMLImportHelper const & rImportHelper, OUString& aPosRange, OUString& aNegRange)
1083 {
1084     const SvXMLStylesContext* pStylesCtxt = rImportHelper.GetAutoStylesContext();
1085     const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(SchXMLImportHelper::GetChartFamilyID(),
1086             aStyleName);
1087 
1088     XMLPropStyleContext * pSeriesStyleContext =
1089         const_cast< XMLPropStyleContext * >( dynamic_cast< const XMLPropStyleContext * >( pStyle ));
1090 
1091     uno::Any aAny = SchXMLTools::getPropertyFromContext(u"ErrorBarStyle",
1092             pSeriesStyleContext,pStylesCtxt);
1093 
1094     if ( !aAny.hasValue() )
1095         return;
1096 
1097     sal_Int32 aBarStyle = css::chart::ErrorBarStyle::NONE;
1098     aAny >>= aBarStyle;
1099     xBarProp->setPropertyValue("ErrorBarStyle", aAny);
1100 
1101     aAny = SchXMLTools::getPropertyFromContext(u"ShowPositiveError",
1102             pSeriesStyleContext,pStylesCtxt);
1103 
1104     if(aAny.hasValue())
1105         xBarProp->setPropertyValue("ShowPositiveError",aAny);
1106 
1107     aAny = SchXMLTools::getPropertyFromContext(u"ShowNegativeError",
1108             pSeriesStyleContext,pStylesCtxt);
1109 
1110     if(aAny.hasValue())
1111         xBarProp->setPropertyValue("ShowNegativeError",aAny);
1112 
1113     aAny = SchXMLTools::getPropertyFromContext(u"PositiveError",
1114             pSeriesStyleContext, pStylesCtxt);
1115 
1116     if(aAny.hasValue())
1117         xBarProp->setPropertyValue("PositiveError", aAny);
1118     else
1119     {
1120         aAny = SchXMLTools::getPropertyFromContext(u"ConstantErrorHigh",
1121                 pSeriesStyleContext, pStylesCtxt);
1122 
1123         if(aAny.hasValue())
1124             xBarProp->setPropertyValue("PositiveError", aAny);
1125     }
1126 
1127     aAny = SchXMLTools::getPropertyFromContext(u"NegativeError",
1128             pSeriesStyleContext, pStylesCtxt);
1129 
1130     if(aAny.hasValue())
1131         xBarProp->setPropertyValue("NegativeError", aAny);
1132     else
1133     {
1134         aAny = SchXMLTools::getPropertyFromContext(u"ConstantErrorLow",
1135                 pSeriesStyleContext, pStylesCtxt);
1136 
1137         if(aAny.hasValue())
1138             xBarProp->setPropertyValue("NegativeError", aAny);
1139     }
1140 
1141     aAny = SchXMLTools::getPropertyFromContext(u"ErrorBarRangePositive",
1142             pSeriesStyleContext, pStylesCtxt);
1143     if( aAny.hasValue() )
1144     {
1145         aAny >>= aPosRange;
1146     }
1147 
1148     aAny = SchXMLTools::getPropertyFromContext(u"ErrorBarRangeNegative",
1149             pSeriesStyleContext, pStylesCtxt);
1150     if( aAny.hasValue() )
1151     {
1152         aAny >>= aNegRange;
1153     }
1154 
1155     aAny = SchXMLTools::getPropertyFromContext(u"Weight",
1156             pSeriesStyleContext, pStylesCtxt);
1157     if( aAny.hasValue() )
1158     {
1159         xBarProp->setPropertyValue("Weight", aAny);
1160     }
1161 
1162     aAny = SchXMLTools::getPropertyFromContext(u"PercentageError",
1163             pSeriesStyleContext, pStylesCtxt);
1164     if( aAny.hasValue() && aBarStyle == css::chart::ErrorBarStyle::RELATIVE )
1165     {
1166         xBarProp->setPropertyValue("PositiveError", aAny);
1167         xBarProp->setPropertyValue("NegativeError", aAny);
1168     }
1169 
1170     switch(aBarStyle)
1171     {
1172         case css::chart::ErrorBarStyle::ERROR_MARGIN:
1173             {
1174                 aAny = SchXMLTools::getPropertyFromContext(u"NegativeError",
1175                         pSeriesStyleContext,pStylesCtxt);
1176 
1177                 xBarProp->setPropertyValue("NegativeError",aAny);
1178 
1179                 aAny = SchXMLTools::getPropertyFromContext(u"PositiveError",
1180                         pSeriesStyleContext,pStylesCtxt);
1181 
1182                 xBarProp->setPropertyValue("PositiveError",aAny);
1183             }
1184             break;
1185         default:
1186             break;
1187     }
1188 
1189 }
1190 
1191 }
1192 
startFastElement(sal_Int32,const css::uno::Reference<css::xml::sax::XFastAttributeList> & xAttrList)1193 void SchXMLStatisticsObjectContext::startFastElement (sal_Int32 /*Element*/,
1194         const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
1195 {
1196     OUString sAutoStyleName;
1197     OUString aPosRange;
1198     OUString aNegRange;
1199     bool bYError = true;    /// Default errorbar, to be backward compatible with older files!
1200 
1201     for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
1202     {
1203         switch (aIter.getToken())
1204         {
1205             case XML_ELEMENT(CHART, XML_STYLE_NAME):
1206                 sAutoStyleName = aIter.toString();
1207                 break;
1208             case XML_ELEMENT(CHART, XML_DIMENSION):
1209                 bYError = aIter.toString() == "y";
1210                 break;
1211             case XML_ELEMENT(CHART, XML_ERROR_UPPER_RANGE):
1212                 aPosRange = aIter.toString();
1213                 break;
1214             case XML_ELEMENT(CHART, XML_ERROR_LOWER_RANGE):
1215                 aNegRange = aIter.toString();
1216                 break;
1217         }
1218     }
1219 
1220     if( sAutoStyleName.isEmpty() )
1221         return;
1222 
1223     DataRowPointStyle aStyle( DataRowPointStyle::MEAN_VALUE, m_xSeries, -1, 1, sAutoStyleName );
1224 
1225     switch( meContextType )
1226     {
1227         case CONTEXT_TYPE_MEAN_VALUE_LINE:
1228             aStyle.meType = DataRowPointStyle::MEAN_VALUE;
1229             break;
1230         case CONTEXT_TYPE_ERROR_INDICATOR:
1231             {
1232                 aStyle.meType = DataRowPointStyle::ERROR_INDICATOR;
1233 
1234                 uno::Reference< lang::XMultiServiceFactory > xFact = comphelper::getProcessServiceFactory();
1235 
1236                 uno::Reference< beans::XPropertySet > xBarProp( xFact->createInstance("com.sun.star.chart2.ErrorBar" ),
1237                                                                 uno::UNO_QUERY );
1238 
1239                 xBarProp->setPropertyValue("ErrorBarStyle",uno::makeAny(css::chart::ErrorBarStyle::NONE));
1240                 xBarProp->setPropertyValue("PositiveError",uno::makeAny(0.0));
1241                 xBarProp->setPropertyValue("NegativeError",uno::makeAny(0.0));
1242                 xBarProp->setPropertyValue("Weight",uno::makeAny(1.0));
1243                 xBarProp->setPropertyValue("ShowPositiveError",uno::makeAny(true));
1244                 xBarProp->setPropertyValue("ShowNegativeError",uno::makeAny(true));
1245 
1246                 // first import defaults from parent style
1247                 SetErrorBarStyleProperties( maSeriesStyleName, xBarProp, mrImportHelper );
1248                 SetErrorBarStyleProperties( sAutoStyleName, xBarProp, mrImportHelper );
1249                 SetErrorBarPropertiesFromStyleName( maSeriesStyleName, xBarProp, mrImportHelper, aPosRange, aNegRange );
1250                 SetErrorBarPropertiesFromStyleName( sAutoStyleName, xBarProp, mrImportHelper, aPosRange, aNegRange );
1251 
1252                 uno::Reference< chart2::XChartDocument > xDoc(GetImport().GetModel(),uno::UNO_QUERY);
1253 
1254                 if (!aPosRange.isEmpty())
1255                     lcl_setErrorBarSequence(xDoc,xBarProp,aPosRange,true,bYError, mrLSequencesPerIndex);
1256 
1257                 if (!aNegRange.isEmpty())
1258                     lcl_setErrorBarSequence(xDoc,xBarProp,aNegRange,false,bYError, mrLSequencesPerIndex);
1259 
1260                 if ( !bYError )
1261                 {
1262                     aStyle.m_xErrorXProperties.set( xBarProp );
1263                 }
1264                 else
1265                 {
1266                     aStyle.m_xErrorYProperties.set( xBarProp );
1267                 }
1268             }
1269             break;
1270     }
1271 
1272     mrStyleVector.push_back( aStyle );
1273 }
1274 
1275 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1276