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