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  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 bSettingZAxisSucceeded = false;
418  try
419  {
420  xDiaProp->getPropertyValue( aPropName ) >>= bSettingZAxisSucceeded;
421  }
422  catch( beans::UnknownPropertyException & )
423  {
424  SAL_INFO("xmloff.chart", "Couldn't turn on z axis" );
425  }
426  if( !bSettingZAxisSucceeded )
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  return;
447 
448  uno::Any aTrueBool( uno::makeAny( true ));
449  uno::Any aFalseBool( uno::makeAny( false ));
450 
451  // #i109879# the line color is black as default, in the model it is a light gray
452  m_xAxisProps->setPropertyValue("LineColor",
453  uno::makeAny( COL_BLACK ));
454 
455  m_xAxisProps->setPropertyValue("DisplayLabels", aFalseBool );
456 
457  // Compatibility option: starting from LibreOffice 5.1 the rotated
458  // layout is preferred to staggering for axis labels.
459  // So the import default value for having compatibility with ODF
460  // documents created with earlier LibreOffice versions is `true`.
461  if( GetImport().getGeneratorVersion() != SvXMLImport::ProductVersionUnknown )
462  m_xAxisProps->setPropertyValue("TryStaggeringFirst", aTrueBool );
463 
464  // #88077# AutoOrigin 'on' is default
465  m_xAxisProps->setPropertyValue("AutoOrigin", aTrueBool );
466 
467  if( m_bAxisTypeImported )
468  m_xAxisProps->setPropertyValue("AxisType", uno::makeAny(m_nAxisType) );
469 
470  if( !m_aAutoStyleName.isEmpty())
471  {
473  if (pStylesCtxt)
474  {
476 
477  if (XMLPropStyleContext * pPropStyleContext = dynamic_cast<XMLPropStyleContext*>(pStyle))
478  {
479  pPropStyleContext->FillPropertySet(m_xAxisProps);
480 
482  {
483  //set scale data of added x axis back to default
484  Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(),
486  if( xAxis.is() )
487  {
488  chart2::ScaleData aScaleData( xAxis->getScaleData());
489  if( lcl_AdaptWrongPercentScaleValues(aScaleData) )
490  xAxis->setScaleData( aScaleData );
491  }
492  }
493 
495  {
496  //copy style from y axis to added x axis:
497 
498  Reference< chart::XAxisSupplier > xAxisSuppl( xDiaProp, uno::UNO_QUERY );
499  if( xAxisSuppl.is() )
500  {
501  Reference< beans::XPropertySet > xXAxisProp( xAxisSuppl->getAxis(0), uno::UNO_QUERY );
502  pPropStyleContext->FillPropertySet(xXAxisProp);
503  }
504 
505  //set scale data of added x axis back to default
506  Reference< chart2::XAxis > xAxis( lcl_getAxis( GetImport().GetModel(),
507  0 /*nDimensionIndex*/, 0 /*nAxisIndex*/ ) );
508  if( xAxis.is() )
509  {
510  chart2::ScaleData aScaleData;
511  aScaleData.AxisType = chart2::AxisType::CATEGORY;
512  aScaleData.Orientation = chart2::AxisOrientation_MATHEMATICAL;
513  xAxis->setScaleData( aScaleData );
514  }
515 
516  //set line style of added x axis to invisible
517  Reference< beans::XPropertySet > xNewAxisProp( xAxis, uno::UNO_QUERY );
518  if( xNewAxisProp.is() )
519  {
520  xNewAxisProp->setPropertyValue("LineStyle"
521  , uno::makeAny(drawing::LineStyle_NONE));
522  }
523  }
524 
526  {
527  bool bIs3DChart = false;
528  if( xDiaProp.is() && ( xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart )
529  && !bIs3DChart )
530  {
531  Reference< chart2::XChartDocument > xChart2Document( GetImport().GetModel(), uno::UNO_QUERY );
532  if( xChart2Document.is() )
533  {
534  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xChart2Document->getFirstDiagram(), uno::UNO_QUERY );
535  if( xCooSysCnt.is() )
536  {
537  uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems() );
538  if( aCooSysSeq.hasElements() )
539  {
540  bool bSwapXandYAxis = false;
541  Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] );
542  Reference< beans::XPropertySet > xCooSysProp( xCooSys, uno::UNO_QUERY );
543  if( xCooSysProp.is() && ( xCooSysProp->getPropertyValue("SwapXAndYAxis") >>= bSwapXandYAxis )
544  && bSwapXandYAxis )
545  {
546  Reference< chart2::XAxis > xAxis = xCooSys->getAxisByDimension( 0, m_aCurrentAxis.nAxisIndex );
547  if( xAxis.is() )
548  {
549  chart2::ScaleData aScaleData = xAxis->getScaleData();
550  aScaleData.Orientation = chart2::AxisOrientation_REVERSE;
551  xAxis->setScaleData( aScaleData );
552  }
553  }
554  }
555  }
556  }
557  }
558  }
559 
561  "CrossoverPosition", pPropStyleContext, pStylesCtxt ).hasValue();
562  }
563  }
564  }
565 
567  return;
568 
570  if (!xAxis.is())
571  return;
572 
573  chart2::ScaleData aScaleData(xAxis->getScaleData());
574  bool bIs3DChart = false;
575  double fMajorOrigin = -1;
576  OUString sChartType = m_xDiagram->getDiagramType();
577  if ((xDiaProp->getPropertyValue("Dim3D") >>= bIs3DChart) && bIs3DChart
578  && (sChartType == "com.sun.star.chart.BarDiagram" || sChartType == "com.sun.star.chart.StockDiagram"))
579  {
580  aScaleData.ShiftedCategoryPosition = true;
581  xAxis->setScaleData(aScaleData);
582  }
583  else if ((m_xAxisProps->getPropertyValue("MajorOrigin") >>= fMajorOrigin)
584  && (rtl::math::approxEqual(fMajorOrigin, 0.0) || rtl::math::approxEqual(fMajorOrigin, 0.5)))
585  {
586  aScaleData.ShiftedCategoryPosition = rtl::math::approxEqual(fMajorOrigin, 0.5);
587  xAxis->setScaleData(aScaleData);
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  return;
758 
759  try
760  {
761  Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xNewDoc->getFirstDiagram(), uno::UNO_QUERY_THROW );
762  uno::Sequence< Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
763  if( aCooSysSeq.hasElements() )
764  {
765  Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[0] );
766  if( xCooSys.is() )
767  {
768  Reference< chart2::XAxis > xMainXAxis = lcl_getAxis( xCooSys, 0, 0 );
769  Reference< chart2::XAxis > xMainYAxis = lcl_getAxis( xCooSys, 1, 0 );
770  //Reference< chart2::XAxis > xMajorZAxis = lcl_getAxis( xCooSys, 2, 0 );
771  Reference< chart2::XAxis > xSecondaryXAxis = lcl_getAxis( xCooSys, 0, 1 );
772  Reference< chart2::XAxis > xSecondaryYAxis = lcl_getAxis( xCooSys, 1, 1 );
773 
774  Reference< beans::XPropertySet > xMainXAxisProp( xMainXAxis, uno::UNO_QUERY );
775  Reference< beans::XPropertySet > xMainYAxisProp( xMainYAxis, uno::UNO_QUERY );
776  Reference< beans::XPropertySet > xSecondaryXAxisProp( xSecondaryXAxis, uno::UNO_QUERY );
777  Reference< beans::XPropertySet > xSecondaryYAxisProp( xSecondaryYAxis, uno::UNO_QUERY );
778 
779  if( xMainXAxisProp.is() && xMainYAxisProp.is() )
780  {
781  chart2::ScaleData aMainXScale = xMainXAxis->getScaleData();
782  if( rChartTypeServiceName == "com.sun.star.chart2.ScatterChartType" )
783  {
784  xMainYAxisProp->setPropertyValue("CrossoverPosition"
785  , uno::makeAny( css::chart::ChartAxisPosition_VALUE) );
786  double fCrossoverValue = 0.0;
787  aMainXScale.Origin >>= fCrossoverValue;
788  xMainYAxisProp->setPropertyValue("CrossoverValue"
789  , uno::makeAny( fCrossoverValue ) );
790 
791  if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE )
792  {
793  xMainYAxisProp->setPropertyValue("LabelPosition"
794  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_END) );
795  xMainYAxisProp->setPropertyValue("MarkPosition"
796  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
797  if( xSecondaryYAxisProp.is() )
798  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
799  , uno::makeAny( css::chart::ChartAxisPosition_START) );
800  }
801  else
802  {
803  xMainYAxisProp->setPropertyValue("LabelPosition"
804  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_START) );
805  xMainYAxisProp->setPropertyValue("MarkPosition"
806  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
807  if( xSecondaryYAxisProp.is() )
808  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
809  , uno::makeAny( css::chart::ChartAxisPosition_END) );
810  }
811  }
812  else
813  {
814  if( aMainXScale.Orientation == chart2::AxisOrientation_REVERSE )
815  {
816  xMainYAxisProp->setPropertyValue("CrossoverPosition"
817  , uno::makeAny( css::chart::ChartAxisPosition_END) );
818  if( xSecondaryYAxisProp.is() )
819  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
820  , uno::makeAny( css::chart::ChartAxisPosition_START) );
821  }
822  else
823  {
824  xMainYAxisProp->setPropertyValue("CrossoverPosition"
825  , uno::makeAny( css::chart::ChartAxisPosition_START) );
826  if( xSecondaryYAxisProp.is() )
827  xSecondaryYAxisProp->setPropertyValue("CrossoverPosition"
828  , uno::makeAny( css::chart::ChartAxisPosition_END) );
829  }
830  }
831 
832  chart2::ScaleData aMainYScale = xMainYAxis->getScaleData();
833  xMainXAxisProp->setPropertyValue("CrossoverPosition"
834  , uno::makeAny( css::chart::ChartAxisPosition_VALUE) );
835  double fCrossoverValue = 0.0;
836  aMainYScale.Origin >>= fCrossoverValue;
837  xMainXAxisProp->setPropertyValue("CrossoverValue"
838  , uno::makeAny( fCrossoverValue ) );
839 
840  if( aMainYScale.Orientation == chart2::AxisOrientation_REVERSE )
841  {
842  xMainXAxisProp->setPropertyValue("LabelPosition"
843  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_END) );
844  xMainXAxisProp->setPropertyValue("MarkPosition"
845  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
846  if( xSecondaryXAxisProp.is() )
847  xSecondaryXAxisProp->setPropertyValue("CrossoverPosition"
848  , uno::makeAny( css::chart::ChartAxisPosition_START) );
849  }
850  else
851  {
852  xMainXAxisProp->setPropertyValue("LabelPosition"
853  , uno::makeAny( css::chart::ChartAxisLabelPosition_OUTSIDE_START) );
854  xMainXAxisProp->setPropertyValue("MarkPosition"
855  , uno::makeAny( css::chart::ChartAxisMarkPosition_AT_LABELS) );
856  if( xSecondaryXAxisProp.is() )
857  xSecondaryXAxisProp->setPropertyValue("CrossoverPosition"
858  , uno::makeAny( css::chart::ChartAxisPosition_END) );
859  }
860  }
861  }
862  }
863  }
864  catch( uno::Exception & )
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:3434
const SvXMLEnumMapEntry< sal_uInt16 > aXMLAxisTypeMap[]
bool hasValue()
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
SvXMLStylesContext * GetAutoStylesContext() const
SvXMLImport & GetImport()
Definition: xmlictxt.hxx:62
sal_Int8 nAxisIndex
SchXMLAxisDimension
css::uno::Reference< css::drawing::XShape > getTitleShape() const
SvXMLNamespaceMap & GetNamespaceMap()
Definition: xmlimp.hxx:402
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
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:567
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
constexpr sal_uInt16 XML_NAMESPACE_CHART_EXT
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:99
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
constexpr sal_uInt16 XML_NAMESPACE_TABLE
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...
#define SAL_INFO(area, stream)
const ::std::vector< Color > ImpSvNumberformatScan::StandardColor COL_BLACK
const SvXMLStyleContext * FindStyleChildContext(XmlStyleFamily nFamily, const OUString &rName, bool bCreateIndex=false) const
Definition: xmlstyle.cxx:808
SchXMLImportHelper & m_rImportHelper
virtual ~SchXMLAxisContext() override
uno::Any getPropertyFromContext(const OUString &rPropertyName, const XMLPropStyleContext *pPropStyleContext, const SvXMLStylesContext *pStylesCtxt)
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)