LibreOffice Module xmloff (master)  1
SchXMLAxisContext.cxx
Go to the documentation of this file.
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 <sax/tools/converter.hxx>
21 
22 #include "SchXMLAxisContext.hxx"
23 #include "SchXMLChartContext.hxx"
24 #include "SchXMLTools.hxx"
25 #include <xmloff/xmlimp.hxx>
26 #include <xmloff/xmlnamespace.hxx>
27 #include <xmloff/xmlement.hxx>
28 #include <xmloff/xmlstyle.hxx>
29 #include <xmloff/prstylei.hxx>
30 #include <xmloff/namespacemap.hxx>
31 #include <xmloff/xmluconv.hxx>
32 
33 #include <rtl/math.hxx>
34 #include <tools/color.hxx>
35 #include <sal/log.hxx>
36 
37 #include <com/sun/star/chart/ChartAxisLabelPosition.hpp>
38 #include <com/sun/star/chart/ChartAxisMarkPosition.hpp>
39 #include <com/sun/star/chart/ChartAxisPosition.hpp>
40 #include <com/sun/star/chart/ChartAxisType.hpp>
41 #include <com/sun/star/chart/TimeIncrement.hpp>
42 #include <com/sun/star/chart/TimeInterval.hpp>
43 #include <com/sun/star/chart/TimeUnit.hpp>
44 #include <com/sun/star/chart/XAxis.hpp>
45 #include <com/sun/star/chart/XAxisSupplier.hpp>
46 #include <com/sun/star/chart/XChartDocument.hpp>
47 #include <com/sun/star/chart2/AxisType.hpp>
48 #include <com/sun/star/chart2/XChartDocument.hpp>
49 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
50 
51 #include <com/sun/star/drawing/LineStyle.hpp>
52 
53 using namespace ::xmloff::token;
54 using namespace com::sun::star;
55 
57 
59 {
60  { XML_X, SCH_XML_AXIS_X },
61  { XML_Y, SCH_XML_AXIS_Y },
62  { XML_Z, SCH_XML_AXIS_Z },
64 };
65 
67 {
68  { XML_AUTO, css::chart::ChartAxisType::AUTOMATIC },
69  { XML_TEXT, css::chart::ChartAxisType::CATEGORY },
70  { XML_DATE, css::chart::ChartAxisType::DATE },
71  { XML_TOKEN_INVALID, 0 }
72 };
73 
74 namespace {
75 
76 class SchXMLCategoriesContext : public SvXMLImportContext
77 {
78 private:
79  OUString& mrAddress;
80 
81 public:
82  SchXMLCategoriesContext( SvXMLImport& rImport,
83  OUString& rAddress );
84  virtual void SAL_CALL startFastElement( sal_Int32 nElement,
85  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
86 };
87 
88 class DateScaleContext : public SvXMLImportContext
89 {
90 public:
91  DateScaleContext( SvXMLImport& rImport,
92  const Reference< beans::XPropertySet >& rAxisProps );
93 
94  virtual void SAL_CALL startFastElement( sal_Int32 nElement,
95  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
96 
97 private:
99 };
100 
101 }
102 
104  SvXMLImport& rImport,
105  Reference< chart::XDiagram > const & xDiagram,
106  std::vector< SchXMLAxis >& rAxes,
107  OUString & rCategoriesAddress,
108  bool bAddMissingXAxisForNetCharts,
109  bool bAdaptWrongPercentScaleValues,
110  bool bAdaptXAxisOrientationForOld2DBarCharts,
111  bool& rbAxisPositionAttributeImported ) :
112  SvXMLImportContext( rImport ),
113  m_rImportHelper( rImpHelper ),
114  m_xDiagram( xDiagram ),
115  m_rAxes( rAxes ),
116  m_rCategoriesAddress( rCategoriesAddress ),
117  m_nAxisType(chart::ChartAxisType::AUTOMATIC),
118  m_bAxisTypeImported(false),
119  m_bDateScaleImported(false),
120  m_bAddMissingXAxisForNetCharts( bAddMissingXAxisForNetCharts ),
121  m_bAdaptWrongPercentScaleValues( bAdaptWrongPercentScaleValues ),
122  m_bAdaptXAxisOrientationForOld2DBarCharts( bAdaptXAxisOrientationForOld2DBarCharts ),
123  m_rbAxisPositionAttributeImported( rbAxisPositionAttributeImported )
124 {
125 }
126 
128 {}
129 
131 {
133  Reference< chart::XAxisSupplier > xAxisSuppl( rDiagram, uno::UNO_QUERY );
134  if( !xAxisSuppl.is() )
135  return xAxis;
136  if( rCurrentAxis.nAxisIndex == 0 )
137  xAxis = xAxisSuppl->getAxis(rCurrentAxis.eDimension);
138  else
139  xAxis = xAxisSuppl->getSecondaryAxis(rCurrentAxis.eDimension);
140  return xAxis;
141 }
142 
143 /* returns a shape for the current axis's title. The property
144  "Has...AxisTitle" is set to "True" to get the shape
145  */
147 {
149  Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY );
151  if( !xDiaProp.is() || !xAxis.is() )
152  return xResult;
153 
154  OUString aPropName;
155  switch( m_aCurrentAxis.eDimension )
156  {
157  case SCH_XML_AXIS_X:
158  if( m_aCurrentAxis.nAxisIndex == 0 )
159  aPropName = "HasXAxisTitle";
160  else
161  aPropName = "HasSecondaryXAxisTitle";
162  break;
163  case SCH_XML_AXIS_Y:
164  if( m_aCurrentAxis.nAxisIndex == 0 )
165  aPropName = "HasYAxisTitle";
166  else
167  aPropName = "HasSecondaryYAxisTitle";
168  break;
169  case SCH_XML_AXIS_Z:
170  aPropName = "HasZAxisTitle";
171  break;
172  case SCH_XML_AXIS_UNDEF:
173  SAL_INFO("xmloff.chart", "Invalid axis" );
174  break;
175  }
176  xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) );
177  xResult.set( xAxis->getAxisTitle(), uno::UNO_QUERY );
178  return xResult;
179 }
180 
181 void SchXMLAxisContext::CreateGrid( const OUString& sAutoStyleName, bool bIsMajor )
182 {
183  Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY );
185  if( !xDiaProp.is() || !xAxis.is() )
186  return;
187 
188  OUString aPropName;
189  switch( m_aCurrentAxis.eDimension )
190  {
191  case SCH_XML_AXIS_X:
192  if( bIsMajor )
193  aPropName = "HasXAxisGrid";
194  else
195  aPropName = "HasXAxisHelpGrid";
196  break;
197  case SCH_XML_AXIS_Y:
198  if( bIsMajor )
199  aPropName = "HasYAxisGrid";
200  else
201  aPropName = "HasYAxisHelpGrid";
202  break;
203  case SCH_XML_AXIS_Z:
204  if( bIsMajor )
205  aPropName = "HasZAxisGrid";
206  else
207  aPropName = "HasZAxisHelpGrid";
208  break;
209  case SCH_XML_AXIS_UNDEF:
210  SAL_INFO("xmloff.chart", "Invalid axis" );
211  break;
212  }
213  xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) );
214 
216  if( bIsMajor )
217  xGridProp = xAxis->getMajorGrid();
218  else
219  xGridProp = xAxis->getMinorGrid();
220 
221  // set properties
222  if( xGridProp.is())
223  {
224  // the line color is black as default, in the model it is a light gray
225  xGridProp->setPropertyValue("LineColor",
226  uno::makeAny( COL_BLACK ));
227  if (!sAutoStyleName.isEmpty())
228  m_rImportHelper.FillAutoStyle(sAutoStyleName, xGridProp);
229  }
230 }
231 
232 void SchXMLAxisContext::startFastElement( sal_Int32 /*nElement*/,
233  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
234 {
235  // parse attributes
236  for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
237  {
238  switch(aIter.getToken())
239  {
241  {
242  SchXMLAxisDimension nEnumVal;
243  if( SvXMLUnitConverter::convertEnum( nEnumVal, aIter.toView(), aXMLAxisDimensionMap ))
244  m_aCurrentAxis.eDimension = nEnumVal;
245  }
246  break;
247  case XML_ELEMENT(CHART, XML_NAME):
248  m_aCurrentAxis.aName = aIter.toString();
249  break;
251  case XML_ELEMENT(CHART_EXT, XML_AXIS_TYPE):
252  sal_uInt16 nEnumVal;
253  if( SvXMLUnitConverter::convertEnum( nEnumVal, aIter.toView(), aXMLAxisTypeMap ))
254  {
255  m_nAxisType = nEnumVal;
256  m_bAxisTypeImported = true;
257  }
258  break;
260  m_aAutoStyleName = aIter.toString();
261  break;
262  default:
263  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
264  }
265  }
266 
267  // check for number of axes with same dimension
269  sal_Int32 nNumOfAxes = m_rAxes.size();
270  for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ )
271  {
272  if( m_rAxes[ nCurrent ].eDimension == m_aCurrentAxis.eDimension )
274  }
275  CreateAxis();
276 }
277 namespace
278 {
279 
280 Reference< chart2::XAxis > lcl_getAxis( const Reference< frame::XModel >& xChartModel,
281  sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
282 {
284 
285  try
286  {
287  Reference< chart2::XChartDocument > xChart2Document( xChartModel, uno::UNO_QUERY );
288  if( xChart2Document.is() )
289  {
290  Reference< chart2::XDiagram > xDiagram( xChart2Document->getFirstDiagram());
291  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
292  uno::Sequence< Reference< chart2::XCoordinateSystem > >
293  aCooSysSeq( xCooSysCnt->getCoordinateSystems());
294  sal_Int32 nCooSysIndex = 0;
295  if( nCooSysIndex < aCooSysSeq.getLength() )
296  {
297  Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] );
298  if( xCooSys.is() && nDimensionIndex < xCooSys->getDimension() )
299  {
300  const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
301  if( nAxisIndex <= nMaxAxisIndex )
302  xAxis = xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex );
303  }
304  }
305  }
306  }
307  catch( uno::Exception & )
308  {
309  SAL_INFO("xmloff.chart", "Couldn't get axis" );
310  }
311 
312  return xAxis;
313 }
314 
315 bool lcl_divideBy100( uno::Any& rDoubleAny )
316 {
317  bool bChanged = false;
318  double fValue=0.0;
319  if( (rDoubleAny>>=fValue) && (fValue!=0.0) )
320  {
321  fValue/=100.0;
322  rDoubleAny <<= fValue;
323  bChanged = true;
324  }
325  return bChanged;
326 }
327 
328 bool lcl_AdaptWrongPercentScaleValues(chart2::ScaleData& rScaleData)
329 {
330  bool bChanged = lcl_divideBy100( rScaleData.Minimum );
331  bChanged = lcl_divideBy100( rScaleData.Maximum ) || bChanged;
332  bChanged = lcl_divideBy100( rScaleData.Origin ) || bChanged;
333  bChanged = lcl_divideBy100( rScaleData.IncrementData.Distance ) || bChanged;
334  return bChanged;
335 }
336 
337 }//end anonymous namespace
338 
340 {
341  m_rAxes.push_back( m_aCurrentAxis );
342 
343  Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY );
344  if( !xDiaProp.is() )
345  return;
346  OUString aPropName;
347  switch( m_aCurrentAxis.eDimension )
348  {
349  case SCH_XML_AXIS_X:
350  if( m_aCurrentAxis.nAxisIndex == 0 )
351  aPropName = "HasXAxis";
352  else
353  aPropName = "HasSecondaryXAxis";
354  break;
355  case SCH_XML_AXIS_Y:
356  if( m_aCurrentAxis.nAxisIndex == 0 )
357  aPropName = "HasYAxis";
358  else
359  aPropName = "HasSecondaryYAxis";
360  break;
361  case SCH_XML_AXIS_Z:
362  if( m_aCurrentAxis.nAxisIndex == 0 )
363  aPropName = "HasZAxis";
364  break;
365  case SCH_XML_AXIS_UNDEF:
366  SAL_INFO("xmloff.chart", "Invalid axis" );
367  break;
368  }
369  try
370  {
371  xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) );
372  }
373  catch( beans::UnknownPropertyException & )
374  {
375  SAL_INFO("xmloff.chart", "Couldn't turn on axis" );
376  }
378  {
379  bool bSettingZAxisSucceeded = false;
380  try
381  {
382  xDiaProp->getPropertyValue( aPropName ) >>= bSettingZAxisSucceeded;
383  }
384  catch( beans::UnknownPropertyException & )
385  {
386  SAL_INFO("xmloff.chart", "Couldn't turn on z axis" );
387  }
388  if( !bSettingZAxisSucceeded )
389  return;
390  }
391 
392  m_xAxisProps.set( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ), uno::UNO_QUERY );
393 
395  {
396  try
397  {
398  xDiaProp->setPropertyValue("HasXAxis", uno::makeAny(true) );
399  }
400  catch( beans::UnknownPropertyException & )
401  {
402  SAL_INFO("xmloff.chart", "Couldn't turn on x axis" );
403  }
404  }
405 
406  // set properties
407  if( !m_xAxisProps.is())
408  return;
409 
410  uno::Any aTrueBool( uno::makeAny( true ));
411  uno::Any aFalseBool( uno::makeAny( false ));
412 
413  // #i109879# the line color is black as default, in the model it is a light gray
414  m_xAxisProps->setPropertyValue("LineColor",
415  uno::makeAny( COL_BLACK ));
416 
417  m_xAxisProps->setPropertyValue("DisplayLabels", aFalseBool );
418 
419  // Compatibility option: starting from LibreOffice 5.1 the rotated
420  // layout is preferred to staggering for axis labels.
421  // So the import default value for having compatibility with ODF
422  // documents created with earlier LibreOffice versions is `true`.
423  if( GetImport().getGeneratorVersion() != SvXMLImport::ProductVersionUnknown )
424  m_xAxisProps->setPropertyValue("TryStaggeringFirst", aTrueBool );
425 
426  // #88077# AutoOrigin 'on' is default
427  m_xAxisProps->setPropertyValue("AutoOrigin", aTrueBool );
428 
429  if( m_bAxisTypeImported )
430  m_xAxisProps->setPropertyValue("AxisType", uno::makeAny(m_nAxisType) );
431 
432  if( !m_aAutoStyleName.isEmpty())
433  {
435  if (pStylesCtxt)
436  {
438 
439  if (XMLPropStyleContext * pPropStyleContext = dynamic_cast<XMLPropStyleContext*>(pStyle))
440  {
441  pPropStyleContext->FillPropertySet(m_xAxisProps);
442 
444  {
445  //set scale data of added x axis back to default
446  Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(),
448  if( xAxis.is() )
449  {
450  chart2::ScaleData aScaleData( xAxis->getScaleData());
451  if( lcl_AdaptWrongPercentScaleValues(aScaleData) )
452  xAxis->setScaleData( aScaleData );
453  }
454  }
455 
457  {
458  //copy style from y axis to added x axis:
459 
460  Reference< chart::XAxisSupplier > xAxisSuppl( xDiaProp, uno::UNO_QUERY );
461  if( xAxisSuppl.is() )
462  {
463  Reference< beans::XPropertySet > xXAxisProp( xAxisSuppl->getAxis(0), uno::UNO_QUERY );
464  pPropStyleContext->FillPropertySet(xXAxisProp);
465  }
466 
467  //set scale data of added x axis back to default
468  Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(),
469  0 /*nDimensionIndex*/, 0 /*nAxisIndex*/ ) );
470  if( xAxis.is() )
471  {
472  chart2::ScaleData aScaleData;
473  aScaleData.AxisType = chart2::AxisType::CATEGORY;
474  aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL;
475  xAxis->setScaleData( aScaleData );
476  }
477 
478  //set line style of added x axis to invisible
479  Reference< beans::XPropertySet > xNewAxisProp( xAxis, uno::UNO_QUERY );
480  if( xNewAxisProp.is() )
481  {
482  xNewAxisProp->setPropertyValue("LineStyle"
483  , uno::makeAny(drawing::LineStyle_NONE));
484  }
485  }
486 
488  {
489  bool bIs3DChart = false;
490  if( xDiaProp.is() && ( xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart )
491  && !bIs3DChart )
492  {
493  Reference< chart2::XChartDocument > xChart2Document( GetImport().GetModel(), uno::UNO_QUERY );
494  if( xChart2Document.is() )
495  {
496  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChart2Document->getFirstDiagram(), uno::UNO_QUERY );
497  if( xCooSysCnt.is() )
498  {
499  uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() );
500  if( aCooSysSeq.hasElements() )
501  {
502  bool bSwapXandYAxis = false;
503  Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] );
504  Reference< beans::XPropertySet > xCooSysProp( xCooSys, uno::UNO_QUERY );
505  if( xCooSysProp.is() && ( xCooSysProp->getPropertyValue("SwapXAndYAxis") >>= bSwapXandYAxis )
506  && bSwapXandYAxis )
507  {
508  Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( 0, m_aCurrentAxis.nAxisIndex );
509  if( xAxis.is() )
510  {
511  chart2::ScaleData aScaleData = xAxis->getScaleData();
512  aScaleData.Orientation = chart2::AxisOrientation_REVERSE;
513  xAxis->setScaleData( aScaleData );
514  }
515  }
516  }
517  }
518  }
519  }
520  }
521 
523  u"CrossoverPosition", pPropStyleContext, pStylesCtxt ).hasValue();
524  }
525  }
526  }
527 
529  return;
530 
532  if (!xAxis.is())
533  return;
534 
535  chart2::ScaleData aScaleData(xAxis->getScaleData());
536  bool bIs3DChart = false;
537  double fMajorOrigin = -1;
538  OUString sChartType = m_xDiagram->getDiagramType();
539  if ((xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart) && bIs3DChart
540  && (sChartType == "com.sun.star.chart.BarDiagram" || sChartType == "com.sun.star.chart.StockDiagram"))
541  {
542  aScaleData.ShiftedCategoryPosition = true;
543  xAxis->setScaleData(aScaleData);
544  }
545  else if ((m_xAxisProps->getPropertyValue("MajorOrigin") >>= fMajorOrigin)
546  && (rtl::math::approxEqual(fMajorOrigin, 0.0) || rtl::math::approxEqual(fMajorOrigin, 0.5)))
547  {
548  aScaleData.ShiftedCategoryPosition = rtl::math::approxEqual(fMajorOrigin, 0.5);
549  xAxis->setScaleData(aScaleData);
550  }
551 }
552 
554 {
555  if( m_aCurrentAxis.aTitle.isEmpty() )
556  return;
557 
559  if( !xAxis.is() )
560  return;
561 
562  Reference< beans::XPropertySet > xTitleProp( xAxis->getAxisTitle() );
563  if( xTitleProp.is() )
564  {
565  try
566  {
567  xTitleProp->setPropertyValue("String", uno::makeAny(m_aCurrentAxis.aTitle) );
568  }
569  catch( beans::UnknownPropertyException & )
570  {
571  SAL_INFO("xmloff.chart", "Property String for Title not available" );
572  }
573  }
574 }
575 
576 css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLAxisContext::createFastChildContext(
577  sal_Int32 nElement,
578  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
579 {
580  switch( nElement )
581  {
582  case XML_ELEMENT(CHART, XML_TITLE):
583  {
587  xTitleShape );
588  }
589  break;
590 
593  return new SchXMLCategoriesContext( GetImport(),
595  break;
596 
598  case XML_ELEMENT(CHART_EXT, XML_DATE_SCALE):
599  m_bDateScaleImported = true;
600  return new DateScaleContext( GetImport(), m_xAxisProps );
601 
602  case XML_ELEMENT(CHART, XML_GRID):
603  {
604  bool bIsMajor = true; // default value for class is "major"
605  OUString sAutoStyleName;
606 
607  for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
608  {
609  switch (aIter.getToken())
610  {
611  case XML_ELEMENT(CHART, XML_CLASS):
612  if( IsXMLToken( aIter, XML_MINOR ) )
613  bIsMajor = false;
614  break;
616  sAutoStyleName = aIter.toString();
617  break;
618  default:
619  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
620  }
621  }
622 
623  CreateGrid( sAutoStyleName, bIsMajor );
624 
625  // don't create a context => use default context. grid elements are empty
626  }
627  break;
628 
629  default:
630  XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
631  break;
632  }
633 
634  return nullptr;
635 }
636 
638 {
639  if( !m_bDateScaleImported && m_nAxisType==chart::ChartAxisType::AUTOMATIC )
640  {
642  if( xAxis.is() )
643  {
644  chart2::ScaleData aScaleData( xAxis->getScaleData());
645  aScaleData.AutoDateAxis = false;//different default for older documents
646  xAxis->setScaleData( aScaleData );
647  }
648  }
649 
650  SetAxisTitle();
651 }
652 
653 namespace
654 {
655 
656 Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& rCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
657 {
659  try
660  {
661  xAxis = rCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex );
662  }
663  catch( uno::Exception & )
664  {
665  }
666  return xAxis;
667 }
668 
669 } // anonymous namespace
670 
672  std::u16string_view rChartTypeServiceName,
673  std::u16string_view rODFVersionOfFile,
674  bool bAxisPositionAttributeImported )
675 {
676  if( !(rODFVersionOfFile.empty() || rODFVersionOfFile == u"1.0" || rODFVersionOfFile == u"1.1"
677  || ( rODFVersionOfFile == u"1.2" && !bAxisPositionAttributeImported )) )
678  return;
679 
680  try
681  {
682  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDoc->getFirstDiagram(), uno::UNO_QUERY_THROW );
683  uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
684  if( aCooSysSeq.hasElements() )
685  {
686  Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] );
687  if( xCooSys.is() )
688  {
689  Reference< chart2::XAxis > xMainXAxis = lcl_getAxis( xCooSys, 0, 0 );
690  Reference< chart2::XAxis > xMainYAxis = lcl_getAxis( xCooSys, 1, 0 );
691  //Reference< chart2::XAxis > xMajorZAxis = lcl_getAxis( xCooSys, 2, 0 );
692  Reference< chart2::XAxis > xSecondaryXAxis = lcl_getAxis( xCooSys, 0, 1 );
693  Reference< chart2::XAxis > xSecondaryYAxis = lcl_getAxis( xCooSys, 1, 1 );
694 
695  Reference< beans::XPropertySet > xMainXAxisProp( xMainXAxis, uno::UNO_QUERY );
696  Reference< beans::XPropertySet > xMainYAxisProp( xMainYAxis, uno::UNO_QUERY );
697  Reference< beans::XPropertySet > xSecondaryXAxisProp( xSecondaryXAxis, uno::UNO_QUERY );
698  Reference< beans::XPropertySet > xSecondaryYAxisProp( xSecondaryYAxis, uno::UNO_QUERY );
699 
700  if( xMainXAxisProp.is() && xMainYAxisProp.is() )
701  {
702  chart2::ScaleData aMainXScale = xMainXAxis->getScaleData();
703  if( rChartTypeServiceName == u"com.sun.star.chart2.ScatterChartType" )
704  {
705  xMainYAxisProp->setPropertyValue("CrossoverPosition"
706  , uno::makeAny( css::chart::ChartAxisPosition_VALUE) );
707  double fCrossoverValue = 0.0;
708  aMainXScale.Origin >>= fCrossoverValue;
709  xMainYAxisProp->setPropertyValue("CrossoverValue"
710  , uno::makeAny( fCrossoverValue ) );
711 
712  if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE )
713  {
714  xMainYAxisProp->setPropertyValue("LabelPosition"
715  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_END) );
716  xMainYAxisProp->setPropertyValue("MarkPosition"
717  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
718  if( xSecondaryYAxisProp.is() )
719  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
720  , uno::makeAny( css::chart::ChartAxisPosition_START) );
721  }
722  else
723  {
724  xMainYAxisProp->setPropertyValue("LabelPosition"
725  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_START) );
726  xMainYAxisProp->setPropertyValue("MarkPosition"
727  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
728  if( xSecondaryYAxisProp.is() )
729  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
730  , uno::makeAny( css::chart::ChartAxisPosition_END) );
731  }
732  }
733  else
734  {
735  if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE )
736  {
737  xMainYAxisProp->setPropertyValue("CrossoverPosition"
738  , uno::makeAny( css::chart::ChartAxisPosition_END) );
739  if( xSecondaryYAxisProp.is() )
740  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
741  , uno::makeAny( css::chart::ChartAxisPosition_START) );
742  }
743  else
744  {
745  xMainYAxisProp->setPropertyValue("CrossoverPosition"
746  , uno::makeAny( css::chart::ChartAxisPosition_START) );
747  if( xSecondaryYAxisProp.is() )
748  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
749  , uno::makeAny( css::chart::ChartAxisPosition_END) );
750  }
751  }
752 
753  chart2::ScaleData aMainYScale = xMainYAxis->getScaleData();
754  xMainXAxisProp->setPropertyValue("CrossoverPosition"
755  , uno::makeAny( css::chart::ChartAxisPosition_VALUE) );
756  double fCrossoverValue = 0.0;
757  aMainYScale.Origin >>= fCrossoverValue;
758  xMainXAxisProp->setPropertyValue("CrossoverValue"
759  , uno::makeAny( fCrossoverValue ) );
760 
761  if( aMainYScale.Orientation == chart2::AxisOrientation_REVERSE )
762  {
763  xMainXAxisProp->setPropertyValue("LabelPosition"
764  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_END) );
765  xMainXAxisProp->setPropertyValue("MarkPosition"
766  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
767  if( xSecondaryXAxisProp.is() )
768  xSecondaryXAxisProp->setPropertyValue("CrossoverPosition"
769  , uno::makeAny( css::chart::ChartAxisPosition_START) );
770  }
771  else
772  {
773  xMainXAxisProp->setPropertyValue("LabelPosition"
774  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_START) );
775  xMainXAxisProp->setPropertyValue("MarkPosition"
776  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
777  if( xSecondaryXAxisProp.is() )
778  xSecondaryXAxisProp->setPropertyValue("CrossoverPosition"
779  , uno::makeAny( css::chart::ChartAxisPosition_END) );
780  }
781  }
782  }
783  }
784  }
785  catch( uno::Exception & )
786  {
787  }
788 }
789 
790 SchXMLCategoriesContext::SchXMLCategoriesContext(
791  SvXMLImport& rImport,
792  OUString& rAddress ) :
793  SvXMLImportContext( rImport ),
794  mrAddress( rAddress )
795 {
796 }
797 
798 void SchXMLCategoriesContext::startFastElement( sal_Int32 /*nElement*/,
799  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
800 {
801  for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
802  {
803  if( aIter.getToken() == XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS) )
804  mrAddress = aIter.toString();
805  else
806  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
807  }
808 }
809 
810 DateScaleContext::DateScaleContext(
811  SvXMLImport& rImport,
812  const Reference< beans::XPropertySet >& rAxisProps ) :
813  SvXMLImportContext( rImport ),
814  m_xAxisProps( rAxisProps )
815 {
816 }
817 
818 namespace
819 {
820 sal_Int32 lcl_getTimeUnit( const sax_fastparser::FastAttributeList::FastAttributeIter& rValue )
821 {
822  sal_Int32 nTimeUnit = css::chart::TimeUnit::DAY;
823  if( IsXMLToken( rValue, XML_DAYS ) )
824  nTimeUnit = css::chart::TimeUnit::DAY;
825  else if( IsXMLToken( rValue, XML_MONTHS ) )
826  nTimeUnit = css::chart::TimeUnit::MONTH;
827  else if( IsXMLToken( rValue, XML_YEARS ) )
828  nTimeUnit = css::chart::TimeUnit::YEAR;
829  return nTimeUnit;
830 }
831 
832 }
833 
834 void DateScaleContext::startFastElement( sal_Int32 /*nElement*/,
835  const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
836 {
837  if( !m_xAxisProps.is() )
838  return;
839 
840  // parse attributes
841  bool bSetNewIncrement=false;
842  chart::TimeIncrement aIncrement;
843  m_xAxisProps->getPropertyValue("TimeIncrement") >>= aIncrement;
844 
845  for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
846  {
847  switch( aIter.getToken() )
848  {
849  case XML_ELEMENT(CHART, XML_BASE_TIME_UNIT):
850  {
851  aIncrement.TimeResolution <<= lcl_getTimeUnit(aIter);
852  bSetNewIncrement = true;
853  }
854  break;
856  {
857  chart::TimeInterval aInterval(1,0);
858  aIncrement.MajorTimeInterval >>= aInterval;
859  ::sax::Converter::convertNumber( aInterval.Number, aIter.toView() );
860  aIncrement.MajorTimeInterval <<= aInterval;
861  bSetNewIncrement = true;
862  }
863  break;
865  {
866  chart::TimeInterval aInterval(1,0);
867  aIncrement.MajorTimeInterval >>= aInterval;
868  aInterval.TimeUnit = lcl_getTimeUnit(aIter);
869  aIncrement.MajorTimeInterval <<= aInterval;
870  bSetNewIncrement = true;
871  }
872  break;
874  {
875  chart::TimeInterval aInterval(1,0);
876  aIncrement.MinorTimeInterval >>= aInterval;
877  ::sax::Converter::convertNumber( aInterval.Number, aIter.toView() );
878  aIncrement.MinorTimeInterval <<= aInterval;
879  bSetNewIncrement = true;
880  }
881  break;
883  {
884  chart::TimeInterval aInterval(1,0);
885  aIncrement.MinorTimeInterval >>= aInterval;
886  aInterval.TimeUnit = lcl_getTimeUnit(aIter);
887  aIncrement.MinorTimeInterval <<= aInterval;
888  bSetNewIncrement = true;
889  }
890  break;
891  default:
892  XMLOFF_WARN_UNKNOWN("xmloff", aIter);
893  }
894  }
895 
896  if( bSetNewIncrement )
897  m_xAxisProps->setPropertyValue("TimeIncrement", uno::makeAny( aIncrement ) );
898 }
899 
900 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &AttrList) override
const SvXMLEnumMapEntry< sal_uInt16 > aXMLAxisTypeMap[]
bool hasValue()
SchXMLAxisContext(SchXMLImportHelper &rImpHelper, SvXMLImport &rImport, css::uno::Reference< css::chart::XDiagram > const &xDiagram, std::vector< SchXMLAxis > &aAxes, OUString &rCategoriesAddress, bool bAddMissingXAxisForNetCharts, bool bAdaptWrongPercentScaleValues, bool bAdaptXAxisOrientationForOld2DBarCharts, bool &rbAxisPositionAttributeImported)
SvXMLStylesContext * GetAutoStylesContext() const
uno::Any getPropertyFromContext(std::u16string_view rPropertyName, const XMLPropStyleContext *pPropStyleContext, const SvXMLStylesContext *pStylesCtxt)
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:59
sal_Int8 nAxisIndex
SchXMLAxisDimension
css::uno::Reference< css::drawing::XShape > getTitleShape() const
css::uno::Reference< css::chart::XDiagram > m_xDiagram
bool IsXMLToken(std::u16string_view rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3508
FastAttributeList & castToFastAttributeList(const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList)
void FillAutoStyle(const OUString &rAutoStyleName, const css::uno::Reference< css::beans::XPropertySet > &rProp)
Fill in the autostyle.
bool & m_rbAxisPositionAttributeImported
virtual void SAL_CALL endFastElement(sal_Int32 nElement) override
endFastElement is called before a context will be destructed, but after an elements context has been ...
static void CorrectAxisPositions(const css::uno::Reference< css::chart2::XChartDocument > &xNewDoc, std::u16string_view rChartTypeServiceName, std::u16string_view rODFVersionOfFile, bool bAxisPositionAttributeImported)
#define XMLOFF_WARN_UNKNOWN(area, rIter)
Definition: xmlictxt.hxx:113
static const sal_uInt16 ProductVersionUnknown
Definition: xmlimp.hxx:561
std::vector< SchXMLAxis > & m_rAxes
OUString aTitle
bool m_bAdaptXAxisOrientationForOld2DBarCharts
enum SchXMLAxisDimension eDimension
static Reference< chart::XAxis > lcl_getChartAxis(const SchXMLAxis &rCurrentAxis, const Reference< chart::XDiagram > &rDiagram)
float u
OUString & m_rCategoriesAddress
static XmlStyleFamily GetChartFamilyID()
css::uno::Reference< css::beans::XPropertySet > m_xAxisProps
OUString aName
With this class you can import a element containing its data as element o...
virtual void SAL_CALL startFastElement(sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList > &xAttrList) override
This class deliberately does not support XWeak, to improve performance when loading large documents...
Definition: xmlictxt.hxx:44
Map an XMLTokenEnum to an enum value.
Definition: ximpshap.hxx:39
const css::uno::Reference< css::chart::XChartDocument > & GetChartDocument() const
Handling of tokens in XML:
#define SAL_INFO(area, stream)
#define XML_ELEMENT(prefix, name)
Definition: xmlimp.hxx:97
static bool convertEnum(EnumT &rEnum, std::u16string_view rValue, const SvXMLEnumMapEntry< EnumT > *pMap)
convert string to enum using given enum map, if the enum is not found in the map, this method will re...
Definition: xmluconv.hxx:145
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
const SvXMLStyleContext * FindStyleChildContext(XmlStyleFamily nFamily, const OUString &rName, bool bCreateIndex=false) const
Definition: xmlstyle.cxx:788
#define XMLOFF_WARN_UNKNOWN_ELEMENT(area, token)
Definition: xmlictxt.hxx:119
SchXMLImportHelper & m_rImportHelper
virtual ~SchXMLAxisContext() override
const SvXMLEnumMapEntry< SchXMLAxisDimension > aXMLAxisDimensionMap[]
AUTOMATIC
static bool convertNumber(sal_Int32 &rValue, std::u16string_view aString, sal_Int32 nMin=SAL_MIN_INT32, sal_Int32 nMax=SAL_MAX_INT32)
void CreateGrid(const OUString &sAutoStyleName, bool bIsMajor)