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/xmlnmspe.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  const OUString sBuildCompare( "$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( const OUString& 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  const OUString & 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  SAL_WARN("xmloff.chart", "Exception caught while creating Categories" );
524  }
525 }
526 
527 uno::Any getPropertyFromContext( const OUString& 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(SvtSaveOptions().GetODFSaneDefaultVersion());
613  if (nCurrentODFVersion == SvtSaveOptions::ODFSVER_010 || nCurrentODFVersion == SvtSaveOptions::ODFSVER_011)
614  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
615 
616  SvXMLElementExport aEmptyShapeGroup( rExport, XML_NAMESPACE_DRAW,
618  true, false );
619  SvXMLElementExport aDescription( rExport, XML_NAMESPACE_SVG,
621  true, false );
622  rExport.GetDocHandler()->characters( rValue );
623 }
624 
626  const Reference< chart2::data::XDataSequence > & xDataSequence,
627  const OUString & rXMLRange )
628 {
629  if( !xDataSequence.is())
630  return;
631  try
632  {
633  const OUString aXMLRangePropName( "CachedXMLRange" );
634  Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
635  Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
636  if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ))
637  xProp->setPropertyValue( aXMLRangePropName, uno::makeAny( rXMLRange ));
638  }
639  catch( const uno::Exception & )
640  {
641  DBG_UNHANDLED_EXCEPTION("xmloff.chart");
642  }
643 }
644 
646  const Reference< chart2::data::XDataSequence > & xDataSequence,
647  OUString & rOutXMLRange,
648  bool bClearProp /* = false */)
649 {
650  bool bResult = false;
651  if( xDataSequence.is())
652  {
653  try
654  {
655  const OUString aXMLRangePropName( "CachedXMLRange" );
656  Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
657  Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
658  bResult =
659  ( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ) &&
660  ( xProp->getPropertyValue( aXMLRangePropName ) >>= rOutXMLRange ) &&
661  !rOutXMLRange.isEmpty());
662  // clear the property after usage
663  if( bClearProp && bResult )
664  xProp->setPropertyValue( aXMLRangePropName, uno::Any( OUString()));
665  }
666  catch( const uno::Exception & )
667  {
668  DBG_UNHANDLED_EXCEPTION("xmloff.chart");
669  }
670  }
671  return bResult;
672 }
673 
675  const Reference< beans::XPropertySet > & xSource,
676  const Reference< beans::XPropertySet > & xDestination )
677 {
678  if( ! (xSource.is() && xDestination.is()) )
679  return;
680 
681  try
682  {
683  Reference< beans::XPropertySetInfo > xSrcInfo( xSource->getPropertySetInfo(), uno::UNO_SET_THROW );
684  Reference< beans::XPropertySetInfo > xDestInfo( xDestination->getPropertySetInfo(), uno::UNO_SET_THROW );
685  const Sequence< beans::Property > aProperties( xSrcInfo->getProperties());
686  for( const auto& rProperty : aProperties )
687  {
688  OUString aName( rProperty.Name);
689  if( xDestInfo->hasPropertyByName( aName ))
690  {
691  beans::Property aProp( xDestInfo->getPropertyByName( aName ));
692  if( (aProp.Attributes & beans::PropertyAttribute::READONLY) == 0 )
693  xDestination->setPropertyValue(
694  aName, xSource->getPropertyValue( aName ));
695  }
696  }
697  }
698  catch( const uno::Exception & )
699  {
700  SAL_WARN("xmloff.chart", "Copying property sets failed!" );
701  }
702 }
703 
704 bool switchBackToDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc, const tSchXMLLSequencesPerIndex & rLSequencesPerIndex )
705 {
706  //return whether the switch is successful
707  if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() )
708  return false;
709  Reference< chart2::data::XDataProvider > xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc ) );
710  if( !xDataProviderFromParent.is() )
711  return false;
712  uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY );
713  if( !xDataReceiver.is() )
714  return false;
715 
716  xDataReceiver->attachDataProvider( xDataProviderFromParent );
717 
718  for( const auto& rLSeq : rLSequencesPerIndex )
719  {
720  Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( rLSeq.second );
721  if( !xLabeledSeq.is() )
722  continue;
723  Reference< chart2::data::XDataSequence > xNewSeq;
724  xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getValues(), xDataProviderFromParent );
725  if( xNewSeq.is() )
726  xLabeledSeq->setValues( xNewSeq );
727  xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getLabel(), xDataProviderFromParent );
728  if( xNewSeq.is() )
729  xLabeledSeq->setLabel( xNewSeq );
730  }
731  return true;
732 }
733 
734 void setBuildIDAtImportInfo( const uno::Reference< frame::XModel >& xModel, const Reference< beans::XPropertySet >& xImportInfo )
735 {
736  OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xModel) );
737  if( !aGenerator.isEmpty() )
738  SvXMLMetaDocumentContext::setBuildId( aGenerator, xImportInfo );
739 }
740 
741 bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const uno::Reference< frame::XModel >& xChartModel )
742 {
743  bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel );
744  if( !bResult )
745  {
746  OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
747  if( aGenerator.indexOf( "OpenOffice.org_project/3" ) != -1 )
748  {
749  if( aGenerator.indexOf( "OpenOffice.org_project/300m" ) != -1 )
750  {
751  sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) );
752  if( nBuilId>0 && nBuilId<9491 ) //9491 is build id of dev300m76
753  bResult= true;
754  }
755  else if( aGenerator.indexOf( "OpenOffice.org_project/310m" ) != -1 )
756  bResult= true;
757  else if( aGenerator.indexOf( "OpenOffice.org_project/320m" ) != -1 )
758  bResult= true;
759  }
760  }
761  return bResult;
762 }
763 
764 bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const uno::Reference< frame::XModel >& xChartModel )
765 {
766  bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel );
767  if( !bResult )
768  {
769  OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
770  if( aGenerator.indexOf( "OpenOffice.org_project/680m" ) != -1 )
771  bResult= true;
772  }
773  return bResult;
774 }
775 
776 bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const uno::Reference< frame::XModel >& xChartModel )
777 {
779  return true;
780 
782  {
783  sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) );
784  if( nBuilId>0 && nBuilId<=9238 ) //9238 is build id of OpenOffice.org 2.3.1
785  return true;
786  }
787  return false;
788 }
789 
790 bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const uno::Reference< frame::XModel >& xChartModel )
791 {
792  bool bResult = false;
793  OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
794  //if there is a meta stream at the chart object it was not written with an older OpenOffice version < 2.3
795  if( aGenerator.isEmpty() )
796  {
797  //if there is no meta stream at the chart object we need to check whether the parent document is OpenOffice at all
798  uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY );
799  if( xChild.is() )
800  {
801  aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) );
802  if( aGenerator.indexOf( "OpenOffice.org_project" ) != -1 )
803  {
804  //the chart application has not created files without a meta stream since OOo 2.3 (OOo 2.3 has written a metastream already)
805  //only the report builder extension has created some files with OOo 3.1 that do not have a meta stream
806  if( aGenerator.indexOf( "OpenOffice.org_project/31" ) != -1 )
807  bResult = false;//#i100102# probably generated with OOo 3.1 by the report designer
808  else
809  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
810  }
811  else if( isDocumentGeneratedWithOpenOfficeOlderThan2_0(xChartModel) )
812  bResult= true;
813  }
814  }
815  return bResult;
816 }
817 
818 bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const css::uno::Reference< css::frame::XModel >& xChartModel)
819 {
820  bool bResult = false;
821  OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xChartModel) );
822  if( aGenerator.startsWith( "OpenOffice.org 1" )
823  || aGenerator.startsWith( "StarOffice 6" )
824  || aGenerator.startsWith( "StarOffice 7" )
825  || aGenerator.startsWith( "StarSuite 6" )
826  || aGenerator.startsWith( "StarSuite 7" )
827  )
828  bResult= true;
829  return bResult;
830 }
831 
832 Reference< chart2::data::XDataProvider > getDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc )
833 {
834  Reference< chart2::data::XDataProvider > xRet;
835  uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY );
836  if( xChild.is() )
837  {
838  Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY );
839  if( xFact.is() )
840  {
841  const OUString aDataProviderServiceName( "com.sun.star.chart2.data.DataProvider");
842  const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames());
843  const OUString * pBegin = aServiceNames.getConstArray();
844  const OUString * pEnd = pBegin + aServiceNames.getLength();
845  if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd )
846  {
847  xRet.set( xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY );
848  }
849  }
850  }
851  return xRet;
852 }
853 
854 } // namespace SchXMLTools
855 
856 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XmlStyleFamily GetFamily() const
Definition: xmlstyle.hxx:112
bool IsXMLToken(const OUString &rString, enum XMLTokenEnum eToken)
compare eToken to the string
Definition: xmltoken.cxx:3422
OUString GetNewChartTypeName(const OUString &rOldChartTypeName)
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
Reference< chart2::data::XDataProvider > getDataProviderFromParent(const Reference< chart2::XChartDocument > &xChartDoc)
void setBuildIDAtImportInfo(const uno::Reference< frame::XModel > &xModel, const Reference< beans::XPropertySet > &xImportInfo)
const char aData[]
Sequence< OUString > aServiceNames
constexpr sal_uInt16 XML_NAMESPACE_TEXT
Definition: xmlnmspe.hxx:31
const css::uno::Reference< css::xml::sax::XDocumentHandler > & GetDocHandler() const
Definition: xmlexp.hxx:386
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
::std::pair< tSchXMLIndex, SchXMLLabeledSequencePart > tSchXMLIndexWithPart
XMLTokenEnum
The enumeration of all XML tokens.
Definition: xmltoken.hxx:47
constexpr sal_uInt16 XML_NAMESPACE_DRAW
Definition: xmlnmspe.hxx:33
#define DBG_UNHANDLED_EXCEPTION(...)
virtual rtl::Reference< SvXMLImportPropertyMapper > GetImportPropertyMapper(XmlStyleFamily nFamily) const
Definition: xmlstyle.cxx:580
#define SCH_XML_CATEGORIES_INDEX
Reference< chart2::data::XLabeledDataSequence2 > GetNewLabeledDataSequence()
::std::vector< XMLPropertyState > & GetProperties()
Definition: prstylei.hxx:79
const Any & any
bool isDocumentGeneratedWithOpenOfficeOlderThan2_0(const css::uno::Reference< css::frame::XModel > &xChartModel)
OUString GetChartTypeByClassName(const OUString &rClassName, bool bUseOldNames)
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:40
static void setBuildId(const OUString &rGenerator, const css::uno::Reference< css::beans::XPropertySet > &xImportInfo)
Definition: xmlmetai.cxx:225
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:3366
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)
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)
SchXMLChartTypeEnum GetChartTypeEnum(const OUString &rClassName)
bool isDocumentGeneratedWithOpenOfficeOlderThan2_3(const uno::Reference< frame::XModel > &xChartModel)
bool isDocumentGeneratedWithOpenOfficeOlderThan2_4(const uno::Reference< frame::XModel > &xChartModel)
XMLTokenEnum getTokenByChartType(const OUString &rChartTypeService, bool bUseOldNames)
uno::Any getPropertyFromContext(const OUString &rPropertyName, const XMLPropStyleContext *pPropStyleContext, const SvXMLStylesContext *pStylesCtxt)
::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
constexpr sal_uInt16 XML_NAMESPACE_SVG
Definition: xmlnmspe.hxx:40
static const SvXMLEnumMapEntry< SchXMLChartTypeEnum > aXMLChartClassMap[]
sal_uInt16 nPos