1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "SchXMLTools.hxx"
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>
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>
48 #include <comphelper/processfactory.hxx>
49 #include <comphelper/diagnose_ex.hxx>
50 #include <sal/log.hxx>
51 #include <o3tl/string_view.hxx>
55 using namespace com::sun::star
;
56 using namespace ::xmloff::token
;
58 using ::com::sun::star::uno::Reference
;
59 using ::com::sun::star::uno::Sequence
;
64 OUString
lcl_getGeneratorFromModel( const uno::Reference
< frame::XModel
>& xChartModel
)
67 uno::Reference
< document::XDocumentPropertiesSupplier
> xChartDocumentPropertiesSupplier( xChartModel
, uno::UNO_QUERY
);
68 if( xChartDocumentPropertiesSupplier
.is() )
70 uno::Reference
< document::XDocumentProperties
> xChartDocumentProperties(
71 xChartDocumentPropertiesSupplier
->getDocumentProperties());
72 if( xChartDocumentProperties
.is() )
73 aGenerator
= xChartDocumentProperties
->getGenerator();
78 OUString
lcl_getGeneratorFromModelOrItsParent( const uno::Reference
< frame::XModel
>& xChartModel
)
80 OUString
aGenerator( lcl_getGeneratorFromModel(xChartModel
) );
81 if( aGenerator
.isEmpty() ) //try to get the missing info from the parent document
83 uno::Reference
< container::XChild
> xChild( xChartModel
, uno::UNO_QUERY
);
85 aGenerator
= lcl_getGeneratorFromModel( uno::Reference
< frame::XModel
>( xChild
->getParent(), uno::UNO_QUERY
) );
90 sal_Int32
lcl_getBuildIDFromGenerator( std::u16string_view rGenerator
)
92 //returns -1 if nothing found
93 sal_Int32 nBuildId
= -1;
94 static constexpr OUString
sBuildCompare( u
"$Build-"_ustr
);
95 size_t nBegin
= rGenerator
.find( sBuildCompare
);
96 if( nBegin
!= std::u16string_view::npos
)
98 std::u16string_view sBuildId
= rGenerator
.substr( nBegin
+ sBuildCompare
.getLength() );
99 nBuildId
= o3tl::toInt32(sBuildId
);
104 OUString
lcl_ConvertRange( const OUString
& rRange
, const Reference
< chart2::data::XDataProvider
>& xDataProvider
)
106 OUString aResult
= rRange
;
107 Reference
< chart2::data::XRangeXMLConversion
> xRangeConversion( xDataProvider
, uno::UNO_QUERY
);
108 if( xRangeConversion
.is())
109 aResult
= xRangeConversion
->convertRangeFromXML( rRange
);
113 Reference
< chart2::data::XDataSequence
> lcl_createNewSequenceFromCachedXMLRange( const Reference
< chart2::data::XDataSequence
>& xSeq
, const Reference
< chart2::data::XDataProvider
>& xDataProvider
)
115 Reference
< chart2::data::XDataSequence
> xRet
;
117 if( xSeq
.is() && SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq
, aRange
, /* bClearProp = */ true ) )
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
));
127 } // anonymous namespace
129 namespace SchXMLTools
132 const SvXMLEnumMapEntry
<SchXMLChartTypeEnum
> aXMLChartClassMap
[] =
134 { XML_LINE
, XML_CHART_CLASS_LINE
},
135 { XML_AREA
, XML_CHART_CLASS_AREA
},
136 { XML_CIRCLE
, XML_CHART_CLASS_CIRCLE
},
137 { XML_RING
, XML_CHART_CLASS_RING
},
138 { XML_SCATTER
, XML_CHART_CLASS_SCATTER
},
139 { XML_RADAR
, XML_CHART_CLASS_RADAR
},
140 { XML_FILLED_RADAR
, XML_CHART_CLASS_FILLED_RADAR
},
141 { XML_BAR
, XML_CHART_CLASS_BAR
},
142 { XML_STOCK
, XML_CHART_CLASS_STOCK
},
143 { XML_BUBBLE
, XML_CHART_CLASS_BUBBLE
},
144 { XML_SURFACE
, XML_CHART_CLASS_BAR
}, //@todo change this if a surface chart is available
145 { XML_ADD_IN
, XML_CHART_CLASS_ADDIN
},
146 { XML_TOKEN_INVALID
, XML_CHART_CLASS_UNKNOWN
}
149 SchXMLChartTypeEnum
GetChartTypeEnum( std::u16string_view rClassName
)
151 SchXMLChartTypeEnum nEnumVal
= XML_CHART_CLASS_UNKNOWN
;
152 SvXMLUnitConverter::convertEnum( nEnumVal
, rClassName
, aXMLChartClassMap
);
156 typedef std::map
< OUString
, OUString
> tMakeStringStringMap
;
158 static const tMakeStringStringMap
& lcl_getChartTypeNameMap()
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
;
185 OUString
GetNewChartTypeName( const OUString
& rOldChartTypeName
)
187 OUString
aNew(rOldChartTypeName
);
189 const tMakeStringStringMap
& rMap
= lcl_getChartTypeNameMap();
190 tMakeStringStringMap::const_iterator
aIt( rMap
.find( rOldChartTypeName
));
191 if( aIt
!= rMap
.end())
198 OUString
GetChartTypeByClassName(
199 std::u16string_view rClassName
, bool bUseOldNames
)
201 OUStringBuffer aResultBuffer
;
202 bool bInternalType
= false;
205 aResultBuffer
.append( "com.sun.star.chart.");
207 aResultBuffer
.append( "com.sun.star.chart2.");
209 bInternalType
= true;
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
))
218 aResultBuffer
.append("Bar");
221 aResultBuffer
.append("Column");
222 // @todo: might be Bar
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
))
232 aResultBuffer
.append("XY");
234 aResultBuffer
.append("Scatter");
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
))
246 aResultBuffer
.append("Stock");
248 aResultBuffer
.append("CandleStick");
250 else if( IsXMLToken( rClassName
, XML_SURFACE
))
252 //@todo change this if a surface chart is available
254 aResultBuffer
.append("Bar");
256 aResultBuffer
.append("Column");
259 bInternalType
= false;
261 if( ! bInternalType
)
265 aResultBuffer
.append("Diagram");
267 aResultBuffer
.append("ChartType");
269 return aResultBuffer
.makeStringAndClear();
273 XMLTokenEnum
getTokenByChartType(
274 std::u16string_view rChartTypeService
, bool bUseOldNames
)
276 XMLTokenEnum eResult
= XML_TOKEN_INVALID
;
277 OUString aPrefix
, aPostfix
;
281 aPrefix
= "com.sun.star.chart.";
282 aPostfix
= "Diagram";
286 aPrefix
= "com.sun.star.chart2.";
287 aPostfix
= "ChartType";
290 if( o3tl::starts_with(rChartTypeService
, aPrefix
))
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
) )
298 std::u16string_view
aServiceName( rChartTypeService
.substr( nSkip
, nTypeLength
));
300 if ( aServiceName
== u
"Line" )
302 else if ( aServiceName
== u
"Area" )
304 else if( aServiceName
== u
"Bar" ||
305 (!bUseOldNames
&& aServiceName
== u
"Column"))
307 else if ( aServiceName
== u
"Pie" )
308 eResult
= XML_CIRCLE
;
309 else if ( aServiceName
== u
"Donut" )
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" )
318 else if ( aServiceName
== u
"FilledNet" )
319 eResult
= XML_FILLED_RADAR
;
320 else if( (bUseOldNames
&& aServiceName
== u
"Stock") ||
321 (!bUseOldNames
&& aServiceName
== u
"CandleStick"))
326 if( eResult
== XML_TOKEN_INVALID
&& !rChartTypeService
.empty() )
327 eResult
= XML_ADD_IN
;
332 Reference
< chart2::data::XLabeledDataSequence2
> GetNewLabeledDataSequence()
334 Reference
< uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
335 Reference
< chart2::data::XLabeledDataSequence2
> xResult
= chart2::data::LabeledDataSequence::create(xContext
);
339 Reference
< chart2::data::XDataSequence
> CreateDataSequence(
340 const OUString
& rRange
,
341 const Reference
< chart2::XChartDocument
>& xChartDoc
)
343 Reference
< chart2::data::XDataSequence
> xRet
;
345 if( !xChartDoc
.is() )
347 SAL_WARN("xmloff.chart", "need a chart document" );
351 Reference
< chart2::data::XDataProvider
> xDataProvider( xChartDoc
->getDataProvider() );
352 if( !xDataProvider
.is() )
354 SAL_WARN("xmloff.chart", "need a data provider" );
358 bool bUseInternal
= false;
359 uno::Reference
<beans::XPropertySet
> xPropSet(xDataProvider
, uno::UNO_QUERY
);
365 uno::Any any
= xPropSet
->getPropertyValue("UseInternalDataProvider");
369 catch (const beans::UnknownPropertyException
&)
379 xRet
.set( xDataProvider
->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange
, xDataProvider
)));
380 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet
, rRange
);
382 catch( const lang::IllegalArgumentException
& )
384 SAL_WARN("xmloff.chart", "could not create data sequence" );
388 if( !xRet
.is() && !xChartDoc
->hasInternalDataProvider() && !rRange
.isEmpty() )
390 //#i103911# switch to internal data in case the parent cannot provide the requested data
391 xChartDoc
->createInternalDataProvider( true /* bCloneExistingData */ );
392 xDataProvider
= xChartDoc
->getDataProvider();
395 xRet
.set( xDataProvider
->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange
, xDataProvider
)));
396 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet
, rRange
);
398 catch( const lang::IllegalArgumentException
& )
400 SAL_WARN("xmloff.chart", "could not create data sequence" );
406 Reference
< chart2::data::XDataSequence
> CreateDataSequenceWithoutConvert(
407 const OUString
& rRange
,
408 const Reference
< chart2::XChartDocument
>& xChartDoc
)
410 Reference
< chart2::data::XDataSequence
> xRet
;
412 if( !xChartDoc
.is() )
414 SAL_WARN("xmloff.chart", "need a chart document" );
418 Reference
< chart2::data::XDataProvider
> xDataProvider( xChartDoc
->getDataProvider() );
419 if( !xDataProvider
.is() )
421 SAL_WARN("xmloff.chart", "need a data provider" );
427 xRet
.set( xDataProvider
->createDataSequenceByRangeRepresentation( rRange
) );
428 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet
, rRange
);
430 catch( const lang::IllegalArgumentException
& )
432 SAL_WARN("xmloff.chart", "could not create data sequence" );
438 void CreateCategories(
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
)
448 if( xNewDoc
.is() && !rRangeAddress
.isEmpty())
450 if( xDataProvider
.is())
452 uno::Reference
< chart2::XDiagram
> xDia( xNewDoc
->getFirstDiagram());
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())
461 uno::Reference
< chart2::XCoordinateSystem
> xCooSys( aCooSysSeq
[nCooSysIndex
] );
462 SAL_WARN_IF( !xCooSys
.is(), "xmloff.chart", "xCooSys is NULL");
463 if( nDimensionIndex
< xCooSys
->getDimension() )
465 const sal_Int32 nMaxAxisIndex
= xCooSys
->getMaximumAxisIndexByDimension(nDimensionIndex
);
466 for(sal_Int32 nI
=0; nI
<=nMaxAxisIndex
; ++nI
)
468 uno::Reference
< chart2::XAxis
> xAxis( xCooSys
->getAxisByDimension( nDimensionIndex
, nI
));
471 chart2::ScaleData
aData( xAxis
->getScaleData());
472 uno::Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq(
473 GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW
);
476 OUString
aConvertedRange( rRangeAddress
);
477 bool bRangeConverted
= false;
478 if( ! (xNewDoc
->hasInternalDataProvider() && aConvertedRange
== "categories"))
480 Reference
< chart2::data::XRangeXMLConversion
> xXMLConv( xDataProvider
, uno::UNO_QUERY
);
483 aConvertedRange
= xXMLConv
->convertRangeFromXML( rRangeAddress
);
484 bRangeConverted
= true;
488 Reference
<chart2::data::XDataSequence
> xSequence
;
489 Reference
<chart2::data::XPivotTableDataProvider
> xPivotTableDataProvider(xDataProvider
, uno::UNO_QUERY
);
490 if (xPivotTableDataProvider
.is())
492 xSequence
.set(xPivotTableDataProvider
->createDataSequenceOfCategories());
496 xSequence
.set(xDataProvider
->createDataSequenceByRangeRepresentation(aConvertedRange
));
498 setXMLRangePropertyAtDataSequence(xSequence
, rRangeAddress
);
500 xLabeledSeq
->setValues(xSequence
);
503 catch( const lang::IllegalArgumentException
& )
505 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
507 aData
.Categories
.set( xLabeledSeq
);
508 if( pLSequencesPerIndex
)
510 // register for setting local data if external data provider is not present
511 pLSequencesPerIndex
->emplace(
512 tSchXMLIndexWithPart( SCH_XML_CATEGORIES_INDEX
, SCH_XML_PART_VALUES
), xLabeledSeq
);
514 xAxis
->setScaleData( aData
);
522 catch( uno::Exception
& )
524 TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception caught while creating Categories" );
528 uno::Any
getPropertyFromContext( std::u16string_view rPropertyName
, const XMLPropStyleContext
* pPropStyleContext
, const SvXMLStylesContext
* pStylesCtxt
)
531 if( !pPropStyleContext
|| !pStylesCtxt
)
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
)
537 sal_Int32 nIdx
= rProp
.mnIndex
;
540 OUString aPropName
= rMapper
->GetEntryAPIName( nIdx
);
541 if(rPropertyName
== aPropName
)
542 return rProp
.maValue
;
547 void exportText( SvXMLExport
& rExport
, const OUString
& rText
, bool bConvertTabsLFs
)
549 SvXMLElementExport
aPara( rExport
, XML_NAMESPACE_TEXT
,
550 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_P
),
553 if( bConvertTabsLFs
)
555 sal_Int32 nStartPos
= 0;
556 sal_Int32 nEndPos
= rText
.getLength();
559 for( sal_Int32 nPos
= 0; nPos
< nEndPos
; nPos
++ )
561 cChar
= rText
[ nPos
];
564 case 0x0009: // tabulator
566 if( nPos
> nStartPos
)
567 rExport
.GetDocHandler()->characters( rText
.copy( nStartPos
, (nPos
- nStartPos
)) );
568 nStartPos
= nPos
+ 1;
570 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_TEXT
,
571 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_TAB_STOP
),
576 case 0x000A: // linefeed
578 if( nPos
> nStartPos
)
579 rExport
.GetDocHandler()->characters( rText
.copy( nStartPos
, (nPos
- nStartPos
)) );
580 nStartPos
= nPos
+ 1;
582 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_TEXT
,
583 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_LINE_BREAK
),
589 if( nEndPos
> nStartPos
)
592 rExport
.GetDocHandler()->characters( rText
);
594 rExport
.GetDocHandler()->characters( rText
.copy( nStartPos
, (nEndPos
- nStartPos
)) );
597 else // do not convert tabs and linefeeds (eg for numbers coming from unit converter)
599 rExport
.GetDocHandler()->characters( rText
);
603 void exportRangeToSomewhere( SvXMLExport
& rExport
, const OUString
& rValue
)
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
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)
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
618 SvXMLElementExport
aEmptyShapeGroup( rExport
, XML_NAMESPACE_DRAW
,
619 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_G
),
621 SvXMLElementExport
aDescription( rExport
, XML_NAMESPACE_SVG
,
622 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DESC
),
624 rExport
.GetDocHandler()->characters( rValue
);
627 void setXMLRangePropertyAtDataSequence(
628 const Reference
< chart2::data::XDataSequence
> & xDataSequence
,
629 const OUString
& rXMLRange
)
631 if( !xDataSequence
.is())
635 static constexpr OUString
aXMLRangePropName( u
"CachedXMLRange"_ustr
);
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
));
641 catch( const uno::Exception
& )
643 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
647 bool getXMLRangePropertyFromDataSequence(
648 const Reference
< chart2::data::XDataSequence
> & xDataSequence
,
649 OUString
& rOutXMLRange
,
650 bool bClearProp
/* = false */)
652 bool bResult
= false;
653 if( xDataSequence
.is())
657 static constexpr OUString
aXMLRangePropName( u
"CachedXMLRange"_ustr
);
658 Reference
< beans::XPropertySet
> xProp( xDataSequence
, uno::UNO_QUERY_THROW
);
659 Reference
< beans::XPropertySetInfo
> xInfo( xProp
->getPropertySetInfo());
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()));
668 catch( const uno::Exception
& )
670 DBG_UNHANDLED_EXCEPTION("xmloff.chart");
677 const Reference
< beans::XPropertySet
> & xSource
,
678 const Reference
< beans::XPropertySet
> & xDestination
)
680 if( ! (xSource
.is() && xDestination
.is()) )
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
)
690 OUString
aName( rProperty
.Name
);
691 if( xDestInfo
->hasPropertyByName( aName
))
693 beans::Property
aProp( xDestInfo
->getPropertyByName( aName
));
694 if( (aProp
.Attributes
& beans::PropertyAttribute::READONLY
) == 0 )
695 xDestination
->setPropertyValue(
696 aName
, xSource
->getPropertyValue( aName
));
700 catch( const uno::Exception
& )
702 SAL_WARN("xmloff.chart", "Copying property sets failed!" );
706 bool switchBackToDataProviderFromParent( const Reference
< chart2::XChartDocument
>& xChartDoc
, const tSchXMLLSequencesPerIndex
& rLSequencesPerIndex
)
708 //return whether the switch is successful
709 if( !xChartDoc
.is() || !xChartDoc
->hasInternalDataProvider() )
711 Reference
< chart2::data::XDataProvider
> xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc
) );
712 if( !xDataProviderFromParent
.is() )
714 uno::Reference
< chart2::data::XDataReceiver
> xDataReceiver( xChartDoc
, uno::UNO_QUERY
);
715 if( !xDataReceiver
.is() )
718 xDataReceiver
->attachDataProvider( xDataProviderFromParent
);
720 for( const auto& rLSeq
: rLSequencesPerIndex
)
722 Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq( rLSeq
.second
);
723 if( !xLabeledSeq
.is() )
725 Reference
< chart2::data::XDataSequence
> xNewSeq
;
726 xNewSeq
= lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq
->getValues(), xDataProviderFromParent
);
728 xLabeledSeq
->setValues( xNewSeq
);
729 xNewSeq
= lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq
->getLabel(), xDataProviderFromParent
);
731 xLabeledSeq
->setLabel( xNewSeq
);
736 void setBuildIDAtImportInfo( const uno::Reference
< frame::XModel
>& xModel
, const Reference
< beans::XPropertySet
>& xImportInfo
)
738 OUString
aGenerator( lcl_getGeneratorFromModelOrItsParent(xModel
) );
739 if( !aGenerator
.isEmpty() )
740 SvXMLMetaDocumentContext::setBuildId( aGenerator
, xImportInfo
);
743 bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const uno::Reference
< frame::XModel
>& xChartModel
)
745 bool bResult
= isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel
);
748 OUString
aGenerator( lcl_getGeneratorFromModel(xChartModel
) );
749 if( aGenerator
.indexOf( "OpenOffice.org_project/3" ) != -1 )
751 if( aGenerator
.indexOf( "OpenOffice.org_project/300m" ) != -1 )
753 sal_Int32 nBuilId
= lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel
) );
754 if( nBuilId
>0 && nBuilId
<9491 ) //9491 is build id of dev300m76
757 else if( aGenerator
.indexOf( "OpenOffice.org_project/310m" ) != -1 )
759 else if( aGenerator
.indexOf( "OpenOffice.org_project/320m" ) != -1 )
766 bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const uno::Reference
< frame::XModel
>& xChartModel
)
768 bool bResult
= isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel
);
771 OUString
aGenerator( lcl_getGeneratorFromModel(xChartModel
) );
772 if( aGenerator
.indexOf( "OpenOffice.org_project/680m" ) != -1 )
778 bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const uno::Reference
< frame::XModel
>& xChartModel
)
780 if( isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel
) )
783 if( isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel
) )
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
792 bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const uno::Reference
< frame::XModel
>& xChartModel
)
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() )
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
);
803 aGenerator
= lcl_getGeneratorFromModel( uno::Reference
< frame::XModel
>( xChild
->getParent(), uno::UNO_QUERY
) );
804 if( aGenerator
.indexOf( "OpenOffice.org_project" ) != -1 )
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
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
813 else if( isDocumentGeneratedWithOpenOfficeOlderThan2_0(xChartModel
) )
820 bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const css::uno::Reference
< css::frame::XModel
>& xChartModel
)
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" )
834 Reference
< chart2::data::XDataProvider
> getDataProviderFromParent( const Reference
< chart2::XChartDocument
>& xChartDoc
)
836 Reference
< chart2::data::XDataProvider
> xRet
;
837 uno::Reference
< container::XChild
> xChild( xChartDoc
, uno::UNO_QUERY
);
840 Reference
< lang::XMultiServiceFactory
> xFact( xChild
->getParent(), uno::UNO_QUERY
);
843 static constexpr OUString
aDataProviderServiceName( u
"com.sun.star.chart2.data.DataProvider"_ustr
);
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
)
849 xRet
.set( xFact
->createInstance( aDataProviderServiceName
), uno::UNO_QUERY
);
856 } // namespace SchXMLTools
858 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */