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