Files
libreoffice/xmloff/source/chart/SchXMLChartContext.cxx
Stephan Bergmann 206b5b2661 New loplugin:external
...warning about (for now only) functions and variables with external linkage
that likely don't need it.

The problems with moving entities into unnamed namespacs and breaking ADL
(as alluded to in comments in compilerplugins/clang/external.cxx) are
illustrated by the fact that while

  struct S1 { int f() { return 0; } };
  int f(S1 s) { return s.f(); }
  namespace N {
    struct S2: S1 { int f() { return 1; } };
    int f(S2 s) { return s.f(); }
  }
  int main() { return f(N::S2()); }

returns 1, both moving just the struct S2 into an nunnamed namespace,

  struct S1 { int f() { return 0; } };
  int f(S1 s) { return s.f(); }
  namespace N {
    namespace { struct S2: S1 { int f() { return 1; } }; }
    int f(S2 s) { return s.f(); }
  }
  int main() { return f(N::S2()); }

as well as moving just the function f overload into an unnamed namespace,

  struct S1 { int f() { return 0; } };
  int f(S1 s) { return s.f(); }
  namespace N {
    struct S2: S1 { int f() { return 1; } };
    namespace { int f(S2 s) { return s.f(); } }
  }
  int main() { return f(N::S2()); }

would each change the program to return 0 instead.

Change-Id: I4d09f7ac5e8f9bcd6e6bde4712608444b642265c
Reviewed-on: https://gerrit.libreoffice.org/60539
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2018-09-17 09:05:38 +02:00

