1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_xmloff.hxx"
30 
31 #include "SchXMLChartContext.hxx"
32 #include "SchXMLImport.hxx"
33 #include "SchXMLLegendContext.hxx"
34 #include "SchXMLPlotAreaContext.hxx"
35 #include "SchXMLParagraphContext.hxx"
36 #include "SchXMLTableContext.hxx"
37 #include "SchXMLSeriesHelper.hxx"
38 #include "SchXMLSeries2Context.hxx"
39 #include "SchXMLTools.hxx"
40 #include <comphelper/mediadescriptor.hxx>
41 #include <tools/debug.hxx>
42 // header for class ByteString
43 #include <tools/string.hxx>
44 #include "xmloff/xmlnmspe.hxx"
45 #include <xmloff/xmlement.hxx>
46 #include <xmloff/xmltoken.hxx>
47 #include <xmloff/nmspmap.hxx>
48 #include <xmloff/xmluconv.hxx>
49 #include <xmloff/xmlstyle.hxx>
50 #include <xmloff/prstylei.hxx>
51 
52 #include "vector"
53 #include <com/sun/star/chart/XChartDocument.hpp>
54 #include <com/sun/star/chart/XDiagram.hpp>
55 #include <com/sun/star/xml/sax/XAttributeList.hpp>
56 #include <com/sun/star/util/XStringMapping.hpp>
57 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
58 #include <com/sun/star/drawing/XDrawPage.hpp>
59 #include <com/sun/star/chart/ChartDataRowSource.hpp>
60 #include <com/sun/star/awt/PosSize.hpp>
61 #include <com/sun/star/embed/Aspects.hpp>
62 #include <com/sun/star/embed/XVisualObject.hpp>
63 
64 #include <com/sun/star/chart2/XChartDocument.hpp>
65 #include <com/sun/star/chart2/data/XDataSink.hpp>
66 #include <com/sun/star/chart2/XDataSeriesContainer.hpp>
67 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
68 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
69 #include <com/sun/star/chart2/XTitled.hpp>
70 
71 using namespace com::sun::star;
72 using namespace ::xmloff::token;
73 using ::rtl::OUString;
74 using com::sun::star::uno::Reference;
75 using namespace ::SchXMLTools;
76 
77 namespace
78 {
79 
80 void lcl_setRoleAtLabeledSequence(
81     const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq,
82     const ::rtl::OUString &rRole )
83 {
84     // set role of sequence
85     uno::Reference< chart2::data::XDataSequence > xValues( xLSeq->getValues());
86     if( xValues.is())
87     {
88         uno::Reference< beans::XPropertySet > xProp( xValues, uno::UNO_QUERY );
89         if( xProp.is())
90             xProp->setPropertyValue(OUString::createFromAscii("Role"), uno::makeAny( rRole ));
91     }
92 }
93 
94 void lcl_MoveDataToCandleStickSeries(
95     const uno::Reference< chart2::data::XDataSource > & xDataSource,
96     const uno::Reference< chart2::XDataSeries > & xDestination,
97     const OUString & rRole )
98 {
99     try
100     {
101         uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq(
102             xDataSource->getDataSequences());
103         if( aLabeledSeq.getLength())
104         {
105             lcl_setRoleAtLabeledSequence( aLabeledSeq[0], rRole );
106 
107             // add to data series
108             uno::Reference< chart2::data::XDataSource > xSource( xDestination, uno::UNO_QUERY_THROW );
109             // @todo: realloc only once outside this function
110             uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xSource->getDataSequences());
111             aData.realloc( aData.getLength() + 1);
112             aData[ aData.getLength() - 1 ] = aLabeledSeq[0];
113             uno::Reference< chart2::data::XDataSink > xSink( xDestination, uno::UNO_QUERY_THROW );
114             xSink->setData( aData );
115         }
116     }
117     catch( uno::Exception & )
118     {
119         OSL_ENSURE( false, "Exception caught while moving data to candlestick series" );
120     }
121 }
122 
123 void lcl_setRoleAtFirstSequence(
124     const uno::Reference< chart2::XDataSeries > & xSeries,
125     const ::rtl::OUString & rRole )
126 {
127     uno::Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
128     if( xSource.is())
129     {
130         uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences());
131         if( aSeq.getLength())
132             lcl_setRoleAtLabeledSequence( aSeq[0], rRole );
133     }
134 }
135 
136 void lcl_removeEmptyChartTypeGroups( const uno::Reference< chart2::XChartDocument > & xDoc )
137 {
138     if( ! xDoc.is())
139         return;
140 
141     uno::Reference< chart2::XDiagram > xDia( xDoc->getFirstDiagram());
142     if( ! xDia.is())
143         return;
144 
145     try
146     {
147         // count all charttype groups to be able to leave at least one
148         sal_Int32 nRemainingGroups = 0;
149         uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW );
150         uno::Sequence< uno::Reference< chart2::XCoordinateSystem > >
151             aCooSysSeq( xCooSysCnt->getCoordinateSystems());
152         for( sal_Int32 nI = aCooSysSeq.getLength(); nI--; )
153         {
154             uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW );
155             nRemainingGroups += xCTCnt->getChartTypes().getLength();
156         }
157 
158         // delete all empty groups, but leave at least  group (empty or not)
159         for( sal_Int32 nI = aCooSysSeq.getLength(); nI-- && (nRemainingGroups > 1); )
160         {
161             uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW );
162             uno::Sequence< uno::Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
163             for( sal_Int32 nJ=aCTSeq.getLength(); nJ-- && (nRemainingGroups > 1); )
164             {
165                 uno::Reference< chart2::XDataSeriesContainer > xDSCnt( aCTSeq[nJ], uno::UNO_QUERY_THROW );
166                 if( xDSCnt->getDataSeries().getLength() == 0 )
167                 {
168                     // note: iterator stays valid as we have a local sequence
169                     xCTCnt->removeChartType( aCTSeq[nJ] );
170                     --nRemainingGroups;
171                 }
172             }
173         }
174     }
175     catch( uno::Exception & ex )
176     {
177         String aStr( ex.Message );
178         ByteString aBStr( aStr, RTL_TEXTENCODING_ASCII_US );
179         DBG_ERROR1( "Exception caught while removing empty chart types: %s", aBStr.GetBuffer());
180     }
181 }
182 
183 uno::Sequence< sal_Int32 > lcl_getNumberSequenceFromString( const ::rtl::OUString& rStr, bool bAddOneToEachOldIndex )
184 {
185     const sal_Unicode aSpace( ' ' );
186 
187     // count number of entries
188     ::std::vector< sal_Int32 > aVec;
189     sal_Int32 nLastPos = 0;
190     sal_Int32 nPos = 0;
191     while( nPos != -1 )
192     {
193         nPos = rStr.indexOf( aSpace, nLastPos );
194         if( nPos > nLastPos )
195         {
196             aVec.push_back( rStr.copy( nLastPos, (nPos - nLastPos) ).toInt32() );
197         }
198         if( nPos != -1 )
199             nLastPos = nPos + 1;
200     }
201     // last entry
202     if( nLastPos != 0 &&
203         rStr.getLength() > nLastPos )
204     {
205         aVec.push_back( rStr.copy( nLastPos, (rStr.getLength() - nLastPos) ).toInt32() );
206     }
207 
208     const sal_Int32 nVecSize = aVec.size();
209     uno::Sequence< sal_Int32 > aSeq( nVecSize );
210 
211     if(!bAddOneToEachOldIndex)
212     {
213         sal_Int32* pSeqArr = aSeq.getArray();
214         for( nPos = 0; nPos < nVecSize; ++nPos )
215         {
216             pSeqArr[ nPos ] = aVec[ nPos ];
217         }
218     }
219     else if( bAddOneToEachOldIndex )
220     {
221         aSeq.realloc( nVecSize+1 );
222         aSeq[0]=0;
223 
224         sal_Int32* pSeqArr = aSeq.getArray();
225         for( nPos = 0; nPos < nVecSize; ++nPos )
226         {
227             pSeqArr[ nPos+1 ] = aVec[ nPos ]+1;
228         }
229     }
230 
231     return aSeq;
232 }
233 
234 } // anonymous namespace
235 
236 // ----------------------------------------
237 
238 SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper,
239 										SvXMLImport& rImport, const rtl::OUString& rLocalName ) :
240 		SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
241 		mrImportHelper( rImpHelper ),
242         m_bHasRangeAtPlotArea( false ),
243         m_bHasTableElement( false ),
244         mbAllRangeAddressesAvailable( sal_True ),
245         mbColHasLabels( sal_False ),
246         mbRowHasLabels( sal_False ),
247         meDataRowSource( chart::ChartDataRowSource_COLUMNS ),
248         mbIsStockChart( false )
249 {
250 }
251 
252 SchXMLChartContext::~SchXMLChartContext()
253 {}
254 
255 void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
256 {
257 	// parse attributes
258 	sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
259 	const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetChartAttrTokenMap();
260 
261     uno::Reference< embed::XVisualObject > xVisualObject( mrImportHelper.GetChartDocument(), uno::UNO_QUERY);
262     DBG_ASSERT(xVisualObject.is(),"need xVisualObject for page size");
263     if( xVisualObject.is() )
264         maChartSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); //#i103460# take the size given from the parent frame as default
265 
266 	// this flag is necessarry for pie charts in the core
267 	sal_Bool bSetSwitchData = sal_False;
268 
269 	::rtl::OUString sAutoStyleName;
270     ::rtl::OUString aOldChartTypeName;
271     bool bHasAddin = false;
272 
273 	for( sal_Int16 i = 0; i < nAttrCount; i++ )
274 	{
275 		rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
276 		rtl::OUString aLocalName;
277 		rtl::OUString aValue = xAttrList->getValueByIndex( i );
278 		sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
279 
280 		switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
281 		{
282             case XML_TOK_CHART_HREF:
283                 m_aXLinkHRefAttributeToIndicateDataProvider = aValue;
284                 break;
285 
286 			case XML_TOK_CHART_CLASS:
287 				{
288 					rtl::OUString sClassName;
289 					sal_uInt16 nClassPrefix =
290 						GetImport().GetNamespaceMap().GetKeyByAttrName(
291 								aValue, &sClassName );
292 					if( XML_NAMESPACE_CHART == nClassPrefix )
293 					{
294 						SchXMLChartTypeEnum eChartTypeEnum = SchXMLTools::GetChartTypeEnum( sClassName );
295                         if( eChartTypeEnum != XML_CHART_CLASS_UNKNOWN )
296 						{
297                             aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( sClassName, true /* bUseOldNames */ );
298                             maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( sClassName, false /* bUseOldNames */ );
299 							switch( eChartTypeEnum )
300 							{
301 							case XML_CHART_CLASS_CIRCLE:
302 								bSetSwitchData = sal_True;
303 								break;
304 							case XML_CHART_CLASS_STOCK:
305                                 mbIsStockChart = true;
306 								break;
307 							default:
308                                 break;
309 							}
310 						}
311 					}
312 					else if( XML_NAMESPACE_OOO == nClassPrefix )
313 					{
314                         // service is taken from add-in-name attribute
315                         bHasAddin = true;
316 
317 						aOldChartTypeName = sClassName;
318 						maChartTypeServiceName = sClassName;
319 					}
320 				}
321 				break;
322 
323 			case XML_TOK_CHART_WIDTH:
324 				GetImport().GetMM100UnitConverter().convertMeasure( maChartSize.Width, aValue );
325 				break;
326 
327 			case XML_TOK_CHART_HEIGHT:
328 				GetImport().GetMM100UnitConverter().convertMeasure( maChartSize.Height, aValue );
329 				break;
330 
331 			case XML_TOK_CHART_STYLE_NAME:
332 				sAutoStyleName = aValue;
333 				break;
334 
335             case XML_TOK_CHART_COL_MAPPING:
336                 msColTrans = aValue;
337                 break;
338             case XML_TOK_CHART_ROW_MAPPING:
339                 msRowTrans = aValue;
340                 break;
341 		}
342 	}
343 
344     if( aOldChartTypeName.getLength()<= 0 )
345     {
346         DBG_ERROR( "need a charttype to create a diagram" );
347         //set a fallback value:
348         ::rtl::OUString aChartClass_Bar( GetXMLToken(XML_BAR ) );
349         aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, true /* bUseOldNames */ );
350         maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, false /* bUseOldNames */ );
351     }
352 
353     //	Set the size of the draw page.
354     if( xVisualObject.is() )
355         xVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, maChartSize );
356 
357 	InitChart( aOldChartTypeName, bSetSwitchData);
358 
359     if( bHasAddin )
360     {
361         //correct charttype serveice name when having an addin
362         //and don't refresh addin during load
363         uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
364         if( xDocProp.is() )
365         {
366             try
367             {
368                 xDocProp->getPropertyValue( ::rtl::OUString::createFromAscii("BaseDiagram")) >>= aOldChartTypeName;
369                 maChartTypeServiceName =  SchXMLTools::GetNewChartTypeName( aOldChartTypeName );
370                 xDocProp->setPropertyValue( rtl::OUString::createFromAscii( "RefreshAddInAllowed" ) , uno::makeAny( sal_False) );
371             }
372             catch( uno::Exception & )
373             {
374                 DBG_ERROR( "Exception during import SchXMLChartContext::StartElement" );
375             }
376         }
377     }
378 
379 	// set auto-styles for Area
380 	uno::Reference< beans::XPropertySet > xProp( mrImportHelper.GetChartDocument()->getArea(), uno::UNO_QUERY );
381 	if( xProp.is())
382 	{
383 		const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
384 		if( pStylesCtxt )
385 		{
386 			const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
387 				mrImportHelper.GetChartFamilyID(), sAutoStyleName );
388 
389 			if( pStyle && pStyle->ISA( XMLPropStyleContext ))
390 				(( XMLPropStyleContext* )pStyle )->FillPropertySet( xProp );
391 		}
392 	}
393 }
394 
395 namespace
396 {
397 
398 struct NewDonutSeries
399 {
400     ::com::sun::star::uno::Reference<
401                 ::com::sun::star::chart2::XDataSeries > m_xSeries;
402     ::rtl::OUString msStyleName;
403 	sal_Int32 mnAttachedAxis;
404 
405     ::std::vector< ::rtl::OUString > m_aSeriesStyles;
406     ::std::vector< ::rtl::OUString > m_aPointStyles;
407 
408     NewDonutSeries( const ::com::sun::star::uno::Reference<
409                 ::com::sun::star::chart2::XDataSeries >& xSeries, sal_Int32 nPointCount )
410                     : m_xSeries( xSeries )
411                     , mnAttachedAxis( 1 )
412     {
413         m_aPointStyles.resize(nPointCount);
414         m_aSeriesStyles.resize(nPointCount);
415     }
416 
417     void setSeriesStyleNameToPoint( const ::rtl::OUString& rStyleName, sal_Int32 nPointIndex )
418     {
419         DBG_ASSERT(nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()),"donut point <-> series count mismatch");
420         if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) )
421             m_aSeriesStyles[nPointIndex]=rStyleName;
422     }
423 
424     void setPointStyleNameToPoint( const ::rtl::OUString& rStyleName, sal_Int32 nPointIndex )
425     {
426         DBG_ASSERT(nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()),"donut point <-> series count mismatch");
427         if( nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()) )
428             m_aPointStyles[nPointIndex]=rStyleName;
429     }
430 
431     ::std::list< DataRowPointStyle > creatStyleList()
432     {
433         ::std::list< DataRowPointStyle > aRet;
434 
435         DataRowPointStyle aSeriesStyle( DataRowPointStyle::DATA_SERIES
436             , m_xSeries, -1, 1, msStyleName, mnAttachedAxis );
437         aRet.push_back( aSeriesStyle );
438 
439         sal_Int32 nPointIndex=0;
440         ::std::vector< ::rtl::OUString >::iterator aPointIt( m_aPointStyles.begin() );
441         ::std::vector< ::rtl::OUString >::iterator aPointEnd( m_aPointStyles.end() );
442         while( aPointIt != aPointEnd )
443         {
444             DataRowPointStyle aPointStyle( DataRowPointStyle::DATA_POINT
445                 , m_xSeries, nPointIndex, 1, *aPointIt, mnAttachedAxis );
446             if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) )
447             {
448                 aPointStyle.msSeriesStyleNameForDonuts = m_aSeriesStyles[nPointIndex];
449             }
450             if( aPointStyle.msSeriesStyleNameForDonuts.getLength()
451                 || aPointStyle.msStyleName.getLength() )
452                 aRet.push_back( aPointStyle );
453             ++aPointIt;
454             ++nPointIndex;
455         }
456 
457         return aRet;
458     }
459 };
460 
461 void lcl_swapPointAndSeriesStylesForDonutCharts( ::std::list< DataRowPointStyle >& rStyleList
462         , const ::std::map< ::com::sun::star::uno::Reference<
463                 ::com::sun::star::chart2::XDataSeries> , sal_Int32 >& rSeriesMap )
464 {
465     ::std::list< DataRowPointStyle >::iterator aIt(rStyleList.begin());
466     ::std::list< DataRowPointStyle >::iterator aEnd(rStyleList.end());
467 
468     //detect old series count
469     //and add old series to aSeriesMap
470     ::std::map< ::com::sun::star::uno::Reference<
471                 ::com::sun::star::chart2::XDataSeries >, sal_Int32 > aSeriesMap(rSeriesMap);
472     sal_Int32 nOldSeriesCount = 0;
473     {
474         sal_Int32 nMaxOldSeriesIndex = 0;
475         sal_Int32 nOldSeriesIndex = 0;
476         for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
477         {
478             DataRowPointStyle aStyle(*aIt);
479             if(aStyle.meType == DataRowPointStyle::DATA_SERIES &&
480                     aStyle.m_xSeries.is() )
481             {
482                 nMaxOldSeriesIndex = nOldSeriesIndex;
483 
484                 if( aSeriesMap.end() == aSeriesMap.find(aStyle.m_xSeries) )
485                     aSeriesMap[aStyle.m_xSeries] = nOldSeriesIndex;
486 
487                 nOldSeriesIndex++;
488             }
489         }
490         nOldSeriesCount = nMaxOldSeriesIndex+1;
491     }
492     /*
493     sal_Int32 nOldSeriesCount = 0;
494     {
495         sal_Int32 nMaxOldSeriesIndex = 0;
496         sal_Int32 nOldSeriesIndex = 0;
497         for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
498         {
499             DataRowPointStyle aStyle(*aIt);
500             if(aStyle.meType == DataRowPointStyle::DATA_SERIES )
501             {
502                 nMaxOldSeriesIndex = nOldSeriesIndex;
503                 nOldSeriesIndex++;
504             }
505         }
506         nOldSeriesCount = nMaxOldSeriesIndex+1;
507     }
508     */
509 
510 
511     //initialize new series styles
512     ::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapIt( aSeriesMap.begin() );
513     ::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapEnd( aSeriesMap.end() );
514 
515     //sort by index
516     ::std::vector< NewDonutSeries > aNewSeriesVector;
517     {
518         ::std::map< sal_Int32, Reference< chart2::XDataSeries > > aIndexSeriesMap;
519         for( ; aSeriesMapIt != aSeriesMapEnd; ++aSeriesMapIt )
520             aIndexSeriesMap[aSeriesMapIt->second] = aSeriesMapIt->first;
521 
522         ::std::map< sal_Int32, Reference< chart2::XDataSeries > >::const_iterator aIndexIt( aIndexSeriesMap.begin() );
523         ::std::map< sal_Int32, Reference< chart2::XDataSeries > >::const_iterator aIndexEnd( aIndexSeriesMap.end() );
524 
525         for( ; aIndexIt != aIndexEnd; ++aIndexIt )
526             aNewSeriesVector.push_back( NewDonutSeries(aIndexIt->second,nOldSeriesCount) );
527     }
528 
529     //overwrite attached axis information according to old series styles
530     for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
531     {
532         DataRowPointStyle aStyle(*aIt);
533         if(aStyle.meType == DataRowPointStyle::DATA_SERIES )
534         {
535             aSeriesMapIt = aSeriesMap.find( aStyle.m_xSeries );
536             if( aSeriesMapIt != aSeriesMapEnd && aSeriesMapIt->second < static_cast<sal_Int32>(aNewSeriesVector.size()) )
537                 aNewSeriesVector[aSeriesMapIt->second].mnAttachedAxis = aStyle.mnAttachedAxis;
538         }
539     }
540 
541     //overwrite new series style names with old series style name information
542     for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
543     {
544         DataRowPointStyle aStyle(*aIt);
545         if( aStyle.meType == DataRowPointStyle::DATA_SERIES )
546         {
547             aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries);
548             if( aSeriesMapEnd != aSeriesMapIt )
549             {
550                 sal_Int32 nNewPointIndex = aSeriesMapIt->second;
551 
552                 ::std::vector< NewDonutSeries >::iterator aNewSeriesIt( aNewSeriesVector.begin() );
553                 ::std::vector< NewDonutSeries >::iterator aNewSeriesEnd( aNewSeriesVector.end() );
554 
555                 for( ;aNewSeriesIt!=aNewSeriesEnd; ++aNewSeriesIt)
556                     aNewSeriesIt->setSeriesStyleNameToPoint( aStyle.msStyleName, nNewPointIndex );
557             }
558         }
559     }
560 
561     //overwrite new series style names with point style name information
562     for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
563     {
564         DataRowPointStyle aStyle(*aIt);
565         if( aStyle.meType == DataRowPointStyle::DATA_POINT )
566         {
567             aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries);
568             if( aSeriesMapEnd != aSeriesMapIt )
569             {
570                 sal_Int32 nNewPointIndex = aSeriesMapIt->second;
571                 sal_Int32 nNewSeriesIndex = aStyle.m_nPointIndex;
572                 sal_Int32 nRepeatCount = aStyle.m_nPointRepeat;
573 
574                 while( nRepeatCount && (nNewSeriesIndex>=0) && (nNewSeriesIndex< static_cast<sal_Int32>(aNewSeriesVector.size()) ) )
575                 {
576                     NewDonutSeries& rNewSeries( aNewSeriesVector[nNewSeriesIndex] );
577                     rNewSeries.setPointStyleNameToPoint( aStyle.msStyleName, nNewPointIndex );
578 
579                     nRepeatCount--;
580                     nNewSeriesIndex++;
581                 }
582             }
583         }
584     }
585 
586     //put information from aNewSeriesVector to output parameter rStyleList
587     rStyleList.clear();
588 
589     ::std::vector< NewDonutSeries >::iterator aNewSeriesIt( aNewSeriesVector.begin() );
590     ::std::vector< NewDonutSeries >::iterator aNewSeriesEnd( aNewSeriesVector.end() );
591     for( ;aNewSeriesIt!=aNewSeriesEnd; ++aNewSeriesIt)
592     {
593         ::std::list< DataRowPointStyle > aList( aNewSeriesIt->creatStyleList() );
594         rStyleList.insert(rStyleList.end(),aList.begin(),aList.end());
595     }
596 }
597 
598 bool lcl_SpecialHandlingForDonutChartNeeded(
599     const ::rtl::OUString & rServiceName,
600     const SvXMLImport & rImport )
601 {
602     bool bResult = false;
603     if( rServiceName.equalsAsciiL(
604             RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.DonutChartType" )))
605     {
606         bResult = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( rImport.GetModel() );
607     }
608     return bResult;
609 }
610 
611 } // anonymous namespace
612 
613 
614 void lcl_ApplyDataFromRectangularRangeToDiagram(
615         const uno::Reference< chart2::XChartDocument >& xNewDoc
616         , const rtl::OUString& rRectangularRange
617         , ::com::sun::star::chart::ChartDataRowSource eDataRowSource
618         , bool bRowHasLabels, bool bColHasLabels
619         , bool bSwitchOnLabelsAndCategoriesForOwnData
620         , const rtl::OUString& sColTrans
621         , const rtl::OUString& sRowTrans )
622 {
623     if( !xNewDoc.is() )
624         return;
625 
626     uno::Reference< chart2::XDiagram > xNewDia( xNewDoc->getFirstDiagram());
627     uno::Reference< chart2::data::XDataProvider > xDataProvider( xNewDoc->getDataProvider() );
628     if( !xNewDia.is() || !xDataProvider.is() )
629         return;
630 
631     sal_Bool bFirstCellAsLabel =
632         (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bRowHasLabels : bColHasLabels;
633     sal_Bool bHasCateories =
634         (eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bColHasLabels : bRowHasLabels;
635 
636     if( bSwitchOnLabelsAndCategoriesForOwnData )
637     {
638         bFirstCellAsLabel = true;
639         bHasCateories = true;
640     }
641 
642     uno::Sequence< beans::PropertyValue > aArgs( 3 );
643     aArgs[0] = beans::PropertyValue(
644         ::rtl::OUString::createFromAscii("CellRangeRepresentation"),
645         -1, uno::makeAny( rRectangularRange ),
646         beans::PropertyState_DIRECT_VALUE );
647     aArgs[1] = beans::PropertyValue(
648         ::rtl::OUString::createFromAscii("DataRowSource"),
649         -1, uno::makeAny( eDataRowSource ),
650         beans::PropertyState_DIRECT_VALUE );
651     aArgs[2] = beans::PropertyValue(
652         ::rtl::OUString::createFromAscii("FirstCellAsLabel"),
653         -1, uno::makeAny( bFirstCellAsLabel ),
654         beans::PropertyState_DIRECT_VALUE );
655 
656     if( sColTrans.getLength() || sRowTrans.getLength() )
657     {
658         aArgs.realloc( aArgs.getLength() + 1 );
659         aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue(
660             ::rtl::OUString::createFromAscii("SequenceMapping"),
661             -1, uno::makeAny( sColTrans.getLength()
662                 ? lcl_getNumberSequenceFromString( sColTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() )
663                 : lcl_getNumberSequenceFromString( sRowTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) ),
664         beans::PropertyState_DIRECT_VALUE );
665     }
666 
667     //work around wrong writer ranges ( see Issue 58464 )
668     {
669         rtl::OUString aChartOleObjectName;
670         uno::Reference< frame::XModel > xModel(xNewDoc, uno::UNO_QUERY );
671         if( xModel.is() )
672         {
673             comphelper::MediaDescriptor aMediaDescriptor( xModel->getArgs() );
674 
675             comphelper::MediaDescriptor::const_iterator aIt(
676                 aMediaDescriptor.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HierarchicalDocumentName" ))));
677             if( aIt != aMediaDescriptor.end() )
678             {
679                 aChartOleObjectName = (*aIt).second.get< ::rtl::OUString >();
680             }
681         }
682         if( aChartOleObjectName.getLength() )
683         {
684             aArgs.realloc( aArgs.getLength() + 1 );
685             aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue(
686                 ::rtl::OUString::createFromAscii("ChartOleObjectName"),
687                 -1, uno::makeAny( aChartOleObjectName ),
688                 beans::PropertyState_DIRECT_VALUE );
689         }
690     }
691 
692 
693     uno::Reference< chart2::data::XDataSource > xDataSource(
694         xDataProvider->createDataSource( aArgs ));
695 
696     aArgs.realloc( aArgs.getLength() + 2 );
697     aArgs[ aArgs.getLength() - 2 ] = beans::PropertyValue(
698         ::rtl::OUString::createFromAscii("HasCategories"),
699         -1, uno::makeAny( bHasCateories ),
700         beans::PropertyState_DIRECT_VALUE );
701     aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue(
702         ::rtl::OUString::createFromAscii("UseCategoriesAsX"),
703         -1, uno::makeAny( sal_False ),//categories in ODF files are not to be used as x values (independent from what is offered in our ui)
704         beans::PropertyState_DIRECT_VALUE );
705 
706     xNewDia->setDiagramData( xDataSource, aArgs );
707 }
708 
709 void SchXMLChartContext::EndElement()
710 {
711 	uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
712 	uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY );
713     uno::Reference< chart2::XChartDocument > xNewDoc( xDoc, uno::UNO_QUERY );
714 
715 	if( xProp.is())
716 	{
717 		if( maMainTitle.getLength())
718 		{
719 			uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getTitle(), uno::UNO_QUERY );
720 			if( xTitleProp.is())
721 			{
722 				try
723 				{
724 					uno::Any aAny;
725 					aAny <<= maMainTitle;
726 					xTitleProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )), aAny );
727 				}
728 				catch( beans::UnknownPropertyException )
729 				{
730 					DBG_ERROR( "Property String for Title not available" );
731 				}
732 			}
733 		}
734 		if( maSubTitle.getLength())
735 		{
736 			uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getSubTitle(), uno::UNO_QUERY );
737 			if( xTitleProp.is())
738 			{
739 				try
740 				{
741 					uno::Any aAny;
742 					aAny <<= maSubTitle;
743 					xTitleProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )), aAny );
744 				}
745 				catch( beans::UnknownPropertyException )
746 				{
747 					DBG_ERROR( "Property String for Title not available" );
748 				}
749 			}
750 		}
751 	}
752 
753     // cleanup: remove empty chart type groups
754     lcl_removeEmptyChartTypeGroups( xNewDoc );
755 
756     // set stack mode before a potential chart type detection (in case we have a rectangular range)
757     uno::Reference< chart::XDiagram > xDiagram( xDoc->getDiagram() );
758     uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
759     if( xDiaProp.is())
760     {
761         if( maSeriesDefaultsAndStyles.maStackedDefault.hasValue())
762             xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Stacked")),maSeriesDefaultsAndStyles.maStackedDefault);
763         if( maSeriesDefaultsAndStyles.maPercentDefault.hasValue())
764             xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Percent")),maSeriesDefaultsAndStyles.maPercentDefault);
765         if( maSeriesDefaultsAndStyles.maDeepDefault.hasValue())
766             xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Deep")),maSeriesDefaultsAndStyles.maDeepDefault);
767         if( maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault.hasValue())
768             xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("StackedBarsConnected")),maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault);
769     }
770 
771     //the OOo 2.0 implementation and older has a bug with donuts
772     bool bSpecialHandlingForDonutChart = lcl_SpecialHandlingForDonutChartNeeded(
773         maChartTypeServiceName, GetImport());
774 
775     // apply data
776     if(!xNewDoc.is())
777         return;
778 
779     bool bHasOwnData = false;
780     if( m_aXLinkHRefAttributeToIndicateDataProvider.equalsAscii( "." ) ) //data comes from the chart itself
781         bHasOwnData = true;
782     else if( m_aXLinkHRefAttributeToIndicateDataProvider.equalsAscii( ".." ) ) //data comes from the parent application
783         bHasOwnData = false;
784     else if( m_aXLinkHRefAttributeToIndicateDataProvider.getLength() ) //not supported so far to get the data by sibling objects -> fall back to chart itself if data are available
785         bHasOwnData = m_bHasTableElement;
786     else
787         bHasOwnData = !m_bHasRangeAtPlotArea;
788 
789     if( xNewDoc->hasInternalDataProvider())
790     {
791         if( !m_bHasTableElement && !m_aXLinkHRefAttributeToIndicateDataProvider.equalsAscii( "." ) )
792         {
793             //#i103147# ODF, workaround broken files with a missing table:cell-range-address at the plot-area
794             bool bSwitchSuccessful = SchXMLTools::switchBackToDataProviderFromParent( xNewDoc, maLSequencesPerIndex );
795             bHasOwnData = !bSwitchSuccessful;
796         }
797         else
798             bHasOwnData = true;//e.g. in case of copy->paste from calc to impress
799     }
800     else if( bHasOwnData )
801     {
802         xNewDoc->createInternalDataProvider( sal_False /* bCloneExistingData */ );
803     }
804     if( bHasOwnData )
805         msChartAddress = ::rtl::OUString::createFromAscii("all");
806 
807     bool bSwitchRangesFromOuterToInternalIfNecessary = false;
808     if( !bHasOwnData && mbAllRangeAddressesAvailable )
809     {
810         // special handling for stock chart (merge series together)
811         if( mbIsStockChart )
812             MergeSeriesForStockChart();
813     }
814     else if( msChartAddress.getLength() )
815     {
816         //own data or only rectangular range available
817 
818         if( xNewDoc->hasInternalDataProvider() )
819             SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc );
820 
821         bool bOlderThan2_3 = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( Reference< frame::XModel >( xNewDoc, uno::UNO_QUERY ));
822         bool bOldFileWithOwnDataFromRows = (bOlderThan2_3 && bHasOwnData && (meDataRowSource==chart::ChartDataRowSource_ROWS)); // in this case there are range addresses that are simply wrong.
823 
824         if( mbAllRangeAddressesAvailable && !bSpecialHandlingForDonutChart && !mbIsStockChart &&
825             !bOldFileWithOwnDataFromRows )
826         {
827             //bHasOwnData is true in this case!
828             //e.g. for normal files with own data or also in case of copy paste scenario (e.g. calc to impress)
829             bSwitchRangesFromOuterToInternalIfNecessary = true;
830         }
831         else
832         {
833             //apply data from rectangular range
834 
835             // create datasource from data provider with rectangular range parameters and change the diagram setDiagramData
836             try
837             {
838                 if( bOlderThan2_3 && xDiaProp.is() )//for older charts the hidden cells were removed by calc on the fly
839                     xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("IncludeHiddenCells")),uno::makeAny(false));
840 
841                 // note: mbRowHasLabels means the first row contains labels, that means we have "column-descriptions",
842                 // (analogously mbColHasLabels means we have "row-descriptions")
843                 lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans );
844             }
845             catch( uno::Exception & )
846             {
847                 //try to fallback to internal data
848                 DBG_ERROR( "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram try to fallback to internal data" );
849                 if(!bHasOwnData)
850                 {
851                     bHasOwnData = true;
852                     msChartAddress = ::rtl::OUString::createFromAscii("all");
853                     if( !xNewDoc->hasInternalDataProvider() )
854                     {
855                         xNewDoc->createInternalDataProvider( sal_False /* bCloneExistingData */ );
856                         SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc );
857                         try
858                         {
859                             lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans );
860                         }
861                         catch( uno::Exception & )
862                         {
863                             DBG_ERROR( "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram fallback to internal data failed also" );
864                         }
865                     }
866                 }
867             }
868         }
869     }
870     else
871     {
872         DBG_ERROR( " Must not get here" );
873     }
874 
875     // now all series and data point properties are available and can be set
876     {
877         if( bSpecialHandlingForDonutChart )
878         {
879             uno::Reference< chart2::XDiagram > xNewDiagram( xNewDoc->getFirstDiagram() );
880             lcl_swapPointAndSeriesStylesForDonutCharts( maSeriesDefaultsAndStyles.maSeriesStyleList
881                 , SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram(xNewDiagram) );
882         }
883 
884         SchXMLSeries2Context::initSeriesPropertySets( maSeriesDefaultsAndStyles, uno::Reference< frame::XModel >(xDoc, uno::UNO_QUERY ) );
885 
886         //set defaults from diagram to the new series:
887         //check whether we need to remove lines from symbol only charts
888         bool bSwitchOffLinesForScatter = false;
889         {
890             bool bLinesOn = true;
891             if( (maSeriesDefaultsAndStyles.maLinesOnProperty >>= bLinesOn) && !bLinesOn )
892             {
893                 if( 0 == maChartTypeServiceName.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.ScatterChartType" ) ) )
894                 {
895                     bSwitchOffLinesForScatter = true;
896                     SchXMLSeries2Context::switchSeriesLinesOff( maSeriesDefaultsAndStyles.maSeriesStyleList );
897                 }
898             }
899         }
900         SchXMLSeries2Context::setDefaultsToSeries( maSeriesDefaultsAndStyles );
901 
902         // set autostyles for series and data points
903         const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
904         const SvXMLStyleContext* pStyle = NULL;
905 	    ::rtl::OUString sCurrStyleName;
906 
907         if( pStylesCtxt )
908 	    {
909             //iterate over data-series first
910             //don't set series styles for donut charts
911             if( !bSpecialHandlingForDonutChart )
912             {
913                 SchXMLSeries2Context::setStylesToSeries( maSeriesDefaultsAndStyles
914                                                          , pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, maLSequencesPerIndex );
915                 // ... then set attributes for statistics (after their existence was set in the series)
916                 SchXMLSeries2Context::setStylesToStatisticsObjects( maSeriesDefaultsAndStyles
917                             , pStylesCtxt, pStyle, sCurrStyleName );
918             }
919         }
920 
921         //#i98319# call switchRangesFromOuterToInternalIfNecessary before the data point styles are applied, otherwise in copy->paste scenario the data point styles do get lost
922         if( bSwitchRangesFromOuterToInternalIfNecessary )
923         {
924             if( xNewDoc->hasInternalDataProvider() )
925                 SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( maTable, maLSequencesPerIndex, xNewDoc, meDataRowSource );
926         }
927 
928         if( pStylesCtxt )
929         {
930             // ... then iterate over data-point attributes, so the latter are not overwritten
931             SchXMLSeries2Context::setStylesToDataPoints( maSeriesDefaultsAndStyles
932                             , pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, bSpecialHandlingForDonutChart, bSwitchOffLinesForScatter );
933 	    }
934     }
935 
936     if( xProp.is())
937 	    xProp->setPropertyValue( rtl::OUString::createFromAscii( "RefreshAddInAllowed" ) , uno::makeAny( sal_True) );
938 }
939 
940 void SchXMLChartContext::MergeSeriesForStockChart()
941 {
942     OSL_ASSERT( mbIsStockChart );
943     try
944     {
945         uno::Reference< chart::XChartDocument > xOldDoc( mrImportHelper.GetChartDocument());
946         uno::Reference< chart2::XChartDocument > xDoc( xOldDoc, uno::UNO_QUERY_THROW );
947         uno::Reference< chart2::XDiagram > xDiagram( xDoc->getFirstDiagram());
948         if( ! xDiagram.is())
949             return;
950 
951         bool bHasJapaneseCandlestick = true;
952         uno::Reference< chart2::XDataSeriesContainer > xDSContainer;
953         uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
954         uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
955         for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
956         {
957             uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
958             uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes());
959             for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx )
960             {
961                 if( aChartTypes[nCTIdx]->getChartType().equalsAsciiL(
962                         RTL_CONSTASCII_STRINGPARAM("com.sun.star.chart2.CandleStickChartType")))
963                 {
964                     xDSContainer.set( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW );
965                     uno::Reference< beans::XPropertySet > xCTProp( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW );
966                     xCTProp->getPropertyValue( ::rtl::OUString::createFromAscii("Japanese")) >>= bHasJapaneseCandlestick;
967                     break;
968                 }
969             }
970         }
971 
972         if( xDSContainer.is())
973         {
974             // with japanese candlesticks: open, low, high, close
975             // otherwise: low, high, close
976             uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDSContainer->getDataSeries());
977             const sal_Int32 nSeriesCount( aSeriesSeq.getLength());
978             const sal_Int32 nSeriesPerCandleStick = bHasJapaneseCandlestick ? 4: 3;
979             sal_Int32 nCandleStickCount = nSeriesCount / nSeriesPerCandleStick;
980             OSL_ASSERT( nSeriesPerCandleStick * nCandleStickCount == nSeriesCount );
981             uno::Sequence< uno::Reference< chart2::XDataSeries > > aNewSeries( nCandleStickCount );
982             for( sal_Int32 i=0; i<nCandleStickCount; ++i )
983             {
984                 sal_Int32 nSeriesIndex = i*nSeriesPerCandleStick;
985                 if( bHasJapaneseCandlestick )
986                 {
987                     // open values
988                     lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], OUString::createFromAscii("values-first"));
989                     aNewSeries[i] = aSeriesSeq[ nSeriesIndex ];
990                     // low values
991                     lcl_MoveDataToCandleStickSeries(
992                         uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
993                         aNewSeries[i], OUString::createFromAscii("values-min"));
994                 }
995                 else
996                 {
997                     // low values
998                     lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], OUString::createFromAscii("values-min"));
999                     aNewSeries[i] = aSeriesSeq[ nSeriesIndex ];
1000                 }
1001                 // high values
1002                 lcl_MoveDataToCandleStickSeries(
1003                     uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
1004                     aNewSeries[i], OUString::createFromAscii("values-max"));
1005                 // close values
1006                 lcl_MoveDataToCandleStickSeries(
1007                     uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
1008                     aNewSeries[i], OUString::createFromAscii("values-last"));
1009             }
1010             xDSContainer->setDataSeries( aNewSeries );
1011         }
1012     }
1013     catch( uno::Exception & )
1014     {
1015         DBG_ERROR( "Exception while merging series for stock chart" );
1016     }
1017 }
1018 
1019 SvXMLImportContext* SchXMLChartContext::CreateChildContext(
1020 	sal_uInt16 nPrefix,
1021 	const rtl::OUString& rLocalName,
1022 	const uno::Reference< xml::sax::XAttributeList >& xAttrList )
1023 {
1024     static const sal_Bool bTrue = sal_True;
1025     static const uno::Any aTrueBool( &bTrue, ::getBooleanCppuType());
1026 
1027 	SvXMLImportContext* pContext = 0;
1028 	const SvXMLTokenMap& rTokenMap = mrImportHelper.GetChartElemTokenMap();
1029 	uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
1030     uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY );
1031 
1032 	switch( rTokenMap.Get( nPrefix, rLocalName ))
1033 	{
1034 		case XML_TOK_CHART_PLOT_AREA:
1035 			pContext = new SchXMLPlotAreaContext( mrImportHelper, GetImport(), rLocalName,
1036                                                   m_aXLinkHRefAttributeToIndicateDataProvider,
1037 												  maSeriesAddresses, msCategoriesAddress,
1038                                                   msChartAddress, m_bHasRangeAtPlotArea, mbAllRangeAddressesAvailable,
1039                                                   mbColHasLabels, mbRowHasLabels,
1040                                                   meDataRowSource,
1041                                                   maSeriesDefaultsAndStyles,
1042                                                   maChartTypeServiceName,
1043                                                   maLSequencesPerIndex, maChartSize );
1044 			break;
1045 
1046 		case XML_TOK_CHART_TITLE:
1047 			if( xDoc.is())
1048 			{
1049 				if( xProp.is())
1050 				{
1051 					xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasMainTitle" ), aTrueBool );
1052 				}
1053 				uno::Reference< drawing::XShape > xTitleShape( xDoc->getTitle(), uno::UNO_QUERY );
1054 				pContext = new SchXMLTitleContext( mrImportHelper, GetImport(),
1055 												   rLocalName, maMainTitle, xTitleShape );
1056 			}
1057 			break;
1058 
1059 		case XML_TOK_CHART_SUBTITLE:
1060 			if( xDoc.is())
1061 			{
1062 				if( xProp.is())
1063 				{
1064 					xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasSubTitle" ), aTrueBool );
1065 				}
1066 				uno::Reference< drawing::XShape > xTitleShape( xDoc->getSubTitle(), uno::UNO_QUERY );
1067 				pContext = new SchXMLTitleContext( mrImportHelper, GetImport(),
1068 												   rLocalName, maSubTitle, xTitleShape );
1069 			}
1070 			break;
1071 
1072 		case XML_TOK_CHART_LEGEND:
1073 			pContext = new SchXMLLegendContext( mrImportHelper, GetImport(), rLocalName );
1074 			break;
1075 
1076 		case XML_TOK_CHART_TABLE:
1077             {
1078                 SchXMLTableContext * pTableContext =
1079                     new SchXMLTableContext( mrImportHelper, GetImport(), rLocalName, maTable );
1080                 m_bHasTableElement = true;
1081                 // #i85913# take into account column- and row- mapping for
1082                 // charts with own data only for those which were not copied
1083                 // from a place where they got data from the container.  Note,
1084                 // that this requires the plot-area been read before the table
1085                 // (which is required in the ODF spec)
1086                 // Note: For stock charts and donut charts with special handling
1087                 // the mapping must not be applied!
1088                 if( !msChartAddress.getLength() && !mbIsStockChart &&
1089                     !lcl_SpecialHandlingForDonutChartNeeded(
1090                         maChartTypeServiceName, GetImport()))
1091                 {
1092                     if( msColTrans.getLength() > 0 )
1093                     {
1094                         OSL_ASSERT( msRowTrans.getLength() == 0 );
1095                         pTableContext->setColumnPermutation( lcl_getNumberSequenceFromString( msColTrans, true ));
1096                         msColTrans = OUString();
1097                     }
1098                     else if( msRowTrans.getLength() > 0 )
1099                     {
1100                         pTableContext->setRowPermutation( lcl_getNumberSequenceFromString( msRowTrans, true ));
1101                         msRowTrans = OUString();
1102                     }
1103                 }
1104                 pContext = pTableContext;
1105             }
1106             break;
1107 
1108         default:
1109             // try importing as an additional shape
1110             if( ! mxDrawPage.is())
1111             {
1112                 uno::Reference< drawing::XDrawPageSupplier  > xSupp( xDoc, uno::UNO_QUERY );
1113                 if( xSupp.is())
1114                     mxDrawPage = uno::Reference< drawing::XShapes >( xSupp->getDrawPage(), uno::UNO_QUERY );
1115 
1116                 DBG_ASSERT( mxDrawPage.is(), "Invalid Chart Page" );
1117             }
1118             if( mxDrawPage.is())
1119                 pContext = GetImport().GetShapeImport()->CreateGroupChildContext(
1120                     GetImport(), nPrefix, rLocalName, xAttrList, mxDrawPage );
1121             break;
1122 	}
1123 
1124 	if( ! pContext )
1125 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1126 
1127 	return pContext;
1128 }
1129 
1130 
1131 /*
1132 	With a locked controller the following is done here:
1133 		1.	Hide title, subtitle, and legend.
1134 		2.	Set the size of the draw page.
1135 		3.	Set a (logically) empty data set.
1136 		4.	Set the chart type.
1137 */
1138 void SchXMLChartContext::InitChart(
1139     const OUString & rChartTypeServiceName, // currently the old service name
1140     sal_Bool /* bSetSwitchData */ )
1141 {
1142     uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
1143 	DBG_ASSERT( xDoc.is(), "No valid document!" );
1144 	uno::Reference< frame::XModel > xModel (xDoc, uno::UNO_QUERY );
1145 
1146 	// Remove Title and Diagram ("De-InitNew")
1147 	uno::Reference< chart2::XChartDocument > xNewDoc( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
1148 	if( xNewDoc.is())
1149 	{
1150         xNewDoc->setFirstDiagram( 0 );
1151         uno::Reference< chart2::XTitled > xTitled( xNewDoc, uno::UNO_QUERY );
1152         if( xTitled.is())
1153             xTitled->setTitleObject( 0 );
1154     }
1155 
1156 	//	Set the chart type via setting the diagram.
1157 	if( rChartTypeServiceName.getLength() &&
1158 		xDoc.is())
1159 	{
1160 		uno::Reference< lang::XMultiServiceFactory > xFact( xDoc, uno::UNO_QUERY );
1161 		if( xFact.is())
1162 		{
1163 			uno::Reference< chart::XDiagram > xDia( xFact->createInstance( rChartTypeServiceName ), uno::UNO_QUERY );
1164             if( xDia.is())
1165 				xDoc->setDiagram( xDia );
1166 		}
1167 	}
1168 }
1169 
1170 // ----------------------------------------
1171 
1172 SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport,
1173 										const rtl::OUString& rLocalName,
1174 										rtl::OUString& rTitle,
1175 										uno::Reference< drawing::XShape >& xTitleShape ) :
1176 		SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
1177 		mrImportHelper( rImpHelper ),
1178 		mrTitle( rTitle ),
1179 		mxTitleShape( xTitleShape )
1180 {
1181 }
1182 
1183 SchXMLTitleContext::~SchXMLTitleContext()
1184 {}
1185 
1186 void SchXMLTitleContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
1187 {
1188 	sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
1189 
1190     com::sun::star::awt::Point maPosition;
1191     bool bHasXPosition=false;
1192     bool bHasYPosition=false;
1193 
1194 	for( sal_Int16 i = 0; i < nAttrCount; i++ )
1195 	{
1196 		rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
1197 		rtl::OUString aLocalName;
1198 		rtl::OUString aValue = xAttrList->getValueByIndex( i );
1199 		sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
1200 
1201 		if( nPrefix == XML_NAMESPACE_SVG )
1202 		{
1203 			if( IsXMLToken( aLocalName, XML_X ) )
1204             {
1205 				GetImport().GetMM100UnitConverter().convertMeasure( maPosition.X, aValue );
1206                 bHasXPosition = true;
1207             }
1208 			else if( IsXMLToken( aLocalName, XML_Y ) )
1209             {
1210 				GetImport().GetMM100UnitConverter().convertMeasure( maPosition.Y, aValue );
1211                 bHasYPosition = true;
1212             }
1213 		}
1214 		else if( nPrefix == XML_NAMESPACE_CHART )
1215 		{
1216 			if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
1217 				msAutoStyleName = aValue;
1218 		}
1219 	}
1220 
1221 
1222 	if( mxTitleShape.is())
1223 	{
1224         if( bHasXPosition && bHasYPosition )
1225             mxTitleShape->setPosition( maPosition );
1226 
1227 		uno::Reference< beans::XPropertySet > xProp( mxTitleShape, uno::UNO_QUERY );
1228 		if( xProp.is())
1229 		{
1230 			const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
1231 			if( pStylesCtxt )
1232 			{
1233 				const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
1234 					mrImportHelper.GetChartFamilyID(), msAutoStyleName );
1235 
1236 				if( pStyle && pStyle->ISA( XMLPropStyleContext ))
1237 					(( XMLPropStyleContext* )pStyle )->FillPropertySet( xProp );
1238 			}
1239 		}
1240 	}
1241 }
1242 
1243 SvXMLImportContext* SchXMLTitleContext::CreateChildContext(
1244 	sal_uInt16 nPrefix,
1245 	const rtl::OUString& rLocalName,
1246 	const uno::Reference< xml::sax::XAttributeList >& )
1247 {
1248 	SvXMLImportContext* pContext = 0;
1249 
1250 	if( nPrefix == XML_NAMESPACE_TEXT &&
1251 		IsXMLToken( rLocalName, XML_P ) )
1252 	{
1253 		pContext = new SchXMLParagraphContext( GetImport(), rLocalName, mrTitle );
1254 	}
1255 	else
1256 		pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
1257 
1258 	return pContext;
1259 }
1260 
1261 // ----------------------------------------
1262