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