1255 lines
50 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 "SchXMLChartContext.hxx"
#include <SchXMLImport.hxx>
#include "SchXMLLegendContext.hxx"
#include "SchXMLPlotAreaContext.hxx"
#include "SchXMLParagraphContext.hxx"
#include "SchXMLTableContext.hxx"
#include "SchXMLSeries2Context.hxx"
#include "SchXMLTools.hxx"
#include <osl/diagnose.h>
#include <sal/log.hxx>
#include <unotools/mediadescriptor.hxx>
#include <xmloff/xmlnmspe.hxx>
#include <xmloff/xmlement.hxx>
#include <xmloff/xmltoken.hxx>
#include <xmloff/nmspmap.hxx>
#include <xmloff/xmluconv.hxx>
#include <xmloff/xmlstyle.hxx>
#include <xmloff/prstylei.hxx>
#include <xmloff/SchXMLSeriesHelper.hxx>
#include <vector>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/chart/XChartDocument.hpp>
#include <com/sun/star/chart/XDiagram.hpp>
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#include <com/sun/star/util/XStringMapping.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/drawing/XDrawPage.hpp>
#include <com/sun/star/chart/ChartDataRowSource.hpp>
#include <com/sun/star/chart/ChartSeriesAddress.hpp>
#include <com/sun/star/awt/PosSize.hpp>
#include <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/embed/XVisualObject.hpp>
#include <com/sun/star/chart2/XChartDocument.hpp>
#include <com/sun/star/chart2/data/XDataSink.hpp>
#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
#include <com/sun/star/chart2/XChartTypeContainer.hpp>
#include <com/sun/star/chart2/XTitled.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/chart2/data/XDataReceiver.hpp>
using namespace com::sun::star;
using namespace ::xmloff::token;
using com::sun::star::uno::Reference;
using namespace ::SchXMLTools;
namespace
{
void lcl_setRoleAtLabeledSequence(
const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq,
const OUString &rRole )
{
// set role of sequence
uno::Reference< chart2::data::XDataSequence > xValues( xLSeq->getValues());
if( xValues.is())
{
uno::Reference< beans::XPropertySet > xProp( xValues, uno::UNO_QUERY );
if( xProp.is())
xProp->setPropertyValue("Role", uno::makeAny( rRole ));
}
}
void lcl_MoveDataToCandleStickSeries(
const uno::Reference< chart2::data::XDataSource > & xDataSource,
const uno::Reference< chart2::XDataSeries > & xDestination,
const OUString & rRole )
{
try
{
uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledSeq(
xDataSource->getDataSequences());
if( aLabeledSeq.getLength())
{
lcl_setRoleAtLabeledSequence( aLabeledSeq[0], rRole );
// add to data series
uno::Reference< chart2::data::XDataSource > xSource( xDestination, uno::UNO_QUERY_THROW );
// @todo: realloc only once outside this function
uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aData( xSource->getDataSequences());
aData.realloc( aData.getLength() + 1);
aData[ aData.getLength() - 1 ] = aLabeledSeq[0];
uno::Reference< chart2::data::XDataSink > xSink( xDestination, uno::UNO_QUERY_THROW );
xSink->setData( aData );
}
}
catch(const uno::Exception&)
{
SAL_WARN("xmloff.chart", "Exception caught while moving data to candlestick series" );
}
}
void lcl_setRoleAtFirstSequence(
const uno::Reference< chart2::XDataSeries > & xSeries,
const OUString & rRole )
{
uno::Reference< chart2::data::XDataSource > xSource( xSeries, uno::UNO_QUERY );
if( xSource.is())
{
uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSeq( xSource->getDataSequences());
if( aSeq.getLength())
lcl_setRoleAtLabeledSequence( aSeq[0], rRole );
}
}
void lcl_removeEmptyChartTypeGroups( const uno::Reference< chart2::XChartDocument > & xDoc )
{
if( ! xDoc.is())
return;
uno::Reference< chart2::XDiagram > xDia( xDoc->getFirstDiagram());
if( ! xDia.is())
return;
try
{
// count all charttype groups to be able to leave at least one
sal_Int32 nRemainingGroups = 0;
uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDia, uno::UNO_QUERY_THROW );
uno::Sequence< uno::Reference< chart2::XCoordinateSystem > >
aCooSysSeq( xCooSysCnt->getCoordinateSystems());
for( sal_Int32 nI = aCooSysSeq.getLength(); nI--; )
{
uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW );
nRemainingGroups += xCTCnt->getChartTypes().getLength();
}
// delete all empty groups, but leave at least group (empty or not)
for( sal_Int32 nI = aCooSysSeq.getLength(); nI-- && (nRemainingGroups > 1); )
{
uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nI], uno::UNO_QUERY_THROW );
uno::Sequence< uno::Reference< chart2::XChartType > > aCTSeq( xCTCnt->getChartTypes());
for( sal_Int32 nJ=aCTSeq.getLength(); nJ-- && (nRemainingGroups > 1); )
{
uno::Reference< chart2::XDataSeriesContainer > xDSCnt( aCTSeq[nJ], uno::UNO_QUERY_THROW );
if( xDSCnt->getDataSeries().getLength() == 0 )
{
// note: iterator stays valid as we have a local sequence
xCTCnt->removeChartType( aCTSeq[nJ] );
--nRemainingGroups;
}
}
}
}
catch(const uno::Exception& ex)
{
SAL_INFO("xmloff.chart", "Exception caught while removing empty chart types: " << ex);
}
}
uno::Sequence< sal_Int32 > lcl_getNumberSequenceFromString( const OUString& rStr, bool bAddOneToEachOldIndex )
{
const sal_Unicode aSpace( ' ' );
// count number of entries
::std::vector< sal_Int32 > aVec;
sal_Int32 nLastPos = 0;
sal_Int32 nPos = 0;
while( nPos != -1 )
{
nPos = rStr.indexOf( aSpace, nLastPos );
if( nPos > nLastPos )
{
aVec.push_back( rStr.copy( nLastPos, (nPos - nLastPos) ).toInt32() );
}
if( nPos != -1 )
nLastPos = nPos + 1;
}
// last entry
if( nLastPos != 0 &&
rStr.getLength() > nLastPos )
{
aVec.push_back( rStr.copy( nLastPos ).toInt32() );
}
const sal_Int32 nVecSize = aVec.size();
uno::Sequence< sal_Int32 > aSeq( nVecSize );
if(!bAddOneToEachOldIndex)
{
sal_Int32* pSeqArr = aSeq.getArray();
for( nPos = 0; nPos < nVecSize; ++nPos )
{
pSeqArr[ nPos ] = aVec[ nPos ];
}
}
else if( bAddOneToEachOldIndex )
{
aSeq.realloc( nVecSize+1 );
aSeq[0]=0;
sal_Int32* pSeqArr = aSeq.getArray();
for( nPos = 0; nPos < nVecSize; ++nPos )
{
pSeqArr[ nPos+1 ] = aVec[ nPos ]+1;
}
}
return aSeq;
}
} // anonymous namespace
SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper,
SvXMLImport& rImport, const OUString& rLocalName ) :
SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
mrImportHelper( rImpHelper ),
m_bHasRangeAtPlotArea( false ),
m_bHasTableElement( false ),
mbAllRangeAddressesAvailable( true ),
mbColHasLabels( false ),
mbRowHasLabels( false ),
meDataRowSource( chart::ChartDataRowSource_COLUMNS ),
mbIsStockChart( false )
{
}
SchXMLChartContext::~SchXMLChartContext()
{}
static bool lcl_hasServiceName(Reference<lang::XMultiServiceFactory> const & xFactory, OUString const & rServiceName)
{
const uno::Sequence<OUString> aServiceNames(xFactory->getAvailableServiceNames());
return std::find(aServiceNames.begin(), aServiceNames.end(), rServiceName) != aServiceNames.end();
}
static void lcl_setDataProvider(uno::Reference<chart2::XChartDocument> const & xChartDoc, OUString const & sDataPilotSource)
{
if (!xChartDoc.is())
return;
try
{
uno::Reference<container::XChild> xChild(xChartDoc, uno::UNO_QUERY);
uno::Reference<chart2::data::XDataReceiver> xDataReceiver(xChartDoc, uno::UNO_QUERY);
if (xChild.is() && xDataReceiver.is())
{
bool bHasOwnData = true;
Reference<lang::XMultiServiceFactory> xFact(xChild->getParent(), uno::UNO_QUERY);
if (xFact.is())
{
if (!xChartDoc->getDataProvider().is())
{
bool bHasDataPilotSource = !sDataPilotSource.isEmpty();
OUString aDataProviderServiceName("com.sun.star.chart2.data.DataProvider");
if (bHasDataPilotSource)
aDataProviderServiceName = "com.sun.star.chart2.data.PivotTableDataProvider";
if (lcl_hasServiceName(xFact, aDataProviderServiceName))
{
Reference<chart2::data::XDataProvider> xProvider(xFact->createInstance(aDataProviderServiceName), uno::UNO_QUERY);
if (xProvider.is())
{
if (bHasDataPilotSource)
{
Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xProvider, uno::UNO_QUERY);
xPivotTableDataProvider->setPivotTableName(sDataPilotSource);
xDataReceiver->attachDataProvider(xProvider);
bHasOwnData = !xPivotTableDataProvider->hasPivotTable();
}
else
{
xDataReceiver->attachDataProvider(xProvider);
bHasOwnData = false;
}
}
}
}
else
bHasOwnData = false;
}
// else we have no parent => we have our own data
if (bHasOwnData && ! xChartDoc->hasInternalDataProvider())
xChartDoc->createInternalDataProvider(false);
}
}
catch (const uno::Exception & rEx)
{
SAL_INFO("xmloff.chart", "SchXMLChartContext::StartElement(): Exception caught: " << rEx);
}
}
void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
{
// parse attributes
sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetChartAttrTokenMap();
uno::Reference< embed::XVisualObject > xVisualObject( mrImportHelper.GetChartDocument(), uno::UNO_QUERY);
SAL_WARN_IF(!xVisualObject.is(), "xmloff.chart", "need xVisualObject for page size");
if( xVisualObject.is() )
maChartSize = xVisualObject->getVisualAreaSize( embed::Aspects::MSOLE_CONTENT ); //#i103460# take the size given from the parent frame as default
OUString sAutoStyleName;
OUString aOldChartTypeName;
bool bHasAddin = false;
for( sal_Int16 i = 0; i < nAttrCount; i++ )
{
OUString sAttrName = xAttrList->getNameByIndex( i );
OUString aLocalName;
OUString aValue = xAttrList->getValueByIndex( i );
sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
{
case XML_TOK_CHART_DATA_PILOT_SOURCE:
msDataPilotSource = aValue;
break;
case XML_TOK_CHART_HREF:
m_aXLinkHRefAttributeToIndicateDataProvider = aValue;
break;
case XML_TOK_CHART_CLASS:
{
OUString sClassName;
sal_uInt16 nClassPrefix =
GetImport().GetNamespaceMap().GetKeyByAttrName(
aValue, &sClassName );
if( XML_NAMESPACE_CHART == nClassPrefix )
{
SchXMLChartTypeEnum eChartTypeEnum = SchXMLTools::GetChartTypeEnum( sClassName );
if( eChartTypeEnum != XML_CHART_CLASS_UNKNOWN )
{
aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( sClassName, true /* bUseOldNames */ );
maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( sClassName, false /* bUseOldNames */ );
switch( eChartTypeEnum )
{
case XML_CHART_CLASS_STOCK:
mbIsStockChart = true;
break;
default:
break;
}
}
}
else if( XML_NAMESPACE_OOO == nClassPrefix )
{
// service is taken from add-in-name attribute
bHasAddin = true;
aOldChartTypeName = sClassName;
maChartTypeServiceName = sClassName;
}
}
break;
case XML_TOK_CHART_WIDTH:
GetImport().GetMM100UnitConverter().convertMeasureToCore(
maChartSize.Width, aValue );
break;
case XML_TOK_CHART_HEIGHT:
GetImport().GetMM100UnitConverter().convertMeasureToCore(
maChartSize.Height, aValue );
break;
case XML_TOK_CHART_STYLE_NAME:
sAutoStyleName = aValue;
break;
case XML_TOK_CHART_COL_MAPPING:
msColTrans = aValue;
break;
case XML_TOK_CHART_ROW_MAPPING:
msRowTrans = aValue;
break;
}
}
uno::Reference<chart::XChartDocument> xDoc = mrImportHelper.GetChartDocument();
uno::Reference<chart2::XChartDocument> xNewDoc(xDoc, uno::UNO_QUERY);
lcl_setDataProvider(xNewDoc, msDataPilotSource);
if( aOldChartTypeName.isEmpty() )
{
SAL_WARN("xmloff.chart", "need a charttype to create a diagram" );
//set a fallback value:
const OUString& aChartClass_Bar( GetXMLToken(XML_BAR ) );
aOldChartTypeName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, true /* bUseOldNames */ );
maChartTypeServiceName = SchXMLTools::GetChartTypeByClassName( aChartClass_Bar, false /* bUseOldNames */ );
}
// Set the size of the draw page.
if( xVisualObject.is() )
xVisualObject->setVisualAreaSize( embed::Aspects::MSOLE_CONTENT, maChartSize );
InitChart( aOldChartTypeName);
if( bHasAddin )
{
//correct charttype service name when having an addin
//and don't refresh addin during load
uno::Reference< beans::XPropertySet > xDocProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
if( xDocProp.is() )
{
try
{
xDocProp->getPropertyValue("BaseDiagram") >>= aOldChartTypeName;
maChartTypeServiceName = SchXMLTools::GetNewChartTypeName( aOldChartTypeName );
xDocProp->setPropertyValue("RefreshAddInAllowed", uno::makeAny( false) );
}
catch(const uno::Exception&)
{
SAL_WARN("xmloff.chart", "Exception during import SchXMLChartContext::StartElement" );
}
}
}
// set auto-styles for Area
uno::Reference<beans::XPropertySet> xProp(mrImportHelper.GetChartDocument()->getArea(), uno::UNO_QUERY);
mrImportHelper.FillAutoStyle(sAutoStyleName, xProp);
}
namespace
{
struct NewDonutSeries
{
css::uno::Reference< css::chart2::XDataSeries > m_xSeries;
OUString const msStyleName;
sal_Int32 mnAttachedAxis;
::std::vector< OUString > m_aSeriesStyles;
::std::vector< OUString > m_aPointStyles;
NewDonutSeries( const css::uno::Reference< css::chart2::XDataSeries >& xSeries, sal_Int32 nPointCount )
: m_xSeries( xSeries )
, mnAttachedAxis( 1 )
{
m_aPointStyles.resize(nPointCount);
m_aSeriesStyles.resize(nPointCount);
}
void setSeriesStyleNameToPoint( const OUString& rStyleName, sal_Int32 nPointIndex )
{
SAL_WARN_IF(nPointIndex >= static_cast<sal_Int32>(m_aSeriesStyles.size()), "xmloff.chart", "donut point <-> series count mismatch");
if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) )
m_aSeriesStyles[nPointIndex]=rStyleName;
}
void setPointStyleNameToPoint( const OUString& rStyleName, sal_Int32 nPointIndex )
{
SAL_WARN_IF(nPointIndex >= static_cast<sal_Int32>(m_aPointStyles.size()), "xmloff.chart", "donut point <-> series count mismatch");
if( nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()) )
m_aPointStyles[nPointIndex]=rStyleName;
}
::std::vector< DataRowPointStyle > creatStyleVector()
{
::std::vector< DataRowPointStyle > aRet;
DataRowPointStyle aSeriesStyle( DataRowPointStyle::DATA_SERIES
, m_xSeries, -1, 1, msStyleName, mnAttachedAxis );
aRet.push_back( aSeriesStyle );
sal_Int32 nPointIndex=0;
for (auto const& pointStyle : m_aPointStyles)
{
DataRowPointStyle aPointStyle( DataRowPointStyle::DATA_POINT
, m_xSeries, nPointIndex, 1, pointStyle, mnAttachedAxis );
if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) )
{
aPointStyle.msSeriesStyleNameForDonuts = m_aSeriesStyles[nPointIndex];
}
if( !aPointStyle.msSeriesStyleNameForDonuts.isEmpty()
|| !aPointStyle.msStyleName.isEmpty() )
aRet.push_back( aPointStyle );
++nPointIndex;
}
return aRet;
}
};
void lcl_swapPointAndSeriesStylesForDonutCharts( ::std::vector< DataRowPointStyle >& rStyleVector
, const ::std::map< css::uno::Reference< css::chart2::XDataSeries> , sal_Int32 >& rSeriesMap )
{
//detect old series count
//and add old series to aSeriesMap
::std::map< css::uno::Reference<
css::chart2::XDataSeries >, sal_Int32 > aSeriesMap(rSeriesMap);
sal_Int32 nOldSeriesCount = 0;
{
sal_Int32 nMaxOldSeriesIndex = 0;
sal_Int32 nOldSeriesIndex = 0;
for (auto const& style : rStyleVector)
{
DataRowPointStyle aStyle(style);
if(aStyle.meType == DataRowPointStyle::DATA_SERIES &&
aStyle.m_xSeries.is() )
{
nMaxOldSeriesIndex = nOldSeriesIndex;
if( aSeriesMap.end() == aSeriesMap.find(aStyle.m_xSeries) )
aSeriesMap[aStyle.m_xSeries] = nOldSeriesIndex;
nOldSeriesIndex++;
}
}
nOldSeriesCount = nMaxOldSeriesIndex+1;
}
//initialize new series styles
::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapEnd( aSeriesMap.end() );
//sort by index
::std::vector< NewDonutSeries > aNewSeriesVector;
{
::std::map< sal_Int32, Reference< chart2::XDataSeries > > aIndexSeriesMap;
for (auto const& series : aSeriesMap)
aIndexSeriesMap[series.second] = series.first;
for (auto const& indexSeries : aIndexSeriesMap)
aNewSeriesVector.emplace_back(indexSeries.second,nOldSeriesCount );
}
//overwrite attached axis information according to old series styles
for (auto const& style : rStyleVector)
{
DataRowPointStyle aStyle(style);
if(aStyle.meType == DataRowPointStyle::DATA_SERIES )
{
auto aSeriesMapIt = aSeriesMap.find( aStyle.m_xSeries );
if( aSeriesMapIt != aSeriesMapEnd && aSeriesMapIt->second < static_cast<sal_Int32>(aNewSeriesVector.size()) )
aNewSeriesVector[aSeriesMapIt->second].mnAttachedAxis = aStyle.mnAttachedAxis;
}
}
//overwrite new series style names with old series style name information
for (auto const& style : rStyleVector)
{
DataRowPointStyle aStyle(style);
if( aStyle.meType == DataRowPointStyle::DATA_SERIES )
{
auto aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries);
if( aSeriesMapEnd != aSeriesMapIt )
{
sal_Int32 nNewPointIndex = aSeriesMapIt->second;
for (auto & newSeries : aNewSeriesVector)
newSeries.setSeriesStyleNameToPoint( aStyle.msStyleName, nNewPointIndex );
}
}
}
//overwrite new series style names with point style name information
for (auto const& style : rStyleVector)
{
DataRowPointStyle aStyle(style);
if( aStyle.meType == DataRowPointStyle::DATA_POINT )
{
auto aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries);
if( aSeriesMapEnd != aSeriesMapIt )
{
sal_Int32 nNewPointIndex = aSeriesMapIt->second;
sal_Int32 nNewSeriesIndex = aStyle.m_nPointIndex;
sal_Int32 nRepeatCount = aStyle.m_nPointRepeat;
while( nRepeatCount && (nNewSeriesIndex>=0) && (nNewSeriesIndex< static_cast<sal_Int32>(aNewSeriesVector.size()) ) )
{
NewDonutSeries& rNewSeries( aNewSeriesVector[nNewSeriesIndex] );
rNewSeries.setPointStyleNameToPoint( aStyle.msStyleName, nNewPointIndex );
nRepeatCount--;
nNewSeriesIndex++;
}
}
}
}
//put information from aNewSeriesVector to output parameter rStyleVector
rStyleVector.clear();
for (auto & newSeries : aNewSeriesVector)
{
::std::vector< DataRowPointStyle > aVector( newSeries.creatStyleVector() );
rStyleVector.insert(rStyleVector.end(),aVector.begin(),aVector.end());
}
}
bool lcl_SpecialHandlingForDonutChartNeeded(
const OUString & rServiceName,
const SvXMLImport & rImport )
{
bool bResult = false;
if( rServiceName == "com.sun.star.chart2.DonutChartType" )
{
bResult = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( rImport.GetModel() );
}
return bResult;
}
} // anonymous namespace
static void lcl_ApplyDataFromRectangularRangeToDiagram(
const uno::Reference< chart2::XChartDocument >& xNewDoc
, const OUString& rRectangularRange
, css::chart::ChartDataRowSource eDataRowSource
, bool bRowHasLabels, bool bColHasLabels
, bool bSwitchOnLabelsAndCategoriesForOwnData
, const OUString& sColTrans
, const OUString& sRowTrans )
{
if( !xNewDoc.is() )
return;
uno::Reference< chart2::XDiagram > xNewDia( xNewDoc->getFirstDiagram());
uno::Reference< chart2::data::XDataProvider > xDataProvider( xNewDoc->getDataProvider() );
if( !xNewDia.is() || !xDataProvider.is() )
return;
bool bFirstCellAsLabel =
(eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bRowHasLabels : bColHasLabels;
bool bHasCateories =
(eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bColHasLabels : bRowHasLabels;
if( bSwitchOnLabelsAndCategoriesForOwnData )
{
bFirstCellAsLabel = true;
bHasCateories = true;
}
uno::Sequence< beans::PropertyValue > aArgs( 3 );
aArgs[0] = beans::PropertyValue(
"CellRangeRepresentation",
-1, uno::makeAny( rRectangularRange ),
beans::PropertyState_DIRECT_VALUE );
aArgs[1] = beans::PropertyValue(
"DataRowSource",
-1, uno::makeAny( eDataRowSource ),
beans::PropertyState_DIRECT_VALUE );
aArgs[2] = beans::PropertyValue(
"FirstCellAsLabel",
-1, uno::makeAny( bFirstCellAsLabel ),
beans::PropertyState_DIRECT_VALUE );
if( !sColTrans.isEmpty() || !sRowTrans.isEmpty() )
{
aArgs.realloc( aArgs.getLength() + 1 );
aArgs[ sal::static_int_cast<sal_uInt32>(aArgs.getLength()) - 1 ] = beans::PropertyValue(
"SequenceMapping",
-1, uno::makeAny( !sColTrans.isEmpty()
? lcl_getNumberSequenceFromString( sColTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() )
: lcl_getNumberSequenceFromString( sRowTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) ),
beans::PropertyState_DIRECT_VALUE );
}
//work around wrong writer ranges ( see Issue 58464 )
{
OUString aChartOleObjectName;
uno::Reference< frame::XModel > xModel(xNewDoc, uno::UNO_QUERY );
if( xModel.is() )
{
utl::MediaDescriptor aMediaDescriptor( xModel->getArgs() );
utl::MediaDescriptor::const_iterator aIt(
aMediaDescriptor.find( OUString( "HierarchicalDocumentName" )));
if( aIt != aMediaDescriptor.end() )
{
aChartOleObjectName = (*aIt).second.get< OUString >();
}
}
if( !aChartOleObjectName.isEmpty() )
{
aArgs.realloc( aArgs.getLength() + 1 );
aArgs[ sal::static_int_cast<sal_uInt32>(aArgs.getLength()) - 1 ] = beans::PropertyValue(
"ChartOleObjectName",
-1, uno::makeAny( aChartOleObjectName ),
beans::PropertyState_DIRECT_VALUE );
}
}
uno::Reference< chart2::data::XDataSource > xDataSource(
xDataProvider->createDataSource( aArgs ));
aArgs.realloc( aArgs.getLength() + 2 );
aArgs[ sal::static_int_cast<sal_uInt32>(aArgs.getLength()) - 2 ] = beans::PropertyValue(
"HasCategories",
-1, uno::makeAny( bHasCateories ),
beans::PropertyState_DIRECT_VALUE );
aArgs[ sal::static_int_cast<sal_uInt32>(aArgs.getLength()) - 1 ] = beans::PropertyValue(
"UseCategoriesAsX",
-1, uno::makeAny( false ),//categories in ODF files are not to be used as x values (independent from what is offered in our ui)
beans::PropertyState_DIRECT_VALUE );
xNewDia->setDiagramData( xDataSource, aArgs );
}
void SchXMLChartContext::EndElement()
{
uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY );
uno::Reference< chart2::XChartDocument > xNewDoc( xDoc, uno::UNO_QUERY );
if( xProp.is())
{
if( !maMainTitle.isEmpty())
{
uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getTitle(), uno::UNO_QUERY );
if( xTitleProp.is())
{
try
{
xTitleProp->setPropertyValue("String", uno::Any(maMainTitle) );
}
catch(const beans::UnknownPropertyException&)
{
SAL_WARN("xmloff.chart", "Property String for Title not available" );
}
}
}
if( !maSubTitle.isEmpty())
{
uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getSubTitle(), uno::UNO_QUERY );
if( xTitleProp.is())
{
try
{
xTitleProp->setPropertyValue("String", uno::Any(maSubTitle) );
}
catch(const beans::UnknownPropertyException&)
{
SAL_WARN("xmloff.chart", "Property String for Title not available" );
}
}
}
}
// cleanup: remove empty chart type groups
lcl_removeEmptyChartTypeGroups( xNewDoc );
// set stack mode before a potential chart type detection (in case we have a rectangular range)
uno::Reference< chart::XDiagram > xDiagram( xDoc->getDiagram() );
uno::Reference< beans::XPropertySet > xDiaProp( xDiagram, uno::UNO_QUERY );
if( xDiaProp.is())
{
if( maSeriesDefaultsAndStyles.maStackedDefault.hasValue())
xDiaProp->setPropertyValue("Stacked",maSeriesDefaultsAndStyles.maStackedDefault);
if( maSeriesDefaultsAndStyles.maPercentDefault.hasValue())
xDiaProp->setPropertyValue("Percent",maSeriesDefaultsAndStyles.maPercentDefault);
if( maSeriesDefaultsAndStyles.maDeepDefault.hasValue())
xDiaProp->setPropertyValue("Deep",maSeriesDefaultsAndStyles.maDeepDefault);
if( maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault.hasValue())
xDiaProp->setPropertyValue("StackedBarsConnected",maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault);
}
//the OOo 2.0 implementation and older has a bug with donuts
bool bSpecialHandlingForDonutChart = lcl_SpecialHandlingForDonutChartNeeded(
maChartTypeServiceName, GetImport());
// apply data
if(!xNewDoc.is())
return;
bool bHasOwnData = false;
if( m_aXLinkHRefAttributeToIndicateDataProvider == "." ) //data comes from the chart itself
bHasOwnData = true;
else if( m_aXLinkHRefAttributeToIndicateDataProvider == ".." ) //data comes from the parent application
bHasOwnData = false;
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
bHasOwnData = m_bHasTableElement;
else
bHasOwnData = !m_bHasRangeAtPlotArea;
if( xNewDoc->hasInternalDataProvider())
{
if( !m_bHasTableElement && m_aXLinkHRefAttributeToIndicateDataProvider != "." )
{
//#i103147# ODF, workaround broken files with a missing table:cell-range-address at the plot-area
bool bSwitchSuccessful = SchXMLTools::switchBackToDataProviderFromParent( xNewDoc, maLSequencesPerIndex );
bHasOwnData = !bSwitchSuccessful;
}
else
bHasOwnData = true;//e.g. in case of copy->paste from calc to impress
}
else if( bHasOwnData )
{
xNewDoc->createInternalDataProvider( false /* bCloneExistingData */ );
}
if( bHasOwnData )
msChartAddress = "all";
bool bSwitchRangesFromOuterToInternalIfNecessary = false;
if( !bHasOwnData && mbAllRangeAddressesAvailable )
{
// special handling for stock chart (merge series together)
if( mbIsStockChart )
MergeSeriesForStockChart();
}
else if( !msChartAddress.isEmpty() )
{
//own data or only rectangular range available
if( xNewDoc->hasInternalDataProvider() )
SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc );
bool bOlderThan2_3 = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( Reference< frame::XModel >( xNewDoc, uno::UNO_QUERY ));
bool bOldFileWithOwnDataFromRows = (bOlderThan2_3 && bHasOwnData && (meDataRowSource==chart::ChartDataRowSource_ROWS)); // in this case there are range addresses that are simply wrong.
if( mbAllRangeAddressesAvailable && !bSpecialHandlingForDonutChart && !mbIsStockChart &&
!bOldFileWithOwnDataFromRows )
{
//bHasOwnData is true in this case!
//e.g. for normal files with own data or also in case of copy paste scenario (e.g. calc to impress)
bSwitchRangesFromOuterToInternalIfNecessary = true;
}
else
{
//apply data from rectangular range
// create datasource from data provider with rectangular range parameters and change the diagram setDiagramData
try
{
if( bOlderThan2_3 && xDiaProp.is() )//for older charts the hidden cells were removed by calc on the fly
xDiaProp->setPropertyValue("IncludeHiddenCells",uno::makeAny(false));
// note: mbRowHasLabels means the first row contains labels, that means we have "column-descriptions",
// (analogously mbColHasLabels means we have "row-descriptions")
lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans );
}
catch(const uno::Exception&)
{
//try to fallback to internal data
SAL_WARN("xmloff.chart", "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram try to fallback to internal data" );
if(!bHasOwnData)
{
bHasOwnData = true;
msChartAddress = "all";
if( !xNewDoc->hasInternalDataProvider() )
{
xNewDoc->createInternalDataProvider( false /* bCloneExistingData */ );
SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc );
try
{
lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans );
}
catch(const uno::Exception&)
{
SAL_WARN("xmloff.chart", "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram fallback to internal data failed also" );
}
}
}
}
}
}
else
{
SAL_WARN("xmloff.chart", "Must not get here" );
}
// now all series and data point properties are available and can be set
{
if( bSpecialHandlingForDonutChart )
{
uno::Reference< chart2::XDiagram > xNewDiagram( xNewDoc->getFirstDiagram() );
lcl_swapPointAndSeriesStylesForDonutCharts( maSeriesDefaultsAndStyles.maSeriesStyleVector
, SchXMLSeriesHelper::getDataSeriesIndexMapFromDiagram(xNewDiagram) );
}
SchXMLSeries2Context::initSeriesPropertySets( maSeriesDefaultsAndStyles, uno::Reference< frame::XModel >(xDoc, uno::UNO_QUERY ) );
//set defaults from diagram to the new series:
//check whether we need to remove lines from symbol only charts
bool bSwitchOffLinesForScatter = false;
{
bool bLinesOn = true;
if( (maSeriesDefaultsAndStyles.maLinesOnProperty >>= bLinesOn) && !bLinesOn )
{
if( maChartTypeServiceName == "com.sun.star.chart2.ScatterChartType" )
{
bSwitchOffLinesForScatter = true;
SchXMLSeries2Context::switchSeriesLinesOff( maSeriesDefaultsAndStyles.maSeriesStyleVector );
}
}
}
SchXMLSeries2Context::setDefaultsToSeries( maSeriesDefaultsAndStyles );
// set autostyles for series and data points
const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
const SvXMLStyleContext* pStyle = nullptr;
OUString sCurrStyleName;
if( pStylesCtxt )
{
//iterate over data-series first
//don't set series styles for donut charts
if( !bSpecialHandlingForDonutChart )
{
SchXMLSeries2Context::setStylesToSeries(
maSeriesDefaultsAndStyles, pStylesCtxt, pStyle,
sCurrStyleName, mrImportHelper, GetImport(),
mbIsStockChart, maLSequencesPerIndex );
// ... then set attributes for statistics (after their existence was set in the series)
SchXMLSeries2Context::setStylesToStatisticsObjects(
maSeriesDefaultsAndStyles, pStylesCtxt,
pStyle, sCurrStyleName );
SchXMLSeries2Context::setStylesToRegressionCurves(
maSeriesDefaultsAndStyles, pStylesCtxt,
pStyle, sCurrStyleName );
}
}
//#i98319# call switchRangesFromOuterToInternalIfNecessary before the data point styles are applied, otherwise in copy->paste scenario the data point styles do get lost
if( bSwitchRangesFromOuterToInternalIfNecessary )
{
if( xNewDoc->hasInternalDataProvider() )
SchXMLTableHelper::switchRangesFromOuterToInternalIfNecessary( maTable, maLSequencesPerIndex, xNewDoc, meDataRowSource );
}
if( pStylesCtxt )
{
// ... then iterate over data-point attributes, so the latter are not overwritten
SchXMLSeries2Context::setStylesToDataPoints( maSeriesDefaultsAndStyles
, pStylesCtxt, pStyle, sCurrStyleName, mrImportHelper, GetImport(), mbIsStockChart, bSpecialHandlingForDonutChart, bSwitchOffLinesForScatter );
}
}
if( xProp.is())
xProp->setPropertyValue("RefreshAddInAllowed", uno::makeAny( true) );
}
void SchXMLChartContext::MergeSeriesForStockChart()
{
OSL_ASSERT( mbIsStockChart );
try
{
uno::Reference< chart::XChartDocument > xOldDoc( mrImportHelper.GetChartDocument());
uno::Reference< chart2::XChartDocument > xDoc( xOldDoc, uno::UNO_QUERY_THROW );
uno::Reference< chart2::XDiagram > xDiagram( xDoc->getFirstDiagram());
if( ! xDiagram.is())
return;
bool bHasJapaneseCandlestick = true;
uno::Reference< chart2::XDataSeriesContainer > xDSContainer;
uno::Reference< chart2::XCoordinateSystemContainer > xCooSysCnt( xDiagram, uno::UNO_QUERY_THROW );
uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > aCooSysSeq( xCooSysCnt->getCoordinateSystems());
for( sal_Int32 nCooSysIdx=0; nCooSysIdx<aCooSysSeq.getLength(); ++nCooSysIdx )
{
uno::Reference< chart2::XChartTypeContainer > xCTCnt( aCooSysSeq[nCooSysIdx], uno::UNO_QUERY_THROW );
uno::Sequence< uno::Reference< chart2::XChartType > > aChartTypes( xCTCnt->getChartTypes());
for( sal_Int32 nCTIdx=0; nCTIdx<aChartTypes.getLength(); ++nCTIdx )
{
if( aChartTypes[nCTIdx]->getChartType() == "com.sun.star.chart2.CandleStickChartType" )
{
xDSContainer.set( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW );
uno::Reference< beans::XPropertySet > xCTProp( aChartTypes[nCTIdx], uno::UNO_QUERY_THROW );
xCTProp->getPropertyValue("Japanese") >>= bHasJapaneseCandlestick;
break;
}
}
}
if( xDSContainer.is())
{
// with japanese candlesticks: open, low, high, close
// otherwise: low, high, close
uno::Sequence< uno::Reference< chart2::XDataSeries > > aSeriesSeq( xDSContainer->getDataSeries());
const sal_Int32 nSeriesCount( aSeriesSeq.getLength());
const sal_Int32 nSeriesPerCandleStick = bHasJapaneseCandlestick ? 4: 3;
sal_Int32 nCandleStickCount = nSeriesCount / nSeriesPerCandleStick;
OSL_ASSERT( nSeriesPerCandleStick * nCandleStickCount == nSeriesCount );
uno::Sequence< uno::Reference< chart2::XDataSeries > > aNewSeries( nCandleStickCount );
for( sal_Int32 i=0; i<nCandleStickCount; ++i )
{
sal_Int32 nSeriesIndex = i*nSeriesPerCandleStick;
if( bHasJapaneseCandlestick )
{
// open values
lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], "values-first");
aNewSeries[i] = aSeriesSeq[ nSeriesIndex ];
// low values
lcl_MoveDataToCandleStickSeries(
uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
aNewSeries[i], "values-min");
}
else
{
// low values
lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], "values-min");
aNewSeries[i] = aSeriesSeq[ nSeriesIndex ];
}
// high values
lcl_MoveDataToCandleStickSeries(
uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
aNewSeries[i], "values-max");
// close values
lcl_MoveDataToCandleStickSeries(
uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
aNewSeries[i], "values-last");
}
xDSContainer->setDataSeries( aNewSeries );
}
}
catch(const uno::Exception&)
{
SAL_WARN("xmloff.chart", "Exception while merging series for stock chart" );
}
}
SvXMLImportContextRef SchXMLChartContext::CreateChildContext(
sal_uInt16 nPrefix,
const OUString& rLocalName,
const uno::Reference< xml::sax::XAttributeList >& xAttrList )
{
SvXMLImportContext* pContext = nullptr;
const SvXMLTokenMap& rTokenMap = mrImportHelper.GetChartElemTokenMap();
uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
uno::Reference< beans::XPropertySet > xProp( xDoc, uno::UNO_QUERY );
switch( rTokenMap.Get( nPrefix, rLocalName ))
{
case XML_TOK_CHART_PLOT_AREA:
pContext = new SchXMLPlotAreaContext( mrImportHelper, GetImport(), rLocalName,
m_aXLinkHRefAttributeToIndicateDataProvider,
msCategoriesAddress,
msChartAddress, m_bHasRangeAtPlotArea, mbAllRangeAddressesAvailable,
mbColHasLabels, mbRowHasLabels,
meDataRowSource,
maSeriesDefaultsAndStyles,
maChartTypeServiceName,
maLSequencesPerIndex, maChartSize );
break;
case XML_TOK_CHART_TITLE:
if( xDoc.is())
{
if( xProp.is())
{
xProp->setPropertyValue("HasMainTitle", uno::makeAny(true) );
}
uno::Reference< drawing::XShape > xTitleShape( xDoc->getTitle(), uno::UNO_QUERY );
pContext = new SchXMLTitleContext( mrImportHelper, GetImport(),
rLocalName, maMainTitle, xTitleShape );
}
break;
case XML_TOK_CHART_SUBTITLE:
if( xDoc.is())
{
if( xProp.is())
{
xProp->setPropertyValue("HasSubTitle", uno::makeAny(true) );
}
uno::Reference< drawing::XShape > xTitleShape( xDoc->getSubTitle(), uno::UNO_QUERY );
pContext = new SchXMLTitleContext( mrImportHelper, GetImport(),
rLocalName, maSubTitle, xTitleShape );
}
break;
case XML_TOK_CHART_LEGEND:
pContext = new SchXMLLegendContext( mrImportHelper, GetImport(), rLocalName );
break;
case XML_TOK_CHART_TABLE:
{
SchXMLTableContext * pTableContext =
new SchXMLTableContext( mrImportHelper, GetImport(), rLocalName, maTable );
m_bHasTableElement = true;
// #i85913# take into account column- and row- mapping for
// charts with own data only for those which were not copied
// from a place where they got data from the container. Note,
// that this requires the plot-area been read before the table
// (which is required in the ODF spec)
// Note: For stock charts and donut charts with special handling
// the mapping must not be applied!
if( msChartAddress.isEmpty() && !mbIsStockChart &&
!lcl_SpecialHandlingForDonutChartNeeded(
maChartTypeServiceName, GetImport()))
{
if( !msColTrans.isEmpty() )
{
OSL_ASSERT( msRowTrans.isEmpty() );
pTableContext->setColumnPermutation( lcl_getNumberSequenceFromString( msColTrans, true ));
msColTrans.clear();
}
else if( !msRowTrans.isEmpty() )
{
pTableContext->setRowPermutation( lcl_getNumberSequenceFromString( msRowTrans, true ));
msRowTrans.clear();
}
}
pContext = pTableContext;
}
break;
default:
// try importing as an additional shape
if( ! mxDrawPage.is())
{
uno::Reference< drawing::XDrawPageSupplier > xSupp( xDoc, uno::UNO_QUERY );
if( xSupp.is())
mxDrawPage.set( xSupp->getDrawPage(), uno::UNO_QUERY );
SAL_WARN_IF( !mxDrawPage.is(), "xmloff.chart", "Invalid Chart Page" );
}
if( mxDrawPage.is())
pContext = GetImport().GetShapeImport()->CreateGroupChildContext(
GetImport(), nPrefix, rLocalName, xAttrList, mxDrawPage );
break;
}
if( ! pContext )
pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
return pContext;
}
/*
With a locked controller the following is done here:
1. Hide title, subtitle, and legend.
2. Set the size of the draw page.
3. Set a (logically) empty data set.
4. Set the chart type.
*/
void SchXMLChartContext::InitChart(
const OUString & rChartTypeServiceName // currently the old service name
)
{
uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
SAL_WARN_IF( !xDoc.is(), "xmloff.chart", "No valid document!" );
// Remove Title and Diagram ("De-InitNew")
uno::Reference< chart2::XChartDocument > xNewDoc( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
if( xNewDoc.is())
{
xNewDoc->setFirstDiagram( nullptr );
uno::Reference< chart2::XTitled > xTitled( xNewDoc, uno::UNO_QUERY );
if( xTitled.is())
xTitled->setTitleObject( nullptr );
}
// Set the chart type via setting the diagram.
if( !rChartTypeServiceName.isEmpty() && xDoc.is())
{
uno::Reference< lang::XMultiServiceFactory > xFact( xDoc, uno::UNO_QUERY );
if( xFact.is())
{
uno::Reference< chart::XDiagram > xDia( xFact->createInstance( rChartTypeServiceName ), uno::UNO_QUERY );
if( xDia.is())
xDoc->setDiagram( xDia );
}
}
}
SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport,
const OUString& rLocalName,
OUString& rTitle,
uno::Reference< drawing::XShape > const & xTitleShape ) :
SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
mrImportHelper( rImpHelper ),
mrTitle( rTitle ),
mxTitleShape( xTitleShape )
{
}
SchXMLTitleContext::~SchXMLTitleContext()
{}
void SchXMLTitleContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
{
sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
css::awt::Point aPosition;
bool bHasXPosition=false;
bool bHasYPosition=false;
for( sal_Int16 i = 0; i < nAttrCount; i++ )
{
OUString sAttrName = xAttrList->getNameByIndex( i );
OUString aLocalName;
OUString aValue = xAttrList->getValueByIndex( i );
sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
if( nPrefix == XML_NAMESPACE_SVG )
{
if( IsXMLToken( aLocalName, XML_X ) )
{
GetImport().GetMM100UnitConverter().convertMeasureToCore(
aPosition.X, aValue );
bHasXPosition = true;
}
else if( IsXMLToken( aLocalName, XML_Y ) )
{
GetImport().GetMM100UnitConverter().convertMeasureToCore(
aPosition.Y, aValue );
bHasYPosition = true;
}
}
else if( nPrefix == XML_NAMESPACE_CHART )
{
if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
msAutoStyleName = aValue;
}
}
if( mxTitleShape.is())
{
if( bHasXPosition && bHasYPosition )
mxTitleShape->setPosition( aPosition );
uno::Reference<beans::XPropertySet> xProp(mxTitleShape, uno::UNO_QUERY);
mrImportHelper.FillAutoStyle(msAutoStyleName, xProp);
}
}
SvXMLImportContextRef SchXMLTitleContext::CreateChildContext(
sal_uInt16 nPrefix,
const OUString& rLocalName,
const uno::Reference< xml::sax::XAttributeList >& )
{
SvXMLImportContext* pContext = nullptr;
if( (nPrefix == XML_NAMESPACE_TEXT ||
nPrefix == XML_NAMESPACE_LO_EXT) &&
IsXMLToken( rLocalName, XML_P ) )
{
pContext = new SchXMLParagraphContext( GetImport(), rLocalName, mrTitle );
}
else
pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
return pContext;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */