ed0b12f4ea
we can just take a "const &". (found by running clang-tidy with the performance-unnecessary-copy-initialization warning) Change-Id: I20fd208c65303da78170b1ac06c638fdf3aa094b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176267 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Jenkins
1307 lines
56 KiB
C++
1307 lines
56 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include "SchXMLSeries2Context.hxx"
|
|
#include "SchXMLPlotAreaContext.hxx"
|
|
#include "SchXMLRegressionCurveObjectContext.hxx"
|
|
#include "SchXMLPropertyMappingContext.hxx"
|
|
#include "SchXMLTools.hxx"
|
|
|
|
#include <com/sun/star/chart2/XChartDocument.hpp>
|
|
#include <com/sun/star/chart2/XRegressionCurve.hpp>
|
|
#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
|
|
#include <com/sun/star/chart2/data/XDataSink.hpp>
|
|
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
|
|
#include <com/sun/star/chart2/RelativePosition.hpp>
|
|
|
|
#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
|
|
#include <com/sun/star/chart2/DataPointCustomLabelFieldType.hpp>
|
|
#include <com/sun/star/chart2/DataPointCustomLabelField.hpp>
|
|
|
|
#include <com/sun/star/chart/ChartAxisAssign.hpp>
|
|
#include <com/sun/star/chart/ChartSymbolType.hpp>
|
|
#include <com/sun/star/chart/ChartDataCaption.hpp>
|
|
#include <com/sun/star/chart/ErrorBarStyle.hpp>
|
|
#include <com/sun/star/chart/XChartDocument.hpp>
|
|
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
|
|
#include <com/sun/star/chart/ChartLegendPosition.hpp>
|
|
#include <com/sun/star/embed/Aspects.hpp>
|
|
#include <com/sun/star/embed/XVisualObject.hpp>
|
|
|
|
#include <comphelper/processfactory.hxx>
|
|
|
|
#include <sal/log.hxx>
|
|
#include <utility>
|
|
#include <xmloff/xmlnamespace.hxx>
|
|
#include <xmloff/xmlimp.hxx>
|
|
#include <xmloff/namespacemap.hxx>
|
|
#include <xmloff/SchXMLSeriesHelper.hxx>
|
|
#include <xmloff/prstylei.hxx>
|
|
#include <comphelper/diagnose_ex.hxx>
|
|
|
|
#include <algorithm> // std::find_if
|
|
|
|
using namespace ::com::sun::star;
|
|
using namespace ::xmloff::token;
|
|
|
|
using ::com::sun::star::uno::Reference;
|
|
using ::com::sun::star::uno::Sequence;
|
|
|
|
namespace
|
|
{
|
|
|
|
class SchXMLDomain2Context : public SvXMLImportContext
|
|
{
|
|
private:
|
|
::std::vector< OUString > & mrAddresses;
|
|
|
|
public:
|
|
SchXMLDomain2Context( SvXMLImport& rImport,
|
|
::std::vector< OUString > & rAddresses );
|
|
virtual void SAL_CALL startFastElement(
|
|
sal_Int32 nElement,
|
|
const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) override;
|
|
};
|
|
|
|
SchXMLDomain2Context::SchXMLDomain2Context(
|
|
SvXMLImport& rImport,
|
|
::std::vector< OUString > & rAddresses ) :
|
|
SvXMLImportContext( rImport ),
|
|
mrAddresses( rAddresses )
|
|
{
|
|
}
|
|
|
|
void SchXMLDomain2Context::startFastElement(
|
|
sal_Int32 /*nElement*/,
|
|
const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList )
|
|
{
|
|
for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
|
|
{
|
|
if (aIter.getToken() == XML_ELEMENT(TABLE, XML_CELL_RANGE_ADDRESS) )
|
|
mrAddresses.push_back( aIter.toString() );
|
|
else
|
|
XMLOFF_WARN_UNKNOWN("xmloff", aIter);
|
|
}
|
|
}
|
|
|
|
void lcl_setAutomaticSymbolSize( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport )
|
|
{
|
|
awt::Size aSymbolSize(140,140);//old default for standard sized charts 7cm height
|
|
|
|
uno::Reference< chart::XChartDocument > xChartDoc( rImport.GetModel(), uno::UNO_QUERY );
|
|
if( xChartDoc.is() )
|
|
{
|
|
double fScale = 1;
|
|
uno::Reference< beans::XPropertySet > xLegendProp( xChartDoc->getLegend(), uno::UNO_QUERY );
|
|
chart::ChartLegendPosition aLegendPosition = chart::ChartLegendPosition_NONE;
|
|
if( xLegendProp.is() && (xLegendProp->getPropertyValue(u"Alignment"_ustr) >>= aLegendPosition)
|
|
&& chart::ChartLegendPosition_NONE != aLegendPosition )
|
|
{
|
|
|
|
double fFontHeight = 6.0;
|
|
if( xLegendProp->getPropertyValue(u"CharHeight"_ustr) >>= fFontHeight )
|
|
fScale = 0.75*fFontHeight/6.0;
|
|
}
|
|
else
|
|
{
|
|
uno::Reference< embed::XVisualObject > xVisualObject( rImport.GetModel(), uno::UNO_QUERY );
|
|
if( xVisualObject.is() )
|
|
{
|
|
awt::Size aPageSize( xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ) );
|
|
fScale = aPageSize.Height/7000.0;
|
|
}
|
|
}
|
|
if( fScale>0 )
|
|
{
|
|
aSymbolSize.Height = static_cast<sal_Int32>( fScale * aSymbolSize.Height );
|
|
aSymbolSize.Width = aSymbolSize.Height;
|
|
}
|
|
}
|
|
xSeriesOrPointProp->setPropertyValue(u"SymbolSize"_ustr,uno::Any( aSymbolSize ));
|
|
}
|
|
|
|
void lcl_setSymbolSizeIfNeeded( const uno::Reference< beans::XPropertySet >& xSeriesOrPointProp, const SvXMLImport& rImport )
|
|
{
|
|
if( !xSeriesOrPointProp.is() )
|
|
return;
|
|
|
|
sal_Int32 nSymbolType = chart::ChartSymbolType::NONE;
|
|
if( !(xSeriesOrPointProp.is() && ( xSeriesOrPointProp->getPropertyValue(u"SymbolType"_ustr) >>= nSymbolType)) )
|
|
return;
|
|
|
|
if(chart::ChartSymbolType::NONE!=nSymbolType)
|
|
{
|
|
if( chart::ChartSymbolType::BITMAPURL==nSymbolType )
|
|
{
|
|
//set special size for graphics to indicate to use the bitmap size itself
|
|
xSeriesOrPointProp->setPropertyValue(u"SymbolSize"_ustr,uno::Any( awt::Size(-1,-1) ));
|
|
}
|
|
else
|
|
{
|
|
lcl_setAutomaticSymbolSize( xSeriesOrPointProp, rImport );
|
|
}
|
|
}
|
|
}
|
|
|
|
void lcl_resetSymbolSizeForPointsIfNecessary( const uno::Reference< beans::XPropertySet >& xPointProp, const SvXMLImport& rImport
|
|
, const XMLPropStyleContext * pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
|
|
{
|
|
uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize", pPropStyleContext, pStylesCtxt ) );
|
|
if( !aASymbolSize.hasValue() )
|
|
lcl_setSymbolSizeIfNeeded( xPointProp, rImport );
|
|
}
|
|
|
|
void lcl_setLinkNumberFormatToSourceIfNeeded( const uno::Reference< beans::XPropertySet >& xPointProp
|
|
, const XMLPropStyleContext* pPropStyleContext, const SvXMLStylesContext* pStylesCtxt )
|
|
{
|
|
uno::Any aAny( SchXMLTools::getPropertyFromContext(u"LinkNumberFormatToSource", pPropStyleContext, pStylesCtxt) );
|
|
if( aAny.hasValue() )
|
|
return;
|
|
|
|
if( !xPointProp.is() )
|
|
return;
|
|
|
|
bool bLinkToSource = false;
|
|
if( xPointProp.is() && (xPointProp->getPropertyValue(u"LinkNumberFormatToSource"_ustr) >>= bLinkToSource) )
|
|
{
|
|
if( bLinkToSource )
|
|
{
|
|
xPointProp->setPropertyValue(u"LinkNumberFormatToSource"_ustr, uno::Any(false));
|
|
}
|
|
}
|
|
}
|
|
|
|
void lcl_insertErrorBarLSequencesToMap(
|
|
tSchXMLLSequencesPerIndex & rInOutMap,
|
|
const uno::Reference< beans::XPropertySet > & xSeriesProp )
|
|
{
|
|
Reference< chart2::data::XDataSource > xErrorBarSource;
|
|
if( ( xSeriesProp->getPropertyValue( u"ErrorBarY"_ustr ) >>= xErrorBarSource ) &&
|
|
xErrorBarSource.is() )
|
|
{
|
|
const Sequence< Reference< chart2::data::XLabeledDataSequence > > aLSequences(
|
|
xErrorBarSource->getDataSequences());
|
|
for( const auto& rLSequence : aLSequences )
|
|
{
|
|
// use "0" as data index. This is ok, as it is not used for error bars
|
|
rInOutMap.emplace(
|
|
tSchXMLIndexWithPart( 0, SCH_XML_PART_ERROR_BARS ), rLSequence );
|
|
}
|
|
}
|
|
}
|
|
|
|
Reference< chart2::data::XLabeledDataSequence2 > lcl_createAndAddSequenceToSeries( const OUString& rRole
|
|
, const OUString& rRange
|
|
, const Reference< chart2::XChartDocument >& xChartDoc
|
|
, const Reference< chart2::XDataSeries >& xSeries )
|
|
{
|
|
Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq;
|
|
|
|
Reference< chart2::data::XDataSource > xSeriesSource( xSeries,uno::UNO_QUERY );
|
|
Reference< chart2::data::XDataSink > xSeriesSink( xSeries, uno::UNO_QUERY );
|
|
|
|
if( !(!rRange.isEmpty() && xChartDoc.is() && xSeriesSource.is() && xSeriesSink.is()) )
|
|
return xLabeledSeq;
|
|
|
|
// create a new sequence
|
|
xLabeledSeq = SchXMLTools::GetNewLabeledDataSequence();
|
|
|
|
// set values at the new sequence
|
|
Reference< chart2::data::XDataSequence > xSeq = SchXMLTools::CreateDataSequence( rRange, xChartDoc );
|
|
Reference< beans::XPropertySet > xSeqProp( xSeq, uno::UNO_QUERY );
|
|
if( xSeqProp.is())
|
|
xSeqProp->setPropertyValue(u"Role"_ustr, uno::Any( rRole));
|
|
xLabeledSeq->setValues( xSeq );
|
|
|
|
// add new sequence to data series / push to front to have the correct sequence order if charttype is changed afterwards
|
|
const Sequence< Reference< chart2::data::XLabeledDataSequence > > aOldSeq( xSeriesSource->getDataSequences());
|
|
sal_Int32 nOldCount = aOldSeq.getLength();
|
|
Sequence< Reference< chart2::data::XLabeledDataSequence > > aNewSeq( nOldCount + 1 );
|
|
auto pNewSeq = aNewSeq.getArray();
|
|
pNewSeq[0].set(xLabeledSeq, uno::UNO_QUERY_THROW);
|
|
std::copy(aOldSeq.begin(), aOldSeq.end(), std::next(pNewSeq));
|
|
xSeriesSink->setData( aNewSeq );
|
|
|
|
return xLabeledSeq;
|
|
}
|
|
|
|
XMLPropStyleContext* lcl_GetStylePropContext(
|
|
const SvXMLStylesContext* pStylesCtxt,
|
|
const SvXMLStyleContext*& rpStyle,
|
|
OUString const & rStyleName )
|
|
{
|
|
rpStyle = pStylesCtxt->FindStyleChildContext( SchXMLImportHelper::GetChartFamilyID(), rStyleName );
|
|
XMLPropStyleContext* pPropStyleContext =
|
|
const_cast< XMLPropStyleContext* >(dynamic_cast< const XMLPropStyleContext* >( rpStyle ));
|
|
return pPropStyleContext;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
SchXMLSeries2Context::SchXMLSeries2Context(
|
|
SchXMLImportHelper& rImpHelper,
|
|
SvXMLImport& rImport,
|
|
const Reference< chart2::XChartDocument > & xNewDoc,
|
|
std::vector< SchXMLAxis >& rAxes,
|
|
::std::vector< DataRowPointStyle >& rStyleVector,
|
|
::std::vector< RegressionStyle >& rRegressionStyleVector,
|
|
sal_Int32 nSeriesIndex,
|
|
bool bStockHasVolume,
|
|
GlobalSeriesImportInfo& rGlobalSeriesImportInfo,
|
|
const OUString & aGlobalChartTypeName,
|
|
tSchXMLLSequencesPerIndex & rLSequencesPerIndex,
|
|
bool& rGlobalChartTypeUsedBySeries,
|
|
const awt::Size & rChartSize ) :
|
|
SvXMLImportContext( rImport ),
|
|
mrImportHelper( rImpHelper ),
|
|
mxNewDoc( xNewDoc ),
|
|
mrAxes( rAxes ),
|
|
mrStyleVector( rStyleVector ),
|
|
mrRegressionStyleVector( rRegressionStyleVector ),
|
|
mnSeriesIndex( nSeriesIndex ),
|
|
mnDataPointIndex( 0 ),
|
|
m_bStockHasVolume( bStockHasVolume ),
|
|
m_rGlobalSeriesImportInfo(rGlobalSeriesImportInfo),
|
|
mpAttachedAxis( nullptr ),
|
|
mnAttachedAxis( 0 ),
|
|
maGlobalChartTypeName( aGlobalChartTypeName ),
|
|
maSeriesChartTypeName( aGlobalChartTypeName ),
|
|
m_bHasDomainContext(false),
|
|
mrLSequencesPerIndex( rLSequencesPerIndex ),
|
|
mrGlobalChartTypeUsedBySeries( rGlobalChartTypeUsedBySeries ),
|
|
mbSymbolSizeIsMissingInFile(false),
|
|
maChartSize( rChartSize ),
|
|
// A series manages the DataRowPointStyle-struct of a data-label child element.
|
|
mDataLabel(DataRowPointStyle::DATA_LABEL_SERIES, OUString{})
|
|
{
|
|
if( aGlobalChartTypeName == "com.sun.star.chart2.DonutChartType" )
|
|
{
|
|
maSeriesChartTypeName = "com.sun.star.chart2.PieChartType";
|
|
maGlobalChartTypeName = maSeriesChartTypeName;
|
|
}
|
|
}
|
|
|
|
SchXMLSeries2Context::~SchXMLSeries2Context()
|
|
{
|
|
SAL_WARN_IF( !maPostponedSequences.empty(), "xmloff.chart", "maPostponedSequences is NULL");
|
|
}
|
|
|
|
void SchXMLSeries2Context::startFastElement (sal_Int32 /*Element*/,
|
|
const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList)
|
|
{
|
|
// parse attributes
|
|
mnAttachedAxis = 1;
|
|
|
|
bool bHasRange = false;
|
|
OUString aSeriesLabelRange;
|
|
OUString aSeriesLabelString;
|
|
bool bHideLegend = false;
|
|
|
|
for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) )
|
|
{
|
|
OUString aValue = aIter.toString();
|
|
switch(aIter.getToken())
|
|
{
|
|
case XML_ELEMENT(CHART, XML_VALUES_CELL_RANGE_ADDRESS):
|
|
m_aSeriesRange = aValue;
|
|
bHasRange = true;
|
|
break;
|
|
case XML_ELEMENT(CHART, XML_LABEL_CELL_ADDRESS):
|
|
aSeriesLabelRange = aValue;
|
|
break;
|
|
case XML_ELEMENT(LO_EXT, XML_LABEL_STRING):
|
|
aSeriesLabelString = aValue;
|
|
break;
|
|
case XML_ELEMENT(CHART, XML_ATTACHED_AXIS):
|
|
{
|
|
sal_Int32 nNumOfAxes = mrAxes.size();
|
|
for( sal_Int32 nCurrent = 0; nCurrent < nNumOfAxes; nCurrent++ )
|
|
{
|
|
if( aValue == mrAxes[ nCurrent ].aName &&
|
|
mrAxes[ nCurrent ].eDimension == SCH_XML_AXIS_Y )
|
|
{
|
|
mpAttachedAxis = &( mrAxes[ nCurrent ] );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case XML_ELEMENT(CHART, XML_STYLE_NAME):
|
|
msAutoStyleName = aValue;
|
|
break;
|
|
case XML_ELEMENT(CHART, XML_CLASS):
|
|
{
|
|
OUString aClassName;
|
|
sal_uInt16 nClassPrefix =
|
|
GetImport().GetNamespaceMap().GetKeyByAttrValueQName(
|
|
aValue, &aClassName );
|
|
if( XML_NAMESPACE_CHART == nClassPrefix )
|
|
maSeriesChartTypeName = SchXMLTools::GetChartTypeByClassName( aClassName, false /* bUseOldNames */ );
|
|
|
|
if( maSeriesChartTypeName.isEmpty())
|
|
maSeriesChartTypeName = aClassName;
|
|
}
|
|
break;
|
|
case XML_ELEMENT(LO_EXT, XML_HIDE_LEGEND):
|
|
bHideLegend = aValue.toBoolean();
|
|
break;
|
|
default:
|
|
XMLOFF_WARN_UNKNOWN("xmloff", aIter);
|
|
}
|
|
}
|
|
|
|
if( mpAttachedAxis )
|
|
{
|
|
if( mpAttachedAxis->nAxisIndex > 0 )
|
|
{
|
|
// secondary axis => property has to be set (primary is default)
|
|
mnAttachedAxis = 2;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
SAL_WARN_IF( !mxNewDoc.is(), "xmloff.chart", "mxNewDoc is NULL");
|
|
if( m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable && ! bHasRange )
|
|
m_rGlobalSeriesImportInfo.rbAllRangeAddressesAvailable = false;
|
|
|
|
bool bIsCandleStick = maGlobalChartTypeName == "com.sun.star.chart2.CandleStickChartType";
|
|
if( !maSeriesChartTypeName.isEmpty() )
|
|
{
|
|
bIsCandleStick = maSeriesChartTypeName == "com.sun.star.chart2.CandleStickChartType";
|
|
}
|
|
else
|
|
{
|
|
if( bIsCandleStick
|
|
&& m_bStockHasVolume
|
|
&& mnSeriesIndex == 0 )
|
|
{
|
|
maSeriesChartTypeName = "com.sun.star.chart2.ColumnChartType";
|
|
bIsCandleStick = false;
|
|
}
|
|
else
|
|
{
|
|
maSeriesChartTypeName = maGlobalChartTypeName;
|
|
}
|
|
}
|
|
if( ! mrGlobalChartTypeUsedBySeries )
|
|
mrGlobalChartTypeUsedBySeries = (maSeriesChartTypeName == maGlobalChartTypeName);
|
|
sal_Int32 const nCoordinateSystemIndex = 0;//so far we can only import one coordinate system
|
|
m_xSeries.set(
|
|
SchXMLImportHelper::GetNewDataSeries( mxNewDoc, nCoordinateSystemIndex, maSeriesChartTypeName, ! mrGlobalChartTypeUsedBySeries ));
|
|
Reference< chart2::data::XLabeledDataSequence > xLabeledSeq( SchXMLTools::GetNewLabeledDataSequence(), uno::UNO_QUERY_THROW );
|
|
|
|
Reference< beans::XPropertySet > xSeriesProp( m_xSeries, uno::UNO_QUERY );
|
|
if (xSeriesProp.is())
|
|
{
|
|
if (bHideLegend)
|
|
xSeriesProp->setPropertyValue(u"ShowLegendEntry"_ustr, uno::Any(false));
|
|
|
|
if( bIsCandleStick )
|
|
{
|
|
// set default color for range-line to black (before applying styles)
|
|
xSeriesProp->setPropertyValue(u"Color"_ustr,
|
|
uno::Any( sal_Int32( 0x000000 ))); // black
|
|
}
|
|
else if ( maSeriesChartTypeName == "com.sun.star.chart2.PieChartType" )
|
|
{
|
|
//@todo: this property should be saved
|
|
xSeriesProp->setPropertyValue(u"VaryColorsByPoint"_ustr,
|
|
uno::Any( true ));
|
|
}
|
|
|
|
}
|
|
|
|
Reference<chart2::data::XDataProvider> xDataProvider(mxNewDoc->getDataProvider());
|
|
Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xDataProvider, uno::UNO_QUERY);
|
|
|
|
Reference<chart2::data::XDataSequence> xSequenceValues;
|
|
|
|
// values
|
|
if (xPivotTableDataProvider.is()) // is pivot chart
|
|
{
|
|
xSequenceValues.set(xPivotTableDataProvider->createDataSequenceOfValuesByIndex(mnSeriesIndex));
|
|
}
|
|
else
|
|
{
|
|
if (bHasRange && !m_aSeriesRange.isEmpty())
|
|
xSequenceValues = SchXMLTools::CreateDataSequence(m_aSeriesRange, mxNewDoc);
|
|
}
|
|
|
|
Reference<beans::XPropertySet> xSeqProp(xSequenceValues, uno::UNO_QUERY);
|
|
if (xSeqProp.is())
|
|
{
|
|
OUString aMainRole(u"values-y"_ustr);
|
|
if (maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType")
|
|
aMainRole = "values-size";
|
|
xSeqProp->setPropertyValue(u"Role"_ustr, uno::Any(aMainRole));
|
|
}
|
|
xLabeledSeq->setValues(xSequenceValues);
|
|
|
|
// register for setting local data if external data provider is not present
|
|
maPostponedSequences.emplace(
|
|
tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_VALUES ), xLabeledSeq );
|
|
|
|
// label
|
|
Reference<chart2::data::XDataSequence> xSequenceLabel;
|
|
|
|
if (xPivotTableDataProvider.is())
|
|
{
|
|
xSequenceLabel.set(xPivotTableDataProvider->createDataSequenceOfLabelsByIndex(mnSeriesIndex));
|
|
}
|
|
else
|
|
{
|
|
if (!aSeriesLabelRange.isEmpty())
|
|
{
|
|
xSequenceLabel.set(SchXMLTools::CreateDataSequence(aSeriesLabelRange, mxNewDoc));
|
|
}
|
|
else if (!aSeriesLabelString.isEmpty())
|
|
{
|
|
xSequenceLabel.set(SchXMLTools::CreateDataSequenceWithoutConvert(aSeriesLabelString, mxNewDoc));
|
|
}
|
|
}
|
|
|
|
//Labels should always include hidden cells
|
|
Reference<beans::XPropertySet> xSeqLabelProp(xSequenceLabel, uno::UNO_QUERY);
|
|
if (xSeqLabelProp.is() && xSeqLabelProp->getPropertySetInfo()->hasPropertyByName(u"IncludeHiddenCells"_ustr))
|
|
{
|
|
xSeqLabelProp->setPropertyValue( u"IncludeHiddenCells"_ustr, uno::Any(true));
|
|
}
|
|
|
|
xLabeledSeq->setLabel(xSequenceLabel);
|
|
|
|
// Note: Even if we have no label, we have to register the label
|
|
// for creation, because internal data always has labels. If
|
|
// they don't exist in the original, auto-generated labels are
|
|
// used for the internal data.
|
|
maPostponedSequences.emplace(
|
|
tSchXMLIndexWithPart( m_rGlobalSeriesImportInfo.nCurrentDataIndex, SCH_XML_PART_LABEL ), xLabeledSeq );
|
|
|
|
Sequence< Reference< chart2::data::XLabeledDataSequence > > aSeq( &xLabeledSeq, 1 );
|
|
Reference< chart2::data::XDataSink > xSink( m_xSeries, uno::UNO_QUERY_THROW );
|
|
xSink->setData( aSeq );
|
|
}
|
|
catch( const uno::Exception &)
|
|
{
|
|
DBG_UNHANDLED_EXCEPTION("xmloff.chart");
|
|
}
|
|
|
|
//init mbSymbolSizeIsMissingInFile:
|
|
try
|
|
{
|
|
if( !msAutoStyleName.isEmpty() )
|
|
{
|
|
const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
|
|
if( pStylesCtxt )
|
|
{
|
|
const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
|
|
SchXMLImportHelper::GetChartFamilyID(), msAutoStyleName );
|
|
|
|
const XMLPropStyleContext* pPropStyleContext = dynamic_cast< const XMLPropStyleContext * >( pStyle );
|
|
|
|
uno::Any aASymbolSize( SchXMLTools::getPropertyFromContext( u"SymbolSize"
|
|
, pPropStyleContext, pStylesCtxt ) );
|
|
mbSymbolSizeIsMissingInFile = !aASymbolSize.hasValue();
|
|
}
|
|
}
|
|
}
|
|
catch( const uno::Exception & )
|
|
{
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
|
|
struct DomainInfo
|
|
{
|
|
DomainInfo( OUString _aRole, OUString _aRange, sal_Int32 nIndex )
|
|
: aRole(std::move(_aRole)), aRange(std::move(_aRange)), nIndexForLocalData(nIndex)
|
|
{}
|
|
|
|
OUString aRole;
|
|
OUString aRange;
|
|
sal_Int32 nIndexForLocalData;
|
|
};
|
|
|
|
}
|
|
|
|
void SchXMLSeries2Context::endFastElement(sal_Int32 )
|
|
{
|
|
// special handling for different chart types. This is necessary as the
|
|
// roles are not yet saved in the file format
|
|
sal_Int32 nDomainCount = maDomainAddresses.size();
|
|
bool bIsScatterChart = maSeriesChartTypeName == "com.sun.star.chart2.ScatterChartType";
|
|
bool bIsBubbleChart = maSeriesChartTypeName == "com.sun.star.chart2.BubbleChartType";
|
|
bool bDeleteSeries = false;
|
|
std::vector< DomainInfo > aDomainInfos;
|
|
|
|
//different handling for different chart types necessary
|
|
if( bIsScatterChart || ( nDomainCount==1 && !bIsBubbleChart ) )
|
|
{
|
|
DomainInfo aDomainInfo( u"values-x"_ustr, m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ;
|
|
bool bCreateXValues = true;
|
|
if( !maDomainAddresses.empty() )
|
|
{
|
|
if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
|
|
{
|
|
m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front();
|
|
m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
|
|
}
|
|
aDomainInfo.aRange = maDomainAddresses.front();
|
|
aDomainInfo.nIndexForLocalData = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
|
|
m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
|
|
}
|
|
else if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() && !m_bHasDomainContext && mnSeriesIndex==0 )
|
|
{
|
|
if( SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( GetImport().GetModel() ) ) //wrong old chart files:
|
|
{
|
|
//for xy charts the first series needs to have a domain
|
|
//if this by error iss not the case the first series is taken s x values
|
|
//needed for wrong files created while having an addin (e.g. BoxPlot)
|
|
m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = m_aSeriesRange;
|
|
m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
|
|
bDeleteSeries = true;
|
|
bCreateXValues = false;//they will be created for the next series
|
|
}
|
|
}
|
|
if( bCreateXValues )
|
|
aDomainInfos.push_back( aDomainInfo );
|
|
}
|
|
else if( bIsBubbleChart )
|
|
{
|
|
if( nDomainCount>1 )
|
|
{
|
|
DomainInfo aDomainInfo( u"values-x"_ustr, maDomainAddresses[1], m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ;
|
|
if( m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() )
|
|
{
|
|
//for bubble chart the second domain contains the x values which should become an index smaller than y values for own data table
|
|
//->so second first
|
|
m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress = maDomainAddresses[1];
|
|
m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
|
|
}
|
|
aDomainInfos.push_back( aDomainInfo );
|
|
m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
|
|
}
|
|
else if( !m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress.isEmpty() )
|
|
{
|
|
DomainInfo aDomainInfo( u"values-x"_ustr, m_rGlobalSeriesImportInfo.aFirstSecondDomainAddress, m_rGlobalSeriesImportInfo.nFirstSecondDomainIndex ) ;
|
|
aDomainInfos.push_back( aDomainInfo );
|
|
}
|
|
if( nDomainCount>0)
|
|
{
|
|
DomainInfo aDomainInfo( u"values-y"_ustr, maDomainAddresses.front(), m_rGlobalSeriesImportInfo.nCurrentDataIndex ) ;
|
|
if( m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
|
|
{
|
|
m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress = maDomainAddresses.front();
|
|
m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex = m_rGlobalSeriesImportInfo.nCurrentDataIndex;
|
|
}
|
|
aDomainInfos.push_back( aDomainInfo );
|
|
m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
|
|
}
|
|
else if( !m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress.isEmpty() )
|
|
{
|
|
DomainInfo aDomainInfo( u"values-y"_ustr, m_rGlobalSeriesImportInfo.aFirstFirstDomainAddress, m_rGlobalSeriesImportInfo.nFirstFirstDomainIndex ) ;
|
|
aDomainInfos.push_back( aDomainInfo );
|
|
}
|
|
}
|
|
|
|
if( bDeleteSeries )
|
|
{
|
|
//delete created series
|
|
SchXMLImportHelper::DeleteDataSeries(
|
|
m_xSeries, Reference< chart2::XChartDocument >( GetImport().GetModel(), uno::UNO_QUERY ) );
|
|
}
|
|
else
|
|
{
|
|
//add style
|
|
if( !msAutoStyleName.isEmpty() || mnAttachedAxis != 1 )
|
|
{
|
|
DataRowPointStyle aStyle(
|
|
DataRowPointStyle::DATA_SERIES,
|
|
m_xSeries,
|
|
-1, 1,
|
|
msAutoStyleName, mnAttachedAxis );
|
|
aStyle.mbSymbolSizeForSeriesIsMissingInFile=mbSymbolSizeIsMissingInFile;
|
|
mrStyleVector.push_back( aStyle );
|
|
}
|
|
// And styles for a data-label child element too. In contrast to data-labels as child of data points,
|
|
// an information about absolute position is useless here. We need only style information.
|
|
if (!mDataLabel.msStyleName.isEmpty())
|
|
{
|
|
mDataLabel.msStyleNameOfParent = msAutoStyleName;
|
|
mDataLabel.m_xSeries = m_xSeries;
|
|
mDataLabel.mnAttachedAxis = mnAttachedAxis; // not needed, but be consistent with its parent
|
|
mrStyleVector.push_back(mDataLabel);
|
|
}
|
|
}
|
|
|
|
for( std::vector< DomainInfo >::reverse_iterator aIt( aDomainInfos.rbegin() ); aIt!= aDomainInfos.rend(); ++aIt )
|
|
{
|
|
DomainInfo aDomainInfo( *aIt );
|
|
Reference< chart2::data::XLabeledDataSequence2 > xLabeledSeq =
|
|
lcl_createAndAddSequenceToSeries( aDomainInfo.aRole, aDomainInfo.aRange, mxNewDoc, m_xSeries );
|
|
if( xLabeledSeq.is() )
|
|
{
|
|
// register for setting local data if external data provider is not present
|
|
mrLSequencesPerIndex.emplace(
|
|
tSchXMLIndexWithPart( aDomainInfo.nIndexForLocalData, SCH_XML_PART_VALUES ),
|
|
Reference< chart2::data::XLabeledDataSequence >(xLabeledSeq, uno::UNO_QUERY_THROW) );
|
|
}
|
|
}
|
|
|
|
if( !bDeleteSeries )
|
|
{
|
|
for (auto const& postponedSequence : maPostponedSequences)
|
|
{
|
|
sal_Int32 nNewIndex = postponedSequence.first.first + nDomainCount;
|
|
mrLSequencesPerIndex.emplace( tSchXMLIndexWithPart( nNewIndex, postponedSequence.first.second ), postponedSequence.second );
|
|
}
|
|
m_rGlobalSeriesImportInfo.nCurrentDataIndex++;
|
|
}
|
|
maPostponedSequences.clear();
|
|
}
|
|
|
|
css::uno::Reference< css::xml::sax::XFastContextHandler > SchXMLSeries2Context::createFastChildContext(
|
|
sal_Int32 nElement,
|
|
const css::uno::Reference< css::xml::sax::XFastAttributeList >& )
|
|
{
|
|
SvXMLImportContext* pContext = nullptr;
|
|
|
|
switch(nElement)
|
|
{
|
|
case XML_ELEMENT(CHART, XML_DOMAIN):
|
|
if( m_xSeries.is())
|
|
{
|
|
m_bHasDomainContext = true;
|
|
pContext = new SchXMLDomain2Context(
|
|
GetImport(), maDomainAddresses );
|
|
}
|
|
break;
|
|
|
|
case XML_ELEMENT(CHART, XML_MEAN_VALUE):
|
|
pContext = new SchXMLStatisticsObjectContext(
|
|
mrImportHelper, GetImport(),
|
|
msAutoStyleName,
|
|
mrStyleVector, m_xSeries,
|
|
SchXMLStatisticsObjectContext::CONTEXT_TYPE_MEAN_VALUE_LINE,
|
|
mrLSequencesPerIndex );
|
|
break;
|
|
case XML_ELEMENT(CHART, XML_REGRESSION_CURVE):
|
|
pContext = new SchXMLRegressionCurveObjectContext(
|
|
mrImportHelper, GetImport(),
|
|
mrRegressionStyleVector,
|
|
m_xSeries, maChartSize );
|
|
break;
|
|
case XML_ELEMENT(CHART, XML_ERROR_INDICATOR):
|
|
pContext = new SchXMLStatisticsObjectContext(
|
|
mrImportHelper, GetImport(),
|
|
msAutoStyleName,
|
|
mrStyleVector, m_xSeries,
|
|
SchXMLStatisticsObjectContext::CONTEXT_TYPE_ERROR_INDICATOR,
|
|
mrLSequencesPerIndex );
|
|
break;
|
|
|
|
case XML_ELEMENT(CHART, XML_DATA_POINT):
|
|
pContext = new SchXMLDataPointContext( GetImport(),
|
|
mrStyleVector, m_xSeries, mnDataPointIndex, mbSymbolSizeIsMissingInFile );
|
|
break;
|
|
case XML_ELEMENT(CHART, XML_DATA_LABEL):
|
|
// CustomLabels are useless for a data label element as child of a series, because it serves as default
|
|
// for all data labels. But the ctor expects it, so use that of the mDataLabel struct as ersatz.
|
|
pContext = new SchXMLDataLabelContext(GetImport(), mDataLabel.mCustomLabels,
|
|
mDataLabel);
|
|
break;
|
|
|
|
case XML_ELEMENT(LO_EXT, XML_PROPERTY_MAPPING):
|
|
pContext = new SchXMLPropertyMappingContext(
|
|
GetImport(),
|
|
mrLSequencesPerIndex, m_xSeries );
|
|
break;
|
|
default:
|
|
XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement);
|
|
}
|
|
|
|
return pContext;
|
|
}
|
|
|
|
//static
|
|
void SchXMLSeries2Context::initSeriesPropertySets( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
|
|
, const uno::Reference< frame::XModel >& xChartModel )
|
|
{
|
|
// iterate over series first and remind propertysets in map
|
|
// new api <-> old api wrapper
|
|
::std::map< Reference< chart2::XDataSeries >, Reference< beans::XPropertySet > > aSeriesMap;
|
|
for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
|
|
{
|
|
if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
|
|
continue;
|
|
|
|
if( !seriesStyle.m_xOldAPISeries.is() )
|
|
seriesStyle.m_xOldAPISeries = SchXMLSeriesHelper::createOldAPISeriesPropertySet( seriesStyle.m_xSeries, xChartModel );
|
|
|
|
aSeriesMap[seriesStyle.m_xSeries] = seriesStyle.m_xOldAPISeries;
|
|
|
|
}
|
|
|
|
//initialize m_xOldAPISeries for all other styles also
|
|
for (auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
|
|
{
|
|
if( seriesStyle.meType == DataRowPointStyle::DATA_SERIES )
|
|
continue;
|
|
seriesStyle.m_xOldAPISeries = aSeriesMap[seriesStyle.m_xSeries];
|
|
}
|
|
}
|
|
|
|
//static
|
|
void SchXMLSeries2Context::setDefaultsToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles )
|
|
{
|
|
// iterate over series
|
|
// call initSeriesPropertySets first
|
|
|
|
for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
|
|
{
|
|
if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
|
|
continue;
|
|
|
|
try
|
|
{
|
|
uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries );
|
|
if( !xSeries.is() )
|
|
continue;
|
|
|
|
if( rSeriesDefaultsAndStyles.maSymbolTypeDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"SymbolType"_ustr,rSeriesDefaultsAndStyles.maSymbolTypeDefault);
|
|
if( rSeriesDefaultsAndStyles.maDataCaptionDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"DataCaption"_ustr,rSeriesDefaultsAndStyles.maDataCaptionDefault);
|
|
|
|
if( rSeriesDefaultsAndStyles.maErrorIndicatorDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"ErrorIndicator"_ustr,rSeriesDefaultsAndStyles.maErrorIndicatorDefault);
|
|
if( rSeriesDefaultsAndStyles.maErrorCategoryDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"ErrorCategory"_ustr,rSeriesDefaultsAndStyles.maErrorCategoryDefault);
|
|
if( rSeriesDefaultsAndStyles.maConstantErrorLowDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"ConstantErrorLow"_ustr,rSeriesDefaultsAndStyles.maConstantErrorLowDefault);
|
|
if( rSeriesDefaultsAndStyles.maConstantErrorHighDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"ConstantErrorHigh"_ustr,rSeriesDefaultsAndStyles.maConstantErrorHighDefault);
|
|
if( rSeriesDefaultsAndStyles.maPercentageErrorDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"PercentageError"_ustr,rSeriesDefaultsAndStyles.maPercentageErrorDefault);
|
|
if( rSeriesDefaultsAndStyles.maErrorMarginDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"ErrorMargin"_ustr,rSeriesDefaultsAndStyles.maErrorMarginDefault);
|
|
|
|
if( rSeriesDefaultsAndStyles.maMeanValueDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"MeanValue"_ustr,rSeriesDefaultsAndStyles.maMeanValueDefault);
|
|
if( rSeriesDefaultsAndStyles.maRegressionCurvesDefault.hasValue() )
|
|
xSeries->setPropertyValue(u"RegressionCurves"_ustr,rSeriesDefaultsAndStyles.maRegressionCurvesDefault);
|
|
}
|
|
catch( uno::Exception & )
|
|
{
|
|
//end of series reached
|
|
}
|
|
}
|
|
}
|
|
|
|
// ODF has the line and fill properties in a <style:style> element, which is referenced by the
|
|
// <chart:data-label> element. But LibreOffice has them as special label properties of the series
|
|
// or point respectively. The following array maps the API name of the ODF property to the name of
|
|
// the internal property. Those are of kind "LabelFoo".
|
|
// The array is used in methods setStylesToSeries and setStylesToDataPoints.
|
|
const std::pair<OUString, OUString> aApiToLabelFooPairs[]
|
|
= { { "LineStyle", "LabelBorderStyle" },
|
|
{ "LineWidth", "LabelBorderWidth" },
|
|
{ "LineColor", "LabelBorderColor" },
|
|
// The name "LabelBorderDash" is defined, but the associated API name "LineDash" belongs to
|
|
// the <draw:stroke-dash> element and is not used directly as line property.
|
|
//{"LineDash", "LabelBorderDash"},
|
|
{ "LineDashName", "LabelBorderDashName" },
|
|
{ "LineTransparence", "LabelBorderTransparency" },
|
|
{ "FillStyle", "LabelFillStyle" },
|
|
{ "FillBackground", "LabelFillBackground" },
|
|
{ "FillHatchName", "LabelFillHatchName" },
|
|
{ "FillColor", "LabelFillColor" } };
|
|
|
|
|
|
//static
|
|
void SchXMLSeries2Context::setStylesToSeries( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
|
|
, const SvXMLStylesContext* pStylesCtxt
|
|
, const SvXMLStyleContext*& rpStyle
|
|
, OUString& rCurrStyleName
|
|
, const SchXMLImportHelper& rImportHelper
|
|
, const SvXMLImport& rImport
|
|
, bool bIsStockChart
|
|
, tSchXMLLSequencesPerIndex & rInOutLSequencesPerIndex )
|
|
{
|
|
// iterate over series
|
|
for (const auto & seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
|
|
{
|
|
if (seriesStyle.meType != DataRowPointStyle::DATA_SERIES)
|
|
continue;
|
|
try
|
|
{
|
|
uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
|
|
if( !xSeriesProp.is() )
|
|
continue;
|
|
|
|
if( seriesStyle.mnAttachedAxis != 1 )
|
|
{
|
|
xSeriesProp->setPropertyValue(u"Axis"_ustr
|
|
, uno::Any(chart::ChartAxisAssign::SECONDARY_Y) );
|
|
}
|
|
|
|
if( seriesStyle.msStyleName.isEmpty())
|
|
continue;
|
|
|
|
if( rCurrStyleName != seriesStyle.msStyleName )
|
|
{
|
|
rCurrStyleName = seriesStyle.msStyleName;
|
|
rpStyle = pStylesCtxt->FindStyleChildContext(
|
|
SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
|
|
}
|
|
|
|
//set style to series
|
|
// note: SvXMLStyleContext::FillPropertySet is not const
|
|
XMLPropStyleContext * pPropStyleContext =
|
|
const_cast< XMLPropStyleContext * >(
|
|
dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
|
|
|
|
if (!pPropStyleContext)
|
|
continue;
|
|
|
|
// error bar style must be set before the other error
|
|
// bar properties (which may be alphabetically before
|
|
// this property)
|
|
bool bHasErrorBarRangesFromData = false;
|
|
{
|
|
static constexpr OUString aErrorBarStylePropName( u"ErrorBarStyle"_ustr);
|
|
uno::Any aErrorBarStyle(
|
|
SchXMLTools::getPropertyFromContext( aErrorBarStylePropName, pPropStyleContext, pStylesCtxt ));
|
|
if( aErrorBarStyle.hasValue())
|
|
{
|
|
xSeriesProp->setPropertyValue( aErrorBarStylePropName, aErrorBarStyle );
|
|
sal_Int32 eEBStyle = chart::ErrorBarStyle::NONE;
|
|
bHasErrorBarRangesFromData =
|
|
( ( aErrorBarStyle >>= eEBStyle ) &&
|
|
eEBStyle == chart::ErrorBarStyle::FROM_DATA );
|
|
}
|
|
}
|
|
|
|
//don't set the style to the min max line series of a stock chart
|
|
//otherwise the min max line properties gets overwritten and the series becomes invisible typically
|
|
if (bIsStockChart)
|
|
{
|
|
if (SchXMLSeriesHelper::isCandleStickSeries(
|
|
seriesStyle.m_xSeries,
|
|
rImportHelper.GetChartDocument()))
|
|
continue;
|
|
}
|
|
|
|
// Has the series a data-label child element?
|
|
auto pItLabel
|
|
= std::find_if(rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(),
|
|
rSeriesDefaultsAndStyles.maSeriesStyleVector.end(),
|
|
[&seriesStyle](const DataRowPointStyle& rStyle) {
|
|
return rStyle.meType == DataRowPointStyle::DATA_LABEL_SERIES
|
|
&& rStyle.msStyleNameOfParent == seriesStyle.msStyleName;
|
|
});
|
|
if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end())
|
|
{
|
|
// Bring the information from the data-label to the series
|
|
const SvXMLStyleContext* pLabelStyleContext(pStylesCtxt->FindStyleChildContext(
|
|
SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName));
|
|
// note: SvXMLStyleContext::FillPropertySet is not const
|
|
XMLPropStyleContext* pLabelPropStyleContext = const_cast<XMLPropStyleContext*>(
|
|
dynamic_cast<const XMLPropStyleContext*>(pLabelStyleContext));
|
|
if (pLabelPropStyleContext)
|
|
{
|
|
// Test each to be mapped property whether the data-label has a value for it.
|
|
// If found, set it at series.
|
|
uno::Reference<beans::XPropertySetInfo> xSeriesPropInfo(
|
|
xSeriesProp->getPropertySetInfo());
|
|
for (const auto& rPropPair : aApiToLabelFooPairs)
|
|
{
|
|
uno::Any aPropValue(SchXMLTools::getPropertyFromContext(
|
|
rPropPair.first, pLabelPropStyleContext, pStylesCtxt));
|
|
if (aPropValue.hasValue()
|
|
&& xSeriesPropInfo->hasPropertyByName(rPropPair.second))
|
|
xSeriesProp->setPropertyValue(rPropPair.second, aPropValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
pPropStyleContext->FillPropertySet( xSeriesProp );
|
|
if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile )
|
|
lcl_setSymbolSizeIfNeeded( xSeriesProp, rImport );
|
|
if( bHasErrorBarRangesFromData )
|
|
lcl_insertErrorBarLSequencesToMap( rInOutLSequencesPerIndex, xSeriesProp );
|
|
|
|
}
|
|
catch( const uno::Exception & )
|
|
{
|
|
TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
|
|
}
|
|
}
|
|
}
|
|
|
|
// static
|
|
void SchXMLSeries2Context::setStylesToRegressionCurves(
|
|
SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles,
|
|
const SvXMLStylesContext* pStylesCtxt,
|
|
const SvXMLStyleContext*& rpStyle,
|
|
OUString const & rCurrentStyleName )
|
|
{
|
|
// iterate over regression etc
|
|
for (auto const& regressionStyle : rSeriesDefaultsAndStyles.maRegressionStyleVector)
|
|
{
|
|
try
|
|
{
|
|
OUString aServiceName;
|
|
XMLPropStyleContext* pPropStyleContext = nullptr;
|
|
|
|
if (!rCurrentStyleName.isEmpty())
|
|
{
|
|
XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, rCurrentStyleName);
|
|
if( pCurrent )
|
|
{
|
|
pPropStyleContext = pCurrent;
|
|
uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt);
|
|
if ( aAny.hasValue() )
|
|
{
|
|
aAny >>= aServiceName;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!regressionStyle.msStyleName.isEmpty())
|
|
{
|
|
XMLPropStyleContext* pCurrent = lcl_GetStylePropContext(pStylesCtxt, rpStyle, regressionStyle.msStyleName);
|
|
if( pCurrent )
|
|
{
|
|
pPropStyleContext = pCurrent;
|
|
uno::Any aAny = SchXMLTools::getPropertyFromContext(u"RegressionType", pPropStyleContext, pStylesCtxt);
|
|
if ( aAny.hasValue() )
|
|
{
|
|
aAny >>= aServiceName;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !aServiceName.isEmpty() )
|
|
{
|
|
Reference< lang::XMultiServiceFactory > xMSF = comphelper::getProcessServiceFactory();
|
|
Reference< chart2::XRegressionCurve > xRegCurve( xMSF->createInstance( aServiceName ), uno::UNO_QUERY_THROW );
|
|
Reference< chart2::XRegressionCurveContainer > xRegCurveCont( regressionStyle.m_xSeries, uno::UNO_QUERY_THROW );
|
|
|
|
Reference< beans::XPropertySet > xCurveProperties( xRegCurve, uno::UNO_QUERY );
|
|
if( pPropStyleContext != nullptr)
|
|
pPropStyleContext->FillPropertySet( xCurveProperties );
|
|
|
|
xRegCurve->setEquationProperties( regressionStyle.m_xEquationProperties );
|
|
|
|
xRegCurveCont->addRegressionCurve( xRegCurve );
|
|
}
|
|
}
|
|
catch( const uno::Exception& )
|
|
{
|
|
TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// static
|
|
void SchXMLSeries2Context::setStylesToStatisticsObjects( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
|
|
, const SvXMLStylesContext* pStylesCtxt
|
|
, const SvXMLStyleContext*& rpStyle
|
|
, OUString& rCurrStyleName )
|
|
{
|
|
// iterate over regression etc
|
|
for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
|
|
{
|
|
if( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR ||
|
|
seriesStyle.meType == DataRowPointStyle::MEAN_VALUE )
|
|
{
|
|
if ( seriesStyle.meType == DataRowPointStyle::ERROR_INDICATOR )
|
|
{
|
|
uno::Reference< beans::XPropertySet > xNewSeriesProp(seriesStyle.m_xSeries,uno::UNO_QUERY);
|
|
|
|
if (seriesStyle.m_xErrorXProperties.is())
|
|
xNewSeriesProp->setPropertyValue(u"ErrorBarX"_ustr,uno::Any(seriesStyle.m_xErrorXProperties));
|
|
|
|
if (seriesStyle.m_xErrorYProperties.is())
|
|
xNewSeriesProp->setPropertyValue(u"ErrorBarY"_ustr,uno::Any(seriesStyle.m_xErrorYProperties));
|
|
}
|
|
|
|
try
|
|
{
|
|
uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
|
|
if( !xSeriesProp.is() )
|
|
continue;
|
|
|
|
if( !seriesStyle.msStyleName.isEmpty())
|
|
{
|
|
if( rCurrStyleName != seriesStyle.msStyleName )
|
|
{
|
|
rCurrStyleName = seriesStyle.msStyleName;
|
|
rpStyle = pStylesCtxt->FindStyleChildContext(
|
|
SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
|
|
}
|
|
|
|
// note: SvXMLStyleContext::FillPropertySet is not const
|
|
XMLPropStyleContext * pPropStyleContext =
|
|
const_cast< XMLPropStyleContext * >(
|
|
dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
|
|
if( pPropStyleContext )
|
|
{
|
|
Reference< beans::XPropertySet > xStatPropSet;
|
|
switch( seriesStyle.meType )
|
|
{
|
|
case DataRowPointStyle::MEAN_VALUE:
|
|
xSeriesProp->getPropertyValue(u"DataMeanValueProperties"_ustr) >>= xStatPropSet;
|
|
break;
|
|
case DataRowPointStyle::ERROR_INDICATOR:
|
|
xSeriesProp->getPropertyValue(u"DataErrorProperties"_ustr) >>= xStatPropSet;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if( xStatPropSet.is())
|
|
pPropStyleContext->FillPropertySet( xStatPropSet );
|
|
}
|
|
}
|
|
}
|
|
catch( const uno::Exception & )
|
|
{
|
|
TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to series" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//static
|
|
void SchXMLSeries2Context::setStylesToDataPoints( SeriesDefaultsAndStyles& rSeriesDefaultsAndStyles
|
|
, const SvXMLStylesContext* pStylesCtxt
|
|
, const SvXMLStyleContext*& rpStyle
|
|
, OUString& rCurrStyleName
|
|
, const SchXMLImportHelper& rImportHelper
|
|
, const SvXMLImport& rImport
|
|
, bool bIsStockChart, bool bIsDonutChart, bool bSwitchOffLinesForScatter )
|
|
{
|
|
for (auto const& seriesStyle : rSeriesDefaultsAndStyles.maSeriesStyleVector)
|
|
{
|
|
if( seriesStyle.meType != DataRowPointStyle::DATA_POINT )
|
|
continue;
|
|
|
|
if( seriesStyle.m_nPointIndex == -1 )
|
|
continue;
|
|
|
|
uno::Reference< beans::XPropertySet > xSeriesProp( seriesStyle.m_xOldAPISeries );
|
|
if(!xSeriesProp.is())
|
|
continue;
|
|
|
|
//ignore datapoint properties for stock charts
|
|
//... todo ...
|
|
if( bIsStockChart )
|
|
{
|
|
if( SchXMLSeriesHelper::isCandleStickSeries( seriesStyle.m_xSeries, rImportHelper.GetChartDocument() ) )
|
|
continue;
|
|
}
|
|
|
|
// data point style
|
|
for( sal_Int32 i = 0; i < seriesStyle.m_nPointRepeat; i++ )
|
|
{
|
|
try
|
|
{
|
|
uno::Reference< beans::XPropertySet > xPointProp(
|
|
SchXMLSeriesHelper::createOldAPIDataPointPropertySet( seriesStyle.m_xSeries, seriesStyle.m_nPointIndex + i
|
|
, rImportHelper.GetChartDocument() ) );
|
|
|
|
if( !xPointProp.is() )
|
|
continue;
|
|
|
|
if( bIsDonutChart )
|
|
{
|
|
//set special series styles for donut charts first
|
|
if( rCurrStyleName != seriesStyle.msSeriesStyleNameForDonuts )
|
|
{
|
|
rCurrStyleName = seriesStyle.msSeriesStyleNameForDonuts;
|
|
rpStyle = pStylesCtxt->FindStyleChildContext(
|
|
SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
|
|
}
|
|
|
|
// note: SvXMLStyleContext::FillPropertySet is not const
|
|
XMLPropStyleContext * pPropStyleContext =
|
|
const_cast< XMLPropStyleContext * >(
|
|
dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
|
|
if( pPropStyleContext )
|
|
pPropStyleContext->FillPropertySet( xPointProp );
|
|
}
|
|
|
|
try
|
|
{
|
|
//need to set this explicitly here for old files as the new api does not support this property fully anymore
|
|
if( bSwitchOffLinesForScatter )
|
|
xPointProp->setPropertyValue(u"Lines"_ustr,uno::Any(false));
|
|
}
|
|
catch( const uno::Exception & )
|
|
{
|
|
}
|
|
|
|
if( rCurrStyleName != seriesStyle.msStyleName )
|
|
{
|
|
rCurrStyleName = seriesStyle.msStyleName;
|
|
rpStyle = pStylesCtxt->FindStyleChildContext(
|
|
SchXMLImportHelper::GetChartFamilyID(), rCurrStyleName );
|
|
}
|
|
|
|
// note: SvXMLStyleContext::FillPropertySet is not const
|
|
XMLPropStyleContext * pPropStyleContext =
|
|
const_cast< XMLPropStyleContext * >(
|
|
dynamic_cast< const XMLPropStyleContext * >( rpStyle ));
|
|
if (pPropStyleContext)
|
|
{
|
|
// Has the point a data-label child element?
|
|
auto pItLabel = std::find_if(
|
|
rSeriesDefaultsAndStyles.maSeriesStyleVector.begin(),
|
|
rSeriesDefaultsAndStyles.maSeriesStyleVector.end(),
|
|
[&seriesStyle](const DataRowPointStyle& rStyle) {
|
|
return rStyle.meType == DataRowPointStyle::DATA_LABEL_POINT
|
|
&& rStyle.msStyleNameOfParent == seriesStyle.msStyleName;
|
|
});
|
|
if (pItLabel != rSeriesDefaultsAndStyles.maSeriesStyleVector.end())
|
|
{
|
|
// Bring the information from the data-label to the point
|
|
const SvXMLStyleContext* pLabelStyleContext(
|
|
pStylesCtxt->FindStyleChildContext(
|
|
SchXMLImportHelper::GetChartFamilyID(), (*pItLabel).msStyleName));
|
|
// note: SvXMLStyleContext::FillPropertySet is not const
|
|
XMLPropStyleContext* pLabelPropStyleContext
|
|
= const_cast<XMLPropStyleContext*>(
|
|
dynamic_cast<const XMLPropStyleContext*>(pLabelStyleContext));
|
|
if (pLabelPropStyleContext)
|
|
{
|
|
// Test each to be mapped property whether the data-label has a value for it.
|
|
// If found, set it at the point.
|
|
uno::Reference<beans::XPropertySetInfo> xPointPropInfo(
|
|
xPointProp->getPropertySetInfo());
|
|
for (const auto& rPropPair : aApiToLabelFooPairs)
|
|
{
|
|
uno::Any aPropValue(SchXMLTools::getPropertyFromContext(
|
|
rPropPair.first, pLabelPropStyleContext, pStylesCtxt));
|
|
if (aPropValue.hasValue()
|
|
&& xPointPropInfo->hasPropertyByName(rPropPair.second))
|
|
xPointProp->setPropertyValue(rPropPair.second, aPropValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
pPropStyleContext->FillPropertySet( xPointProp );
|
|
if( seriesStyle.mbSymbolSizeForSeriesIsMissingInFile )
|
|
lcl_resetSymbolSizeForPointsIfNecessary( xPointProp, rImport, pPropStyleContext, pStylesCtxt );
|
|
if( !pPropStyleContext->isEmptyDataStyleName() )
|
|
lcl_setLinkNumberFormatToSourceIfNeeded( xPointProp, pPropStyleContext, pStylesCtxt );
|
|
}
|
|
|
|
// Custom labels might be passed as property
|
|
if(const size_t nLabelCount = seriesStyle.mCustomLabels.mLabels.size(); nLabelCount > 0)
|
|
{
|
|
auto& rCustomLabels = seriesStyle.mCustomLabels;
|
|
|
|
Sequence< Reference<chart2::XDataPointCustomLabelField>> xLabels(nLabelCount);
|
|
auto pxLabels = xLabels.getArray();
|
|
const Reference< uno::XComponentContext >& xContext( comphelper::getProcessComponentContext() );
|
|
for( size_t j = 0; j < nLabelCount; ++j )
|
|
{
|
|
Reference< chart2::XDataPointCustomLabelField > xCustomLabel = chart2::DataPointCustomLabelField::create(xContext);
|
|
pxLabels[j] = xCustomLabel;
|
|
xCustomLabel->setString(rCustomLabels.mLabels[j]);
|
|
if ( j == 0 && rCustomLabels.mbDataLabelsRange)
|
|
{
|
|
xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_CELLRANGE);
|
|
xCustomLabel->setGuid(rCustomLabels.msLabelGuid);
|
|
xCustomLabel->setCellRange(rCustomLabels.msLabelsCellRange);
|
|
xCustomLabel->setDataLabelsRange(true);
|
|
}
|
|
else
|
|
{
|
|
xCustomLabel->setFieldType(chart2::DataPointCustomLabelFieldType::DataPointCustomLabelFieldType_TEXT);
|
|
}
|
|
|
|
// Restore character properties on the text span manually, till
|
|
// SchXMLExportHelper_Impl::exportCustomLabel() does not write the style.
|
|
uno::Reference<beans::XPropertySetInfo> xPointPropInfo
|
|
= xPointProp->getPropertySetInfo();
|
|
if (xPointPropInfo.is())
|
|
{
|
|
uno::Sequence<beans::Property> aProperties = xPointPropInfo->getProperties();
|
|
for (const auto& rProperty : aProperties)
|
|
{
|
|
if (!rProperty.Name.startsWith("Char")
|
|
|| rProperty.Name.startsWith("Chart"))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
xCustomLabel->setPropertyValue(
|
|
rProperty.Name, xPointProp->getPropertyValue(rProperty.Name));
|
|
}
|
|
}
|
|
}
|
|
|
|
xPointProp->setPropertyValue(u"CustomLabelFields"_ustr, uno::Any(xLabels));
|
|
xPointProp->setPropertyValue(u"DataCaption"_ustr, uno::Any(chart::ChartDataCaption::CUSTOM));
|
|
}
|
|
|
|
if( seriesStyle.mCustomLabelPos[0] != 0.0 || seriesStyle.mCustomLabelPos[1] != 0.0 )
|
|
{
|
|
chart2::RelativePosition aCustomlabelPosition;
|
|
aCustomlabelPosition.Primary = seriesStyle.mCustomLabelPos[0];
|
|
aCustomlabelPosition.Secondary = seriesStyle.mCustomLabelPos[1];
|
|
xPointProp->setPropertyValue(u"CustomLabelPosition"_ustr, uno::Any(aCustomlabelPosition));
|
|
}
|
|
}
|
|
catch( const uno::Exception & )
|
|
{
|
|
TOOLS_INFO_EXCEPTION("xmloff.chart", "Exception caught during setting styles to data points" );
|
|
}
|
|
}
|
|
} // styles iterator
|
|
}
|
|
|
|
//static
|
|
void SchXMLSeries2Context::switchSeriesLinesOff( ::std::vector< DataRowPointStyle >& rSeriesStyleVector )
|
|
{
|
|
// iterate over series
|
|
for (auto const& seriesStyle : rSeriesStyleVector)
|
|
{
|
|
if( seriesStyle.meType != DataRowPointStyle::DATA_SERIES )
|
|
continue;
|
|
|
|
try
|
|
{
|
|
uno::Reference< beans::XPropertySet > xSeries( seriesStyle.m_xOldAPISeries );
|
|
if( !xSeries.is() )
|
|
continue;
|
|
|
|
xSeries->setPropertyValue(u"Lines"_ustr,uno::Any(false));
|
|
}
|
|
catch( uno::Exception & )
|
|
{
|
|
//end of series reached
|
|
}
|
|
}
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|