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/xmlnmspe.hxx>
27 #include <xmloff/xmlement.hxx>
28 #include <xmloff/xmlstyle.hxx>
29 #include <xmloff/prstylei.hxx>
30 #include <xmloff/nmspmap.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  sal_uInt16 nPrefix,
84  const OUString& rLocalName,
85  OUString& rAddress );
86  virtual void StartElement( const Reference< css::xml::sax::XAttributeList >& xAttrList ) override;
87 };
88 
89 class DateScaleContext : public SvXMLImportContext
90 {
91 public:
92  DateScaleContext( SvXMLImport& rImport,
93  sal_uInt16 nPrefix, const OUString& rLocalName,
94  const Reference< beans::XPropertySet >& rAxisProps );
95 
96  virtual void StartElement( const Reference< css::xml::sax::XAttributeList >& xAttrList ) override;
97 
98 private:
100 };
101 
102 }
103 
105  SvXMLImport& rImport, const OUString& rLocalName,
106  Reference< chart::XDiagram > const & xDiagram,
107  std::vector< SchXMLAxis >& rAxes,
108  OUString & rCategoriesAddress,
109  bool bAddMissingXAxisForNetCharts,
110  bool bAdaptWrongPercentScaleValues,
111  bool bAdaptXAxisOrientationForOld2DBarCharts,
112  bool& rbAxisPositionAttributeImported ) :
113  SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
114  m_rImportHelper( rImpHelper ),
115  m_xDiagram( xDiagram ),
116  m_rAxes( rAxes ),
117  m_rCategoriesAddress( rCategoriesAddress ),
118  m_nAxisType(chart::ChartAxisType::AUTOMATIC),
119  m_bAxisTypeImported(false),
120  m_bDateScaleImported(false),
121  m_bAddMissingXAxisForNetCharts( bAddMissingXAxisForNetCharts ),
122  m_bAdaptWrongPercentScaleValues( bAdaptWrongPercentScaleValues ),
123  m_bAdaptXAxisOrientationForOld2DBarCharts( bAdaptXAxisOrientationForOld2DBarCharts ),
124  m_rbAxisPositionAttributeImported( rbAxisPositionAttributeImported )
125 {
126 }
127 
129 {}
130 
132 {
134  Reference< chart::XAxisSupplier > xAxisSuppl( rDiagram, uno::UNO_QUERY );
135  if( !xAxisSuppl.is() )
136  return xAxis;
137  if( rCurrentAxis.nAxisIndex == 0 )
138  xAxis = xAxisSuppl->getAxis(rCurrentAxis.eDimension);
139  else
140  xAxis = xAxisSuppl->getSecondaryAxis(rCurrentAxis.eDimension);
141  return xAxis;
142 }
143 
144 /* returns a shape for the current axis's title. The property
145  "Has...AxisTitle" is set to "True" to get the shape
146  */
148 {
150  Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY );
152  if( !xDiaProp.is() || !xAxis.is() )
153  return xResult;
154 
155  OUString aPropName;
156  switch( m_aCurrentAxis.eDimension )
157  {
158  case SCH_XML_AXIS_X:
159  if( m_aCurrentAxis.nAxisIndex == 0 )
160  aPropName = "HasXAxisTitle";
161  else
162  aPropName = "HasSecondaryXAxisTitle";
163  break;
164  case SCH_XML_AXIS_Y:
165  if( m_aCurrentAxis.nAxisIndex == 0 )
166  aPropName = "HasYAxisTitle";
167  else
168  aPropName = "HasSecondaryYAxisTitle";
169  break;
170  case SCH_XML_AXIS_Z:
171  aPropName = "HasZAxisTitle";
172  break;
173  case SCH_XML_AXIS_UNDEF:
174  SAL_INFO("xmloff.chart", "Invalid axis" );
175  break;
176  }
177  xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) );
178  xResult.set( xAxis->getAxisTitle(), uno::UNO_QUERY );
179  return xResult;
180 }
181 
182 void SchXMLAxisContext::CreateGrid( const OUString& sAutoStyleName, bool bIsMajor )
183 {
184  Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY );
186  if( !xDiaProp.is() || !xAxis.is() )
187  return;
188 
189  OUString aPropName;
190  switch( m_aCurrentAxis.eDimension )
191  {
192  case SCH_XML_AXIS_X:
193  if( bIsMajor )
194  aPropName = "HasXAxisGrid";
195  else
196  aPropName = "HasXAxisHelpGrid";
197  break;
198  case SCH_XML_AXIS_Y:
199  if( bIsMajor )
200  aPropName = "HasYAxisGrid";
201  else
202  aPropName = "HasYAxisHelpGrid";
203  break;
204  case SCH_XML_AXIS_Z:
205  if( bIsMajor )
206  aPropName = "HasZAxisGrid";
207  else
208  aPropName = "HasZAxisHelpGrid";
209  break;
210  case SCH_XML_AXIS_UNDEF:
211  SAL_INFO("xmloff.chart", "Invalid axis" );
212  break;
213  }
214  xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) );
215 
217  if( bIsMajor )
218  xGridProp = xAxis->getMajorGrid();
219  else
220  xGridProp = xAxis->getMinorGrid();
221 
222  // set properties
223  if( xGridProp.is())
224  {
225  // the line color is black as default, in the model it is a light gray
226  xGridProp->setPropertyValue("LineColor",
227  uno::makeAny( COL_BLACK ));
228  if (!sAutoStyleName.isEmpty())
229  m_rImportHelper.FillAutoStyle(sAutoStyleName, xGridProp);
230  }
231 }
232 
233 namespace
234 {
236 {
237  XML_TOK_AXIS_DIMENSION,
238  XML_TOK_AXIS_NAME,
239  XML_TOK_AXIS_STYLE_NAME,
240  XML_TOK_AXIS_TYPE,
241  XML_TOK_AXIS_TYPE_EXT
242 };
243 
244 const SvXMLTokenMapEntry aAxisAttributeTokenMap[] =
245 {
246  { XML_NAMESPACE_CHART, XML_DIMENSION, XML_TOK_AXIS_DIMENSION },
247  { XML_NAMESPACE_CHART, XML_NAME, XML_TOK_AXIS_NAME },
248  { XML_NAMESPACE_CHART, XML_STYLE_NAME, XML_TOK_AXIS_STYLE_NAME },
249  { XML_NAMESPACE_CHART, XML_AXIS_TYPE, XML_TOK_AXIS_TYPE },
250  { XML_NAMESPACE_CHART_EXT, XML_AXIS_TYPE, XML_TOK_AXIS_TYPE_EXT },
252 };
253 
254 class AxisAttributeTokenMap : public SvXMLTokenMap
255 {
256 public:
257  AxisAttributeTokenMap(): SvXMLTokenMap( aAxisAttributeTokenMap ) {}
258  virtual ~AxisAttributeTokenMap() {}
259 };
260 
261 //a AxisAttributeTokenMap Singleton
262 struct theAxisAttributeTokenMap : public rtl::Static< AxisAttributeTokenMap, theAxisAttributeTokenMap > {};
263 }
264 
266 {
267  // parse attributes
268  sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
269  const SvXMLTokenMap& rAttrTokenMap = theAxisAttributeTokenMap::get();
270 
271  for( sal_Int16 i = 0; i < nAttrCount; i++ )
272  {
273  OUString sAttrName = xAttrList->getNameByIndex( i );
274  OUString aLocalName;
275  OUString aValue = xAttrList->getValueByIndex( i );
276  sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
277 
278  switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
279  {
280  case XML_TOK_AXIS_DIMENSION:
281  {
282  SchXMLAxisDimension nEnumVal;
283  if( SvXMLUnitConverter::convertEnum( nEnumVal, aValue, aXMLAxisDimensionMap ))
284  m_aCurrentAxis.eDimension = nEnumVal;
285  }
286  break;
287  case XML_TOK_AXIS_NAME:
288  m_aCurrentAxis.aName = aValue;
289  break;
290  case XML_TOK_AXIS_TYPE:
291  case XML_TOK_AXIS_TYPE_EXT:
292  sal_uInt16 nEnumVal;
293  if( SvXMLUnitConverter::convertEnum( nEnumVal, aValue, aXMLAxisTypeMap ))
294  {
295  m_nAxisType = nEnumVal;
296  m_bAxisTypeImported = true;
297  }
298  break;
299  case XML_TOK_AXIS_STYLE_NAME:
300  m_aAutoStyleName = aValue;
301  break;
302  }
303  }
304 
305  // check for number of axes with same dimension
307  sal_Int32 nNumOfAxes = m_rAxes.size();
308  for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ )
309  {
310  if( m_rAxes[ nCurrent ].eDimension == m_aCurrentAxis.eDimension )
312  }
313  CreateAxis();
314 }
315 namespace
316 {
317 
318 Reference< chart2::XAxis > lcl_getAxis( const Reference< frame::XModel >& xChartModel,
319  sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
320 {
322 
323  try
324  {
325  Reference< chart2::XChartDocument > xChart2Document( xChartModel, uno::UNO_QUERY );
326  if( xChart2Document.is() )
327  {
328  Reference< chart2::XDiagram > xDiagram( xChart2Document->getFirstDiagram());
329  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
330  uno::Sequence< Reference< chart2::XCoordinateSystem > >
331  aCooSysSeq( xCooSysCnt->getCoordinateSystems());
332  sal_Int32 nCooSysIndex = 0;
333  if( nCooSysIndex < aCooSysSeq.getLength() )
334  {
335  Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] );
336  if( xCooSys.is() && nDimensionIndex < xCooSys->getDimension() )
337  {
338  const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
339  if( nAxisIndex <= nMaxAxisIndex )
340  xAxis = xCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex );
341  }
342  }
343  }
344  }
345  catch( uno::Exception & )
346  {
347  SAL_INFO("xmloff.chart", "Couldn't get axis" );
348  }
349 
350  return xAxis;
351 }
352 
353 bool lcl_divideBy100( uno::Any& rDoubleAny )
354 {
355  bool bChanged = false;
356  double fValue=0.0;
357  if( (rDoubleAny>>=fValue) && (fValue!=0.0) )
358  {
359  fValue/=100.0;
360  rDoubleAny <<= fValue;
361  bChanged = true;
362  }
363  return bChanged;
364 }
365 
366 bool lcl_AdaptWrongPercentScaleValues(chart2::ScaleData& rScaleData)
367 {
368  bool bChanged = lcl_divideBy100( rScaleData.Minimum );
369  bChanged = lcl_divideBy100( rScaleData.Maximum ) || bChanged;
370  bChanged = lcl_divideBy100( rScaleData.Origin ) || bChanged;
371  bChanged = lcl_divideBy100( rScaleData.IncrementData.Distance ) || bChanged;
372  return bChanged;
373 }
374 
375 }//end anonymous namespace
376 
378 {
379  m_rAxes.push_back( m_aCurrentAxis );
380 
381  Reference< beans::XPropertySet > xDiaProp( m_rImportHelper.GetChartDocument()->getDiagram(), uno::UNO_QUERY );
382  if( !xDiaProp.is() )
383  return;
384  OUString aPropName;
385  switch( m_aCurrentAxis.eDimension )
386  {
387  case SCH_XML_AXIS_X:
388  if( m_aCurrentAxis.nAxisIndex == 0 )
389  aPropName = "HasXAxis";
390  else
391  aPropName = "HasSecondaryXAxis";
392  break;
393  case SCH_XML_AXIS_Y:
394  if( m_aCurrentAxis.nAxisIndex == 0 )
395  aPropName = "HasYAxis";
396  else
397  aPropName = "HasSecondaryYAxis";
398  break;
399  case SCH_XML_AXIS_Z:
400  if( m_aCurrentAxis.nAxisIndex == 0 )
401  aPropName = "HasZAxis";
402  break;
403  case SCH_XML_AXIS_UNDEF:
404  SAL_INFO("xmloff.chart", "Invalid axis" );
405  break;
406  }
407  try
408  {
409  xDiaProp->setPropertyValue( aPropName, uno::makeAny(true) );
410  }
411  catch( beans::UnknownPropertyException & )
412  {
413  SAL_INFO("xmloff.chart", "Couldn't turn on axis" );
414  }
416  {
417  bool bSettingZAxisSuccedded = false;
418  try
419  {
420  xDiaProp->getPropertyValue( aPropName ) >>= bSettingZAxisSuccedded;
421  }
422  catch( beans::UnknownPropertyException & )
423  {
424  SAL_INFO("xmloff.chart", "Couldn't turn on z axis" );
425  }
426  if( !bSettingZAxisSuccedded )
427  return;
428  }
429 
430  m_xAxisProps.set( lcl_getChartAxis( m_aCurrentAxis, m_xDiagram ), uno::UNO_QUERY );
431 
433  {
434  try
435  {
436  xDiaProp->setPropertyValue("HasXAxis", uno::makeAny(true) );
437  }
438  catch( beans::UnknownPropertyException & )
439  {
440  SAL_INFO("xmloff.chart", "Couldn't turn on x axis" );
441  }
442  }
443 
444  // set properties
445  if( m_xAxisProps.is())
446  {
447  uno::Any aTrueBool( uno::makeAny( true ));
448  uno::Any aFalseBool( uno::makeAny( false ));
449 
450  // #i109879# the line color is black as default, in the model it is a light gray
451  m_xAxisProps->setPropertyValue("LineColor",
452  uno::makeAny( COL_BLACK ));
453 
454  m_xAxisProps->setPropertyValue("DisplayLabels", aFalseBool );
455 
456  // Compatibility option: starting from LibreOffice 5.1 the rotated
457  // layout is preferred to staggering for axis labels.
458  // So the import default value for having compatibility with ODF
459  // documents created with earlier LibreOffice versions is `true`.
460  if( GetImport().getGeneratorVersion() != SvXMLImport::ProductVersionUnknown )
461  m_xAxisProps->setPropertyValue("TryStaggeringFirst", aTrueBool );
462 
463  // #88077# AutoOrigin 'on' is default
464  m_xAxisProps->setPropertyValue("AutoOrigin", aTrueBool );
465 
466  if( m_bAxisTypeImported )
467  m_xAxisProps->setPropertyValue("AxisType", uno::makeAny(m_nAxisType) );
468 
469  if( !m_aAutoStyleName.isEmpty())
470  {
472  if (pStylesCtxt)
473  {
475 
476  if (XMLPropStyleContext * pPropStyleContext = dynamic_cast<XMLPropStyleContext*>(pStyle))
477  {
478  pPropStyleContext->FillPropertySet(m_xAxisProps);
479 
481  {
482  //set scale data of added x axis back to default
483  Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(),
485  if( xAxis.is() )
486  {
487  chart2::ScaleData aScaleData( xAxis->getScaleData());
488  if( lcl_AdaptWrongPercentScaleValues(aScaleData) )
489  xAxis->setScaleData( aScaleData );
490  }
491  }
492 
494  {
495  //copy style from y axis to added x axis:
496 
497  Reference< chart::XAxisSupplier > xAxisSuppl( xDiaProp, uno::UNO_QUERY );
498  if( xAxisSuppl.is() )
499  {
500  Reference< beans::XPropertySet > xXAxisProp( xAxisSuppl->getAxis(0), uno::UNO_QUERY );
501  pPropStyleContext->FillPropertySet(xXAxisProp);
502  }
503 
504  //set scale data of added x axis back to default
505  Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(),
506  0 /*nDimensionIndex*/, 0 /*nAxisIndex*/ ) );
507  if( xAxis.is() )
508  {
509  chart2::ScaleData aScaleData;
510  aScaleData.AxisType = chart2::AxisType::CATEGORY;
511  aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL;
512  xAxis->setScaleData( aScaleData );
513  }
514 
515  //set line style of added x axis to invisible
516  Reference< beans::XPropertySet > xNewAxisProp( xAxis, uno::UNO_QUERY );
517  if( xNewAxisProp.is() )
518  {
519  xNewAxisProp->setPropertyValue("LineStyle"
520  , uno::makeAny(drawing::LineStyle_NONE));
521  }
522  }
523 
525  {
526  bool bIs3DChart = false;
527  if( xDiaProp.is() && ( xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart )
528  && !bIs3DChart )
529  {
530  Reference< chart2::XChartDocument > xChart2Document( GetImport().GetModel(), uno::UNO_QUERY );
531  if( xChart2Document.is() )
532  {
533  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChart2Document->getFirstDiagram(), uno::UNO_QUERY );
534  if( xCooSysCnt.is() )
535  {
536  uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() );
537  if( aCooSysSeq.hasElements() )
538  {
539  bool bSwapXandYAxis = false;
540  Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] );
541  Reference< beans::XPropertySet > xCooSysProp( xCooSys, uno::UNO_QUERY );
542  if( xCooSysProp.is() && ( xCooSysProp->getPropertyValue("SwapXAndYAxis") >>= bSwapXandYAxis )
543  && bSwapXandYAxis )
544  {
545  Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( 0, m_aCurrentAxis.nAxisIndex );
546  if( xAxis.is() )
547  {
548  chart2::ScaleData aScaleData = xAxis->getScaleData();
549  aScaleData.Orientation = chart2::AxisOrientation_REVERSE;
550  xAxis->setScaleData( aScaleData );
551  }
552  }
553  }
554  }
555  }
556  }
557  }
558 
560  "CrossoverPosition", pPropStyleContext, pStylesCtxt ).hasValue();
561  }
562  }
563  }
564 
566  {
568  if (xAxis.is())
569  {
570  chart2::ScaleData aScaleData(xAxis->getScaleData());
571  bool bIs3DChart = false;
572  double fMajorOrigin = -1;
573  OUString sChartType = m_xDiagram->getDiagramType();
574  if ((xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart) && bIs3DChart
575  && (sChartType == "com.sun.star.chart.BarDiagram" || sChartType == "com.sun.star.chart.StockDiagram"))
576  {
577  aScaleData.ShiftedCategoryPosition = true;
578  xAxis->setScaleData(aScaleData);
579  }
580  else if ((m_xAxisProps->getPropertyValue("MajorOrigin") >>= fMajorOrigin)
581  && (rtl::math::approxEqual(fMajorOrigin, 0.0) || rtl::math::approxEqual(fMajorOrigin, 0.5)))
582  {
583  aScaleData.ShiftedCategoryPosition = rtl::math::approxEqual(fMajorOrigin, 0.5);
584  xAxis->setScaleData(aScaleData);
585  }
586  }
587  }
588  }
589 }
590 
592 {
593  if( m_aCurrentAxis.aTitle.isEmpty() )
594  return;
595 
597  if( !xAxis.is() )
598  return;
599 
600  Reference< beans::XPropertySet > xTitleProp( xAxis->getAxisTitle() );
601  if( xTitleProp.is() )
602  {
603  try
604  {
605  xTitleProp->setPropertyValue("String", uno::makeAny(m_aCurrentAxis.aTitle) );
606  }
607  catch( beans::UnknownPropertyException & )
608  {
609  SAL_INFO("xmloff.chart", "Property String for Title not available" );
610  }
611  }
612 }
613 
614 namespace
615 {
617 {
618  XML_TOK_AXIS_TITLE,
619  XML_TOK_AXIS_CATEGORIES,
620  XML_TOK_AXIS_GRID,
621  XML_TOK_AXIS_DATE_SCALE,
622  XML_TOK_AXIS_DATE_SCALE_EXT
623 };
624 
625 const SvXMLTokenMapEntry aAxisChildTokenMap[] =
626 {
627  { XML_NAMESPACE_CHART, XML_TITLE, XML_TOK_AXIS_TITLE },
628  { XML_NAMESPACE_CHART, XML_CATEGORIES, XML_TOK_AXIS_CATEGORIES },
629  { XML_NAMESPACE_CHART, XML_GRID, XML_TOK_AXIS_GRID },
630  { XML_NAMESPACE_CHART, XML_DATE_SCALE, XML_TOK_AXIS_DATE_SCALE },
631  { XML_NAMESPACE_CHART_EXT, XML_DATE_SCALE, XML_TOK_AXIS_DATE_SCALE_EXT },
633 };
634 
635 class AxisChildTokenMap : public SvXMLTokenMap
636 {
637 public:
638  AxisChildTokenMap(): SvXMLTokenMap( aAxisChildTokenMap ) {}
639  virtual ~AxisChildTokenMap() {}
640 };
641 
642 //a AxisChildTokenMap Singleton
643 struct theAxisChildTokenMap : public rtl::Static< AxisChildTokenMap, theAxisChildTokenMap > {};
644 }
645 
647  sal_uInt16 p_nPrefix,
648  const OUString& rLocalName,
649  const Reference< xml::sax::XAttributeList >& xAttrList )
650 {
651  SvXMLImportContext* pContext = nullptr;
652  const SvXMLTokenMap& rTokenMap = theAxisChildTokenMap::get();
653 
654  switch( rTokenMap.Get( p_nPrefix, rLocalName ))
655  {
656  case XML_TOK_AXIS_TITLE:
657  {
659  pContext = new SchXMLTitleContext( m_rImportHelper, GetImport(), rLocalName,
661  xTitleShape );
662  }
663  break;
664 
665  case XML_TOK_AXIS_CATEGORIES:
666  pContext = new SchXMLCategoriesContext( GetImport(),
667  p_nPrefix, rLocalName,
670  break;
671 
672  case XML_TOK_AXIS_DATE_SCALE:
673  case XML_TOK_AXIS_DATE_SCALE_EXT:
674  pContext = new DateScaleContext( GetImport(),
675  p_nPrefix, rLocalName, m_xAxisProps );
676  m_bDateScaleImported = true;
677  break;
678 
679  case XML_TOK_AXIS_GRID:
680  {
681  sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
682  bool bIsMajor = true; // default value for class is "major"
683  OUString sAutoStyleName;
684 
685  for( sal_Int16 i = 0; i < nAttrCount; i++ )
686  {
687  OUString sAttrName = xAttrList->getNameByIndex( i );
688  OUString aLocalName;
689  sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
690 
691  if( nPrefix == XML_NAMESPACE_CHART )
692  {
693  if( IsXMLToken( aLocalName, XML_CLASS ) )
694  {
695  if( IsXMLToken( xAttrList->getValueByIndex( i ), XML_MINOR ) )
696  bIsMajor = false;
697  }
698  else if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
699  sAutoStyleName = xAttrList->getValueByIndex( i );
700  }
701  }
702 
703  CreateGrid( sAutoStyleName, bIsMajor );
704 
705  // don't create a context => use default context. grid elements are empty
706  }
707  break;
708 
709  default:
710  break;
711  }
712 
713  return pContext;
714 }
715 
717 {
718  if( !m_bDateScaleImported && m_nAxisType==chart::ChartAxisType::AUTOMATIC )
719  {
721  if( xAxis.is() )
722  {
723  chart2::ScaleData aScaleData( xAxis->getScaleData());
724  aScaleData.AutoDateAxis = false;//different default for older documents
725  xAxis->setScaleData( aScaleData );
726  }
727  }
728 
729  SetAxisTitle();
730 }
731 
732 namespace
733 {
734 
735 Reference< chart2::XAxis > lcl_getAxis( const Reference< chart2::XCoordinateSystem >& rCooSys, sal_Int32 nDimensionIndex, sal_Int32 nAxisIndex )
736 {
738  try
739  {
740  xAxis = rCooSys->getAxisByDimension( nDimensionIndex, nAxisIndex );
741  }
742  catch( uno::Exception & )
743  {
744  }
745  return xAxis;
746 }
747 
748 } // anonymous namespace
749 
751  const OUString& rChartTypeServiceName,
752  const OUString& rODFVersionOfFile,
753  bool bAxisPositionAttributeImported )
754 {
755  if( rODFVersionOfFile.isEmpty() || rODFVersionOfFile == "1.0" || rODFVersionOfFile == "1.1"
756  || ( rODFVersionOfFile == "1.2" && !bAxisPositionAttributeImported ) )
757  {
758  try
759  {
760  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDoc->getFirstDiagram(), uno::UNO_QUERY_THROW );
761  uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
762  if( aCooSysSeq.hasElements() )
763  {
764  Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] );
765  if( xCooSys.is() )
766  {
767  Reference< chart2::XAxis > xMainXAxis = lcl_getAxis( xCooSys, 0, 0 );
768  Reference< chart2::XAxis > xMainYAxis = lcl_getAxis( xCooSys, 1, 0 );
769  //Reference< chart2::XAxis > xMajorZAxis = lcl_getAxis( xCooSys, 2, 0 );
770  Reference< chart2::XAxis > xSecondaryXAxis = lcl_getAxis( xCooSys, 0, 1 );
771  Reference< chart2::XAxis > xSecondaryYAxis = lcl_getAxis( xCooSys, 1, 1 );
772 
773  Reference< beans::XPropertySet > xMainXAxisProp( xMainXAxis, uno::UNO_QUERY );
774  Reference< beans::XPropertySet > xMainYAxisProp( xMainYAxis, uno::UNO_QUERY );
775  Reference< beans::XPropertySet > xSecondaryXAxisProp( xSecondaryXAxis, uno::UNO_QUERY );
776  Reference< beans::XPropertySet > xSecondaryYAxisProp( xSecondaryYAxis, uno::UNO_QUERY );
777 
778  if( xMainXAxisProp.is() && xMainYAxisProp.is() )
779  {
780  chart2::ScaleData aMainXScale = xMainXAxis->getScaleData();
781  if( rChartTypeServiceName == "com.sun.star.chart2.ScatterChartType" )
782  {
783  xMainYAxisProp->setPropertyValue("CrossoverPosition"
784  , uno::makeAny( css::chart::ChartAxisPosition_VALUE) );
785  double fCrossoverValue = 0.0;
786  aMainXScale.Origin >>= fCrossoverValue;
787  xMainYAxisProp->setPropertyValue("CrossoverValue"
788  , uno::makeAny( fCrossoverValue ) );
789 
790  if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE )
791  {
792  xMainYAxisProp->setPropertyValue("LabelPosition"
793  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_END) );
794  xMainYAxisProp->setPropertyValue("MarkPosition"
795  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
796  if( xSecondaryYAxisProp.is() )
797  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
798  , uno::makeAny( css::chart::ChartAxisPosition_START) );
799  }
800  else
801  {
802  xMainYAxisProp->setPropertyValue("LabelPosition"
803  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_START) );
804  xMainYAxisProp->setPropertyValue("MarkPosition"
805  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
806  if( xSecondaryYAxisProp.is() )
807  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
808  , uno::makeAny( css::chart::ChartAxisPosition_END) );
809  }
810  }
811  else
812  {
813  if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE )
814  {
815  xMainYAxisProp->setPropertyValue("CrossoverPosition"
816  , uno::makeAny( css::chart::ChartAxisPosition_END) );
817  if( xSecondaryYAxisProp.is() )
818  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
819  , uno::makeAny( css::chart::ChartAxisPosition_START) );
820  }
821  else
822  {
823  xMainYAxisProp->setPropertyValue("CrossoverPosition"
824  , uno::makeAny( css::chart::ChartAxisPosition_START) );
825  if( xSecondaryYAxisProp.is() )
826  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
827  , uno::makeAny( css::chart::ChartAxisPosition_END) );
828  }
829  }
830 
831  chart2::ScaleData aMainYScale = xMainYAxis->getScaleData();
832  xMainXAxisProp->setPropertyValue("CrossoverPosition"
833  , uno::makeAny( css::chart::ChartAxisPosition_VALUE) );
834  double fCrossoverValue = 0.0;
835  aMainYScale.Origin >>= fCrossoverValue;
836  xMainXAxisProp->setPropertyValue("CrossoverValue"
837  , uno::makeAny( fCrossoverValue ) );
838 
839  if( aMainYScale.Orientation == chart2::AxisOrientation_REVERSE )
840  {
841  xMainXAxisProp->setPropertyValue("LabelPosition"
842  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_END) );
843  xMainXAxisProp->setPropertyValue("MarkPosition"
844  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
845  if( xSecondaryXAxisProp.is() )
846  xSecondaryXAxisProp->setPropertyValue("CrossoverPosition"
847  , uno::makeAny( css::chart::ChartAxisPosition_START) );
848  }
849  else
850  {
851  xMainXAxisProp->setPropertyValue("LabelPosition"
852  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_START) );
853  xMainXAxisProp->setPropertyValue("MarkPosition"
854  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
855  if( xSecondaryXAxisProp.is() )
856  xSecondaryXAxisProp->setPropertyValue("CrossoverPosition"
857  , uno::makeAny( css::chart::ChartAxisPosition_END) );
858  }
859  }
860  }
861  }
862  }
863  catch( uno::Exception & )
864  {
865  }
866  }
867 }
868 
869 SchXMLCategoriesContext::SchXMLCategoriesContext(
870  SvXMLImport& rImport,
871  sal_uInt16 nPrefix,
872  const OUString& rLocalName,
873  OUString& rAddress ) :
874  SvXMLImportContext( rImport, nPrefix, rLocalName ),
875  mrAddress( rAddress )
876 {
877 }
878 
879 void SchXMLCategoriesContext::StartElement( const Reference< xml::sax::XAttributeList >& xAttrList )
880 {
881  sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
882 
883  for( sal_Int16 i = 0; i < nAttrCount; i++ )
884  {
885  OUString sAttrName = xAttrList->getNameByIndex( i );
886  OUString aLocalName;
887  sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
888 
889  if( nPrefix == XML_NAMESPACE_TABLE &&
890  IsXMLToken( aLocalName, XML_CELL_RANGE_ADDRESS ) )
891  {
892  mrAddress = xAttrList->getValueByIndex( i );
893  }
894  }
895 }
896 
897 DateScaleContext::DateScaleContext(
898  SvXMLImport& rImport,
899  sal_uInt16 nPrefix,
900  const OUString& rLocalName,
901  const Reference< beans::XPropertySet >& rAxisProps ) :
902  SvXMLImportContext( rImport, nPrefix, rLocalName ),
903  m_xAxisProps( rAxisProps )
904 {
905 }
906 
907 namespace
908 {
910 {
911  XML_TOK_DATESCALE_BASE_TIME_UNIT,
912  XML_TOK_DATESCALE_MAJOR_INTERVAL_VALUE,
913  XML_TOK_DATESCALE_MAJOR_INTERVAL_UNIT,
914  XML_TOK_DATESCALE_MINOR_INTERVAL_VALUE,
915  XML_TOK_DATESCALE_MINOR_INTERVAL_UNIT
916 };
917 
918 const SvXMLTokenMapEntry aDateScaleAttributeTokenMap[] =
919 {
920  { XML_NAMESPACE_CHART, XML_BASE_TIME_UNIT, XML_TOK_DATESCALE_BASE_TIME_UNIT },
921  { XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_VALUE, XML_TOK_DATESCALE_MAJOR_INTERVAL_VALUE },
922  { XML_NAMESPACE_CHART, XML_MAJOR_INTERVAL_UNIT, XML_TOK_DATESCALE_MAJOR_INTERVAL_UNIT },
923  { XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_VALUE, XML_TOK_DATESCALE_MINOR_INTERVAL_VALUE },
924  { XML_NAMESPACE_CHART, XML_MINOR_INTERVAL_UNIT, XML_TOK_DATESCALE_MINOR_INTERVAL_UNIT },
926 };
927 
928 class DateScaleAttributeTokenMap : public SvXMLTokenMap
929 {
930 public:
931  DateScaleAttributeTokenMap(): SvXMLTokenMap( aDateScaleAttributeTokenMap ) {}
932  virtual ~DateScaleAttributeTokenMap() {}
933 };
934 
935 struct theDateScaleAttributeTokenMap : public rtl::Static< DateScaleAttributeTokenMap, theDateScaleAttributeTokenMap > {};
936 
937 sal_Int32 lcl_getTimeUnit( const OUString& rValue )
938 {
939  sal_Int32 nTimeUnit = css::chart::TimeUnit::DAY;
940  if( IsXMLToken( rValue, XML_DAYS ) )
941  nTimeUnit = css::chart::TimeUnit::DAY;
942  else if( IsXMLToken( rValue, XML_MONTHS ) )
943  nTimeUnit = css::chart::TimeUnit::MONTH;
944  else if( IsXMLToken( rValue, XML_YEARS ) )
945  nTimeUnit = css::chart::TimeUnit::YEAR;
946  return nTimeUnit;
947 }
948 
949 }
950 
951 void DateScaleContext::StartElement( const Reference< xml::sax::XAttributeList >& xAttrList )
952 {
953  if( !m_xAxisProps.is() )
954  return;
955 
956  // parse attributes
957  sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
958  const SvXMLTokenMap& rAttrTokenMap = theDateScaleAttributeTokenMap::get();
959 
960  bool bSetNewIncrement=false;
961  chart::TimeIncrement aIncrement;
962  m_xAxisProps->getPropertyValue("TimeIncrement") >>= aIncrement;
963 
964  for( sal_Int16 i = 0; i < nAttrCount; i++ )
965  {
966  OUString sAttrName = xAttrList->getNameByIndex( i );
967  OUString aLocalName;
968  OUString aValue = xAttrList->getValueByIndex( i );
969  sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
970 
971  switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
972  {
973  case XML_TOK_DATESCALE_BASE_TIME_UNIT:
974  {
975  aIncrement.TimeResolution <<= lcl_getTimeUnit(aValue);
976  bSetNewIncrement = true;
977  }
978  break;
979  case XML_TOK_DATESCALE_MAJOR_INTERVAL_VALUE:
980  {
981  chart::TimeInterval aInterval(1,0);
982  aIncrement.MajorTimeInterval >>= aInterval;
983  ::sax::Converter::convertNumber( aInterval.Number, aValue );
984  aIncrement.MajorTimeInterval <<= aInterval;
985  bSetNewIncrement = true;
986  }
987  break;
988  case XML_TOK_DATESCALE_MAJOR_INTERVAL_UNIT:
989  {
990  chart::TimeInterval aInterval(1,0);
991  aIncrement.MajorTimeInterval >>= aInterval;
992  aInterval.TimeUnit = lcl_getTimeUnit(aValue);
993  aIncrement.MajorTimeInterval <<= aInterval;
994  bSetNewIncrement = true;
995  }
996  break;
997  case XML_TOK_DATESCALE_MINOR_INTERVAL_VALUE:
998  {
999  chart::TimeInterval aInterval(1,0);
1000  aIncrement.MinorTimeInterval >>= aInterval;
1001  ::sax::Converter::convertNumber( aInterval.Number, aValue );
1002  aIncrement.MinorTimeInterval <<= aInterval;
1003  bSetNewIncrement = true;
1004  }
1005  break;
1006  case XML_TOK_DATESCALE_MINOR_INTERVAL_UNIT:
1007  {
1008  chart::TimeInterval aInterval(1,0);
1009  aIncrement.MinorTimeInterval >>= aInterval;
1010  aInterval.TimeUnit = lcl_getTimeUnit(aValue);
1011  aIncrement.MinorTimeInterval <<= aInterval;
1012  bSetNewIncrement = true;
1013  }
1014  break;
1015  }
1016  }
1017 
1018  if( bSetNewIncrement )
1019  m_xAxisProps->setPropertyValue("TimeIncrement", uno::makeAny( aIncrement ) );
1020 }
1021 
1022 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsXMLToken(const OUString &rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3422
static const SvXMLEnumMapEntry< sal_uInt16 > aXMLAxisTypeMap[]
bool hasValue()
constexpr::Color COL_BLACK(0x00, 0x00, 0x00)
static bool convertEnum(EnumT &rEnum, const OUString &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:128
constexpr sal_uInt16 XML_NAMESPACE_CHART_EXT
Definition: xmlnmspe.hxx:77
SvXMLStylesContext * GetAutoStylesContext() const
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:62
constexpr sal_uInt16 XML_NAMESPACE_CHART
Definition: xmlnmspe.hxx:41
sal_Int8 nAxisIndex
SchXMLAxisDimension
css::uno::Reference< css::drawing::XShape > getTitleShape() const
SvXMLNamespaceMap & GetNamespaceMap()
Definition: xmlimp.hxx:397
css::uno::Reference< css::chart::XDiagram > m_xDiagram
virtual void StartElement(const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList) override
StartElement is called after a context has been constructed and before an elements context is parsed...
void FillAutoStyle(const OUString &rAutoStyleName, const css::uno::Reference< css::beans::XPropertySet > &rProp)
Fill in the autostyle.
sal_uInt16 GetKeyByAttrName(const OUString &rAttrName, OUString *pPrefix, OUString *pLocalName, OUString *pNamespace) const
Definition: nmspmap.cxx:437
bool & m_rbAxisPositionAttributeImported
#define XML_TOKEN_MAP_END
Definition: xmltkmap.hxx:33
css::uno::Any const & rValue
Definition: ImageStyle.hxx:38
static const sal_uInt16 ProductVersionUnknown
Definition: xmlimp.hxx:561
SchXMLAxisContext(SchXMLImportHelper &rImpHelper, SvXMLImport &rImport, const OUString &rLocalName, css::uno::Reference< css::chart::XDiagram > const &xDiagram, std::vector< SchXMLAxis > &aAxes, OUString &rCategoriesAddress, bool bAddMissingXAxisForNetCharts, bool bAdaptWrongPercentScaleValues, bool bAdaptXAxisOrientationForOld2DBarCharts, bool &rbAxisPositionAttributeImported)
std::vector< SchXMLAxis > & m_rAxes
OUString aTitle
DateScaleAttributeTokens
AxisAttributeTokens
bool m_bAdaptXAxisOrientationForOld2DBarCharts
int i
enum SchXMLAxisDimension eDimension
static Reference< chart::XAxis > lcl_getChartAxis(const SchXMLAxis &rCurrentAxis, const Reference< chart::XDiagram > &rDiagram)
virtual SvXMLImportContextRef CreateChildContext(sal_uInt16 nPrefix, const OUString &rLocalName, const css::uno::Reference< css::xml::sax::XAttributeList > &xAttrList) override
Create a children element context.
sal_uInt16 Get(sal_uInt16 nPrefix, const OUString &rLName) const
Definition: xmltkmap.cxx:93
static void CorrectAxisPositions(const css::uno::Reference< css::chart2::XChartDocument > &xNewDoc, const OUString &rChartTypeServiceName, const OUString &rODFVersionOfFile, bool bAxisPositionAttributeImported)
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...
AxisChildTokens
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:40
const css::uno::Reference< css::chart::XChartDocument > & GetChartDocument() const
Handling of tokens in XML:
virtual void EndElement() override
EndElement is called before a context will be destructed, but after an elements context has been pars...
constexpr sal_uInt16 XML_NAMESPACE_TABLE
Definition: xmlnmspe.hxx:32
#define SAL_INFO(area, stream)
const SvXMLStyleContext * FindStyleChildContext(XmlStyleFamily nFamily, const OUString &rName, bool bCreateIndex=false) const
Definition: xmlstyle.cxx:870
SchXMLImportHelper & m_rImportHelper
virtual ~SchXMLAxisContext() override
uno::Any getPropertyFromContext(const OUString &rPropertyName, const XMLPropStyleContext *pPropStyleContext, const SvXMLStylesContext *pStylesCtxt)
static 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)