xref: /trunk/main/xmloff/source/chart/SchXMLTools.cxx (revision d666495c4f609ab94ddded8b0141831070b22d11)
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