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