blob: f084a761cbe1a6dcde3bade8235155b3df2f48da [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"
#include "SchXMLChartContext.hxx"
#include "SchXMLImport.hxx"
#include "SchXMLLegendContext.hxx"
#include "SchXMLPlotAreaContext.hxx"
#include "SchXMLParagraphContext.hxx"
#include "SchXMLTableContext.hxx"
#include "SchXMLSeriesHelper.hxx"
#include "SchXMLSeries2Context.hxx"
#include "SchXMLTools.hxx"
#include <comphelper/mediadescriptor.hxx>
#include <tools/debug.hxx>
// header for class ByteString
#include <tools/string.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 "vector"
#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/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/XDataSeriesContainer.hpp>
#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
#include <com/sun/star/chart2/XChartTypeContainer.hpp>
#include <com/sun/star/chart2/XTitled.hpp>
using namespace com::sun::star;
using namespace ::xmloff::token;
using ::rtl::OUString;
using com::sun::star::uno::Reference;
using namespace ::SchXMLTools;
namespace
{
void lcl_setRoleAtLabeledSequence(
const uno::Reference< chart2::data::XLabeledDataSequence > & xLSeq,
const ::rtl::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(OUString::createFromAscii("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( uno::Exception & )
{
OSL_ENSURE( false, "Exception caught while moving data to candlestick series" );
}
}
void lcl_setRoleAtFirstSequence(
const uno::Reference< chart2::XDataSeries > & xSeries,
const ::rtl::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( uno::Exception & ex )
{
String aStr( ex.Message );
ByteString aBStr( aStr, RTL_TEXTENCODING_ASCII_US );
DBG_ERROR1( "Exception caught while removing empty chart types: %s", aBStr.GetBuffer());
}
}
uno::Sequence< sal_Int32 > lcl_getNumberSequenceFromString( const ::rtl::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, (rStr.getLength() - 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 rtl::OUString& rLocalName ) :
SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
mrImportHelper( rImpHelper ),
m_bHasRangeAtPlotArea( false ),
m_bHasTableElement( false ),
mbAllRangeAddressesAvailable( sal_True ),
mbColHasLabels( sal_False ),
mbRowHasLabels( sal_False ),
meDataRowSource( chart::ChartDataRowSource_COLUMNS ),
mbIsStockChart( false )
{
}
SchXMLChartContext::~SchXMLChartContext()
{}
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);
DBG_ASSERT(xVisualObject.is(),"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
// this flag is necessarry for pie charts in the core
sal_Bool bSetSwitchData = sal_False;
::rtl::OUString sAutoStyleName;
::rtl::OUString aOldChartTypeName;
bool bHasAddin = false;
for( sal_Int16 i = 0; i < nAttrCount; i++ )
{
rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
rtl::OUString aLocalName;
rtl::OUString aValue = xAttrList->getValueByIndex( i );
sal_uInt16 nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );
switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
{
case XML_TOK_CHART_HREF:
m_aXLinkHRefAttributeToIndicateDataProvider = aValue;
break;
case XML_TOK_CHART_CLASS:
{
rtl::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_CIRCLE:
bSetSwitchData = sal_True;
break;
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().convertMeasure( maChartSize.Width, aValue );
break;
case XML_TOK_CHART_HEIGHT:
GetImport().GetMM100UnitConverter().convertMeasure( 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;
}
}
if( aOldChartTypeName.getLength()<= 0 )
{
DBG_ERROR( "need a charttype to create a diagram" );
//set a fallback value:
::rtl::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, bSetSwitchData);
if( bHasAddin )
{
//correct charttype serveice 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( ::rtl::OUString::createFromAscii("BaseDiagram")) >>= aOldChartTypeName;
maChartTypeServiceName = SchXMLTools::GetNewChartTypeName( aOldChartTypeName );
xDocProp->setPropertyValue( rtl::OUString::createFromAscii( "RefreshAddInAllowed" ) , uno::makeAny( sal_False) );
}
catch( uno::Exception & )
{
DBG_ERROR( "Exception during import SchXMLChartContext::StartElement" );
}
}
}
// set auto-styles for Area
uno::Reference< beans::XPropertySet > xProp( mrImportHelper.GetChartDocument()->getArea(), uno::UNO_QUERY );
if( xProp.is())
{
const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
if( pStylesCtxt )
{
const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
mrImportHelper.GetChartFamilyID(), sAutoStyleName );
if( pStyle && pStyle->ISA( XMLPropStyleContext ))
(( XMLPropStyleContext* )pStyle )->FillPropertySet( xProp );
}
}
}
namespace
{
struct NewDonutSeries
{
::com::sun::star::uno::Reference<
::com::sun::star::chart2::XDataSeries > m_xSeries;
::rtl::OUString msStyleName;
sal_Int32 mnAttachedAxis;
::std::vector< ::rtl::OUString > m_aSeriesStyles;
::std::vector< ::rtl::OUString > m_aPointStyles;
NewDonutSeries( const ::com::sun::star::uno::Reference<
::com::sun::star::chart2::XDataSeries >& xSeries, sal_Int32 nPointCount )
: m_xSeries( xSeries )
, mnAttachedAxis( 1 )
{
m_aPointStyles.resize(nPointCount);
m_aSeriesStyles.resize(nPointCount);
}
void setSeriesStyleNameToPoint( const ::rtl::OUString& rStyleName, sal_Int32 nPointIndex )
{
DBG_ASSERT(nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()),"donut point <-> series count mismatch");
if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) )
m_aSeriesStyles[nPointIndex]=rStyleName;
}
void setPointStyleNameToPoint( const ::rtl::OUString& rStyleName, sal_Int32 nPointIndex )
{
DBG_ASSERT(nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()),"donut point <-> series count mismatch");
if( nPointIndex < static_cast<sal_Int32>(m_aPointStyles.size()) )
m_aPointStyles[nPointIndex]=rStyleName;
}
::std::list< DataRowPointStyle > creatStyleList()
{
::std::list< DataRowPointStyle > aRet;
DataRowPointStyle aSeriesStyle( DataRowPointStyle::DATA_SERIES
, m_xSeries, -1, 1, msStyleName, mnAttachedAxis );
aRet.push_back( aSeriesStyle );
sal_Int32 nPointIndex=0;
::std::vector< ::rtl::OUString >::iterator aPointIt( m_aPointStyles.begin() );
::std::vector< ::rtl::OUString >::iterator aPointEnd( m_aPointStyles.end() );
while( aPointIt != aPointEnd )
{
DataRowPointStyle aPointStyle( DataRowPointStyle::DATA_POINT
, m_xSeries, nPointIndex, 1, *aPointIt, mnAttachedAxis );
if( nPointIndex < static_cast<sal_Int32>(m_aSeriesStyles.size()) )
{
aPointStyle.msSeriesStyleNameForDonuts = m_aSeriesStyles[nPointIndex];
}
if( aPointStyle.msSeriesStyleNameForDonuts.getLength()
|| aPointStyle.msStyleName.getLength() )
aRet.push_back( aPointStyle );
++aPointIt;
++nPointIndex;
}
return aRet;
}
};
void lcl_swapPointAndSeriesStylesForDonutCharts( ::std::list< DataRowPointStyle >& rStyleList
, const ::std::map< ::com::sun::star::uno::Reference<
::com::sun::star::chart2::XDataSeries> , sal_Int32 >& rSeriesMap )
{
::std::list< DataRowPointStyle >::iterator aIt(rStyleList.begin());
::std::list< DataRowPointStyle >::iterator aEnd(rStyleList.end());
//detect old series count
//and add old series to aSeriesMap
::std::map< ::com::sun::star::uno::Reference<
::com::sun::star::chart2::XDataSeries >, sal_Int32 > aSeriesMap(rSeriesMap);
sal_Int32 nOldSeriesCount = 0;
{
sal_Int32 nMaxOldSeriesIndex = 0;
sal_Int32 nOldSeriesIndex = 0;
for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
{
DataRowPointStyle aStyle(*aIt);
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;
}
/*
sal_Int32 nOldSeriesCount = 0;
{
sal_Int32 nMaxOldSeriesIndex = 0;
sal_Int32 nOldSeriesIndex = 0;
for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
{
DataRowPointStyle aStyle(*aIt);
if(aStyle.meType == DataRowPointStyle::DATA_SERIES )
{
nMaxOldSeriesIndex = nOldSeriesIndex;
nOldSeriesIndex++;
}
}
nOldSeriesCount = nMaxOldSeriesIndex+1;
}
*/
//initialize new series styles
::std::map< Reference< chart2::XDataSeries >, sal_Int32 >::const_iterator aSeriesMapIt( aSeriesMap.begin() );
::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( ; aSeriesMapIt != aSeriesMapEnd; ++aSeriesMapIt )
aIndexSeriesMap[aSeriesMapIt->second] = aSeriesMapIt->first;
::std::map< sal_Int32, Reference< chart2::XDataSeries > >::const_iterator aIndexIt( aIndexSeriesMap.begin() );
::std::map< sal_Int32, Reference< chart2::XDataSeries > >::const_iterator aIndexEnd( aIndexSeriesMap.end() );
for( ; aIndexIt != aIndexEnd; ++aIndexIt )
aNewSeriesVector.push_back( NewDonutSeries(aIndexIt->second,nOldSeriesCount) );
}
//overwrite attached axis information according to old series styles
for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
{
DataRowPointStyle aStyle(*aIt);
if(aStyle.meType == DataRowPointStyle::DATA_SERIES )
{
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( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
{
DataRowPointStyle aStyle(*aIt);
if( aStyle.meType == DataRowPointStyle::DATA_SERIES )
{
aSeriesMapIt = aSeriesMap.find(aStyle.m_xSeries);
if( aSeriesMapEnd != aSeriesMapIt )
{
sal_Int32 nNewPointIndex = aSeriesMapIt->second;
::std::vector< NewDonutSeries >::iterator aNewSeriesIt( aNewSeriesVector.begin() );
::std::vector< NewDonutSeries >::iterator aNewSeriesEnd( aNewSeriesVector.end() );
for( ;aNewSeriesIt!=aNewSeriesEnd; ++aNewSeriesIt)
aNewSeriesIt->setSeriesStyleNameToPoint( aStyle.msStyleName, nNewPointIndex );
}
}
}
//overwrite new series style names with point style name information
for( aIt = rStyleList.begin(); aIt != aEnd; ++aIt )
{
DataRowPointStyle aStyle(*aIt);
if( aStyle.meType == DataRowPointStyle::DATA_POINT )
{
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 rStyleList
rStyleList.clear();
::std::vector< NewDonutSeries >::iterator aNewSeriesIt( aNewSeriesVector.begin() );
::std::vector< NewDonutSeries >::iterator aNewSeriesEnd( aNewSeriesVector.end() );
for( ;aNewSeriesIt!=aNewSeriesEnd; ++aNewSeriesIt)
{
::std::list< DataRowPointStyle > aList( aNewSeriesIt->creatStyleList() );
rStyleList.insert(rStyleList.end(),aList.begin(),aList.end());
}
}
bool lcl_SpecialHandlingForDonutChartNeeded(
const ::rtl::OUString & rServiceName,
const SvXMLImport & rImport )
{
bool bResult = false;
if( rServiceName.equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.DonutChartType" )))
{
bResult = SchXMLTools::isDocumentGeneratedWithOpenOfficeOlderThan2_3( rImport.GetModel() );
}
return bResult;
}
} // anonymous namespace
void lcl_ApplyDataFromRectangularRangeToDiagram(
const uno::Reference< chart2::XChartDocument >& xNewDoc
, const rtl::OUString& rRectangularRange
, ::com::sun::star::chart::ChartDataRowSource eDataRowSource
, bool bRowHasLabels, bool bColHasLabels
, bool bSwitchOnLabelsAndCategoriesForOwnData
, const rtl::OUString& sColTrans
, const rtl::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;
sal_Bool bFirstCellAsLabel =
(eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bRowHasLabels : bColHasLabels;
sal_Bool bHasCateories =
(eDataRowSource==chart::ChartDataRowSource_COLUMNS)? bColHasLabels : bRowHasLabels;
if( bSwitchOnLabelsAndCategoriesForOwnData )
{
bFirstCellAsLabel = true;
bHasCateories = true;
}
uno::Sequence< beans::PropertyValue > aArgs( 3 );
aArgs[0] = beans::PropertyValue(
::rtl::OUString::createFromAscii("CellRangeRepresentation"),
-1, uno::makeAny( rRectangularRange ),
beans::PropertyState_DIRECT_VALUE );
aArgs[1] = beans::PropertyValue(
::rtl::OUString::createFromAscii("DataRowSource"),
-1, uno::makeAny( eDataRowSource ),
beans::PropertyState_DIRECT_VALUE );
aArgs[2] = beans::PropertyValue(
::rtl::OUString::createFromAscii("FirstCellAsLabel"),
-1, uno::makeAny( bFirstCellAsLabel ),
beans::PropertyState_DIRECT_VALUE );
if( sColTrans.getLength() || sRowTrans.getLength() )
{
aArgs.realloc( aArgs.getLength() + 1 );
aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue(
::rtl::OUString::createFromAscii("SequenceMapping"),
-1, uno::makeAny( sColTrans.getLength()
? lcl_getNumberSequenceFromString( sColTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() )
: lcl_getNumberSequenceFromString( sRowTrans, bHasCateories && !xNewDoc->hasInternalDataProvider() ) ),
beans::PropertyState_DIRECT_VALUE );
}
//work around wrong writer ranges ( see Issue 58464 )
{
rtl::OUString aChartOleObjectName;
uno::Reference< frame::XModel > xModel(xNewDoc, uno::UNO_QUERY );
if( xModel.is() )
{
comphelper::MediaDescriptor aMediaDescriptor( xModel->getArgs() );
comphelper::MediaDescriptor::const_iterator aIt(
aMediaDescriptor.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "HierarchicalDocumentName" ))));
if( aIt != aMediaDescriptor.end() )
{
aChartOleObjectName = (*aIt).second.get< ::rtl::OUString >();
}
}
if( aChartOleObjectName.getLength() )
{
aArgs.realloc( aArgs.getLength() + 1 );
aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue(
::rtl::OUString::createFromAscii("ChartOleObjectName"),
-1, uno::makeAny( aChartOleObjectName ),
beans::PropertyState_DIRECT_VALUE );
}
}
uno::Reference< chart2::data::XDataSource > xDataSource(
xDataProvider->createDataSource( aArgs ));
aArgs.realloc( aArgs.getLength() + 2 );
aArgs[ aArgs.getLength() - 2 ] = beans::PropertyValue(
::rtl::OUString::createFromAscii("HasCategories"),
-1, uno::makeAny( bHasCateories ),
beans::PropertyState_DIRECT_VALUE );
aArgs[ aArgs.getLength() - 1 ] = beans::PropertyValue(
::rtl::OUString::createFromAscii("UseCategoriesAsX"),
-1, uno::makeAny( sal_False ),//categories in ODF files are not to be used as x values (independent from what is offered in our ui)
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.getLength())
{
uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getTitle(), uno::UNO_QUERY );
if( xTitleProp.is())
{
try
{
uno::Any aAny;
aAny <<= maMainTitle;
xTitleProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )), aAny );
}
catch( beans::UnknownPropertyException )
{
DBG_ERROR( "Property String for Title not available" );
}
}
}
if( maSubTitle.getLength())
{
uno::Reference< beans::XPropertySet > xTitleProp( xDoc->getSubTitle(), uno::UNO_QUERY );
if( xTitleProp.is())
{
try
{
uno::Any aAny;
aAny <<= maSubTitle;
xTitleProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "String" )), aAny );
}
catch( beans::UnknownPropertyException )
{
DBG_ERROR( "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(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Stacked")),maSeriesDefaultsAndStyles.maStackedDefault);
if( maSeriesDefaultsAndStyles.maPercentDefault.hasValue())
xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Percent")),maSeriesDefaultsAndStyles.maPercentDefault);
if( maSeriesDefaultsAndStyles.maDeepDefault.hasValue())
xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Deep")),maSeriesDefaultsAndStyles.maDeepDefault);
if( maSeriesDefaultsAndStyles.maStackedBarsConnectedDefault.hasValue())
xDiaProp->setPropertyValue(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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.equalsAscii( "." ) ) //data comes from the chart itself
bHasOwnData = true;
else if( m_aXLinkHRefAttributeToIndicateDataProvider.equalsAscii( ".." ) ) //data comes from the parent application
bHasOwnData = false;
else if( m_aXLinkHRefAttributeToIndicateDataProvider.getLength() ) //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.equalsAscii( "." ) )
{
//#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( sal_False /* bCloneExistingData */ );
}
if( bHasOwnData )
msChartAddress = ::rtl::OUString::createFromAscii("all");
bool bSwitchRangesFromOuterToInternalIfNecessary = false;
if( !bHasOwnData && mbAllRangeAddressesAvailable )
{
// special handling for stock chart (merge series together)
if( mbIsStockChart )
MergeSeriesForStockChart();
}
else if( msChartAddress.getLength() )
{
//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(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("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( uno::Exception & )
{
//try to fallback to internal data
DBG_ERROR( "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram try to fallback to internal data" );
if(!bHasOwnData)
{
bHasOwnData = true;
msChartAddress = ::rtl::OUString::createFromAscii("all");
if( !xNewDoc->hasInternalDataProvider() )
{
xNewDoc->createInternalDataProvider( sal_False /* bCloneExistingData */ );
SchXMLTableHelper::applyTableToInternalDataProvider( maTable, xNewDoc );
try
{
lcl_ApplyDataFromRectangularRangeToDiagram( xNewDoc, msChartAddress, meDataRowSource, mbRowHasLabels, mbColHasLabels, bHasOwnData, msColTrans, msRowTrans );
}
catch( uno::Exception & )
{
DBG_ERROR( "Exception during import SchXMLChartContext::lcl_ApplyDataFromRectangularRangeToDiagram fallback to internal data failed also" );
}
}
}
}
}
}
else
{
DBG_ERROR( " 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.maSeriesStyleList
, 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( 0 == maChartTypeServiceName.reverseCompareToAsciiL( RTL_CONSTASCII_STRINGPARAM( "com.sun.star.chart2.ScatterChartType" ) ) )
{
bSwitchOffLinesForScatter = true;
SchXMLSeries2Context::switchSeriesLinesOff( maSeriesDefaultsAndStyles.maSeriesStyleList );
}
}
}
SchXMLSeries2Context::setDefaultsToSeries( maSeriesDefaultsAndStyles );
// set autostyles for series and data points
const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
const SvXMLStyleContext* pStyle = NULL;
::rtl::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 );
}
}
//#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( rtl::OUString::createFromAscii( "RefreshAddInAllowed" ) , uno::makeAny( sal_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().equalsAsciiL(
RTL_CONSTASCII_STRINGPARAM("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( ::rtl::OUString::createFromAscii("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 ], OUString::createFromAscii("values-first"));
aNewSeries[i] = aSeriesSeq[ nSeriesIndex ];
// low values
lcl_MoveDataToCandleStickSeries(
uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
aNewSeries[i], OUString::createFromAscii("values-min"));
}
else
{
// low values
lcl_setRoleAtFirstSequence( aSeriesSeq[ nSeriesIndex ], OUString::createFromAscii("values-min"));
aNewSeries[i] = aSeriesSeq[ nSeriesIndex ];
}
// high values
lcl_MoveDataToCandleStickSeries(
uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
aNewSeries[i], OUString::createFromAscii("values-max"));
// close values
lcl_MoveDataToCandleStickSeries(
uno::Reference< chart2::data::XDataSource >( aSeriesSeq[ ++nSeriesIndex ], uno::UNO_QUERY_THROW ),
aNewSeries[i], OUString::createFromAscii("values-last"));
}
xDSContainer->setDataSeries( aNewSeries );
}
}
catch( uno::Exception & )
{
DBG_ERROR( "Exception while merging series for stock chart" );
}
}
SvXMLImportContext* SchXMLChartContext::CreateChildContext(
sal_uInt16 nPrefix,
const rtl::OUString& rLocalName,
const uno::Reference< xml::sax::XAttributeList >& xAttrList )
{
static const sal_Bool bTrue = sal_True;
static const uno::Any aTrueBool( &bTrue, ::getBooleanCppuType());
SvXMLImportContext* pContext = 0;
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,
maSeriesAddresses, 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( rtl::OUString::createFromAscii( "HasMainTitle" ), aTrueBool );
}
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( rtl::OUString::createFromAscii( "HasSubTitle" ), aTrueBool );
}
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.getLength() && !mbIsStockChart &&
!lcl_SpecialHandlingForDonutChartNeeded(
maChartTypeServiceName, GetImport()))
{
if( msColTrans.getLength() > 0 )
{
OSL_ASSERT( msRowTrans.getLength() == 0 );
pTableContext->setColumnPermutation( lcl_getNumberSequenceFromString( msColTrans, true ));
msColTrans = OUString();
}
else if( msRowTrans.getLength() > 0 )
{
pTableContext->setRowPermutation( lcl_getNumberSequenceFromString( msRowTrans, true ));
msRowTrans = OUString();
}
}
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 = uno::Reference< drawing::XShapes >( xSupp->getDrawPage(), uno::UNO_QUERY );
DBG_ASSERT( mxDrawPage.is(), "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
sal_Bool /* bSetSwitchData */ )
{
uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
DBG_ASSERT( xDoc.is(), "No valid document!" );
uno::Reference< frame::XModel > xModel (xDoc, uno::UNO_QUERY );
// Remove Title and Diagram ("De-InitNew")
uno::Reference< chart2::XChartDocument > xNewDoc( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
if( xNewDoc.is())
{
xNewDoc->setFirstDiagram( 0 );
uno::Reference< chart2::XTitled > xTitled( xNewDoc, uno::UNO_QUERY );
if( xTitled.is())
xTitled->setTitleObject( 0 );
}
// Set the chart type via setting the diagram.
if( rChartTypeServiceName.getLength() &&
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 rtl::OUString& rLocalName,
rtl::OUString& rTitle,
uno::Reference< drawing::XShape >& 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;
com::sun::star::awt::Point maPosition;
bool bHasXPosition=false;
bool bHasYPosition=false;
for( sal_Int16 i = 0; i < nAttrCount; i++ )
{
rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
rtl::OUString aLocalName;
rtl::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().convertMeasure( maPosition.X, aValue );
bHasXPosition = true;
}
else if( IsXMLToken( aLocalName, XML_Y ) )
{
GetImport().GetMM100UnitConverter().convertMeasure( maPosition.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( maPosition );
uno::Reference< beans::XPropertySet > xProp( mxTitleShape, uno::UNO_QUERY );
if( xProp.is())
{
const SvXMLStylesContext* pStylesCtxt = mrImportHelper.GetAutoStylesContext();
if( pStylesCtxt )
{
const SvXMLStyleContext* pStyle = pStylesCtxt->FindStyleChildContext(
mrImportHelper.GetChartFamilyID(), msAutoStyleName );
if( pStyle && pStyle->ISA( XMLPropStyleContext ))
(( XMLPropStyleContext* )pStyle )->FillPropertySet( xProp );
}
}
}
}
SvXMLImportContext* SchXMLTitleContext::CreateChildContext(
sal_uInt16 nPrefix,
const rtl::OUString& rLocalName,
const uno::Reference< xml::sax::XAttributeList >& )
{
SvXMLImportContext* pContext = 0;
if( nPrefix == XML_NAMESPACE_TEXT &&
IsXMLToken( rLocalName, XML_P ) )
{
pContext = new SchXMLParagraphContext( GetImport(), rLocalName, mrTitle );
}
else
pContext = new SvXMLImportContext( GetImport(), nPrefix, rLocalName );
return pContext;
}
// ----------------------------------------