LibreOffice Module xmloff (master)  1
SchXMLTools.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 "SchXMLTools.hxx"
21 
22 #include <rtl/ustrbuf.hxx>
23 #include <xmloff/xmluconv.hxx>
24 #include <xmloff/xmlement.hxx>
25 #include <xmloff/xmlimppr.hxx>
26 #include <xmloff/prstylei.hxx>
27 #include <xmloff/xmlprmap.hxx>
28 #include <xmloff/xmlexp.hxx>
29 #include <xmloff/xmlnamespace.hxx>
30 #include <xmloff/xmlmetai.hxx>
31 #include <xmloff/maptype.hxx>
32 
33 #include <com/sun/star/beans/PropertyAttribute.hpp>
34 #include <com/sun/star/uno/XComponentContext.hpp>
35 #include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
36 #include <com/sun/star/chart2/data/XDataProvider.hpp>
37 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
38 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
39 #include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
40 #include <com/sun/star/chart2/XChartDocument.hpp>
41 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
42 #include <com/sun/star/container/XChild.hpp>
43 #include <com/sun/star/document/XDocumentProperties.hpp>
44 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
45 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
46 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
47 
49 #include <tools/diagnose_ex.h>
50 #include <sal/log.hxx>
51 #include <algorithm>
52 #include <map>
53 
54 using namespace com::sun::star;
55 using namespace ::xmloff::token;
56 
57 using ::com::sun::star::uno::Reference;
58 using ::com::sun::star::uno::Sequence;
59 
60 namespace
61 {
62 
63 OUString lcl_getGeneratorFromModel( const uno::Reference< frame::XModel >& xChartModel )
64 {
65  OUString aGenerator;
66  uno::Reference< document::XDocumentPropertiesSupplier> xChartDocumentPropertiesSupplier( xChartModel, uno::UNO_QUERY );
67  if( xChartDocumentPropertiesSupplier.is() )
68  {
69  uno::Reference< document::XDocumentProperties > xChartDocumentProperties(
70  xChartDocumentPropertiesSupplier->getDocumentProperties());
71  if( xChartDocumentProperties.is() )
72  aGenerator = xChartDocumentProperties->getGenerator();
73  }
74  return aGenerator;
75 }
76 
77 OUString lcl_getGeneratorFromModelOrItsParent( const uno::Reference< frame::XModel >& xChartModel )
78 {
79  OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
80  if( aGenerator.isEmpty() ) //try to get the missing info from the parent document
81  {
82  uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY );
83  if( xChild.is() )
84  aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) );
85  }
86  return aGenerator;
87 }
88 
89 sal_Int32 lcl_getBuildIDFromGenerator( const OUString& rGenerator )
90 {
91  //returns -1 if nothing found
92  sal_Int32 nBuildId = -1;
93  static const OUStringLiteral sBuildCompare( u"$Build-" );
94  sal_Int32 nBegin = rGenerator.indexOf( sBuildCompare );
95  if( nBegin >= 0 )
96  {
97  OUString sBuildId( rGenerator.copy( nBegin + sBuildCompare.getLength() ) );
98  nBuildId = sBuildId.toInt32();
99  }
100  return nBuildId;
101 }
102 
103 OUString lcl_ConvertRange( const OUString & rRange, const Reference< chart2::data::XDataProvider >& xDataProvider )
104 {
105  OUString aResult = rRange;
106  Reference< chart2::data::XRangeXMLConversion > xRangeConversion( xDataProvider, uno::UNO_QUERY );
107  if( xRangeConversion.is())
108  aResult = xRangeConversion->convertRangeFromXML( rRange );
109  return aResult;
110 }
111 
112 Reference< chart2::data::XDataSequence > lcl_createNewSequenceFromCachedXMLRange( const Reference< chart2::data::XDataSequence >& xSeq, const Reference< chart2::data::XDataProvider >& xDataProvider )
113 {
114  Reference< chart2::data::XDataSequence > xRet;
115  OUString aRange;
116  if( xSeq.is() && SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) )
117  {
118  xRet.set( xDataProvider->createDataSequenceByRangeRepresentation(
119  lcl_ConvertRange( aRange, xDataProvider )) );
121  Reference< beans::XPropertySet >( xRet, uno::UNO_QUERY ));
122  }
123  return xRet;
124 }
125 
126 } // anonymous namespace
127 
128 namespace SchXMLTools
129 {
130 
132 {
143  { XML_SURFACE, XML_CHART_CLASS_BAR }, //@todo change this if a surface chart is available
146 };
147 
148 SchXMLChartTypeEnum GetChartTypeEnum( std::u16string_view rClassName )
149 {
151  SvXMLUnitConverter::convertEnum( nEnumVal, rClassName, aXMLChartClassMap );
152  return nEnumVal;
153 }
154 
155 typedef std::map< OUString, OUString > tMakeStringStringMap;
156 //static
157 static const tMakeStringStringMap& lcl_getChartTypeNameMap()
158 {
159  //shape property -- chart model object property
160  static const tMakeStringStringMap g_aChartTypeNameMap{
161  {"com.sun.star.chart.LineDiagram",
162  "com.sun.star.chart2.LineChartType"},
163  {"com.sun.star.chart.AreaDiagram",
164  "com.sun.star.chart2.AreaChartType"},
165  {"com.sun.star.chart.BarDiagram",
166  "com.sun.star.chart2.ColumnChartType"},
167  {"com.sun.star.chart.PieDiagram",
168  "com.sun.star.chart2.PieChartType"},
169  {"com.sun.star.chart.DonutDiagram",
170  "com.sun.star.chart2.DonutChartType"},
171  {"com.sun.star.chart.XYDiagram",
172  "com.sun.star.chart2.ScatterChartType"},
173  {"com.sun.star.chart.NetDiagram",
174  "com.sun.star.chart2.NetChartType"},
175  {"com.sun.star.chart.FilledNetDiagram",
176  "com.sun.star.chart2.FilledNetChartType"},
177  {"com.sun.star.chart.StockDiagram",
178  "com.sun.star.chart2.CandleStickChartType"},
179  {"com.sun.star.chart.BubbleDiagram",
180  "com.sun.star.chart2.BubbleChartType"}};
181  return g_aChartTypeNameMap;
182 }
183 
184 OUString GetNewChartTypeName( const OUString & rOldChartTypeName )
185 {
186  OUString aNew(rOldChartTypeName);
187 
188  const tMakeStringStringMap& rMap = lcl_getChartTypeNameMap();
189  tMakeStringStringMap::const_iterator aIt( rMap.find( rOldChartTypeName ));
190  if( aIt != rMap.end())
191  {
192  aNew = aIt->second;
193  }
194  return aNew;
195 }
196 
198  std::u16string_view rClassName, bool bUseOldNames )
199 {
200  OUStringBuffer aResultBuffer;
201  bool bInternalType = false;
202 
203  if( bUseOldNames )
204  aResultBuffer.append( "com.sun.star.chart.");
205  else
206  aResultBuffer.append( "com.sun.star.chart2.");
207 
208  bInternalType = true;
209 
210  if( IsXMLToken( rClassName, XML_LINE ))
211  aResultBuffer.append("Line");
212  else if( IsXMLToken( rClassName, XML_AREA ))
213  aResultBuffer.append("Area");
214  else if( IsXMLToken( rClassName, XML_BAR ))
215  {
216  if( bUseOldNames )
217  aResultBuffer.append("Bar");
218  else
219  {
220  aResultBuffer.append("Column");
221  // @todo: might be Bar
222  }
223  }
224  else if( IsXMLToken( rClassName, XML_CIRCLE ))
225  aResultBuffer.append("Pie");
226  else if( IsXMLToken( rClassName, XML_RING ))
227  aResultBuffer.append("Donut");
228  else if( IsXMLToken( rClassName, XML_SCATTER ))
229  {
230  if( bUseOldNames )
231  aResultBuffer.append("XY");
232  else
233  aResultBuffer.append("Scatter");
234  }
235 
236  else if( IsXMLToken( rClassName, XML_BUBBLE ))
237  aResultBuffer.append("Bubble");
238  else if( IsXMLToken( rClassName, XML_RADAR ))
239  aResultBuffer.append("Net");
240  else if( IsXMLToken( rClassName, XML_FILLED_RADAR ))
241  aResultBuffer.append("FilledNet");
242  else if( IsXMLToken( rClassName, XML_STOCK ))
243  {
244  if( bUseOldNames )
245  aResultBuffer.append("Stock");
246  else
247  aResultBuffer.append("CandleStick");
248  }
249  else if( IsXMLToken( rClassName, XML_SURFACE ))
250  {
251  //@todo change this if a surface chart is available
252  if( bUseOldNames )
253  aResultBuffer.append("Bar");
254  else
255  aResultBuffer.append("Column");
256  }
257  else
258  bInternalType = false;
259 
260  if( ! bInternalType )
261  return OUString();
262 
263  if( bUseOldNames )
264  aResultBuffer.append("Diagram");
265  else
266  aResultBuffer.append("ChartType");
267 
268  return aResultBuffer.makeStringAndClear();
269 
270 }
271 
273  const OUString & rChartTypeService, bool bUseOldNames )
274 {
276  OUString aPrefix, aPostfix;
277 
278  if( bUseOldNames )
279  {
280  aPrefix = "com.sun.star.chart.";
281  aPostfix = "Diagram";
282  }
283  else
284  {
285  aPrefix = "com.sun.star.chart2.";
286  aPostfix = "ChartType";
287  }
288 
289  if( rChartTypeService.match( aPrefix ))
290  {
291  sal_Int32 nSkip = aPrefix.getLength();
292  SAL_WARN_IF( rChartTypeService.getLength() < nSkip, "xmloff.chart", "ChartTypeService.getLength() < nSkip" );
293  sal_Int32 nTypeLength = rChartTypeService.getLength() - nSkip - aPostfix.getLength();
294  // if postfix matches and leaves a non-empty type
295  if( nTypeLength > 0 && rChartTypeService.match( aPostfix, nSkip + nTypeLength ))
296  {
297  OUString aServiceName( rChartTypeService.copy( nSkip, nTypeLength ));
298 
299  if ( aServiceName == "Line" )
300  eResult = XML_LINE;
301  else if ( aServiceName == "Area" )
302  eResult = XML_AREA;
303  else if( aServiceName == "Bar" ||
304  (!bUseOldNames && aServiceName == "Column"))
305  eResult = XML_BAR;
306  else if ( aServiceName == "Pie" )
307  eResult = XML_CIRCLE;
308  else if ( aServiceName == "Donut" )
309  eResult = XML_RING;
310  else if( (bUseOldNames && aServiceName == "XY") ||
311  (!bUseOldNames && aServiceName == "Scatter"))
312  eResult = XML_SCATTER;
313  else if ( aServiceName == "Bubble" )
314  eResult = XML_BUBBLE;
315  else if ( aServiceName == "Net" )
316  eResult = XML_RADAR;
317  else if ( aServiceName == "FilledNet" )
318  eResult = XML_FILLED_RADAR;
319  else if( (bUseOldNames && aServiceName == "Stock") ||
320  (!bUseOldNames && aServiceName == "CandleStick"))
321  eResult = XML_STOCK;
322  }
323  }
324 
325  if( eResult == XML_TOKEN_INVALID && !rChartTypeService.isEmpty() )
326  eResult = XML_ADD_IN;
327 
328  return eResult;
329 }
330 
331 Reference< chart2::data::XLabeledDataSequence2 > GetNewLabeledDataSequence()
332 {
334  Reference< chart2::data::XLabeledDataSequence2 > xResult = chart2::data::LabeledDataSequence::create(xContext);
335  return xResult;
336 }
337 
338 Reference< chart2::data::XDataSequence > CreateDataSequence(
339  const OUString & rRange,
340  const Reference< chart2::XChartDocument >& xChartDoc )
341 {
342  Reference< chart2::data::XDataSequence > xRet;
343 
344  if( !xChartDoc.is() )
345  {
346  SAL_WARN("xmloff.chart", "need a chart document" );
347  return xRet;
348  }
349 
350  Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
351  if( !xDataProvider.is() )
352  {
353  SAL_WARN("xmloff.chart", "need a data provider" );
354  return xRet;
355  }
356 
357  bool bUseInternal = false;
358  uno::Reference<beans::XPropertySet> xPropSet(xDataProvider, uno::UNO_QUERY);
359  if (xPropSet.is())
360  {
361  try
362  {
363  bool bVal = false;
364  uno::Any any = xPropSet->getPropertyValue("UseInternalDataProvider");
365  if (any >>= bVal)
366  bUseInternal = bVal;
367  }
368  catch (const beans::UnknownPropertyException&)
369  {
370  // Do nothing
371  }
372  }
373 
374  if (!bUseInternal)
375  {
376  try
377  {
378  xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider )));
380  }
381  catch( const lang::IllegalArgumentException & )
382  {
383  SAL_WARN("xmloff.chart", "could not create data sequence" );
384  }
385  }
386 
387  if( !xRet.is() && !xChartDoc->hasInternalDataProvider() && !rRange.isEmpty() )
388  {
389  //#i103911# switch to internal data in case the parent cannot provide the requested data
390  xChartDoc->createInternalDataProvider( true /* bCloneExistingData */ );
391  xDataProvider = xChartDoc->getDataProvider();
392  try
393  {
394  xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider )));
396  }
397  catch( const lang::IllegalArgumentException & )
398  {
399  SAL_WARN("xmloff.chart", "could not create data sequence" );
400  }
401  }
402  return xRet;
403 }
404 
405 Reference< chart2::data::XDataSequence > CreateDataSequenceWithoutConvert(
406  const OUString & rRange,
407  const Reference< chart2::XChartDocument >& xChartDoc )
408 {
409  Reference< chart2::data::XDataSequence > xRet;
410 
411  if( !xChartDoc.is() )
412  {
413  SAL_WARN("xmloff.chart", "need a chart document" );
414  return xRet;
415  }
416 
417  Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
418  if( !xDataProvider.is() )
419  {
420  SAL_WARN("xmloff.chart", "need a data provider" );
421  return xRet;
422  }
423 
424  try
425  {
426  xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( rRange ) );
428  }
429  catch( const lang::IllegalArgumentException & )
430  {
431  SAL_WARN("xmloff.chart", "could not create data sequence" );
432  }
433 
434  return xRet;
435 }
436 
438  const uno::Reference< chart2::data::XDataProvider > & xDataProvider,
439  const uno::Reference< chart2::XChartDocument > & xNewDoc,
440  const OUString & rRangeAddress,
441  sal_Int32 nCooSysIndex,
442  sal_Int32 nDimensionIndex,
443  tSchXMLLSequencesPerIndex * pLSequencesPerIndex )
444 {
445  try
446  {
447  if( xNewDoc.is() && !rRangeAddress.isEmpty())
448  {
449  if( xDataProvider.is())
450  {
451  uno::Reference< chart2::XDiagram > xDia( xNewDoc->getFirstDiagram());
452  if( !xDia.is())
453  return;
454 
455  uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW );
456  uno::Sequence< uno::Reference< chart2::XCoordinateSystem > >
457  aCooSysSeq( xCooSysCnt->getCoordinateSystems());
458  if( nCooSysIndex < aCooSysSeq.getLength())
459  {
460  uno::Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] );
461  SAL_WARN_IF( !xCooSys.is(), "xmloff.chart", "xCooSys is NULL");
462  if( nDimensionIndex < xCooSys->getDimension() )
463  {
464  const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
465  for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI)
466  {
467  uno::Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nI ));
468  if( xAxis.is() )
469  {
470  chart2::ScaleData aData( xAxis->getScaleData());
471  uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
472  GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW);
473  try
474  {
475  OUString aConvertedRange( rRangeAddress );
476  bool bRangeConverted = false;
477  if( ! (xNewDoc->hasInternalDataProvider() && aConvertedRange == "categories"))
478  {
479  Reference< chart2::data::XRangeXMLConversion > xXMLConv( xDataProvider, uno::UNO_QUERY );
480  if( xXMLConv.is())
481  {
482  aConvertedRange = xXMLConv->convertRangeFromXML( rRangeAddress );
483  bRangeConverted = true;
484  }
485  }
486 
487  Reference<chart2::data::XDataSequence> xSequence;
488  Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY);
489  if (xPivotTableDataProvider.is())
490  {
491  xSequence.set(xPivotTableDataProvider->createDataSequenceOfCategories());
492  }
493  else
494  {
495  xSequence.set(xDataProvider->createDataSequenceByRangeRepresentation(aConvertedRange));
496  if (bRangeConverted)
497  setXMLRangePropertyAtDataSequence(xSequence, rRangeAddress);
498  }
499  xLabeledSeq->setValues(xSequence);
500 
501  }
502  catch( const lang::IllegalArgumentException & )
503  {
504  DBG_UNHANDLED_EXCEPTION("xmloff.chart");
505  }
506  aData.Categories.set( xLabeledSeq );
507  if( pLSequencesPerIndex )
508  {
509  // register for setting local data if external data provider is not present
510  pLSequencesPerIndex->emplace(
512  }
513  xAxis->setScaleData( aData );
514  }
515  }
516  }
517  }
518  }
519  }
520  }
521  catch( uno::Exception & )
522  {
523  TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception caught while creating Categories" );
524  }
525 }
526 
527 uno::Any getPropertyFromContext( std::u16string_view rPropertyName, const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
528 {
529  uno::Any aRet;
530  if( !pPropStyleContext || !pStylesCtxt )
531  return aRet;
532  const ::std::vector< XMLPropertyState >& rProperties = pPropStyleContext->GetProperties();
533  const rtl::Reference< XMLPropertySetMapper >& rMapper = pStylesCtxt->GetImportPropertyMapper( pPropStyleContext->GetFamily()/*XML_STYLE_FAMILY_SCH_CHART_ID*/ )->getPropertySetMapper();
534  for( const auto& rProp : rProperties )
535  {
536  sal_Int32 nIdx = rProp.mnIndex;
537  if( nIdx == -1 )
538  continue;
539  OUString aPropName = rMapper->GetEntryAPIName( nIdx );
540  if(rPropertyName == aPropName)
541  return rProp.maValue;
542  }
543  return aRet;
544 }
545 
546 void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsLFs )
547 {
548  SvXMLElementExport aPara( rExport, XML_NAMESPACE_TEXT,
550  true, false );
551 
552  if( bConvertTabsLFs )
553  {
554  sal_Int32 nStartPos = 0;
555  sal_Int32 nEndPos = rText.getLength();
556  sal_Unicode cChar;
557 
558  for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ )
559  {
560  cChar = rText[ nPos ];
561  switch( cChar )
562  {
563  case 0x0009: // tabulator
564  {
565  if( nPos > nStartPos )
566  rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) );
567  nStartPos = nPos + 1;
568 
569  SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT,
571  false, false );
572  }
573  break;
574 
575  case 0x000A: // linefeed
576  {
577  if( nPos > nStartPos )
578  rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) );
579  nStartPos = nPos + 1;
580 
581  SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT,
583  false, false );
584  }
585  break;
586  }
587  }
588  if( nEndPos > nStartPos )
589  {
590  if( nStartPos == 0 )
591  rExport.GetDocHandler()->characters( rText );
592  else
593  rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nEndPos - nStartPos)) );
594  }
595  }
596  else // do not convert tabs and linefeeds (eg for numbers coming from unit converter)
597  {
598  rExport.GetDocHandler()->characters( rText );
599  }
600 }
601 
603 {
604  //with issue #i366# and CWS chart20 ranges for error bars were introduced
605  //to keep them during copy paste from calc to impress for example it
606  //was necessary to introduce a mapping between the used ranges within calc and the data written to the local table
607  //this is why we write this ranges here
608 
609  //#i113950# first the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore within ODF 1.2
610  //as an alternative the range info is now saved into the description at an empty group element (not very nice, but ODF conform)
611 
612  const SvtSaveOptions::ODFSaneDefaultVersion nCurrentODFVersion(
613  rExport.getSaneDefaultVersion());
614  if (nCurrentODFVersion == SvtSaveOptions::ODFSVER_010 || nCurrentODFVersion == SvtSaveOptions::ODFSVER_011)
615  return;//svg:desc is not allowed at draw:g in ODF1.0; but as the ranges for error bars are anyhow not allowed within ODF1.0 nor ODF1.1 we do not need the information
616 
617  SvXMLElementExport aEmptyShapeGroup( rExport, XML_NAMESPACE_DRAW,
619  true, false );
620  SvXMLElementExport aDescription( rExport, XML_NAMESPACE_SVG,
622  true, false );
623  rExport.GetDocHandler()->characters( rValue );
624 }
625 
627  const Reference< chart2::data::XDataSequence > & xDataSequence,
628  const OUString & rXMLRange )
629 {
630  if( !xDataSequence.is())
631  return;
632  try
633  {
634  static const OUStringLiteral aXMLRangePropName( u"CachedXMLRange" );
635  Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
636  Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
637  if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ))
638  xProp->setPropertyValue( aXMLRangePropName, uno::makeAny( rXMLRange ));
639  }
640  catch( const uno::Exception & )
641  {
642  DBG_UNHANDLED_EXCEPTION("xmloff.chart");
643  }
644 }
645 
647  const Reference< chart2::data::XDataSequence > & xDataSequence,
648  OUString & rOutXMLRange,
649  bool bClearProp /* = false */)
650 {
651  bool bResult = false;
652  if( xDataSequence.is())
653  {
654  try
655  {
656  static const OUStringLiteral aXMLRangePropName( u"CachedXMLRange" );
657  Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
658  Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
659  bResult =
660  ( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ) &&
661  ( xProp->getPropertyValue( aXMLRangePropName ) >>= rOutXMLRange ) &&
662  !rOutXMLRange.isEmpty());
663  // clear the property after usage
664  if( bClearProp && bResult )
665  xProp->setPropertyValue( aXMLRangePropName, uno::Any( OUString()));
666  }
667  catch( const uno::Exception & )
668  {
669  DBG_UNHANDLED_EXCEPTION("xmloff.chart");
670  }
671  }
672  return bResult;
673 }
674 
676  const Reference< beans::XPropertySet > & xSource,
677  const Reference< beans::XPropertySet > & xDestination )
678 {
679  if( ! (xSource.is() && xDestination.is()) )
680  return;
681 
682  try
683  {
684  Reference< beans::XPropertySetInfo > xSrcInfo( xSource->getPropertySetInfo(), uno::UNO_SET_THROW );
685  Reference< beans::XPropertySetInfo > xDestInfo( xDestination->getPropertySetInfo(), uno::UNO_SET_THROW );
686  const Sequence< beans::Property > aProperties( xSrcInfo->getProperties());
687  for( const auto& rProperty : aProperties )
688  {
689  OUString aName( rProperty.Name);
690  if( xDestInfo->hasPropertyByName( aName ))
691  {
692  beans::Property aProp( xDestInfo->getPropertyByName( aName ));
693  if( (aProp.Attributes & beans::PropertyAttribute::READONLY) == 0 )
694  xDestination->setPropertyValue(
695  aName, xSource->getPropertyValue( aName ));
696  }
697  }
698  }
699  catch( const uno::Exception & )
700  {
701  SAL_WARN("xmloff.chart", "Copying property sets failed!" );
702  }
703 }
704 
705 bool switchBackToDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc, const tSchXMLLSequencesPerIndex & rLSequencesPerIndex )
706 {
707  //return whether the switch is successful
708  if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() )
709  return false;
710  Reference< chart2::data::XDataProvider > xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc ) );
711  if( !xDataProviderFromParent.is() )
712  return false;
713  uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY );
714  if( !xDataReceiver.is() )
715  return false;
716 
717  xDataReceiver->attachDataProvider( xDataProviderFromParent );
718 
719  for( const auto& rLSeq : rLSequencesPerIndex )
720  {
721  Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( rLSeq.second );
722  if( !xLabeledSeq.is() )
723  continue;
724  Reference< chart2::data::XDataSequence > xNewSeq;
725  xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getValues(), xDataProviderFromParent );
726  if( xNewSeq.is() )
727  xLabeledSeq->setValues( xNewSeq );
728  xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getLabel(), xDataProviderFromParent );
729  if( xNewSeq.is() )
730  xLabeledSeq->setLabel( xNewSeq );
731  }
732  return true;
733 }
734 
735 void setBuildIDAtImportInfo( const uno::Reference< frame::XModel >& xModel, const Reference< beans::XPropertySet >& xImportInfo )
736 {
737  OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xModel) );
738  if( !aGenerator.isEmpty() )
739  SvXMLMetaDocumentContext::setBuildId( aGenerator, xImportInfo );
740 }
741 
742 bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const uno::Reference< frame::XModel >& xChartModel )
743 {
744  bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel );
745  if( !bResult )
746  {
747  OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
748  if( aGenerator.indexOf( "OpenOffice.org_project/3" ) != -1 )
749  {
750  if( aGenerator.indexOf( "OpenOffice.org_project/300m" ) != -1 )
751  {
752  sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) );
753  if( nBuilId>0 && nBuilId<9491 ) //9491 is build id of dev300m76
754  bResult= true;
755  }
756  else if( aGenerator.indexOf( "OpenOffice.org_project/310m" ) != -1 )
757  bResult= true;
758  else if( aGenerator.indexOf( "OpenOffice.org_project/320m" ) != -1 )
759  bResult= true;
760  }
761  }
762  return bResult;
763 }
764 
765 bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const uno::Reference< frame::XModel >& xChartModel )
766 {
767  bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel );
768  if( !bResult )
769  {
770  OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
771  if( aGenerator.indexOf( "OpenOffice.org_project/680m" ) != -1 )
772  bResult= true;
773  }
774  return bResult;
775 }
776 
777 bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const uno::Reference< frame::XModel >& xChartModel )
778 {
780  return true;
781 
783  {
784  sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) );
785  if( nBuilId>0 && nBuilId<=9238 ) //9238 is build id of OpenOffice.org 2.3.1
786  return true;
787  }
788  return false;
789 }
790 
791 bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const uno::Reference< frame::XModel >& xChartModel )
792 {
793  bool bResult = false;
794  OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
795  //if there is a meta stream at the chart object it was not written with an older OpenOffice version < 2.3
796  if( aGenerator.isEmpty() )
797  {
798  //if there is no meta stream at the chart object we need to check whether the parent document is OpenOffice at all
799  uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY );
800  if( xChild.is() )
801  {
802  aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) );
803  if( aGenerator.indexOf( "OpenOffice.org_project" ) != -1 )
804  {
805  //the chart application has not created files without a meta stream since OOo 2.3 (OOo 2.3 has written a metastream already)
806  //only the report builder extension has created some files with OOo 3.1 that do not have a meta stream
807  if( aGenerator.indexOf( "OpenOffice.org_project/31" ) != -1 )
808  bResult = false;//#i100102# probably generated with OOo 3.1 by the report designer
809  else
810  bResult= true; //in this case the OLE chart was created by an older version, as OLE objects are sometimes stream copied the version can differ from the parents version, so the parents version is not a reliable indicator
811  }
812  else if( isDocumentGeneratedWithOpenOfficeOlderThan2_0(xChartModel) )
813  bResult= true;
814  }
815  }
816  return bResult;
817 }
818 
819 bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const css::uno::Reference< css::frame::XModel >& xChartModel)
820 {
821  bool bResult = false;
822  OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xChartModel) );
823  if( aGenerator.startsWith( "OpenOffice.org 1" )
824  || aGenerator.startsWith( "StarOffice 6" )
825  || aGenerator.startsWith( "StarOffice 7" )
826  || aGenerator.startsWith( "StarSuite 6" )
827  || aGenerator.startsWith( "StarSuite 7" )
828  )
829  bResult= true;
830  return bResult;
831 }
832 
833 Reference< chart2::data::XDataProvider > getDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc )
834 {
835  Reference< chart2::data::XDataProvider > xRet;
836  uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY );
837  if( xChild.is() )
838  {
839  Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY );
840  if( xFact.is() )
841  {
842  static const OUStringLiteral aDataProviderServiceName( u"com.sun.star.chart2.data.DataProvider");
843  const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames());
844  const OUString * pBegin = aServiceNames.getConstArray();
845  const OUString * pEnd = pBegin + aServiceNames.getLength();
846  if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd )
847  {
848  xRet.set( xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY );
849  }
850  }
851  }
852  return xRet;
853 }
854 
855 } // namespace SchXMLTools
856 
857 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XmlStyleFamily GetFamily() const
Definition: xmlstyle.hxx:83
OUString GetNewChartTypeName(const OUString &rOldChartTypeName)
Reference< chart2::data::XDataProvider > getDataProviderFromParent(const Reference< chart2::XChartDocument > &xChartDoc)
void setBuildIDAtImportInfo(const uno::Reference< frame::XModel > &xModel, const Reference< beans::XPropertySet > &xImportInfo)
uno::Any getPropertyFromContext(std::u16string_view rPropertyName, const XMLPropStyleContext *pPropStyleContext, const SvXMLStylesContext *pStylesCtxt)
Sequence< OUString > aServiceNames
bool IsXMLToken(std::u16string_view rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3482
const css::uno::Reference< css::xml::sax::XDocumentHandler > & GetDocHandler() const
Definition: xmlexp.hxx:388
bool isDocumentGeneratedWithOpenOfficeOlderThan3_3(const uno::Reference< frame::XModel > &xChartModel)
css::uno::Any const & rValue
Definition: ImageStyle.hxx:38
sal_uInt16 sal_Unicode
void setXMLRangePropertyAtDataSequence(const Reference< chart2::data::XDataSequence > &xDataSequence, const OUString &rXMLRange)
PropertiesInfo aProperties
OUString GetChartTypeByClassName(std::u16string_view rClassName, bool bUseOldNames)
::std::pair< tSchXMLIndex, SchXMLLabeledSequencePart > tSchXMLIndexWithPart
constexpr sal_uInt16 XML_NAMESPACE_DRAW
XMLTokenEnum
The enumeration of all XML tokens.
Definition: xmltoken.hxx:49
constexpr OUStringLiteral aData
SvtSaveOptions::ODFSaneDefaultVersion getSaneDefaultVersion() const
returns the deterministic version for odf export
Definition: xmlexp.cxx:2324
#define DBG_UNHANDLED_EXCEPTION(...)
virtual rtl::Reference< SvXMLImportPropertyMapper > GetImportPropertyMapper(XmlStyleFamily nFamily) const
Definition: xmlstyle.cxx:510
constexpr sal_uInt16 XML_NAMESPACE_SVG
#define TOOLS_WARN_EXCEPTION(area, stream)
#define SCH_XML_CATEGORIES_INDEX
Reference< chart2::data::XLabeledDataSequence2 > GetNewLabeledDataSequence()
constexpr sal_uInt16 XML_NAMESPACE_TEXT
::std::vector< XMLPropertyState > & GetProperties()
Definition: prstylei.hxx:79
const Any & any
float u
bool isDocumentGeneratedWithOpenOfficeOlderThan2_0(const css::uno::Reference< css::frame::XModel > &xChartModel)
void exportText(SvXMLExport &rExport, const OUString &rText, bool bConvertTabsLFs)
void exportRangeToSomewhere(SvXMLExport &rExport, const OUString &rValue)
Map an XMLTokenEnum to an enum value.
Definition: ximpshap.hxx:39
static void setBuildId(const OUString &rGenerator, const css::uno::Reference< css::beans::XPropertySet > &xImportInfo)
Definition: xmlmetai.cxx:230
Reference< chart2::data::XDataSequence > CreateDataSequenceWithoutConvert(const OUString &rRange, const Reference< chart2::XChartDocument > &xChartDoc)
void CreateCategories(const uno::Reference< chart2::data::XDataProvider > &xDataProvider, const uno::Reference< chart2::XChartDocument > &xNewDoc, const OUString &rRangeAddress, sal_Int32 nCooSysIndex, sal_Int32 nDimensionIndex, tSchXMLLSequencesPerIndex *pLSequencesPerIndex)
Any makeAny(Color const &value)
#define SAL_WARN_IF(condition, area, stream)
const OUString & GetXMLToken(enum XMLTokenEnum eToken)
return the OUString representation for eToken
Definition: xmltoken.cxx:3426
Handling of tokens in XML:
OUString aName
static const tMakeStringStringMap & lcl_getChartTypeNameMap()
bool getXMLRangePropertyFromDataSequence(const Reference< chart2::data::XDataSequence > &xDataSequence, OUString &rOutXMLRange, bool bClearProp)
bool isDocumentGeneratedWithOpenOfficeOlderThan3_0(const uno::Reference< frame::XModel > &xChartModel)
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
Reference< XComponentContext > getProcessComponentContext()
bool switchBackToDataProviderFromParent(const Reference< chart2::XChartDocument > &xChartDoc, const tSchXMLLSequencesPerIndex &rLSequencesPerIndex)
Reference< chart2::data::XDataSequence > CreateDataSequence(const OUString &rRange, const Reference< chart2::XChartDocument > &xChartDoc)
#define SAL_WARN(area, stream)
bool isDocumentGeneratedWithOpenOfficeOlderThan2_3(const uno::Reference< frame::XModel > &xChartModel)
bool isDocumentGeneratedWithOpenOfficeOlderThan2_4(const uno::Reference< frame::XModel > &xChartModel)
SchXMLChartTypeEnum GetChartTypeEnum(std::u16string_view rClassName)
XMLTokenEnum getTokenByChartType(const OUString &rChartTypeService, bool bUseOldNames)
::std::multimap< tSchXMLIndexWithPart, css::uno::Reference< css::chart2::data::XLabeledDataSequence > > tSchXMLLSequencesPerIndex
css::uno::Any const SvXMLExport & rExport
Definition: ImageStyle.hxx:38
void copyProperties(const Reference< beans::XPropertySet > &xSource, const Reference< beans::XPropertySet > &xDestination)
std::map< OUString, OUString > tMakeStringStringMap
const SvXMLEnumMapEntry< SchXMLChartTypeEnum > aXMLChartClassMap[]
sal_uInt16 nPos