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 // text:tab-stop is not in ODF 1.2
567 SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT,
568 ::xmloff::token::GetXMLToken( SvtSaveOptions::IsODFStrict( rExport.getDefaultVersion() ) ? ::xmloff::token::XML_TAB : ::xmloff::token::XML_TAB_STOP ),
569 sal_False, sal_False );
570 }
571 break;
572
573 case 0x000A: // linefeed
574 {
575 if( nPos > nStartPos )
576 rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nPos - nStartPos)) );
577 nStartPos = nPos + 1;
578
579 SvXMLElementExport aElem( rExport, XML_NAMESPACE_TEXT,
580 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_LINE_BREAK ),
581 sal_False, sal_False );
582 }
583 break;
584 }
585 }
586 if( nEndPos > nStartPos )
587 {
588 if( nStartPos == 0 )
589 rExport.GetDocHandler()->characters( rText );
590 else
591 rExport.GetDocHandler()->characters( rText.copy( nStartPos, (nEndPos - nStartPos)) );
592 }
593 }
594 else // do not convert tabs and linefeeds (eg for numbers coming from unit converter)
595 {
596 rExport.GetDocHandler()->characters( rText );
597 }
598 }
599
exportRangeToSomewhere(SvXMLExport & rExport,const::rtl::OUString & rValue)600 void exportRangeToSomewhere( SvXMLExport& rExport, const ::rtl::OUString& rValue )
601 {
602 //with issue #i366# and CWS chart20 ranges for error bars were introduced
603 //to keep them during copy paste from calc to impress for example it
604 //was necessary to introduce a mapping between the used ranges within calc and the data written to the local table
605 //this is why we write this ranges here
606
607 //#i113950# first the range was exported to attribute text:id, but that attribute does not allow arbitrary strings anymore within ODF 1.2
608 //as an alternative the range info is now saved into the description at an empty group element (not very nice, but ODF conform)
609
610 const SvtSaveOptions::ODFDefaultVersion nCurrentODFVersion( SvtSaveOptions().GetODFDefaultVersion() );
611 if( nCurrentODFVersion == SvtSaveOptions::ODFVER_010 || nCurrentODFVersion == SvtSaveOptions::ODFVER_011 )
612 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
613
614 SvXMLElementExport aEmptyShapeGroup( rExport, XML_NAMESPACE_DRAW,
615 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_G ),
616 sal_True, sal_False );
617 SvXMLElementExport aDescription( rExport, XML_NAMESPACE_SVG,
618 ::xmloff::token::GetXMLToken( ::xmloff::token::XML_DESC ),
619 sal_True, sal_False );
620 rExport.GetDocHandler()->characters( rValue );
621 }
622
getRegressionCurve(const Reference<chart2::XDataSeries> & xDataSeries)623 Reference< chart2::XRegressionCurve > getRegressionCurve(
624 const Reference< chart2::XDataSeries > & xDataSeries )
625 {
626 Reference< chart2::XRegressionCurve > xResult;
627
628 Reference< chart2::XRegressionCurveContainer > xRegCurveCnt( xDataSeries, uno::UNO_QUERY );
629 if( xRegCurveCnt.is())
630 {
631 // find equation properties of first regression curve
632 Sequence< Reference< chart2::XRegressionCurve > > aCurveSeq(
633 xRegCurveCnt->getRegressionCurves() );
634 for( sal_Int32 nI=0; nI<aCurveSeq.getLength(); ++nI )
635 {
636 // skip mean-value line
637 Reference< lang::XServiceName > xServiceName( aCurveSeq[nI], uno::UNO_QUERY );
638 if( xServiceName.is())
639 {
640 OUString aServiceName( xServiceName->getServiceName());
641 if( aServiceName.equalsAsciiL(
642 RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.MeanValueRegressionCurve" )))
643 continue;
644 }
645 // take first non-empty curve
646 if( aCurveSeq[nI].is())
647 {
648 xResult.set( aCurveSeq[nI] );
649 break;
650 }
651 }
652 }
653 return xResult;
654 }
655
setXMLRangePropertyAtDataSequence(const Reference<chart2::data::XDataSequence> & xDataSequence,const OUString & rXMLRange)656 void setXMLRangePropertyAtDataSequence(
657 const Reference< chart2::data::XDataSequence > & xDataSequence,
658 const OUString & rXMLRange )
659 {
660 if( !xDataSequence.is())
661 return;
662 try
663 {
664 const OUString aXMLRangePropName( RTL_CONSTASCII_USTRINGPARAM( "CachedXMLRange" ));
665 Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
666 Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
667 if( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ))
668 xProp->setPropertyValue( aXMLRangePropName, uno::makeAny( rXMLRange ));
669 }
670 catch( const uno::Exception & ex )
671 {
672 (void)ex; // avoid warning for pro build
673 OSL_ENSURE( false, ::rtl::OUStringToOString(
674 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught, Message: " )) +
675 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
676 }
677 }
678
getXMLRangePropertyFromDataSequence(const Reference<chart2::data::XDataSequence> & xDataSequence,OUString & rOutXMLRange,bool bClearProp)679 bool getXMLRangePropertyFromDataSequence(
680 const Reference< chart2::data::XDataSequence > & xDataSequence,
681 OUString & rOutXMLRange,
682 bool bClearProp /* = false */)
683 {
684 bool bResult = false;
685 if( xDataSequence.is())
686 {
687 try
688 {
689 const OUString aXMLRangePropName( RTL_CONSTASCII_USTRINGPARAM( "CachedXMLRange" ));
690 Reference< beans::XPropertySet > xProp( xDataSequence, uno::UNO_QUERY_THROW );
691 Reference< beans::XPropertySetInfo > xInfo( xProp->getPropertySetInfo());
692 bResult =
693 ( xInfo.is() && xInfo->hasPropertyByName( aXMLRangePropName ) &&
694 ( xProp->getPropertyValue( aXMLRangePropName ) >>= rOutXMLRange ) &&
695 rOutXMLRange.getLength());
696 // clear the property after usage
697 if( bClearProp && bResult )
698 xProp->setPropertyValue( aXMLRangePropName, uno::Any( OUString()));
699 }
700 catch( const uno::Exception & ex )
701 {
702 (void)ex; // avoid warning for pro build
703 OSL_ENSURE( false, ::rtl::OUStringToOString(
704 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Exception caught, Message: " )) +
705 ex.Message, RTL_TEXTENCODING_ASCII_US ).getStr());
706 }
707 }
708 return bResult;
709 }
710
copyProperties(const Reference<beans::XPropertySet> & xSource,const Reference<beans::XPropertySet> & xDestination)711 void copyProperties(
712 const Reference< beans::XPropertySet > & xSource,
713 const Reference< beans::XPropertySet > & xDestination )
714 {
715 if( ! (xSource.is() && xDestination.is()) )
716 return;
717
718 try
719 {
720 Reference< beans::XPropertySetInfo > xSrcInfo( xSource->getPropertySetInfo(), uno::UNO_QUERY_THROW );
721 Reference< beans::XPropertySetInfo > xDestInfo( xDestination->getPropertySetInfo(), uno::UNO_QUERY_THROW );
722 Sequence< beans::Property > aProperties( xSrcInfo->getProperties());
723 const sal_Int32 nLength = aProperties.getLength();
724 for( sal_Int32 i = 0; i < nLength; ++i )
725 {
726 OUString aName( aProperties[i].Name);
727 if( xDestInfo->hasPropertyByName( aName ))
728 {
729 beans::Property aProp( xDestInfo->getPropertyByName( aName ));
730 if( (aProp.Attributes & beans::PropertyAttribute::READONLY) == 0 )
731 xDestination->setPropertyValue(
732 aName, xSource->getPropertyValue( aName ));
733 }
734 }
735 }
736 catch( const uno::Exception & )
737 {
738 OSL_ENSURE( false, "Copying property sets failed!" );
739 }
740 }
741
switchBackToDataProviderFromParent(const Reference<chart2::XChartDocument> & xChartDoc,const tSchXMLLSequencesPerIndex & rLSequencesPerIndex)742 bool switchBackToDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc, const tSchXMLLSequencesPerIndex & rLSequencesPerIndex )
743 {
744 //return whether the switch is successful
745 if( !xChartDoc.is() || !xChartDoc->hasInternalDataProvider() )
746 return false;
747 Reference< chart2::data::XDataProvider > xDataProviderFromParent( SchXMLTools::getDataProviderFromParent( xChartDoc ) );
748 if( !xDataProviderFromParent.is() )
749 return false;
750 uno::Reference< chart2::data::XDataReceiver > xDataReceiver( xChartDoc, uno::UNO_QUERY );
751 if( !xDataReceiver.is() )
752 return false;
753
754 xDataReceiver->attachDataProvider( xDataProviderFromParent );
755
756 for( tSchXMLLSequencesPerIndex::const_iterator aLSeqIt( rLSequencesPerIndex.begin() );
757 aLSeqIt != rLSequencesPerIndex.end(); ++aLSeqIt )
758 {
759 Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( aLSeqIt->second );
760 if( !xLabeledSeq.is() )
761 continue;
762 Reference< chart2::data::XDataSequence > xNewSeq;
763 xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getValues(), xDataProviderFromParent );
764 if( xNewSeq.is() )
765 xLabeledSeq->setValues( xNewSeq );
766 xNewSeq = lcl_createNewSequenceFromCachedXMLRange( xLabeledSeq->getLabel(), xDataProviderFromParent );
767 if( xNewSeq.is() )
768 xLabeledSeq->setLabel( xNewSeq );
769 }
770 return true;
771 }
772
setBuildIDAtImportInfo(uno::Reference<frame::XModel> xModel,Reference<beans::XPropertySet> xImportInfo)773 void setBuildIDAtImportInfo( uno::Reference< frame::XModel > xModel, Reference< beans::XPropertySet > xImportInfo )
774 {
775 ::rtl::OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xModel) );
776 if( aGenerator.getLength() )
777 SvXMLMetaDocumentContext::setBuildId( aGenerator, xImportInfo );
778 }
779
isDocumentGeneratedWithOpenOfficeOlderThan3_3(const uno::Reference<frame::XModel> & xChartModel)780 bool isDocumentGeneratedWithOpenOfficeOlderThan3_3( const uno::Reference< frame::XModel >& xChartModel )
781 {
782 bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel );
783 if( !bResult )
784 {
785 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
786 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/3") ) ) != -1 )
787 {
788 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/300m") ) ) != -1 )
789 {
790 sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) );
791 if( nBuilId>0 && nBuilId<9491 ) //9491 is build id of dev300m76
792 bResult= true;
793 }
794 else if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/310m") ) ) != -1 )
795 bResult= true;
796 else if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/320m") ) ) != -1 )
797 bResult= true;
798 }
799 }
800 return bResult;
801 }
802
isDocumentGeneratedWithOpenOfficeOlderThan3_0(const uno::Reference<frame::XModel> & xChartModel)803 bool isDocumentGeneratedWithOpenOfficeOlderThan3_0( const uno::Reference< frame::XModel >& xChartModel )
804 {
805 bool bResult = isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel );
806 if( !bResult )
807 {
808 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
809 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/680m") ) ) != -1 )
810 bResult= true;
811 }
812 return bResult;
813 }
814
isDocumentGeneratedWithOpenOfficeOlderThan2_4(const uno::Reference<frame::XModel> & xChartModel)815 bool isDocumentGeneratedWithOpenOfficeOlderThan2_4( const uno::Reference< frame::XModel >& xChartModel )
816 {
817 if( isDocumentGeneratedWithOpenOfficeOlderThan2_3( xChartModel ) )
818 return true;
819
820 if( isDocumentGeneratedWithOpenOfficeOlderThan3_0( xChartModel ) )
821 {
822 sal_Int32 nBuilId = lcl_getBuildIDFromGenerator( lcl_getGeneratorFromModel(xChartModel) );
823 if( nBuilId>0 && nBuilId<=9238 ) //9238 is build id of OpenOffice.org 2.3.1
824 return true;
825 }
826 return false;
827 }
828
isDocumentGeneratedWithOpenOfficeOlderThan2_3(const uno::Reference<frame::XModel> & xChartModel)829 bool isDocumentGeneratedWithOpenOfficeOlderThan2_3( const uno::Reference< frame::XModel >& xChartModel )
830 {
831 bool bResult = false;
832 ::rtl::OUString aGenerator( lcl_getGeneratorFromModel(xChartModel) );
833 //if there is a meta stream at the chart object it was not written with an older OpenOffice version < 2.3
834 if( !aGenerator.getLength() )
835 {
836 //if there is no meta stream at the chart object we need to check whether the parent document is OpenOffice at all
837 uno::Reference< container::XChild > xChild( xChartModel, uno::UNO_QUERY );
838 if( xChild.is() )
839 {
840 aGenerator = lcl_getGeneratorFromModel( uno::Reference< frame::XModel >( xChild->getParent(), uno::UNO_QUERY) );
841 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project") ) ) != -1 )
842 {
843 //the chart application has not created files without a meta stream since OOo 2.3 (OOo 2.3 has written a metastream already)
844 //only the report builder extension has created some files with OOo 3.1 that do not have a meta stream
845 if( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org_project/31") ) ) != -1 )
846 bResult = false;//#i100102# probably generated with OOo 3.1 by the report designer
847 else
848 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
849 }
850 else if( isDocumentGeneratedWithOpenOfficeOlderThan2_0(xChartModel) )
851 bResult= true;
852 }
853 }
854 return bResult;
855 }
856
isDocumentGeneratedWithOpenOfficeOlderThan2_0(const::com::sun::star::uno::Reference<::com::sun::star::frame::XModel> & xChartModel)857 bool isDocumentGeneratedWithOpenOfficeOlderThan2_0( const ::com::sun::star::uno::Reference< ::com::sun::star::frame::XModel >& xChartModel)
858 {
859 bool bResult = false;
860 ::rtl::OUString aGenerator( lcl_getGeneratorFromModelOrItsParent(xChartModel) );
861 if( ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("OpenOffice.org 1") ) ) == 0 )
862 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarOffice 6") ) ) == 0 )
863 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarOffice 7") ) ) == 0 )
864 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarSuite 6") ) ) == 0 )
865 || ( aGenerator.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("StarSuite 7") ) ) == 0 )
866 )
867 bResult= true;
868 return bResult;
869 }
870
getDataProviderFromParent(const Reference<chart2::XChartDocument> & xChartDoc)871 Reference< chart2::data::XDataProvider > getDataProviderFromParent( const Reference< chart2::XChartDocument >& xChartDoc )
872 {
873 Reference< chart2::data::XDataProvider > xRet;
874 uno::Reference< container::XChild > xChild( xChartDoc, uno::UNO_QUERY );
875 if( xChild.is() )
876 {
877 Reference< lang::XMultiServiceFactory > xFact( xChild->getParent(), uno::UNO_QUERY );
878 if( xFact.is() )
879 {
880 const OUString aDataProviderServiceName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.chart2.data.DataProvider"));
881 const uno::Sequence< OUString > aServiceNames( xFact->getAvailableServiceNames());
882 const OUString * pBegin = aServiceNames.getConstArray();
883 const OUString * pEnd = pBegin + aServiceNames.getLength();
884 if( ::std::find( pBegin, pEnd, aDataProviderServiceName ) != pEnd )
885 {
886 xRet = Reference< chart2::data::XDataProvider >(
887 xFact->createInstance( aDataProviderServiceName ), uno::UNO_QUERY );
888 }
889 }
890 }
891 return xRet;
892 }
893
894 } // namespace SchXMLTools
895