1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_xmloff.hxx"
26
27 #include "SchXMLTools.hxx"
28
29 /*
30 #include <tools/debug.hxx>
31 */
32 #include <rtl/ustrbuf.hxx>
33 #include <comphelper/InlineContainer.hxx>
34 // header for class SvXMLUnitConverter
35 #include <xmloff/xmluconv.hxx>
36 // header for struct SvXMLEnumMapEntry
37 #include <xmloff/xmlement.hxx>
38 // header for define __FAR_DATA
39 #include <tools/solar.h>
40
41 // header for class SvXMLImportPropertyMapper
42 #include <xmloff/xmlimppr.hxx>
43 // header for class XMLPropStyleContext
44 #include <xmloff/prstylei.hxx>
45 // header for class XMLPropertySetMapper
46 #include <xmloff/xmlprmap.hxx>
47 #include <xmloff/xmlexp.hxx>
48 #include "xmloff/xmlnmspe.hxx"
49 #include <xmloff/xmlmetai.hxx>
50
51 #include <com/sun/star/beans/PropertyAttribute.hpp>
52 #include <com/sun/star/uno/XComponentContext.hpp>
53 #include <com/sun/star/chart2/data/XDataProvider.hpp>
54 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
55 #include <com/sun/star/chart2/data/XRangeXMLConversion.hpp>
56 #include <com/sun/star/chart2/XChartDocument.hpp>
57 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
58 #include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
59 #include <com/sun/star/container/XChild.hpp>
60 #include <com/sun/star/document/XDocumentProperties.hpp>
61 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
62 #include <com/sun/star/lang/XServiceName.hpp>
63
64 #include <comphelper/processfactory.hxx>
65
66 using namespace com::sun::star;
67 using namespace ::xmloff::token;
68
69 using ::rtl::OUString;
70 using ::rtl::OUStringBuffer;
71 using ::com::sun::star::uno::Reference;
72 using ::com::sun::star::uno::Sequence;
73
74 namespace
75 {
lcl_getComponentContext()76 Reference< uno::XComponentContext > lcl_getComponentContext()
77 {
78 Reference< uno::XComponentContext > xContext;
79 try
80 {
81 Reference< beans::XPropertySet > xFactProp( comphelper::getProcessServiceFactory(), uno::UNO_QUERY );
82 if( xFactProp.is())
83 xFactProp->getPropertyValue(OUString::createFromAscii("DefaultContext")) >>= xContext;
84 }
85 catch( uno::Exception& )
86 {}
87
88 return xContext;
89 }
90
lcl_getGeneratorFromModel(const uno::Reference<frame::XModel> & xChartModel)91 rtl::OUString lcl_getGeneratorFromModel( const uno::Reference< frame::XModel >& xChartModel )
92 {
93 ::rtl::OUString aGenerator;
94 uno::Reference< document::XDocumentPropertiesSupplier> xChartDocumentPropertiesSupplier( xChartModel, uno::UNO_QUERY );
95 if( xChartDocumentPropertiesSupplier.is() )
96 {
97 uno::Reference< document::XDocumentProperties > xChartDocumentProperties(
98 xChartDocumentPropertiesSupplier->getDocumentProperties());
99 if( xChartDocumentProperties.is() )
100 aGenerator = xChartDocumentProperties->getGenerator();
101 }
102 return aGenerator;
103 }
104
lcl_getGeneratorFromModelOrItsParent(const uno::Reference<frame::XModel> & xChartModel)105 rtl::OUString lcl_getGeneratorFromModelOrItsParent( const uno::Reference< frame::XModel >& xChartModel )
106 {
107 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
108 if( !aGenerator.getLength() ) //try to get the missing info from the parent document
109 {
110 uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY );
111 if( xChild.is() )
112 aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) );
113 }
114 return aGenerator;
115 }
116
lcl_getBuildIDFromGenerator(const::rtl::OUString & rGenerator)117 sal_Int32 lcl_getBuildIDFromGenerator( const ::rtl::OUString& rGenerator )
118 {
119 //returns -1 if nothing found
120 sal_Int32 nBuildId = -1;
121 const OUString sBuildCompare( RTL_CONSTASCII_USTRINGPARAM( "$Build-" ) );
122 sal_Int32 nEnd = -1;
123 sal_Int32 nBegin = rGenerator.indexOf( sBuildCompare, nEnd );
124 if( nBegin != -1 )
125 {
126 OUString sBuildId( rGenerator.copy( nBegin + sBuildCompare.getLength() ) );
127 nBuildId = sBuildId.toInt32();
128 }
129 return nBuildId;
130 }
131
lcl_ConvertRange(const::rtl::OUString & rRange,const Reference<chart2::data::XDataProvider> & xDataProvider)132 OUString lcl_ConvertRange( const ::rtl::OUString & rRange, const Reference< chart2::data::XDataProvider >& xDataProvider )
133 {
134 OUString aResult = rRange;
135 Reference< chart2::data::XRangeXMLConversion > xRangeConversion( xDataProvider, uno::UNO_QUERY );
136 if( xRangeConversion.is())
137 aResult = xRangeConversion->convertRangeFromXML( rRange );
138 return aResult;
139 }
140
lcl_createNewSequenceFromCachedXMLRange(const Reference<chart2::data::XDataSequence> & xSeq,const Reference<chart2::data::XDataProvider> & xDataProvider)141 Reference< chart2::data::XDataSequence > lcl_createNewSequenceFromCachedXMLRange( const Reference< chart2::data::XDataSequence >& xSeq, const Reference< chart2::data::XDataProvider >& xDataProvider )
142 {
143 Reference< chart2::data::XDataSequence > xRet;
144 OUString aRange;
145 if( xSeq.is() && SchXMLTools::getXMLRangePropertyFromDataSequence( xSeq, aRange, /* bClearProp = */ true ) )
146 {
147 xRet.set( xDataProvider->createDataSequenceByRangeRepresentation(
148 lcl_ConvertRange( aRange, xDataProvider )) );
149 SchXMLTools::copyProperties( Reference< beans::XPropertySet >( xSeq, uno::UNO_QUERY ),
150 Reference< beans::XPropertySet >( xRet, uno::UNO_QUERY ));
151 }
152 return xRet;
153 }
154
155 } // anonymous namespace
156
157 // ----------------------------------------
158
159 namespace SchXMLTools
160 {
161
162 static __FAR_DATA SvXMLEnumMapEntry aXMLChartClassMap[] =
163 {
164 { XML_LINE, XML_CHART_CLASS_LINE },
165 { XML_AREA, XML_CHART_CLASS_AREA },
166 { XML_CIRCLE, XML_CHART_CLASS_CIRCLE },
167 { XML_RING, XML_CHART_CLASS_RING },
168 { XML_SCATTER, XML_CHART_CLASS_SCATTER },
169 { XML_RADAR, XML_CHART_CLASS_RADAR },
170 { XML_FILLED_RADAR, XML_CHART_CLASS_FILLED_RADAR },
171 { XML_BAR, XML_CHART_CLASS_BAR },
172 { XML_STOCK, XML_CHART_CLASS_STOCK },
173 { XML_BUBBLE, XML_CHART_CLASS_BUBBLE },
174 { XML_SURFACE, XML_CHART_CLASS_BAR }, //@todo change this if a surface chart is available
175 { XML_ADD_IN, XML_CHART_CLASS_ADDIN },
176 { XML_TOKEN_INVALID, XML_CHART_CLASS_UNKNOWN }
177 };
178
GetChartTypeEnum(const OUString & rClassName)179 SchXMLChartTypeEnum GetChartTypeEnum( const OUString& rClassName )
180 {
181 sal_uInt16 nEnumVal = XML_CHART_CLASS_UNKNOWN;
182 if( !SvXMLUnitConverter::convertEnum(
183 nEnumVal, rClassName, aXMLChartClassMap ) )
184 nEnumVal = XML_CHART_CLASS_UNKNOWN;
185 return SchXMLChartTypeEnum(nEnumVal);
186 }
187
188 typedef ::comphelper::MakeMap< ::rtl::OUString, ::rtl::OUString > tMakeStringStringMap;
189 //static
lcl_getChartTypeNameMap()190 const tMakeStringStringMap& lcl_getChartTypeNameMap()
191 {
192 //shape property -- chart model object property
193 static tMakeStringStringMap g_aChartTypeNameMap =
194 tMakeStringStringMap
195 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.LineDiagram" )
196 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.LineChartType" ) )
197
198 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.AreaDiagram" )
199 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.AreaChartType" ) )
200
201 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.BarDiagram" )
202 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.ColumnChartType" ) )
203
204 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.PieDiagram" )
205 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.PieChartType" ) )
206
207 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.DonutDiagram" )
208 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.DonutChartType" ) )
209
210 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.XYDiagram" )
211 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.ScatterChartType" ) )
212
213 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.NetDiagram" )
214 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.NetChartType" ) )
215
216 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.FilledNetDiagram" )
217 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.FilledNetChartType" ) )
218
219 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.StockDiagram" )
220 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.CandleStickChartType" ) )
221
222 ( ::rtl::OUString::createFromAscii( "com.sun.star.chart.BubbleDiagram" )
223 , ::rtl::OUString::createFromAscii( "com.sun.star.chart2.BubbleChartType" ) )
224
225 ;
226 return g_aChartTypeNameMap;
227 }
228
229
GetNewChartTypeName(const OUString & rOldChartTypeName)230 OUString GetNewChartTypeName( const OUString & rOldChartTypeName )
231 {
232 OUString aNew(rOldChartTypeName);
233
234 const tMakeStringStringMap& rMap = lcl_getChartTypeNameMap();
235 tMakeStringStringMap::const_iterator aIt( rMap.find( rOldChartTypeName ));
236 if( aIt != rMap.end())
237 {
238 aNew = aIt->second;
239 }
240 return aNew;
241 }
242
GetChartTypeByClassName(const OUString & rClassName,bool bUseOldNames)243 OUString GetChartTypeByClassName(
244 const OUString & rClassName, bool bUseOldNames )
245 {
246 OUStringBuffer aResultBuffer;
247 bool bInternalType = false;
248
249 if( bUseOldNames )
250 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart."));
251 else
252 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart2."));
253
254 bInternalType = true;
255
256 if( IsXMLToken( rClassName, XML_LINE ))
257 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Line"));
258 else if( IsXMLToken( rClassName, XML_AREA ))
259 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Area"));
260 else if( IsXMLToken( rClassName, XML_BAR ))
261 {
262 if( bUseOldNames )
263 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Bar"));
264 else
265 {
266 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Column"));
267 // @todo: might be Bar
268 }
269 }
270 else if( IsXMLToken( rClassName, XML_CIRCLE ))
271 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Pie"));
272 else if( IsXMLToken( rClassName, XML_RING ))
273 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Donut"));
274 else if( IsXMLToken( rClassName, XML_SCATTER ))
275 {
276 if( bUseOldNames )
277 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("XY"));
278 else
279 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Scatter"));
280 }
281
282 else if( IsXMLToken( rClassName, XML_BUBBLE ))
283 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Bubble"));
284 else if( IsXMLToken( rClassName, XML_RADAR ))
285 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Net"));
286 else if( IsXMLToken( rClassName, XML_FILLED_RADAR ))
287 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("FilledNet"));
288 else if( IsXMLToken( rClassName, XML_STOCK ))
289 {
290 if( bUseOldNames )
291 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Stock"));
292 else
293 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("CandleStick"));
294 }
295 else if( IsXMLToken( rClassName, XML_SURFACE ))
296 {
297 //@todo change this if a surface chart is available
298 if( bUseOldNames )
299 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Bar"));
300 else
301 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Column"));
302 }
303 else
304 bInternalType = false;
305
306 if( ! bInternalType )
307 return OUString();
308
309 if( bUseOldNames )
310 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Diagram"));
311 else
312 aResultBuffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("ChartType"));
313
314 return aResultBuffer.makeStringAndClear();
315
316 }
317
getTokenByChartType(const OUString & rChartTypeService,bool bUseOldNames)318 XMLTokenEnum getTokenByChartType(
319 const OUString & rChartTypeService, bool bUseOldNames )
320 {
321 XMLTokenEnum eResult = XML_TOKEN_INVALID;
322 OUString aPrefix, aPostfix;
323
324 if( bUseOldNames )
325 {
326 aPrefix = OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart."));
327 aPostfix = OUString( RTL_CONSTASCII_USTRINGPARAM("Diagram"));
328 }
329 else
330 {
331 aPrefix = OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart2."));
332 aPostfix = OUString( RTL_CONSTASCII_USTRINGPARAM("ChartType"));
333 }
334
335 if( rChartTypeService.match( aPrefix ))
336 {
337 sal_Int32 nSkip = aPrefix.getLength();
338 OSL_ASSERT( rChartTypeService.getLength() >= nSkip );
339 sal_Int32 nTypeLength = rChartTypeService.getLength() - nSkip - aPostfix.getLength();
340 // if postfix matches and leaves a non-empty type
341 if( nTypeLength > 0 && rChartTypeService.match( aPostfix, nSkip + nTypeLength ))
342 {
343 OUString aServiceName( rChartTypeService.copy( nSkip, nTypeLength ));
344
345 if( aServiceName.equalsAscii("Line"))
346 eResult = XML_LINE;
347 else if( aServiceName.equalsAscii("Area"))
348 eResult = XML_AREA;
349 else if( aServiceName.equalsAscii("Bar") ||
350 (!bUseOldNames && aServiceName.equalsAscii("Column")))
351 eResult = XML_BAR;
352 else if( aServiceName.equalsAscii("Pie"))
353 eResult = XML_CIRCLE;
354 else if( aServiceName.equalsAscii("Donut"))
355 eResult = XML_RING;
356 else if( (bUseOldNames && aServiceName.equalsAscii("XY")) ||
357 (!bUseOldNames && aServiceName.equalsAscii("Scatter")))
358 eResult = XML_SCATTER;
359 else if( aServiceName.equalsAscii("Bubble"))
360 eResult = XML_BUBBLE;
361 else if( aServiceName.equalsAscii("Net"))
362 eResult = XML_RADAR;
363 else if( aServiceName.equalsAscii("FilledNet"))
364 eResult = XML_FILLED_RADAR;
365 else if( (bUseOldNames && aServiceName.equalsAscii("Stock")) ||
366 (!bUseOldNames && aServiceName.equalsAscii("CandleStick")))
367 eResult = XML_STOCK;
368 }
369 }
370
371 if( eResult == XML_TOKEN_INVALID && rChartTypeService.getLength() > 0 )
372 eResult = XML_ADD_IN;
373
374 return eResult;
375 }
376
GetNewLabeledDataSequence()377 Reference< chart2::data::XLabeledDataSequence > GetNewLabeledDataSequence()
378 {
379 Reference< chart2::data::XLabeledDataSequence > xResult;
380 Reference< uno::XComponentContext > xContext( lcl_getComponentContext());
381 if( xContext.is() )
382 xResult.set(
383 xContext->getServiceManager()->createInstanceWithContext(
384 OUString::createFromAscii("com.sun.star.chart2.data.LabeledDataSequence"),
385 xContext ), uno::UNO_QUERY_THROW );
386 return xResult;
387 }
388
CreateDataSequence(const OUString & rRange,const Reference<chart2::XChartDocument> & xChartDoc)389 Reference< chart2::data::XDataSequence > CreateDataSequence(
390 const OUString & rRange,
391 const Reference< chart2::XChartDocument >& xChartDoc )
392 {
393 Reference< chart2::data::XDataSequence > xRet;
394
395 if( !xChartDoc.is() )
396 {
397 DBG_ERROR( "need a chart document" );
398 return xRet;
399 }
400
401 Reference< chart2::data::XDataProvider > xDataProvider( xChartDoc->getDataProvider() );
402 if( !xDataProvider.is() )
403 {
404 DBG_ERROR( "need a data provider" );
405 return xRet;
406 }
407
408 try
409 {
410 xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider )));
411 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange );
412 }
413 catch( const lang::IllegalArgumentException & )
414 {
415 DBG_ERROR( "could not create data sequence" );
416 }
417
418 if( !xRet.is() && !xChartDoc->hasInternalDataProvider() && rRange.getLength() )
419 {
420 //#i103911# switch to internal data in case the parent cannot provide the requested data
421 xChartDoc->createInternalDataProvider( sal_True /* bCloneExistingData */ );
422 xDataProvider = xChartDoc->getDataProvider();
423 try
424 {
425 xRet.set( xDataProvider->createDataSequenceByRangeRepresentation( lcl_ConvertRange( rRange, xDataProvider )));
426 SchXMLTools::setXMLRangePropertyAtDataSequence( xRet, rRange );
427 }
428 catch( const lang::IllegalArgumentException & )
429 {
430 DBG_ERROR( "could not create data sequence" );
431 }
432 }
433 return xRet;
434 }
435
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)436 void CreateCategories(
437 const uno::Reference< chart2::data::XDataProvider > & xDataProvider,
438 const uno::Reference< chart2::XChartDocument > & xNewDoc,
439 const OUString & rRangeAddress,
440 sal_Int32 nCooSysIndex,
441 sal_Int32 nDimensionIndex,
442 tSchXMLLSequencesPerIndex * pLSequencesPerIndex )
443 {
444 try
445 {
446 if( xNewDoc.is() && rRangeAddress.getLength())
447 {
448 if( xDataProvider.is())
449 {
450 uno::Reference< chart2::XDiagram > xDia( xNewDoc->getFirstDiagram());
451 if( !xDia.is())
452 return;
453
454 uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW );
455 uno::Sequence< uno::Reference< chart2::XCoordinateSystem > >
456 aCooSysSeq( xCooSysCnt->getCoordinateSystems());
457 if( nCooSysIndex < aCooSysSeq.getLength())
458 {
459 uno::Reference< chart2::XCoordinateSystem > xCooSys( aCooSysSeq[nCooSysIndex] );
460 OSL_ASSERT( xCooSys.is());
461 if( nDimensionIndex < xCooSys->getDimension() )
462 {
463 const sal_Int32 nMaxAxisIndex = xCooSys->getMaximumAxisIndexByDimension(nDimensionIndex);
464 for(sal_Int32 nI=0; nI<=nMaxAxisIndex; ++nI)
465 {
466 uno::Reference< chart2::XAxis > xAxis( xCooSys->getAxisByDimension( nDimensionIndex, nI ));
467 if( xAxis.is() )
468 {
469 chart2::ScaleData aData( xAxis->getScaleData());
470 uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSeq(
471 GetNewLabeledDataSequence());
472 try
473 {
474 OUString aConvertedRange( rRangeAddress );
475 bool bRangeConverted = false;
476 if( ! (xNewDoc->hasInternalDataProvider() &&
477 aConvertedRange.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("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 Reference< chart2::data::XDataSequence > xSeq(
487 xDataProvider->createDataSequenceByRangeRepresentation( aConvertedRange ));
488 xLabeledSeq->setValues( xSeq );
489 if( bRangeConverted )
490 setXMLRangePropertyAtDataSequence( xSeq, rRangeAddress );
491 }
492 catch( const lang::IllegalArgumentException & ex )
493 {
494 (void)ex; // avoid warning for pro build
495 OSL_ENSURE( false, ::rtl::OUStringToOString(
496 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "IllegalArgumentException caught, Message: " )) +
497 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
498 }
499 aData.Categories.set( xLabeledSeq );
500 if( pLSequencesPerIndex )
501 {
502 // register for setting local data if external data provider is not present
503 pLSequencesPerIndex->insert(
504 tSchXMLLSequencesPerIndex::value_type(
505 tSchXMLIndexWithPart( SCH_XML_CATEGORIES_INDEX, SCH_XML_PART_VALUES ), xLabeledSeq ));
506 }
507 xAxis->setScaleData( aData );
508 }
509 }
510 }
511 }
512 }
513 }
514 }
515 catch( uno::Exception & )
516 {
517 OSL_ENSURE( false, "Exception caught while creating Categories" );
518 }
519 }
520
521
getPropertyFromContext(const rtl::OUString & rPropertyName,const XMLPropStyleContext * pPropStyleContext,const SvXMLStylesContext * pStylesCtxt)522 uno::Any getPropertyFromContext( const rtl::OUString& rPropertyName, const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
523 {
524 uno::Any aRet;
525 if( !pPropStyleContext || !pStylesCtxt )
526 return aRet;
527 const ::std::vector< XMLPropertyState >& rProperties = pPropStyleContext->GetProperties();
528 const UniReference< XMLPropertySetMapper >& rMapper = pStylesCtxt->GetImportPropertyMapper( pPropStyleContext->GetFamily()/*XML_STYLE_FAMILY_SCH_CHART_ID*/ )->getPropertySetMapper();
529 ::std::vector< XMLPropertyState >::const_iterator aEnd( rProperties.end() );
530 ::std::vector< XMLPropertyState >::const_iterator aPropIter( rProperties.begin() );
531 for( aPropIter = rProperties.begin(); aPropIter != aEnd; ++aPropIter )
532 {
533 sal_Int32 nIdx = aPropIter->mnIndex;
534 if( nIdx == -1 )
535 continue;
536 OUString aPropName = rMapper->GetEntryAPIName( nIdx );
537 if(rPropertyName.equals(aPropName))
538 return aPropIter->maValue;
539 }
540 return aRet;
541 }
542
exportText(SvXMLExport & rExport,const OUString & rText,bool bConvertTabsLFs)543 void exportText( SvXMLExport& rExport, const OUString& rText, bool bConvertTabsLFs )
544 {
545 SvXMLElementExport aPara( rExport, XML_NAMESPACE_TEXT,
546 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_P ),
547 sal_True, sal_False );
548
549 if( bConvertTabsLFs )
550 {
551 sal_Int32 nStartPos = 0;
552 sal_Int32 nEndPos = rText.getLength();
553 sal_Unicode cChar;
554
555 for( sal_Int32 nPos = 0; nPos < nEndPos; nPos++ )
556 {
557 cChar = rText[ nPos ];
558 switch( cChar )
559 {
560 case 0x0009: // tabulator
561 {
562 if( nPos > nStartPos )
563 rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) );
564 nStartPos = nPos + 1;
565
566 SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT,
567 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_TAB_STOP ),
568 sal_False, sal_False );
569 }
570 break;
571
572 case 0x000A: // linefeed
573 {
574 if( nPos > nStartPos )
575 rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) );
576 nStartPos = nPos + 1;
577
578 SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT,
579 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_LINE_BREAK ),
580 sal_False, sal_False );
581 }
582 break;
583 }
584 }
585 if( nEndPos > nStartPos )
586 {
587 if( nStartPos == 0 )
588 rExport.GetDocHandler()->characters( rText );
589 else
590 rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nEndPos - nStartPos)) );
591 }
592 }
593 else // do not convert tabs and linefeeds (eg for numbers coming from unit converter)
594 {
595 rExport.GetDocHandler()->characters( rText );
596 }
597 }
598
exportRangeToSomewhere(SvXMLExport & rExport,const::rtl::OUString & rValue)599 void exportRangeToSomewhere( SvXMLExport& rExport, const ::rtl::OUString& rValue )
600 {
601 //with issue #i366# and CWS chart20 ranges for error bars were introduced
602 //to keep them during copy paste from calc to impress for example it
603 //was necessary to introduce a mapping between the used ranges within calc and the data written to the local table
604 //this is why we write this ranges here
605
606 //#i113950# first the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore within ODF 1.2
607 //as an alternative the range info is now saved into the description at an empty group element (not very nice, but ODF conform)
608
609 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
610 if( nCurrentODFVersion == SvtSaveOptions::ODFVER_010 || nCurrentODFVersion == SvtSaveOptions::ODFVER_011 )
611 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
612
613 SvXMLElementExport aEmptyShapeGroup( rExport, XML_NAMESPACE_DRAW,
614 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_G ),
615 sal_True, sal_False );
616 SvXMLElementExport aDescription( rExport, XML_NAMESPACE_SVG,
617 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DESC ),
618 sal_True, sal_False );
619 rExport.GetDocHandler()->characters( rValue );
620 }
621
getRegressionCurve(const Reference<chart2::XDataSeries> & xDataSeries)622 Reference< chart2::XRegressionCurve > getRegressionCurve(
623 const Reference< chart2::XDataSeries > & xDataSeries )
624 {
625 Reference< chart2::XRegressionCurve > xResult;
626
627 Reference< chart2::XRegressionCurveContainer > xRegCurveCnt( xDataSeries, uno::UNO_QUERY );
628 if( xRegCurveCnt.is())
629 {
630 // find equation properties of first regression curve
631 Sequence< Reference< chart2::XRegressionCurve > > aCurveSeq(
632 xRegCurveCnt->getRegressionCurves() );
633 for( sal_Int32 nI=0; nI<aCurveSeq.getLength(); ++nI )
634 {
635 // skip mean-value line
636 Reference< lang::XServiceName > xServiceName( aCurveSeq[nI], uno::UNO_QUERY );
637 if( xServiceName.is())
638 {
639 OUString aServiceName( xServiceName->getServiceName());
640 if( aServiceName.equalsAsciiL(
641 RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.MeanValueRegressionCurve" )))
642 continue;
643 }
644 // take first non-empty curve
645 if( aCurveSeq[nI].is())
646 {
647 xResult.set( aCurveSeq[nI] );
648 break;
649 }
650 }
651 }
652 return xResult;
653 }
654
setXMLRangePropertyAtDataSequence(const Reference<chart2::data::XDataSequence> & xDataSequence,const OUString & rXMLRange)655 void setXMLRangePropertyAtDataSequence(
656 const Reference< chart2::data::XDataSequence > & xDataSequence,
657 const OUString & rXMLRange )
658 {
659 if( !xDataSequence.is())
660 return;
661 try
662 {
663 const OUString aXMLRangePropName( RTL_CONSTASCII_USTRINGPARAM( "CachedXMLRange" ));
664 Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
665 Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
666 if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ))
667 xProp->setPropertyValue( aXMLRangePropName, uno::makeAny( rXMLRange ));
668 }
669 catch( const uno::Exception & ex )
670 {
671 (void)ex; // avoid warning for pro build
672 OSL_ENSURE( false, ::rtl::OUStringToOString(
673 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught, Message: " )) +
674 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
675 }
676 }
677
getXMLRangePropertyFromDataSequence(const Reference<chart2::data::XDataSequence> & xDataSequence,OUString & rOutXMLRange,bool bClearProp)678 bool getXMLRangePropertyFromDataSequence(
679 const Reference< chart2::data::XDataSequence > & xDataSequence,
680 OUString & rOutXMLRange,
681 bool bClearProp /* = false */)
682 {
683 bool bResult = false;
684 if( xDataSequence.is())
685 {
686 try
687 {
688 const OUString aXMLRangePropName( RTL_CONSTASCII_USTRINGPARAM( "CachedXMLRange" ));
689 Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
690 Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
691 bResult =
692 ( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ) &&
693 ( xProp->getPropertyValue( aXMLRangePropName ) >>= rOutXMLRange ) &&
694 rOutXMLRange.getLength());
695 // clear the property after usage
696 if( bClearProp && bResult )
697 xProp->setPropertyValue( aXMLRangePropName, uno::Any( OUString()));
698 }
699 catch( const uno::Exception & ex )
700 {
701 (void)ex; // avoid warning for pro build
702 OSL_ENSURE( false, ::rtl::OUStringToOString(
703 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught, Message: " )) +
704 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
705 }
706 }
707 return bResult;
708 }
709
copyProperties(const Reference<beans::XPropertySet> & xSource,const Reference<beans::XPropertySet> & xDestination)710 void copyProperties(
711 const Reference< beans::XPropertySet > & xSource,
712 const Reference< beans::XPropertySet > & xDestination )
713 {
714 if( ! (xSource.is() && xDestination.is()) )
715 return;
716
717 try
718 {
719 Reference< beans::XPropertySetInfo > xSrcInfo( xSource->getPropertySetInfo(), uno::UNO_QUERY_THROW );
720 Reference< beans::XPropertySetInfo > xDestInfo( xDestination->getPropertySetInfo(), uno::UNO_QUERY_THROW );
721 Sequence< beans::Property > aProperties( xSrcInfo->getProperties());
722 const sal_Int32 nLength = aProperties.getLength();
723 for( sal_Int32 i = 0; i < nLength; ++i )
724 {
725 OUString aName( aProperties[i].Name);
726 if( xDestInfo->hasPropertyByName( aName ))
727 {
728 beans::Property aProp( xDestInfo->getPropertyByName( aName ));
729 if( (aProp.Attributes & beans::PropertyAttribute::READONLY) == 0 )
730 xDestination->setPropertyValue(
731 aName, xSource->getPropertyValue( aName ));
732 }
733 }
734 }
735 catch( const uno::Exception & )
736 {
737 OSL_ENSURE( false, "Copying property sets failed!" );
738 }
739 }
740
switchBackToDataProviderFromParent(const Reference<chart2::XChartDocument> & xChartDoc,const tSchXMLLSequencesPerIndex & rLSequencesPerIndex)741 bool switchBackToDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc, const tSchXMLLSequencesPerIndex & rLSequencesPerIndex )
742 {
743 //return whether the switch is successful
744 if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() )
745 return false;
746 Reference< chart2::data::XDataProvider > xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc ) );
747 if( !xDataProviderFromParent.is() )
748 return false;
749 uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY );
750 if( !xDataReceiver.is() )
751 return false;
752
753 xDataReceiver->attachDataProvider( xDataProviderFromParent );
754
755 for( tSchXMLLSequencesPerIndex::const_iterator aLSeqIt( rLSequencesPerIndex.begin() );
756 aLSeqIt != rLSequencesPerIndex.end(); ++aLSeqIt )
757 {
758 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( aLSeqIt->second );
759 if( !xLabeledSeq.is() )
760 continue;
761 Reference< chart2::data::XDataSequence > xNewSeq;
762 xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getValues(), xDataProviderFromParent );
763 if( xNewSeq.is() )
764 xLabeledSeq->setValues( xNewSeq );
765 xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getLabel(), xDataProviderFromParent );
766 if( xNewSeq.is() )
767 xLabeledSeq->setLabel( xNewSeq );
768 }
769 return true;
770 }
771
setBuildIDAtImportInfo(uno::Reference<frame::XModel> xModel,Reference<beans::XPropertySet> xImportInfo)772 void setBuildIDAtImportInfo( uno::Reference< frame::XModel > xModel, Reference< beans::XPropertySet > xImportInfo )
773 {
774 ::rtl::OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xModel) );
775 if( aGenerator.getLength() )
776 SvXMLMetaDocumentContext::setBuildId( aGenerator, xImportInfo );
777 }
778
isDocumentGeneratedWithOpenOfficeOlderThan3_3(const uno::Reference<frame::XModel> & xChartModel)779 bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const uno::Reference< frame::XModel >& xChartModel )
780 {
781 bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel );
782 if( !bResult )
783 {
784 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
785 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/3") ) ) != -1 )
786 {
787 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/300m") ) ) != -1 )
788 {
789 sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) );
790 if( nBuilId>0 && nBuilId<9491 ) //9491 is build id of dev300m76
791 bResult= true;
792 }
793 else if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/310m") ) ) != -1 )
794 bResult= true;
795 else if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/320m") ) ) != -1 )
796 bResult= true;
797 }
798 }
799 return bResult;
800 }
801
isDocumentGeneratedWithOpenOfficeOlderThan3_0(const uno::Reference<frame::XModel> & xChartModel)802 bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const uno::Reference< frame::XModel >& xChartModel )
803 {
804 bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel );
805 if( !bResult )
806 {
807 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
808 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/680m") ) ) != -1 )
809 bResult= true;
810 }
811 return bResult;
812 }
813
isDocumentGeneratedWithOpenOfficeOlderThan2_4(const uno::Reference<frame::XModel> & xChartModel)814 bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const uno::Reference< frame::XModel >& xChartModel )
815 {
816 if( isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel ) )
817 return true;
818
819 if( isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel ) )
820 {
821 sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) );
822 if( nBuilId>0 && nBuilId<=9238 ) //9238 is build id of OpenOffice.org 2.3.1
823 return true;
824 }
825 return false;
826 }
827
isDocumentGeneratedWithOpenOfficeOlderThan2_3(const uno::Reference<frame::XModel> & xChartModel)828 bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const uno::Reference< frame::XModel >& xChartModel )
829 {
830 bool bResult = false;
831 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
832 //if there is a meta stream at the chart object it was not written with an older OpenOffice version < 2.3
833 if( !aGenerator.getLength() )
834 {
835 //if there is no meta stream at the chart object we need to check whether the parent document is OpenOffice at all
836 uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY );
837 if( xChild.is() )
838 {
839 aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) );
840 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project") ) ) != -1 )
841 {
842 //the chart application has not created files without a meta stream since OOo 2.3 (OOo 2.3 has written a metastream already)
843 //only the report builder extension has created some files with OOo 3.1 that do not have a meta stream
844 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/31") ) ) != -1 )
845 bResult = false;//#i100102# probably generated with OOo 3.1 by the report designer
846 else
847 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
848 }
849 else if( isDocumentGeneratedWithOpenOfficeOlderThan2_0(xChartModel) )
850 bResult= true;
851 }
852 }
853 return bResult;
854 }
855
isDocumentGeneratedWithOpenOfficeOlderThan2_0(const::com::sun::star::uno::Reference<::com::sun::star::frame::XModel> & xChartModel)856 bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& xChartModel)
857 {
858 bool bResult = false;
859 ::rtl::OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xChartModel) );
860 if( ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org 1") ) ) == 0 )
861 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarOffice 6") ) ) == 0 )
862 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarOffice 7") ) ) == 0 )
863 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarSuite 6") ) ) == 0 )
864 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarSuite 7") ) ) == 0 )
865 )
866 bResult= true;
867 return bResult;
868 }
869
getDataProviderFromParent(const Reference<chart2::XChartDocument> & xChartDoc)870 Reference< chart2::data::XDataProvider > getDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc )
871 {
872 Reference< chart2::data::XDataProvider > xRet;
873 uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY );
874 if( xChild.is() )
875 {
876 Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY );
877 if( xFact.is() )
878 {
879 const OUString aDataProviderServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart2.data.DataProvider"));
880 const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames());
881 const OUString * pBegin = aServiceNames.getConstArray();
882 const OUString * pEnd = pBegin + aServiceNames.getLength();
883 if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd )
884 {
885 xRet = Reference< chart2::data::XDataProvider >(
886 xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY );
887 }
888 }
889 }
890 return xRet;
891 }
892
893 } // namespace SchXMLTools
894