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