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