1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "SchXMLChartContext.hxx"
21 #include <SchXMLImport.hxx>
22 #include "SchXMLLegendContext.hxx"
23 #include "SchXMLDataTableContext.hxx"
24 #include "SchXMLPlotAreaContext.hxx"
25 #include "SchXMLParagraphContext.hxx"
26 #include "SchXMLTableContext.hxx"
27 #include "SchXMLSeries2Context.hxx"
28 #include "SchXMLTools.hxx"
29 #include <osl/diagnose.h>
30 #include <sal/log.hxx>
31 #include <comphelper/diagnose_ex.hxx>
32 #include <unotools/mediadescriptor.hxx>
34 #include <xmloff/xmlnamespace.hxx>
35 #include <xmloff/xmltoken.hxx>
36 #include <xmloff/namespacemap.hxx>
37 #include <xmloff/xmluconv.hxx>
38 #include <xmloff/xmlstyle.hxx>
39 #include <xmloff/SchXMLSeriesHelper.hxx>
42 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
43 #include <com/sun/star/chart/XChartDocument.hpp>
44 #include <com/sun/star/chart/XDiagram.hpp>
45 #include <com/sun/star/xml/sax/XAttributeList.hpp>
46 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
47 #include <com/sun/star/drawing/XDrawPage.hpp>
48 #include <com/sun/star/chart/ChartDataRowSource.hpp>
49 #include <com/sun/star/embed/Aspects.hpp>
50 #include <com/sun/star/embed/XVisualObject.hpp>
52 #include <com/sun/star/chart2/XChartDocument.hpp>
53 #include <com/sun/star/chart2/data/XDataSink.hpp>
54 #include <com/sun/star/chart2/data/XPivotTableDataProvider.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>
60 #include <com/sun/star/container/XChild.hpp>
61 #include <com/sun/star/chart2/data/XDataReceiver.hpp>
62 #include <o3tl/safeint.hxx>
63 #include <o3tl/string_view.hxx>
65 using namespace com::sun::star
;
66 using namespace ::xmloff::token
;
67 using com::sun::star::uno::Reference
;
68 using namespace ::SchXMLTools
;
73 void lcl_setRoleAtLabeledSequence(
74 const uno::Reference
< chart2::data::XLabeledDataSequence
> & xLSeq
,
75 const OUString
&rRole
)
77 // set role of sequence
78 uno::Reference
< chart2::data::XDataSequence
> xValues( xLSeq
->getValues());
81 uno::Reference
< beans::XPropertySet
> xProp( xValues
, uno::UNO_QUERY
);
83 xProp
->setPropertyValue("Role", uno::Any( rRole
));
87 void lcl_MoveDataToCandleStickSeries(
88 const uno::Reference
< chart2::data::XDataSource
> & xDataSource
,
89 const uno::Reference
< chart2::XDataSeries
> & xDestination
,
90 const OUString
& rRole
)
94 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aLabeledSeq(
95 xDataSource
->getDataSequences());
96 if( aLabeledSeq
.hasElements())
98 lcl_setRoleAtLabeledSequence( aLabeledSeq
[0], rRole
);
100 // add to data series
101 uno::Reference
< chart2::data::XDataSource
> xSource( xDestination
, uno::UNO_QUERY_THROW
);
102 // @todo: realloc only once outside this function
103 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aData( xSource
->getDataSequences());
104 aData
.realloc( aData
.getLength() + 1);
105 aData
.getArray()[ aData
.getLength() - 1 ] = aLabeledSeq
[0];
106 uno::Reference
< chart2::data::XDataSink
> xSink( xDestination
, uno::UNO_QUERY_THROW
);
107 xSink
->setData( aData
);
110 catch(const uno::Exception
&)
112 TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception caught while moving data to candlestick series" );
116 void lcl_setRoleAtFirstSequence(
117 const uno::Reference
< chart2::XDataSeries
> & xSeries
,
118 const OUString
& rRole
)
120 uno::Reference
< chart2::data::XDataSource
> xSource( xSeries
, uno::UNO_QUERY
);
123 uno::Sequence
< uno::Reference
< chart2::data::XLabeledDataSequence
> > aSeq( xSource
->getDataSequences());
124 if( aSeq
.hasElements())
125 lcl_setRoleAtLabeledSequence( aSeq
[0], rRole
);
129 void lcl_removeEmptyChartTypeGroups( const uno::Reference
< chart2::XChartDocument
> & xDoc
)
134 uno::Reference
< chart2::XDiagram
> xDia( xDoc
->getFirstDiagram());
140 // count all charttype groups to be able to leave at least one
141 sal_Int32 nRemainingGroups
= 0;
142 uno::Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt( xDia
, uno::UNO_QUERY_THROW
);
143 const uno::Sequence
< uno::Reference
< chart2::XCoordinateSystem
> >
144 aCooSysSeq( xCooSysCnt
->getCoordinateSystems());
145 for( auto const & i
: aCooSysSeq
)
147 uno::Reference
< chart2::XChartTypeContainer
> xCTCnt( i
, uno::UNO_QUERY_THROW
);
148 nRemainingGroups
+= xCTCnt
->getChartTypes().getLength();
151 // delete all empty groups, but leave at least group (empty or not)
152 for( sal_Int32 nI
= aCooSysSeq
.getLength(); nI
-- && (nRemainingGroups
> 1); )
154 uno::Reference
< chart2::XChartTypeContainer
> xCTCnt( aCooSysSeq
[nI
], uno::UNO_QUERY_THROW
);
155 uno::Sequence
< uno::Reference
< chart2::XChartType
> > aCTSeq( xCTCnt
->getChartTypes());
156 for( sal_Int32 nJ
=aCTSeq
.getLength(); nJ
-- && (nRemainingGroups
> 1); )
158 uno::Reference
< chart2::XDataSeriesContainer
> xDSCnt( aCTSeq
[nJ
], uno::UNO_QUERY_THROW
);
159 if( !xDSCnt
->getDataSeries().hasElements() )
161 // note: iterator stays valid as we have a local sequence
162 xCTCnt
->removeChartType( aCTSeq
[nJ
] );
168 catch(const uno::Exception
&)
170 TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught while removing empty chart types");
174 uno::Sequence
< sal_Int32
> lcl_getNumberSequenceFromString( std::u16string_view rStr
, bool bAddOneToEachOldIndex
)
176 const sal_Unicode
aSpace( ' ' );
178 // count number of entries
179 ::std::vector
< sal_Int32
> aVec
;
182 while( nPos
!= std::u16string_view::npos
)
184 nPos
= rStr
.find( aSpace
, nLastPos
);
185 if( nPos
!= std::u16string_view::npos
)
187 if( nPos
> nLastPos
)
188 aVec
.push_back( o3tl::toInt32(rStr
.substr( nLastPos
, (nPos
- nLastPos
) )) );
194 rStr
.size() > nLastPos
)
196 aVec
.push_back( o3tl::toInt32(rStr
.substr( nLastPos
)) );
199 const size_t nVecSize
= aVec
.size();
200 uno::Sequence
< sal_Int32
> aSeq( nVecSize
);
202 if(!bAddOneToEachOldIndex
)
204 sal_Int32
* pSeqArr
= aSeq
.getArray();
205 for( nPos
= 0; nPos
< nVecSize
; ++nPos
)
207 pSeqArr
[ nPos
] = aVec
[ nPos
];
210 else if( bAddOneToEachOldIndex
)
212 aSeq
.realloc( nVecSize
+1 );
213 auto pSeqArr
= aSeq
.getArray();
216 for( nPos
= 0; nPos
< nVecSize
; ++nPos
)
218 pSeqArr
[ nPos
+1 ] = aVec
[ nPos
]+1;
225 } // anonymous namespace
227 SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper
& rImpHelper
,
228 SvXMLImport
& rImport
) :
229 SvXMLImportContext( rImport
),
230 mrImportHelper( rImpHelper
),
231 m_bHasRangeAtPlotArea( false ),
232 m_bHasTableElement( false ),
233 mbAllRangeAddressesAvailable( true ),
234 mbColHasLabels( false ),
235 mbRowHasLabels( false ),
236 meDataRowSource( chart::ChartDataRowSource_COLUMNS
),
237 mbIsStockChart( false )
241 SchXMLChartContext::~SchXMLChartContext()
244 static bool lcl_hasServiceName(Reference
<lang::XMultiServiceFactory
> const & xFactory
, OUString
const & rServiceName
)
246 const uno::Sequence
<OUString
> aServiceNames(xFactory
->getAvailableServiceNames());
248 return std::find(aServiceNames
.begin(), aServiceNames
.end(), rServiceName
) != aServiceNames
.end();
251 void setDataProvider(uno::Reference
<chart2::XChartDocument
> const & xChartDoc
, OUString
const & sDataPilotSource
)
258 uno::Reference
<container::XChild
> xChild(xChartDoc
, uno::UNO_QUERY
);
259 uno::Reference
<chart2::data::XDataReceiver
> xDataReceiver(xChartDoc
, uno::UNO_QUERY
);
260 if (xChild
.is() && xDataReceiver
.is())
262 bool bHasOwnData
= true;
264 Reference
<lang::XMultiServiceFactory
> xFact(xChild
->getParent(), uno::UNO_QUERY
);
267 if (!xChartDoc
->getDataProvider().is())
269 bool bHasDataPilotSource
= !sDataPilotSource
.isEmpty();
270 OUString
aDataProviderServiceName("com.sun.star.chart2.data.DataProvider");
271 if (bHasDataPilotSource
)
272 aDataProviderServiceName
= "com.sun.star.chart2.data.PivotTableDataProvider";
274 if (lcl_hasServiceName(xFact
, aDataProviderServiceName
))
276 Reference
<chart2::data::XDataProvider
> xProvider(xFact
->createInstance(aDataProviderServiceName
), uno::UNO_QUERY
);
280 if (bHasDataPilotSource
)
282 Reference
<chart2::data::XPivotTableDataProvider
> xPivotTableDataProvider(xProvider
, uno::UNO_QUERY
);
283 xPivotTableDataProvider
->setPivotTableName(sDataPilotSource
);
284 xDataReceiver
->attachDataProvider(xProvider
);
285 bHasOwnData
= !xPivotTableDataProvider
->hasPivotTable();
289 xDataReceiver
->attachDataProvider(xProvider
);
298 // else we have no parent => we have our own data
300 if (bHasOwnData
&& ! xChartDoc
->hasInternalDataProvider())
301 xChartDoc
->createInternalDataProvider(false);
304 catch (const uno::Exception
&)
306 TOOLS_INFO_EXCEPTION("xmloff.chart", "SchXMLChartContext::StartElement()");
310 void SchXMLChartContext::startFastElement( sal_Int32
/*nElement*/,
311 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
)
315 uno::Reference
< embed::XVisualObject
> xVisualObject( mrImportHelper
.GetChartDocument(), uno::UNO_QUERY
);
316 SAL_WARN_IF(!xVisualObject
.is(), "xmloff.chart", "need xVisualObject for page size");
317 if( xVisualObject
.is() )
318 maChartSize
= xVisualObject
->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT
); //#i103460# take the size given from the parent frame as default
320 OUString sAutoStyleName
;
321 OUString aOldChartTypeName
;
322 bool bHasAddin
= false;
324 for( auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
) )
326 switch( aIter
.getToken() )
328 case XML_ELEMENT(LO_EXT
, XML_DATA_PILOT_SOURCE
):
329 msDataPilotSource
= aIter
.toString();
331 case XML_ELEMENT(XLINK
, XML_HREF
):
332 m_aXLinkHRefAttributeToIndicateDataProvider
= aIter
.toString();
334 case XML_ELEMENT(CHART
, XML_CLASS
):
336 OUString aValue
= aIter
.toString();
338 sal_uInt16 nClassPrefix
=
339 GetImport().GetNamespaceMap().GetKeyByAttrValueQName(
340 aValue
, &sClassName
);
341 if( XML_NAMESPACE_CHART
== nClassPrefix
)
343 SchXMLChartTypeEnum eChartTypeEnum
= SchXMLTools::GetChartTypeEnum( sClassName
);
344 if( eChartTypeEnum
!= XML_CHART_CLASS_UNKNOWN
)
346 aOldChartTypeName
= SchXMLTools::GetChartTypeByClassName( sClassName
, true /* bUseOldNames */ );
347 maChartTypeServiceName
= SchXMLTools::GetChartTypeByClassName( sClassName
, false /* bUseOldNames */ );
348 switch( eChartTypeEnum
)
350 case XML_CHART_CLASS_STOCK
:
351 mbIsStockChart
= true;
358 else if( XML_NAMESPACE_OOO
== nClassPrefix
)
360 // service is taken from add-in-name attribute
363 aOldChartTypeName
= sClassName
;
364 maChartTypeServiceName
= sClassName
;
369 case XML_ELEMENT(SVG
, XML_WIDTH
):
370 case XML_ELEMENT(SVG_COMPAT
, XML_WIDTH
):
371 GetImport().GetMM100UnitConverter().convertMeasureToCore(
372 maChartSize
.Width
, aIter
.toView() );
375 case XML_ELEMENT(SVG
, XML_HEIGHT
):
376 case XML_ELEMENT(SVG_COMPAT
, XML_HEIGHT
):
377 GetImport().GetMM100UnitConverter().convertMeasureToCore(
378 maChartSize
.Height
, aIter
.toView() );
381 case XML_ELEMENT(CHART
, XML_STYLE_NAME
):
382 sAutoStyleName
= aIter
.toString();
385 case XML_ELEMENT(CHART
, XML_COLUMN_MAPPING
):
386 msColTrans
= aIter
.toString();
388 case XML_ELEMENT(CHART
, XML_ROW_MAPPING
):
389 msRowTrans
= aIter
.toString();
392 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
396 uno::Reference
<chart::XChartDocument
> xDoc
= mrImportHelper
.GetChartDocument();
397 uno::Reference
<chart2::XChartDocument
> xNewDoc(xDoc
, uno::UNO_QUERY
);
399 setDataProvider(xNewDoc
, msDataPilotSource
);
401 if( aOldChartTypeName
.isEmpty() )
403 SAL_WARN("xmloff.chart", "need a charttype to create a diagram" );
404 //set a fallback value:
405 const OUString
& aChartClass_Bar( GetXMLToken(XML_BAR
) );
406 aOldChartTypeName
= SchXMLTools::GetChartTypeByClassName( aChartClass_Bar
, true /* bUseOldNames */ );
407 maChartTypeServiceName
= SchXMLTools::GetChartTypeByClassName( aChartClass_Bar
, false /* bUseOldNames */ );
410 // Set the size of the draw page.
411 if( xVisualObject
.is() )
412 xVisualObject
->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT
, maChartSize
);
414 InitChart( aOldChartTypeName
);
418 //correct charttype service name when having an addin
419 //and don't refresh addin during load
420 uno::Reference
< beans::XPropertySet
> xDocProp( mrImportHelper
.GetChartDocument(), uno::UNO_QUERY
);
425 xDocProp
->getPropertyValue("BaseDiagram") >>= aOldChartTypeName
;
426 maChartTypeServiceName
= SchXMLTools::GetNewChartTypeName( aOldChartTypeName
);
427 xDocProp
->setPropertyValue("RefreshAddInAllowed", uno::Any( false) );
429 catch(const uno::Exception
&)
431 TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception during import SchXMLChartContext::StartElement" );
436 // set auto-styles for Area
437 uno::Reference
<beans::XPropertySet
> xProp
= mrImportHelper
.GetChartDocument()->getArea();
438 mrImportHelper
.FillAutoStyle(sAutoStyleName
, xProp
);
444 struct NewDonutSeries
446 css::uno::Reference
< css::chart2::XDataSeries
> m_xSeries
;
447 OUString msStyleName
;
448 sal_Int32 mnAttachedAxis
;
450 ::std::vector
< OUString
> m_aSeriesStyles
;
451 ::std::vector
< OUString
> m_aPointStyles
;
453 NewDonutSeries( css::uno::Reference
< css::chart2::XDataSeries
> xSeries
, sal_Int32 nPointCount
)
454 : m_xSeries(std::move( xSeries
))
455 , mnAttachedAxis( 1 )
457 m_aPointStyles
.resize(nPointCount
);
458 m_aSeriesStyles
.resize(nPointCount
);
461 void setSeriesStyleNameToPoint( const OUString
& rStyleName
, sal_Int32 nPointIndex
)
463 SAL_WARN_IF(nPointIndex
>= static_cast<sal_Int32
>(m_aSeriesStyles
.size()), "xmloff.chart", "donut point <-> series count mismatch");
464 if( nPointIndex
< static_cast<sal_Int32
>(m_aSeriesStyles
.size()) )
465 m_aSeriesStyles
[nPointIndex
]=rStyleName
;
468 void setPointStyleNameToPoint( const OUString
& rStyleName
, sal_Int32 nPointIndex
)
470 SAL_WARN_IF(nPointIndex
>= static_cast<sal_Int32
>(m_aPointStyles
.size()), "xmloff.chart", "donut point <-> series count mismatch");
471 if( nPointIndex
< static_cast<sal_Int32
>(m_aPointStyles
.size()) )
472 m_aPointStyles
[nPointIndex
]=rStyleName
;
475 ::std::vector
< DataRowPointStyle
> creatStyleVector()
477 ::std::vector
< DataRowPointStyle
> aRet
;
479 DataRowPointStyle
aSeriesStyle( DataRowPointStyle::DATA_SERIES
480 , m_xSeries
, -1, 1, msStyleName
, mnAttachedAxis
);
481 aRet
.push_back( aSeriesStyle
);
483 sal_Int32 nPointIndex
=0;
484 for (auto const& pointStyle
: m_aPointStyles
)
486 DataRowPointStyle
aPointStyle( DataRowPointStyle::DATA_POINT
487 , m_xSeries
, nPointIndex
, 1, pointStyle
, mnAttachedAxis
);
488 if( nPointIndex
< static_cast<sal_Int32
>(m_aSeriesStyles
.size()) )
490 aPointStyle
.msSeriesStyleNameForDonuts
= m_aSeriesStyles
[nPointIndex
];
492 if( !aPointStyle
.msSeriesStyleNameForDonuts
.isEmpty()
493 || !aPointStyle
.msStyleName
.isEmpty() )
494 aRet
.push_back( aPointStyle
);
502 void lcl_swapPointAndSeriesStylesForDonutCharts( ::std::vector
< DataRowPointStyle
>& rStyleVector
503 , ::std::map
< css::uno::Reference
< css::chart2::XDataSeries
> , sal_Int32
>&& aSeriesMap
)
505 //detect old series count
506 //and add old series to aSeriesMap
507 sal_Int32 nOldSeriesCount
= 0;
509 sal_Int32 nMaxOldSeriesIndex
= 0;
510 sal_Int32 nOldSeriesIndex
= 0;
511 for (auto const& style
: rStyleVector
)
513 DataRowPointStyle
aStyle(style
);
514 if(aStyle
.meType
== DataRowPointStyle::DATA_SERIES
&&
515 aStyle
.m_xSeries
.is() )
517 nMaxOldSeriesIndex
= nOldSeriesIndex
;
519 if( aSeriesMap
.end() == aSeriesMap
.find(aStyle
.m_xSeries
) )
520 aSeriesMap
[aStyle
.m_xSeries
] = nOldSeriesIndex
;
525 nOldSeriesCount
= nMaxOldSeriesIndex
+1;
528 //initialize new series styles
529 ::std::map
< Reference
< chart2::XDataSeries
>, sal_Int32
>::const_iterator
aSeriesMapEnd( aSeriesMap
.end() );
532 ::std::vector
< NewDonutSeries
> aNewSeriesVector
;
534 ::std::map
< sal_Int32
, Reference
< chart2::XDataSeries
> > aIndexSeriesMap
;
535 for (auto const& series
: aSeriesMap
)
536 aIndexSeriesMap
[series
.second
] = series
.first
;
538 for (auto const& indexSeries
: aIndexSeriesMap
)
539 aNewSeriesVector
.emplace_back(indexSeries
.second
,nOldSeriesCount
);
542 //overwrite attached axis information according to old series styles
543 for (auto const& style
: rStyleVector
)
545 DataRowPointStyle
aStyle(style
);
546 if(aStyle
.meType
== DataRowPointStyle::DATA_SERIES
)
548 auto aSeriesMapIt
= aSeriesMap
.find( aStyle
.m_xSeries
);
549 if( aSeriesMapIt
!= aSeriesMapEnd
&& aSeriesMapIt
->second
< static_cast<sal_Int32
>(aNewSeriesVector
.size()) )
550 aNewSeriesVector
[aSeriesMapIt
->second
].mnAttachedAxis
= aStyle
.mnAttachedAxis
;
554 //overwrite new series style names with old series style name information
555 for (auto const& style
: rStyleVector
)
557 DataRowPointStyle
aStyle(style
);
558 if( aStyle
.meType
== DataRowPointStyle::DATA_SERIES
)
560 auto aSeriesMapIt
= aSeriesMap
.find(aStyle
.m_xSeries
);
561 if( aSeriesMapEnd
!= aSeriesMapIt
)
563 sal_Int32 nNewPointIndex
= aSeriesMapIt
->second
;
565 for (auto & newSeries
: aNewSeriesVector
)
566 newSeries
.setSeriesStyleNameToPoint( aStyle
.msStyleName
, nNewPointIndex
);
571 //overwrite new series style names with point style name information
572 for (auto const& style
: rStyleVector
)
574 DataRowPointStyle
aStyle(style
);
575 if( aStyle
.meType
== DataRowPointStyle::DATA_POINT
)
577 auto aSeriesMapIt
= aSeriesMap
.find(aStyle
.m_xSeries
);
578 if( aSeriesMapEnd
!= aSeriesMapIt
)
580 sal_Int32 nNewPointIndex
= aSeriesMapIt
->second
;
581 sal_Int32 nNewSeriesIndex
= aStyle
.m_nPointIndex
;
582 sal_Int32 nRepeatCount
= aStyle
.m_nPointRepeat
;
584 while( nRepeatCount
&& (nNewSeriesIndex
>=0) && (o3tl::make_unsigned(nNewSeriesIndex
)< aNewSeriesVector
.size() ) )
586 NewDonutSeries
& rNewSeries( aNewSeriesVector
[nNewSeriesIndex
] );
587 rNewSeries
.setPointStyleNameToPoint( aStyle
.msStyleName
, nNewPointIndex
);
596 //put information from aNewSeriesVector to output parameter rStyleVector
597 rStyleVector
.clear();
599 for (auto & newSeries
: aNewSeriesVector
)
601 ::std::vector
< DataRowPointStyle
> aVector( newSeries
.creatStyleVector() );
602 rStyleVector
.insert(rStyleVector
.end(),aVector
.begin(),aVector
.end());
606 bool lcl_SpecialHandlingForDonutChartNeeded(
607 std::u16string_view rServiceName
,
608 const SvXMLImport
& rImport
)
610 bool bResult
= false;
611 if( rServiceName
== u
"com.sun.star.chart2.DonutChartType" )
613 bResult
= SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( rImport
.GetModel() );
618 } // anonymous namespace
620 static void lcl_ApplyDataFromRectangularRangeToDiagram(
621 const uno::Reference
< chart2::XChartDocument
>& xNewDoc
622 , const OUString
& rRectangularRange
623 , css::chart::ChartDataRowSource eDataRowSource
624 , bool bRowHasLabels
, bool bColHasLabels
625 , bool bSwitchOnLabelsAndCategoriesForOwnData
626 , std::u16string_view sColTrans
627 , std::u16string_view sRowTrans
)
632 uno::Reference
< chart2::XDiagram
> xNewDia( xNewDoc
->getFirstDiagram());
633 uno::Reference
< chart2::data::XDataProvider
> xDataProvider( xNewDoc
->getDataProvider() );
634 if( !xNewDia
.is() || !xDataProvider
.is() )
637 bool bFirstCellAsLabel
=
638 (eDataRowSource
==chart::ChartDataRowSource_COLUMNS
)? bRowHasLabels
: bColHasLabels
;
640 (eDataRowSource
==chart::ChartDataRowSource_COLUMNS
)? bColHasLabels
: bRowHasLabels
;
642 if( bSwitchOnLabelsAndCategoriesForOwnData
)
644 bFirstCellAsLabel
= true;
645 bHasCateories
= true;
648 uno::Sequence
< beans::PropertyValue
> aArgs
{
649 beans::PropertyValue(
650 "CellRangeRepresentation",
651 -1, uno::Any( rRectangularRange
),
652 beans::PropertyState_DIRECT_VALUE
),
653 beans::PropertyValue(
655 -1, uno::Any( eDataRowSource
),
656 beans::PropertyState_DIRECT_VALUE
),
657 beans::PropertyValue(
659 -1, uno::Any( bFirstCellAsLabel
),
660 beans::PropertyState_DIRECT_VALUE
)
663 if( !sColTrans
.empty() || !sRowTrans
.empty() )
665 aArgs
.realloc( aArgs
.getLength() + 1 );
666 aArgs
.getArray()[ sal::static_int_cast
<sal_uInt32
>(aArgs
.getLength()) - 1 ] = beans::PropertyValue(
668 -1, uno::Any( !sColTrans
.empty()
669 ? lcl_getNumberSequenceFromString( sColTrans
, bHasCateories
&& !xNewDoc
->hasInternalDataProvider() )
670 : lcl_getNumberSequenceFromString( sRowTrans
, bHasCateories
&& !xNewDoc
->hasInternalDataProvider() ) ),
671 beans::PropertyState_DIRECT_VALUE
);
674 //work around wrong writer ranges ( see Issue 58464 )
676 OUString aChartOleObjectName
;
679 utl::MediaDescriptor
aMediaDescriptor( xNewDoc
->getArgs() );
681 utl::MediaDescriptor::const_iterator
aIt(
682 aMediaDescriptor
.find( OUString( "HierarchicalDocumentName" )));
683 if( aIt
!= aMediaDescriptor
.end() )
685 aChartOleObjectName
= (*aIt
).second
.get
< OUString
>();
688 if( !aChartOleObjectName
.isEmpty() )
690 aArgs
.realloc( aArgs
.getLength() + 1 );
691 aArgs
.getArray()[ sal::static_int_cast
<sal_uInt32
>(aArgs
.getLength()) - 1 ] = beans::PropertyValue(
692 "ChartOleObjectName",
693 -1, uno::Any( aChartOleObjectName
),
694 beans::PropertyState_DIRECT_VALUE
);
698 uno::Reference
< chart2::data::XDataSource
> xDataSource(
699 xDataProvider
->createDataSource( aArgs
));
701 aArgs
.realloc( aArgs
.getLength() + 2 );
702 auto pArgs
= aArgs
.getArray();
703 pArgs
[ sal::static_int_cast
<sal_uInt32
>(aArgs
.getLength()) - 2 ] = beans::PropertyValue(
705 -1, uno::Any( bHasCateories
),
706 beans::PropertyState_DIRECT_VALUE
);
707 pArgs
[ sal::static_int_cast
<sal_uInt32
>(aArgs
.getLength()) - 1 ] = beans::PropertyValue(
709 -1, uno::Any( false ),//categories in ODF files are not to be used as x values (independent from what is offered in our ui)
710 beans::PropertyState_DIRECT_VALUE
);
712 xNewDia
->setDiagramData( xDataSource
, aArgs
);
715 void SchXMLChartContext::endFastElement(sal_Int32
)
717 uno::Reference
< chart::XChartDocument
> xDoc
= mrImportHelper
.GetChartDocument();
718 uno::Reference
< beans::XPropertySet
> xProp( xDoc
, uno::UNO_QUERY
);
719 uno::Reference
< chart2::XChartDocument
> xNewDoc( xDoc
, uno::UNO_QUERY
);
723 if( !maMainTitle
.isEmpty())
725 uno::Reference
< beans::XPropertySet
> xTitleProp( xDoc
->getTitle(), uno::UNO_QUERY
);
730 xTitleProp
->setPropertyValue("String", uno::Any(maMainTitle
) );
732 catch(const beans::UnknownPropertyException
&)
734 SAL_WARN("xmloff.chart", "Property String for Title not available" );
738 if( !maSubTitle
.isEmpty())
740 uno::Reference
< beans::XPropertySet
> xTitleProp( xDoc
->getSubTitle(), uno::UNO_QUERY
);
745 xTitleProp
->setPropertyValue("String", uno::Any(maSubTitle
) );
747 catch(const beans::UnknownPropertyException
&)
749 SAL_WARN("xmloff.chart", "Property String for Title not available" );
755 // cleanup: remove empty chart type groups
756 lcl_removeEmptyChartTypeGroups( xNewDoc
);
758 // set stack mode before a potential chart type detection (in case we have a rectangular range)
759 uno::Reference
< chart::XDiagram
> xDiagram( xDoc
->getDiagram() );
760 uno::Reference
< beans::XPropertySet
> xDiaProp( xDiagram
, uno::UNO_QUERY
);
763 if( maSeriesDefaultsAndStyles
.maStackedDefault
.hasValue())
764 xDiaProp
->setPropertyValue("Stacked",maSeriesDefaultsAndStyles
.maStackedDefault
);
765 if( maSeriesDefaultsAndStyles
.maPercentDefault
.hasValue())
766 xDiaProp
->setPropertyValue("Percent",maSeriesDefaultsAndStyles
.maPercentDefault
);
767 if( maSeriesDefaultsAndStyles
.maDeepDefault
.hasValue())
768 xDiaProp
->setPropertyValue("Deep",maSeriesDefaultsAndStyles
.maDeepDefault
);
769 if( maSeriesDefaultsAndStyles
.maStackedBarsConnectedDefault
.hasValue())
770 xDiaProp
->setPropertyValue("StackedBarsConnected",maSeriesDefaultsAndStyles
.maStackedBarsConnectedDefault
);
773 //the OOo 2.0 implementation and older has a bug with donuts
774 bool bSpecialHandlingForDonutChart
= lcl_SpecialHandlingForDonutChartNeeded(
775 maChartTypeServiceName
, GetImport());
781 bool bHasOwnData
= false;
782 if( m_aXLinkHRefAttributeToIndicateDataProvider
== "." ) //data comes from the chart itself
784 else if( m_aXLinkHRefAttributeToIndicateDataProvider
== ".." ) //data comes from the parent application
786 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
787 bHasOwnData
= m_bHasTableElement
;
789 bHasOwnData
= !m_bHasRangeAtPlotArea
;
791 if( xNewDoc
->hasInternalDataProvider())
793 if( !m_bHasTableElement
&& m_aXLinkHRefAttributeToIndicateDataProvider
!= "." )
795 //#i103147# ODF, workaround broken files with a missing table:cell-range-address at the plot-area
796 bool bSwitchSuccessful
= SchXMLTools::switchBackToDataProviderFromParent( xNewDoc
, maLSequencesPerIndex
);
797 bHasOwnData
= !bSwitchSuccessful
;
800 bHasOwnData
= true;//e.g. in case of copy->paste from calc to impress
802 else if( bHasOwnData
)
804 xNewDoc
->createInternalDataProvider( false /* bCloneExistingData */ );
807 msChartAddress
= "all";
809 bool bSwitchRangesFromOuterToInternalIfNecessary
= false;
810 if( !bHasOwnData
&& mbAllRangeAddressesAvailable
)
812 // special handling for stock chart (merge series together)
814 MergeSeriesForStockChart();
816 else if( !msChartAddress
.isEmpty() )
818 //own data or only rectangular range available
820 if( xNewDoc
->hasInternalDataProvider() )
821 SchXMLTableHelper::applyTableToInternalDataProvider( maTable
, xNewDoc
);
823 bool bOlderThan2_3
= SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( xNewDoc
);
824 bool bOldFileWithOwnDataFromRows
= (bOlderThan2_3
&& bHasOwnData
&& (meDataRowSource
==chart::ChartDataRowSource_ROWS
)); // in this case there are range addresses that are simply wrong.
826 if( mbAllRangeAddressesAvailable
&& !bSpecialHandlingForDonutChart
&& !mbIsStockChart
&&
827 !bOldFileWithOwnDataFromRows
)
829 //bHasOwnData is true in this case!
830 //e.g. for normal files with own data or also in case of copy paste scenario (e.g. calc to impress)
831 bSwitchRangesFromOuterToInternalIfNecessary
= true;
835 //apply data from rectangular range
837 // create datasource from data provider with rectangular range parameters and change the diagram setDiagramData
840 if( bOlderThan2_3
&& xDiaProp
.is() )//for older charts the hidden cells were removed by calc on the fly
841 xDiaProp
->setPropertyValue("IncludeHiddenCells",uno::Any(false));
843 // note: mbRowHasLabels means the first row contains labels, that means we have "column-descriptions",
844 // (analogously mbColHasLabels means we have "row-descriptions")
845 lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc
, msChartAddress
, meDataRowSource
, mbRowHasLabels
, mbColHasLabels
, bHasOwnData
, msColTrans
, msRowTrans
);
847 catch(const uno::Exception
&)
849 //try to fallback to internal data
850 TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram try to fallback to internal data" );
854 msChartAddress
= "all";
855 if( !xNewDoc
->hasInternalDataProvider() )
857 xNewDoc
->createInternalDataProvider( false /* bCloneExistingData */ );
858 SchXMLTableHelper::applyTableToInternalDataProvider( maTable
, xNewDoc
);
861 lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc
, msChartAddress
, meDataRowSource
, mbRowHasLabels
, mbColHasLabels
, bHasOwnData
, msColTrans
, msRowTrans
);
863 catch(const uno::Exception
&)
865 TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram fallback to internal data failed also" );
874 SAL_WARN("xmloff.chart", "Must not get here" );
877 // now all series and data point properties are available and can be set
879 if( bSpecialHandlingForDonutChart
)
881 uno::Reference
< chart2::XDiagram
> xNewDiagram( xNewDoc
->getFirstDiagram() );
882 lcl_swapPointAndSeriesStylesForDonutCharts( maSeriesDefaultsAndStyles
.maSeriesStyleVector
883 , SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram(xNewDiagram
) );
886 SchXMLSeries2Context::initSeriesPropertySets( maSeriesDefaultsAndStyles
, xDoc
);
888 //set defaults from diagram to the new series:
889 //check whether we need to remove lines from symbol only charts
890 bool bSwitchOffLinesForScatter
= false;
892 bool bLinesOn
= true;
893 if( (maSeriesDefaultsAndStyles
.maLinesOnProperty
>>= bLinesOn
) && !bLinesOn
)
895 if( maChartTypeServiceName
== "com.sun.star.chart2.ScatterChartType" )
897 bSwitchOffLinesForScatter
= true;
898 SchXMLSeries2Context::switchSeriesLinesOff( maSeriesDefaultsAndStyles
.maSeriesStyleVector
);
902 SchXMLSeries2Context::setDefaultsToSeries( maSeriesDefaultsAndStyles
);
904 // set autostyles for series and data points
905 const SvXMLStylesContext
* pStylesCtxt
= mrImportHelper
.GetAutoStylesContext();
906 const SvXMLStyleContext
* pStyle
= nullptr;
907 OUString sCurrStyleName
;
911 //iterate over data-series first
912 //don't set series styles for donut charts
913 if( !bSpecialHandlingForDonutChart
)
915 SchXMLSeries2Context::setStylesToSeries(
916 maSeriesDefaultsAndStyles
, pStylesCtxt
, pStyle
,
917 sCurrStyleName
, mrImportHelper
, GetImport(),
918 mbIsStockChart
, maLSequencesPerIndex
);
919 // ... then set attributes for statistics (after their existence was set in the series)
920 SchXMLSeries2Context::setStylesToStatisticsObjects(
921 maSeriesDefaultsAndStyles
, pStylesCtxt
,
922 pStyle
, sCurrStyleName
);
924 SchXMLSeries2Context::setStylesToRegressionCurves(
925 maSeriesDefaultsAndStyles
, pStylesCtxt
,
926 pStyle
, sCurrStyleName
);
930 //#i98319# call switchRangesFromOuterToInternalIfNecessary before the data point styles are applied, otherwise in copy->paste scenario the data point styles do get lost
931 if( bSwitchRangesFromOuterToInternalIfNecessary
)
933 if( xNewDoc
->hasInternalDataProvider() )
934 SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( maTable
, maLSequencesPerIndex
, xNewDoc
, meDataRowSource
);
939 // ... then iterate over data-point attributes, so the latter are not overwritten
940 SchXMLSeries2Context::setStylesToDataPoints( maSeriesDefaultsAndStyles
941 , pStylesCtxt
, pStyle
, sCurrStyleName
, mrImportHelper
, GetImport(), mbIsStockChart
, bSpecialHandlingForDonutChart
, bSwitchOffLinesForScatter
);
946 xProp
->setPropertyValue("RefreshAddInAllowed", uno::Any( true) );
949 void SchXMLChartContext::MergeSeriesForStockChart()
951 OSL_ASSERT( mbIsStockChart
);
954 uno::Reference
< chart::XChartDocument
> xOldDoc( mrImportHelper
.GetChartDocument());
955 uno::Reference
< chart2::XChartDocument
> xDoc( xOldDoc
, uno::UNO_QUERY_THROW
);
956 uno::Reference
< chart2::XDiagram
> xDiagram( xDoc
->getFirstDiagram());
960 bool bHasJapaneseCandlestick
= true;
961 uno::Reference
< chart2::XDataSeriesContainer
> xDSContainer
;
962 uno::Reference
< chart2::XCoordinateSystemContainer
> xCooSysCnt( xDiagram
, uno::UNO_QUERY_THROW
);
963 const uno::Sequence
< uno::Reference
< chart2::XCoordinateSystem
> > aCooSysSeq( xCooSysCnt
->getCoordinateSystems());
964 for( const auto& rCooSys
: aCooSysSeq
)
966 uno::Reference
< chart2::XChartTypeContainer
> xCTCnt( rCooSys
, uno::UNO_QUERY_THROW
);
967 const uno::Sequence
< uno::Reference
< chart2::XChartType
> > aChartTypes( xCTCnt
->getChartTypes());
968 auto pChartType
= std::find_if(aChartTypes
.begin(), aChartTypes
.end(),
969 [](const auto& rChartType
) { return rChartType
->getChartType() == "com.sun.star.chart2.CandleStickChartType"; });
970 if (pChartType
!= aChartTypes
.end())
972 xDSContainer
.set( *pChartType
, uno::UNO_QUERY_THROW
);
973 uno::Reference
< beans::XPropertySet
> xCTProp( *pChartType
, uno::UNO_QUERY_THROW
);
974 xCTProp
->getPropertyValue("Japanese") >>= bHasJapaneseCandlestick
;
978 if( xDSContainer
.is())
980 // with japanese candlesticks: open, low, high, close
981 // otherwise: low, high, close
982 uno::Sequence
< uno::Reference
< chart2::XDataSeries
> > aSeriesSeq( xDSContainer
->getDataSeries());
983 const sal_Int32
nSeriesCount( aSeriesSeq
.getLength());
984 const sal_Int32 nSeriesPerCandleStick
= bHasJapaneseCandlestick
? 4: 3;
985 sal_Int32 nCandleStickCount
= nSeriesCount
/ nSeriesPerCandleStick
;
986 OSL_ASSERT( nSeriesPerCandleStick
* nCandleStickCount
== nSeriesCount
);
987 uno::Sequence
< uno::Reference
< chart2::XDataSeries
> > aNewSeries( nCandleStickCount
);
988 auto aNewSeriesRange
= asNonConstRange(aNewSeries
);
989 for( sal_Int32 i
=0; i
<nCandleStickCount
; ++i
)
991 sal_Int32 nSeriesIndex
= i
*nSeriesPerCandleStick
;
992 if( bHasJapaneseCandlestick
)
995 lcl_setRoleAtFirstSequence( aSeriesSeq
[ nSeriesIndex
], "values-first");
996 aNewSeriesRange
[i
] = aSeriesSeq
[ nSeriesIndex
];
998 lcl_MoveDataToCandleStickSeries(
999 uno::Reference
< chart2::data::XDataSource
>( aSeriesSeq
[ ++nSeriesIndex
], uno::UNO_QUERY_THROW
),
1000 aNewSeries
[i
], "values-min");
1005 lcl_setRoleAtFirstSequence( aSeriesSeq
[ nSeriesIndex
], "values-min");
1006 aNewSeriesRange
[i
] = aSeriesSeq
[ nSeriesIndex
];
1009 lcl_MoveDataToCandleStickSeries(
1010 uno::Reference
< chart2::data::XDataSource
>( aSeriesSeq
[ ++nSeriesIndex
], uno::UNO_QUERY_THROW
),
1011 aNewSeries
[i
], "values-max");
1013 lcl_MoveDataToCandleStickSeries(
1014 uno::Reference
< chart2::data::XDataSource
>( aSeriesSeq
[ ++nSeriesIndex
], uno::UNO_QUERY_THROW
),
1015 aNewSeries
[i
], "values-last");
1017 xDSContainer
->setDataSeries( aNewSeries
);
1020 catch(const uno::Exception
&)
1022 TOOLS_WARN_EXCEPTION("xmloff.chart", "Exception while merging series for stock chart" );
1026 css::uno::Reference
< css::xml::sax::XFastContextHandler
> SchXMLChartContext::createFastChildContext(
1028 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
)
1030 SvXMLImportContext
* pContext
= nullptr;
1031 uno::Reference
< chart::XChartDocument
> xDoc
= mrImportHelper
.GetChartDocument();
1032 uno::Reference
< beans::XPropertySet
> xProp( xDoc
, uno::UNO_QUERY
);
1036 case XML_ELEMENT(CHART
, XML_PLOT_AREA
):
1037 pContext
= new SchXMLPlotAreaContext( mrImportHelper
, GetImport(),
1038 m_aXLinkHRefAttributeToIndicateDataProvider
,
1039 msCategoriesAddress
,
1040 msChartAddress
, m_bHasRangeAtPlotArea
, mbAllRangeAddressesAvailable
,
1041 mbColHasLabels
, mbRowHasLabels
,
1043 maSeriesDefaultsAndStyles
,
1044 maChartTypeServiceName
,
1045 maLSequencesPerIndex
, maChartSize
);
1047 case XML_ELEMENT(CHART
, XML_TITLE
):
1052 xProp
->setPropertyValue("HasMainTitle", uno::Any(true) );
1054 uno::Reference
< drawing::XShape
> xTitleShape
= xDoc
->getTitle();
1055 pContext
= new SchXMLTitleContext( mrImportHelper
, GetImport(),
1056 maMainTitle
, xTitleShape
);
1059 case XML_ELEMENT(CHART
, XML_SUBTITLE
):
1064 xProp
->setPropertyValue("HasSubTitle", uno::Any(true) );
1066 uno::Reference
< drawing::XShape
> xTitleShape
= xDoc
->getSubTitle();
1067 pContext
= new SchXMLTitleContext( mrImportHelper
, GetImport(),
1068 maSubTitle
, xTitleShape
);
1071 case XML_ELEMENT(CHART
, XML_LEGEND
):
1072 pContext
= new SchXMLLegendContext( mrImportHelper
, GetImport() );
1074 case XML_ELEMENT(LO_EXT
, XML_DATA_TABLE
):
1075 pContext
= new SchXMLDataTableContext(mrImportHelper
, GetImport());
1077 case XML_ELEMENT(TABLE
, XML_TABLE
):
1079 SchXMLTableContext
* pTableContext
=
1080 new SchXMLTableContext( GetImport(), maTable
);
1081 m_bHasTableElement
= true;
1082 // #i85913# take into account column- and row- mapping for
1083 // charts with own data only for those which were not copied
1084 // from a place where they got data from the container. Note,
1085 // that this requires the plot-area been read before the table
1086 // (which is required in the ODF spec)
1087 // Note: For stock charts and donut charts with special handling
1088 // the mapping must not be applied!
1089 if( msChartAddress
.isEmpty() && !mbIsStockChart
&&
1090 !lcl_SpecialHandlingForDonutChartNeeded(
1091 maChartTypeServiceName
, GetImport()))
1093 if( !msColTrans
.isEmpty() )
1095 OSL_ASSERT( msRowTrans
.isEmpty() );
1096 pTableContext
->setColumnPermutation( lcl_getNumberSequenceFromString( msColTrans
, true ));
1099 else if( !msRowTrans
.isEmpty() )
1101 pTableContext
->setRowPermutation( lcl_getNumberSequenceFromString( msRowTrans
, true ));
1105 pContext
= pTableContext
;
1110 // try importing as an additional shape
1111 if( ! mxDrawPage
.is())
1113 uno::Reference
< drawing::XDrawPageSupplier
> xSupp( xDoc
, uno::UNO_QUERY
);
1115 mxDrawPage
= xSupp
->getDrawPage();
1117 SAL_WARN_IF( !mxDrawPage
.is(), "xmloff.chart", "Invalid Chart Page" );
1119 if( mxDrawPage
.is())
1120 pContext
= XMLShapeImportHelper::CreateGroupChildContext(
1121 GetImport(), nElement
, xAttrList
, mxDrawPage
);
1129 With a locked controller the following is done here:
1130 1. Hide title, subtitle, and legend.
1131 2. Set the size of the draw page.
1132 3. Set a (logically) empty data set.
1133 4. Set the chart type.
1135 void SchXMLChartContext::InitChart(
1136 const OUString
& rChartTypeServiceName
// currently the old service name
1139 uno::Reference
< chart::XChartDocument
> xDoc
= mrImportHelper
.GetChartDocument();
1140 SAL_WARN_IF( !xDoc
.is(), "xmloff.chart", "No valid document!" );
1142 // Remove Title and Diagram ("De-InitNew")
1143 uno::Reference
< chart2::XChartDocument
> xNewDoc( mrImportHelper
.GetChartDocument(), uno::UNO_QUERY
);
1146 xNewDoc
->setFirstDiagram( nullptr );
1147 uno::Reference
< chart2::XTitled
> xTitled( xNewDoc
, uno::UNO_QUERY
);
1149 xTitled
->setTitleObject( nullptr );
1152 // Set the chart type via setting the diagram.
1153 if( !rChartTypeServiceName
.isEmpty() && xDoc
.is())
1155 uno::Reference
< lang::XMultiServiceFactory
> xFact( xDoc
, uno::UNO_QUERY
);
1158 uno::Reference
< chart::XDiagram
> xDia( xFact
->createInstance( rChartTypeServiceName
), uno::UNO_QUERY
);
1160 xDoc
->setDiagram( xDia
);
1165 SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper
& rImpHelper
, SvXMLImport
& rImport
,
1167 uno::Reference
< drawing::XShape
> xTitleShape
) :
1168 SvXMLImportContext( rImport
),
1169 mrImportHelper( rImpHelper
),
1171 mxTitleShape(std::move( xTitleShape
))
1175 SchXMLTitleContext::~SchXMLTitleContext()
1178 void SchXMLTitleContext::startFastElement( sal_Int32
/*nElement*/,
1179 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& xAttrList
)
1181 css::awt::Point aPosition
;
1182 bool bHasXPosition
=false;
1183 bool bHasYPosition
=false;
1185 for( auto& aIter
: sax_fastparser::castToFastAttributeList(xAttrList
) )
1187 switch (aIter
.getToken())
1189 case XML_ELEMENT(SVG
, XML_X
):
1190 case XML_ELEMENT(SVG_COMPAT
, XML_X
):
1192 GetImport().GetMM100UnitConverter().convertMeasureToCore(
1193 aPosition
.X
, aIter
.toView() );
1194 bHasXPosition
= true;
1197 case XML_ELEMENT(SVG
, XML_Y
):
1198 case XML_ELEMENT(SVG_COMPAT
, XML_Y
):
1200 GetImport().GetMM100UnitConverter().convertMeasureToCore(
1201 aPosition
.Y
, aIter
.toView() );
1202 bHasYPosition
= true;
1205 case XML_ELEMENT(CHART
, XML_STYLE_NAME
):
1206 msAutoStyleName
= aIter
.toString();
1209 XMLOFF_WARN_UNKNOWN("xmloff", aIter
);
1213 if( mxTitleShape
.is())
1215 if( bHasXPosition
&& bHasYPosition
)
1216 mxTitleShape
->setPosition( aPosition
);
1218 uno::Reference
<beans::XPropertySet
> xProp(mxTitleShape
, uno::UNO_QUERY
);
1219 mrImportHelper
.FillAutoStyle(msAutoStyleName
, xProp
);
1223 css::uno::Reference
< css::xml::sax::XFastContextHandler
> SchXMLTitleContext::createFastChildContext(
1225 const css::uno::Reference
< css::xml::sax::XFastAttributeList
>& /*xAttrList*/ )
1227 SvXMLImportContext
* pContext
= nullptr;
1229 if( nElement
== XML_ELEMENT(TEXT
, XML_P
) ||
1230 nElement
== XML_ELEMENT(LO_EXT
, XML_P
) )
1232 pContext
= new SchXMLParagraphContext( GetImport(), mrTitle
);
1235 XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement
);
1240 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */