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/xmlnmspe.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/XChartDocument.hpp>
40 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
41 #include <com/sun/star/chart2/XRegressionCurveContainer.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/lang/XServiceName.hpp>
48 #include <comphelper/processfactory.hxx>
52 using namespace com::sun::star
;
53 using namespace ::xmloff::token
;
55 using ::com::sun::star::uno::Reference
;
56 using ::com::sun::star::uno::Sequence
;
61 OUString
lcl_getGeneratorFromModel( const uno::Reference
< frame::XModel
>& xChartModel
)
64 uno::Reference
< document::XDocumentPropertiesSupplier
> xChartDocumentPropertiesSupplier( xChartModel
, uno::UNO_QUERY
);
65 if( xChartDocumentPropertiesSupplier
.is() )
67 uno::Reference
< document::XDocumentProperties
> xChartDocumentProperties(
68 xChartDocumentPropertiesSupplier
->getDocumentProperties());
69 if( xChartDocumentProperties
.is() )
70 aGenerator
= xChartDocumentProperties
->getGenerator();
75 OUString
lcl_getGeneratorFromModelOrItsParent( const uno::Reference
< frame::XModel
>& xChartModel
)
77 OUString
aGenerator( lcl_getGeneratorFromModel(xChartModel
) );
78 if( aGenerator
.isEmpty() ) //try to get the missing info from the parent document
80 uno::Reference
< container::XChild
> xChild( xChartModel
, uno::UNO_QUERY
);
82 aGenerator
= lcl_getGeneratorFromModel( uno::Reference
< frame::XModel
>( xChild
->getParent(), uno::UNO_QUERY
) );
87 sal_Int32
lcl_getBuildIDFromGenerator( const OUString
& rGenerator
)
89 //returns -1 if nothing found
90 sal_Int32 nBuildId
= -1;
91 const OUString
sBuildCompare( "$Build-" );
92 sal_Int32 nBegin
= rGenerator
.indexOf( sBuildCompare
);
95 OUString
sBuildId( rGenerator
.copy( nBegin
+ sBuildCompare
.getLength() ) );
96 nBuildId
= sBuildId
.toInt32();
101 OUString
lcl_ConvertRange( const OUString
& rRange
, const Reference
< chart2::data::XDataProvider
>& xDataProvider
)
103 OUString aResult
= rRange
;
104 Reference
< chart2::data::XRangeXMLConversion
> xRangeConversion( xDataProvider
, uno::UNO_QUERY
);
105 if( xRangeConversion
.is())
106 aResult
= xRangeConversion
->convertRangeFromXML( rRange
);
110 Reference
< chart2::data::XDataSequence
> lcl_createNewSequenceFromCachedXMLRange( const Reference
< chart2::data::XDataSequence
>& xSeq
, const Reference
< chart2::data::XDataProvider
>& xDataProvider
)
112 Reference
< chart2::data::XDataSequence
> xRet
;
114 if( xSeq
.is() && SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq
, aRange
, /* bClearProp = */ true ) )
116 xRet
.set( xDataProvider
->createDataSequenceByRangeRepresentation(
117 lcl_ConvertRange( aRange
, xDataProvider
)) );
118 SchXMLTools::copyProperties( Reference
< beans::XPropertySet
>( xSeq
, uno::UNO_QUERY
),
119 Reference
< beans::XPropertySet
>( xRet
, uno::UNO_QUERY
));
124 } // anonymous namespace
126 namespace SchXMLTools
129 static const SvXMLEnumMapEntry aXMLChartClassMap
[] =
131 { XML_LINE
, XML_CHART_CLASS_LINE
},
132 { XML_AREA
, XML_CHART_CLASS_AREA
},
133 { XML_CIRCLE
, XML_CHART_CLASS_CIRCLE
},
134 { XML_RING
, XML_CHART_CLASS_RING
},
135 { XML_SCATTER
, XML_CHART_CLASS_SCATTER
},
136 { XML_RADAR
, XML_CHART_CLASS_RADAR
},
137 { XML_FILLED_RADAR
, XML_CHART_CLASS_FILLED_RADAR
},
138 { XML_BAR
, XML_CHART_CLASS_BAR
},
139 { XML_STOCK
, XML_CHART_CLASS_STOCK
},
140 { XML_BUBBLE
, XML_CHART_CLASS_BUBBLE
},
141 { XML_GL3DBAR
, XML_CHART_CLASS_GL3DBAR
},
142 { XML_SURFACE
, XML_CHART_CLASS_BAR
}, //@todo change this if a surface chart is available
143 { XML_ADD_IN
, XML_CHART_CLASS_ADDIN
},
144 { XML_TOKEN_INVALID
, XML_CHART_CLASS_UNKNOWN
}
147 SchXMLChartTypeEnum
GetChartTypeEnum( const OUString
& rClassName
)
149 sal_uInt16 nEnumVal
= XML_CHART_CLASS_UNKNOWN
;
150 if( !SvXMLUnitConverter::convertEnum(
151 nEnumVal
, rClassName
, aXMLChartClassMap
) )
152 nEnumVal
= XML_CHART_CLASS_UNKNOWN
;
153 return SchXMLChartTypeEnum(nEnumVal
);
156 typedef std::map
< OUString
, OUString
> tMakeStringStringMap
;
158 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 {"com.sun.star.chart.GL3DBarDiagram",
183 "com.sun.star.chart2.GL3DBarChartType"}};
184 return g_aChartTypeNameMap
;
187 OUString
GetNewChartTypeName( const OUString
& rOldChartTypeName
)
189 OUString
aNew(rOldChartTypeName
);
191 const tMakeStringStringMap
& rMap
= lcl_getChartTypeNameMap();
192 tMakeStringStringMap::const_iterator
aIt( rMap
.find( rOldChartTypeName
));
193 if( aIt
!= rMap
.end())
200 OUString
GetChartTypeByClassName(
201 const OUString
& rClassName
, bool bUseOldNames
)
203 OUStringBuffer aResultBuffer
;
204 bool bInternalType
= false;
207 aResultBuffer
.append( "com.sun.star.chart.");
209 aResultBuffer
.append( "com.sun.star.chart2.");
211 bInternalType
= true;
213 if( IsXMLToken( rClassName
, XML_LINE
))
214 aResultBuffer
.append("Line");
215 else if( IsXMLToken( rClassName
, XML_AREA
))
216 aResultBuffer
.append("Area");
217 else if( IsXMLToken( rClassName
, XML_BAR
))
220 aResultBuffer
.append("Bar");
223 aResultBuffer
.append("Column");
224 // @todo: might be Bar
227 else if( IsXMLToken( rClassName
, XML_CIRCLE
))
228 aResultBuffer
.append("Pie");
229 else if( IsXMLToken( rClassName
, XML_RING
))
230 aResultBuffer
.append("Donut");
231 else if( IsXMLToken( rClassName
, XML_SCATTER
))
234 aResultBuffer
.append("XY");
236 aResultBuffer
.append("Scatter");
239 else if( IsXMLToken( rClassName
, XML_BUBBLE
))
240 aResultBuffer
.append("Bubble");
241 else if( IsXMLToken( rClassName
, XML_RADAR
))
242 aResultBuffer
.append("Net");
243 else if( IsXMLToken( rClassName
, XML_FILLED_RADAR
))
244 aResultBuffer
.append("FilledNet");
245 else if( IsXMLToken( rClassName
, XML_STOCK
))
248 aResultBuffer
.append("Stock");
250 aResultBuffer
.append("CandleStick");
252 else if( IsXMLToken( rClassName
, XML_SURFACE
))
254 //@todo change this if a surface chart is available
256 aResultBuffer
.append("Bar");
258 aResultBuffer
.append("Column");
260 else if (IsXMLToken(rClassName
, XML_GL3DBAR
))
261 aResultBuffer
.append("GL3DBar");
263 bInternalType
= false;
265 if( ! bInternalType
)
269 aResultBuffer
.append("Diagram");
271 aResultBuffer
.append("ChartType");
273 return aResultBuffer
.makeStringAndClear();
277 XMLTokenEnum
getTokenByChartType(
278 const OUString
& rChartTypeService
, bool bUseOldNames
)
280 XMLTokenEnum eResult
= XML_TOKEN_INVALID
;
281 OUString aPrefix
, aPostfix
;
285 aPrefix
= "com.sun.star.chart.";
286 aPostfix
= "Diagram";
290 aPrefix
= "com.sun.star.chart2.";
291 aPostfix
= "ChartType";
294 if( rChartTypeService
.match( aPrefix
))
296 sal_Int32 nSkip
= aPrefix
.getLength();
297 SAL_WARN_IF( rChartTypeService
.getLength() < nSkip
, "xmloff.chart", "ChartTypeService.getLength() < nSkip" );
298 sal_Int32 nTypeLength
= rChartTypeService
.getLength() - nSkip
- aPostfix
.getLength();
299 // if postfix matches and leaves a non-empty type
300 if( nTypeLength
> 0 && rChartTypeService
.match( aPostfix
, nSkip
+ nTypeLength
))
302 OUString
aServiceName( rChartTypeService
.copy( nSkip
, nTypeLength
));
304 if ( aServiceName
== "Line" )
306 else if ( aServiceName
== "Area" )
308 else if( aServiceName
== "Bar" ||
309 (!bUseOldNames
&& aServiceName
== "Column"))
311 else if ( aServiceName
== "Pie" )
312 eResult
= XML_CIRCLE
;
313 else if ( aServiceName
== "Donut" )
315 else if( (bUseOldNames
&& aServiceName
== "XY") ||
316 (!bUseOldNames
&& aServiceName
== "Scatter"))
317 eResult
= XML_SCATTER
;
318 else if ( aServiceName
== "Bubble" )
319 eResult
= XML_BUBBLE
;
320 else if ( aServiceName
== "Net" )
322 else if ( aServiceName
== "FilledNet" )
323 eResult
= XML_FILLED_RADAR
;
324 else if( (bUseOldNames
&& aServiceName
== "Stock") ||
325 (!bUseOldNames
&& aServiceName
== "CandleStick"))
327 else if (aServiceName
== "GL3DBar")
328 eResult
= XML_GL3DBAR
;
332 if( eResult
== XML_TOKEN_INVALID
&& !rChartTypeService
.isEmpty() )
333 eResult
= XML_ADD_IN
;
338 Reference
< chart2::data::XLabeledDataSequence2
> GetNewLabeledDataSequence()
340 Reference
< uno::XComponentContext
> xContext( comphelper::getProcessComponentContext() );
341 Reference
< chart2::data::XLabeledDataSequence2
> xResult
= chart2::data::LabeledDataSequence::create(xContext
);
345 Reference
< chart2::data::XDataSequence
> CreateDataSequence(
346 const OUString
& rRange
,
347 const Reference
< chart2::XChartDocument
>& xChartDoc
)
349 Reference
< chart2::data::XDataSequence
> xRet
;
351 if( !xChartDoc
.is() )
353 SAL_WARN("xmloff.chart", "need a chart document" );
357 Reference
< chart2::data::XDataProvider
> xDataProvider( xChartDoc
->getDataProvider() );
358 if( !xDataProvider
.is() )
360 SAL_WARN("xmloff.chart", "need a data provider" );
364 bool bUseInternal
= false;
365 uno::Reference
<beans::XPropertySet
> xPropSet(xDataProvider
, uno::UNO_QUERY
);
371 uno::Any any
= xPropSet
->getPropertyValue("UseInternalDataProvider");
373 bUseInternal
= static_cast<bool>(bVal
);
375 catch (const beans::UnknownPropertyException
&)
385 xRet
.set( xDataProvider
->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange
, xDataProvider
)));
386 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet
, rRange
);
388 catch( const lang::IllegalArgumentException
& )
390 SAL_WARN("xmloff.chart", "could not create data sequence" );
394 if( !xRet
.is() && !xChartDoc
->hasInternalDataProvider() && !rRange
.isEmpty() )
396 //#i103911# switch to internal data in case the parent cannot provide the requested data
397 xChartDoc
->createInternalDataProvider( true /* bCloneExistingData */ );
398 xDataProvider
= xChartDoc
->getDataProvider();
401 xRet
.set( xDataProvider
->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange
, xDataProvider
)));
402 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet
, rRange
);
404 catch( const lang::IllegalArgumentException
& )
406 SAL_WARN("xmloff.chart", "could not create data sequence" );
412 Reference
< chart2::data::XDataSequence
> CreateDataSequenceWithoutConvert(
413 const OUString
& rRange
,
414 const Reference
< chart2::XChartDocument
>& xChartDoc
)
416 Reference
< chart2::data::XDataSequence
> xRet
;
418 if( !xChartDoc
.is() )
420 SAL_WARN("xmloff.chart", "need a chart document" );
424 Reference
< chart2::data::XDataProvider
> xDataProvider( xChartDoc
->getDataProvider() );
425 if( !xDataProvider
.is() )
427 SAL_WARN("xmloff.chart", "need a data provider" );
433 xRet
.set( xDataProvider
->createDataSequenceByRangeRepresentation( rRange
) );
434 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet
, rRange
);
436 catch( const lang::IllegalArgumentException
& )
438 SAL_WARN("xmloff.chart", "could not create data sequence" );
444 void CreateCategories(
445 const uno::Reference
< chart2::data::XDataProvider
> & xDataProvider
,
446 const uno::Reference
< chart2::XChartDocument
> & xNewDoc
,
447 const OUString
& rRangeAddress
,
448 sal_Int32 nCooSysIndex
,
449 sal_Int32 nDimensionIndex
,
450 tSchXMLLSequencesPerIndex
* pLSequencesPerIndex
)
454 if( xNewDoc
.is() && !rRangeAddress
.isEmpty())
456 if( xDataProvider
.is())
458 uno::Reference
< chart2::XDiagram
> xDia( xNewDoc
->getFirstDiagram());
462 uno::Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt( xDia
, uno::UNO_QUERY_THROW
);
463 uno::Sequence
< uno::Reference
< chart2::XCoordinateSystem
> >
464 aCooSysSeq( xCooSysCnt
->getCoordinateSystems());
465 if( nCooSysIndex
< aCooSysSeq
.getLength())
467 uno::Reference
< chart2::XCoordinateSystem
> xCooSys( aCooSysSeq
[nCooSysIndex
] );
468 SAL_WARN_IF( !xCooSys
.is(), "xmloff.chart", "xCooSys is NULL");
469 if( nDimensionIndex
< xCooSys
->getDimension() )
471 const sal_Int32 nMaxAxisIndex
= xCooSys
->getMaximumAxisIndexByDimension(nDimensionIndex
);
472 for(sal_Int32 nI
=0; nI
<=nMaxAxisIndex
; ++nI
)
474 uno::Reference
< chart2::XAxis
> xAxis( xCooSys
->getAxisByDimension( nDimensionIndex
, nI
));
477 chart2::ScaleData
aData( xAxis
->getScaleData());
478 uno::Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq(
479 GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW
);
482 OUString
aConvertedRange( rRangeAddress
);
483 bool bRangeConverted
= false;
484 if( ! (xNewDoc
->hasInternalDataProvider() && aConvertedRange
== "categories"))
486 Reference
< chart2::data::XRangeXMLConversion
> xXMLConv( xDataProvider
, uno::UNO_QUERY
);
489 aConvertedRange
= xXMLConv
->convertRangeFromXML( rRangeAddress
);
490 bRangeConverted
= true;
493 Reference
< chart2::data::XDataSequence
> xSeq(
494 xDataProvider
->createDataSequenceByRangeRepresentation( aConvertedRange
));
495 xLabeledSeq
->setValues( xSeq
);
496 if( bRangeConverted
)
497 setXMLRangePropertyAtDataSequence( xSeq
, rRangeAddress
);
499 catch( const lang::IllegalArgumentException
& ex
)
501 SAL_WARN("xmloff.chart", "IllegalArgumentException caught, Message: " << ex
.Message
);
503 aData
.Categories
.set( xLabeledSeq
);
504 if( pLSequencesPerIndex
)
506 // register for setting local data if external data provider is not present
507 pLSequencesPerIndex
->insert(
508 tSchXMLLSequencesPerIndex::value_type(
509 tSchXMLIndexWithPart( SCH_XML_CATEGORIES_INDEX
, SCH_XML_PART_VALUES
), xLabeledSeq
));
511 xAxis
->setScaleData( aData
);
519 catch( uno::Exception
& )
521 SAL_WARN("xmloff.chart", "Exception caught while creating Categories" );
525 uno::Any
getPropertyFromContext( const OUString
& rPropertyName
, const XMLPropStyleContext
* pPropStyleContext
, const SvXMLStylesContext
* pStylesCtxt
)
528 if( !pPropStyleContext
|| !pStylesCtxt
)
530 const ::std::vector
< XMLPropertyState
>& rProperties
= pPropStyleContext
->GetProperties();
531 const rtl::Reference
< XMLPropertySetMapper
>& rMapper
= pStylesCtxt
->GetImportPropertyMapper( pPropStyleContext
->GetFamily()/*XML_STYLE_FAMILY_SCH_CHART_ID*/ )->getPropertySetMapper();
532 ::std::vector
< XMLPropertyState
>::const_iterator
aEnd( rProperties
.end() );
533 ::std::vector
< XMLPropertyState
>::const_iterator
aPropIter( rProperties
.begin() );
534 for( aPropIter
= rProperties
.begin(); aPropIter
!= aEnd
; ++aPropIter
)
536 sal_Int32 nIdx
= aPropIter
->mnIndex
;
539 OUString aPropName
= rMapper
->GetEntryAPIName( nIdx
);
540 if(rPropertyName
.equals(aPropName
))
541 return aPropIter
->maValue
;
546 void exportText( SvXMLExport
& rExport
, const OUString
& rText
, bool bConvertTabsLFs
)
548 SvXMLElementExport
aPara( rExport
, XML_NAMESPACE_TEXT
,
549 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_P
),
552 if( bConvertTabsLFs
)
554 sal_Int32 nStartPos
= 0;
555 sal_Int32 nEndPos
= rText
.getLength();
558 for( sal_Int32 nPos
= 0; nPos
< nEndPos
; nPos
++ )
560 cChar
= rText
[ nPos
];
563 case 0x0009: // tabulator
565 if( nPos
> nStartPos
)
566 rExport
.GetDocHandler()->characters( rText
.copy( nStartPos
, (nPos
- nStartPos
)) );
567 nStartPos
= nPos
+ 1;
569 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_TEXT
,
570 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_TAB_STOP
),
575 case 0x000A: // linefeed
577 if( nPos
> nStartPos
)
578 rExport
.GetDocHandler()->characters( rText
.copy( nStartPos
, (nPos
- nStartPos
)) );
579 nStartPos
= nPos
+ 1;
581 SvXMLElementExport
aElem( rExport
, XML_NAMESPACE_TEXT
,
582 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_LINE_BREAK
),
588 if( nEndPos
> nStartPos
)
591 rExport
.GetDocHandler()->characters( rText
);
593 rExport
.GetDocHandler()->characters( rText
.copy( nStartPos
, (nEndPos
- nStartPos
)) );
596 else // do not convert tabs and linefeeds (eg for numbers coming from unit converter)
598 rExport
.GetDocHandler()->characters( rText
);
602 void exportRangeToSomewhere( SvXMLExport
& rExport
, const OUString
& rValue
)
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
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)
612 const SvtSaveOptions::ODFDefaultVersion
nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
613 if( nCurrentODFVersion
== SvtSaveOptions::ODFVER_010
|| nCurrentODFVersion
== SvtSaveOptions::ODFVER_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
616 SvXMLElementExport
aEmptyShapeGroup( rExport
, XML_NAMESPACE_DRAW
,
617 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_G
),
619 SvXMLElementExport
aDescription( rExport
, XML_NAMESPACE_SVG
,
620 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DESC
),
622 rExport
.GetDocHandler()->characters( rValue
);
625 void setXMLRangePropertyAtDataSequence(
626 const Reference
< chart2::data::XDataSequence
> & xDataSequence
,
627 const OUString
& rXMLRange
)
629 if( !xDataSequence
.is())
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
));
639 catch( const uno::Exception
& ex
)
641 SAL_WARN("xmloff.chart", "Exception caught, Message: " << ex
.Message
);
645 bool getXMLRangePropertyFromDataSequence(
646 const Reference
< chart2::data::XDataSequence
> & xDataSequence
,
647 OUString
& rOutXMLRange
,
648 bool bClearProp
/* = false */)
650 bool bResult
= false;
651 if( xDataSequence
.is())
655 const OUString
aXMLRangePropName( "CachedXMLRange" );
656 Reference
< beans::XPropertySet
> xProp( xDataSequence
, uno::UNO_QUERY_THROW
);
657 Reference
< beans::XPropertySetInfo
> xInfo( xProp
->getPropertySetInfo());
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()));
666 catch( const uno::Exception
& ex
)
668 SAL_WARN("xmloff.chart", "Exception caught, Message: " << ex
.Message
);
675 const Reference
< beans::XPropertySet
> & xSource
,
676 const Reference
< beans::XPropertySet
> & xDestination
)
678 if( ! (xSource
.is() && xDestination
.is()) )
683 Reference
< beans::XPropertySetInfo
> xSrcInfo( xSource
->getPropertySetInfo(), uno::UNO_QUERY_THROW
);
684 Reference
< beans::XPropertySetInfo
> xDestInfo( xDestination
->getPropertySetInfo(), uno::UNO_QUERY_THROW
);
685 Sequence
< beans::Property
> aProperties( xSrcInfo
->getProperties());
686 const sal_Int32 nLength
= aProperties
.getLength();
687 for( sal_Int32 i
= 0; i
< nLength
; ++i
)
689 OUString
aName( aProperties
[i
].Name
);
690 if( xDestInfo
->hasPropertyByName( aName
))
692 beans::Property
aProp( xDestInfo
->getPropertyByName( aName
));
693 if( (aProp
.Attributes
& beans::PropertyAttribute::READONLY
) == 0 )
694 xDestination
->setPropertyValue(
695 aName
, xSource
->getPropertyValue( aName
));
699 catch( const uno::Exception
& )
701 SAL_WARN("xmloff.chart", "Copying property sets failed!" );
705 bool switchBackToDataProviderFromParent( const Reference
< chart2::XChartDocument
>& xChartDoc
, const tSchXMLLSequencesPerIndex
& rLSequencesPerIndex
)
707 //return whether the switch is successful
708 if( !xChartDoc
.is() || !xChartDoc
->hasInternalDataProvider() )
710 Reference
< chart2::data::XDataProvider
> xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc
) );
711 if( !xDataProviderFromParent
.is() )
713 uno::Reference
< chart2::data::XDataReceiver
> xDataReceiver( xChartDoc
, uno::UNO_QUERY
);
714 if( !xDataReceiver
.is() )
717 xDataReceiver
->attachDataProvider( xDataProviderFromParent
);
719 for( tSchXMLLSequencesPerIndex::const_iterator
aLSeqIt( rLSequencesPerIndex
.begin() );
720 aLSeqIt
!= rLSequencesPerIndex
.end(); ++aLSeqIt
)
722 Reference
< chart2::data::XLabeledDataSequence
> xLabeledSeq( aLSeqIt
->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 const OUString
aDataProviderServiceName( "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
)
849 xRet
.set( xFact
->createInstance( aDataProviderServiceName
), uno::UNO_QUERY
);
856 } // namespace SchXMLTools
858 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */