/*************************************************************************
 *
 *  $RCSfile: SchXMLChartContext.cxx,v $
 *
 *  $Revision: 1.31 $
 *
 *  last change: $Author: obo $ $Date: 2005-07-05 10:54:44 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "SchXMLChartContext.hxx"
#include "SchXMLImport.hxx"
#include "SchXMLPlotAreaContext.hxx"
#include "SchXMLParagraphContext.hxx"
#include "SchXMLTableContext.hxx"

#ifndef _TOOLS_DEBUG_HXX
#include <tools/debug.hxx>
#endif

#ifndef _XMLOFF_XMLNMSPE_HXX
#include "xmlnmspe.hxx"
#endif
#ifndef _XMLOFF_XMLEMENT_HXX
#include "xmlement.hxx"
#endif
#ifndef _XMLOFF_XMLTOKEN_HXX
#include "xmltoken.hxx"
#endif
#ifndef _XMLOFF_NMSPMAP_HXX
#include "nmspmap.hxx"
#endif
#ifndef _XMLOFF_XMLUCONV_HXX
#include "xmluconv.hxx"
#endif
#ifndef _XMLOFF_XMLSTYLE_HXX
#include "xmlstyle.hxx"
#endif
#ifndef _XMLOFF_PRSTYLEI_HXX_
#include "prstylei.hxx"
#endif

#include "vector"

#ifndef _COM_SUN_STAR_CHART_XCHARTDOCUMENT_HPP_
#include <com/sun/star/chart/XChartDocument.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART_XDIAGRAM_HPP_
#include <com/sun/star/chart/XDiagram.hpp>
#endif
#ifndef _COM_SUN_STAR_XML_SAX_XATTRIBUTELIST_HPP_
#include <com/sun/star/xml/sax/XAttributeList.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART_CHARTLEGENDPOSITION_HPP_
#include <com/sun/star/chart/ChartLegendPosition.hpp>
#endif
#ifndef _COM_SUN_STAR_UTIL_XSTRINGMAPPING_HPP_
#include <com/sun/star/util/XStringMapping.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGESUPPLIER_HPP_
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#endif
#ifndef _COM_SUN_STAR_DRAWING_XDRAWPAGE_HPP_
#include <com/sun/star/drawing/XDrawPage.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART_CHARTDATAROWSOURCE_HPP_
#include <com/sun/star/chart/ChartDataRowSource.hpp>
#endif
#ifndef _COM_SUN_STAR_CHART_XCHARTDATAARRAY_HPP_
#include <com/sun/star/chart/XChartDataArray.hpp>
#endif

using namespace com::sun::star;
using namespace ::xmloff::token;

#define SCH_BUILDCHART(xDoc) if( xDoc->hasControllersLocked() ) {\
    xDoc->unlockControllers();\
    xDoc->lockControllers(); }

enum SchXMLChartType
{
    XML_CHART_CLASS_LINE,
    XML_CHART_CLASS_AREA,
    XML_CHART_CLASS_CIRCLE,
    XML_CHART_CLASS_RING,
    XML_CHART_CLASS_SCATTER,
    XML_CHART_CLASS_RADAR,
    XML_CHART_CLASS_BAR,
    XML_CHART_CLASS_STOCK,
    XML_CHART_CLASS_BUBBLE, // not yet implemented
    XML_CHART_CLASS_ADDIN
};

// ----------------------------------------

static __FAR_DATA SvXMLEnumMapEntry aXMLChartClassMap[] =
{
    { XML_LINE,         XML_CHART_CLASS_LINE    },
    { XML_AREA,         XML_CHART_CLASS_AREA    },
    { XML_CIRCLE,       XML_CHART_CLASS_CIRCLE  },
    { XML_RING,         XML_CHART_CLASS_RING    },
    { XML_SCATTER,      XML_CHART_CLASS_SCATTER },
    { XML_RADAR,        XML_CHART_CLASS_RADAR   },
    { XML_BAR,          XML_CHART_CLASS_BAR     },
    { XML_STOCK,        XML_CHART_CLASS_STOCK   },
    { XML_BUBBLE,       XML_CHART_CLASS_BUBBLE  },
    { XML_ADD_IN,       XML_CHART_CLASS_ADDIN   },
    { XML_TOKEN_INVALID, 0 }
};

static __FAR_DATA SvXMLEnumMapEntry aXMLLegendAlignmentMap[] =
{
//  { XML_LEFT,         chart::ChartLegendPosition_LEFT     },
    // #i35421#
    { XML_START,        chart::ChartLegendPosition_LEFT     },
    { XML_TOP,          chart::ChartLegendPosition_TOP      },
//  { XML_RIGHT,        chart::ChartLegendPosition_RIGHT    },
    // #i35421#
    { XML_END,          chart::ChartLegendPosition_RIGHT    },
    { XML_BOTTOM,       chart::ChartLegendPosition_BOTTOM   },
    { XML_TOKEN_INVALID, 0 }
};

// ----------------------------------------

SchXMLChartContext::SchXMLChartContext( SchXMLImportHelper& rImpHelper,
                                        SvXMLImport& rImport, const rtl::OUString& rLocalName ) :
        SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
        mrImportHelper( rImpHelper ),
        mbSetMainTitlePos( false ),
        mbSetSubTitlePos( false ),
        mbSetLegendPos( false ),
        mbHasOwnTable( sal_False ),
        mbHasLegend( sal_False )
{
}

SchXMLChartContext::~SchXMLChartContext()
{}

void SchXMLChartContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
{
    // parse attributes
    sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
    rtl::OUString aValue;
    const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetChartAttrTokenMap();
    awt::Size aChartSize;
    // this flag is necessarry for pie charts in the core
    sal_Bool bSetSwitchData = sal_False;
    sal_Bool bDomainForDefaultDataNeeded = sal_False;

    rtl::OUString aServiceName;
    rtl::OUString sAutoStyleName;

    for( sal_Int16 i = 0; i < nAttrCount; i++ )
    {
        rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
        rtl::OUString aLocalName;
        rtl::OUString aValue = xAttrList->getValueByIndex( i );
        USHORT nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );

        switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
        {
            case XML_TOK_CHART_CLASS:
                {
                    rtl::OUString sClassName;
                    sal_uInt16 nClassPrefix =
                        GetImport().GetNamespaceMap().GetKeyByAttrName(
                                aValue, &sClassName );
                    if( XML_NAMESPACE_CHART == nClassPrefix )
                    {
                        USHORT nEnumVal;
                        if( GetImport().GetMM100UnitConverter().convertEnum(
                                    nEnumVal, sClassName, aXMLChartClassMap ))
                        {
                            switch( nEnumVal )
                            {
                            case XML_CHART_CLASS_LINE:
                                aServiceName =
                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.chart.LineDiagram" ));
                                break;
                            case XML_CHART_CLASS_AREA:
                                aServiceName =
                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.chart.AreaDiagram" ));
                                break;
                            case XML_CHART_CLASS_CIRCLE:
                                aServiceName =
                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.chart.PieDiagram" ));
                                bSetSwitchData = sal_True;
                                break;
                            case XML_CHART_CLASS_RING:
                                aServiceName =
                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.chart.DonutDiagram" ));
                                break;
                            case XML_CHART_CLASS_SCATTER:
                                aServiceName =
                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.chart.XYDiagram" ));
                                bDomainForDefaultDataNeeded = sal_True;
                                break;
                            case XML_CHART_CLASS_RADAR:
                                aServiceName =
                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.chart.NetDiagram" ));
                                break;
                            case XML_CHART_CLASS_BAR:
                                aServiceName =
                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.chart.BarDiagram" ));
                                break;
                            case XML_CHART_CLASS_STOCK:
                                aServiceName =
                                    rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
                                        "com.sun.star.chart.StockDiagram" ));
                                break;
                            case XML_CHART_CLASS_BUBBLE:
                                DBG_ERROR( "Bubble chart not supported yet" );
                                break;
                            }
                        }
                    }
                    else if( XML_NAMESPACE_OOO == nClassPrefix )
                    {
                        // service is taken from add-in-name attribute

                        // for service charts assume domain in base type
                        // if base type doesn't use a domain this is ok,
                        // the data just grows bigger
                        bDomainForDefaultDataNeeded = sal_True;
                        aServiceName = sClassName;
                    }
                }
                break;

            case XML_TOK_CHART_WIDTH:
                GetImport().GetMM100UnitConverter().convertMeasure( aChartSize.Width, aValue );
                break;

            case XML_TOK_CHART_HEIGHT:
                GetImport().GetMM100UnitConverter().convertMeasure( aChartSize.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;
        }
    }

    InitChart (aChartSize, bDomainForDefaultDataNeeded, aServiceName, bSetSwitchData);

    // 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 );
        }
    }

    // prevent BuildChart from now on
    uno::Reference< frame::XModel > xModel( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
    if( xModel.is())
        xModel->lockControllers();
}

void SchXMLChartContext::EndElement()
{
    uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
    uno::Reference< beans::XPropertySet > xProp( 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" );
                }
/*              uno::Reference< drawing::XShape > xShape( xTitleProp, uno::UNO_QUERY );
                if( xShape.is())
                {
                    // perform build chart with new title string
                    // so that setting the position works correctly
                    if( xDoc.is())
                    {
                        xDoc->unlockControllers();
                        xDoc->lockControllers();
                    }
                    xShape->setPosition( maMainTitlePos );
                }
*/          }
        }
        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" );
                }
/*              uno::Reference< drawing::XShape > xShape( xTitleProp, uno::UNO_QUERY );
                if( xShape.is())
                {
                    // perform build chart with new title string
                    // so that setting the position works correctly
                    if( xDoc.is())
                    {
                        xDoc->unlockControllers();
                        xDoc->lockControllers();
                    }
                    xShape->setPosition( maSubTitlePos );
                }
*/          }
        }
    }


    if( mbHasOwnTable )
    {
        // apply data read in table sub-element to chart
//          SchXMLTableHelper::applyTable( maTable, maSeriesAddresses, msCategoriesAddress, xDoc );
          SchXMLTableHelper::applyTableSimple( maTable, xDoc );
    }
    else
    {
        // deprecated method
        // translate cell-address strings
        if( maSeriesAddresses.getLength() ||
            msCategoriesAddress.getLength())
        {
            uno::Reference< util::XStringMapping > xTableAddressMapper = mrImportHelper.GetTableAddressMapper();
            if( xTableAddressMapper.is())
            {
                // series
                sal_Int32 nLength = maSeriesAddresses.getLength();
                sal_Int32 nIdx;
                uno::Sequence< rtl::OUString > aStrSeq( nLength * 2 + 1 );
                sal_Bool bHasDomain = sal_False;

                for( nIdx = 0; nIdx < nLength; nIdx++ )
                {
                    aStrSeq[ nIdx * 2 ] = maSeriesAddresses[ nIdx ].DataRangeAddress;
                    aStrSeq[ nIdx * 2 + 1 ] = maSeriesAddresses[ nIdx ].LabelAddress;

                    // domains
                    if( maSeriesAddresses[ nIdx ].DomainRangeAddresses.getLength())
                    {
                        xTableAddressMapper->mapStrings( maSeriesAddresses[ nIdx ].DomainRangeAddresses );
                        bHasDomain = sal_True;
                    }
                }
                // categories
                aStrSeq[ nLength * 2 ] = msCategoriesAddress;

                // translate
                xTableAddressMapper->mapStrings( aStrSeq );

                // write back
                sal_Int32 nOffset = 0;
                for( nIdx = 0; nIdx < nLength; nIdx++ )
                {
                    // #81525# convert addresses for xy charts
                    // this should be done by calc in the future
                    if( nIdx == 0 &&
                        bHasDomain )
                    {
                        // enlarge the sequence
                        maSeriesAddresses.realloc( maSeriesAddresses.getLength() + 1 );

                        // copy the domain as first series
                        if( maSeriesAddresses[ nIdx + nOffset ].DomainRangeAddresses.getLength() > 0 )
                            maSeriesAddresses[ nIdx + nOffset ].DataRangeAddress =
                                maSeriesAddresses[ nIdx + nOffset ].DomainRangeAddresses[ 0 ];
                        // the current data range becomes the second series
                        nOffset++;
                    }

                    maSeriesAddresses[ nIdx + nOffset ].DataRangeAddress = aStrSeq[ nIdx * 2 ];
                    maSeriesAddresses[ nIdx + nOffset ].LabelAddress = aStrSeq[ nIdx * 2 + 1 ];
                }
                msCategoriesAddress = aStrSeq[ nLength * 2 ];
            }
        }
    }

    // set table references at document
    // even when having own table (Writer)
    if( xProp.is())
    {
        try
        {
            uno::Any aAny;
            if( msChartAddress.getLength())
            {
                aAny <<= msChartAddress;
                xProp->setPropertyValue( ::rtl::OUString::createFromAscii( "ChartRangeAddress" ), aAny );

                if( msTableNumberList.getLength())
                {
                    aAny <<= msTableNumberList;
                    xProp->setPropertyValue( ::rtl::OUString::createFromAscii( "TableNumberList" ), aAny );
                }
            }
            else
            {
                // deprecated
                if( msCategoriesAddress.getLength())
                {
                    aAny <<= msCategoriesAddress;
                    xProp->setPropertyValue( rtl::OUString::createFromAscii( "CategoriesRangeAddress" ), aAny );
                }

                // deprecated
                if( maSeriesAddresses.getLength())
                {
                    aAny <<= maSeriesAddresses;
                    xProp->setPropertyValue( rtl::OUString::createFromAscii( "SeriesAddresses" ), aAny );
                }
            }

            // row / col translations
            bool bHasColTrans = (msColTrans.getLength() > 0);
            bool bHasRowTrans = (msRowTrans.getLength() > 0);
            if( bHasColTrans )
            {
                uno::Sequence< sal_Int32 > aSeq = GetNumberSequenceFromString( msColTrans );
                aAny <<= aSeq;
                xProp->setPropertyValue( ::rtl::OUString::createFromAscii( "TranslatedColumns" ), aAny );
            }
            else if( bHasRowTrans )
            {
                uno::Sequence< sal_Int32 > aSeq = GetNumberSequenceFromString( msRowTrans );
                aAny <<= aSeq;
                xProp->setPropertyValue( ::rtl::OUString::createFromAscii( "TranslatedRows" ), aAny );
            }
        }
        catch( beans::UnknownPropertyException )
        {
            DBG_WARNING( "Required property not found in ChartDocument" );
        }
    }

    // allow BuildChart again
/*  uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
    if( xModel.is())
        xModel->unlockControllers();
*/
    //  Set the main title's and subtitle's positions.
    if( mbSetMainTitlePos && maMainTitle.getLength() > 0)
    {
        uno::Reference<drawing::XShape> xMainTitleShape(xDoc->getTitle(), uno::UNO_QUERY);
        if( xMainTitleShape.is())
            xMainTitleShape->setPosition( maMainTitlePos );
    }
    if( mbSetSubTitlePos && maSubTitle.getLength() > 0)
    {
        uno::Reference<drawing::XShape> xSubTitleShape(xDoc->getSubTitle(), uno::UNO_QUERY);
        if( xSubTitleShape.is())
            xSubTitleShape->setPosition( maSubTitlePos );
    }

    // set absolute legend position after (BuildChart!)
    if( mbSetLegendPos && mbHasLegend )
    {
        uno::Reference< drawing::XShape > xLegendShape( xDoc->getLegend(), uno::UNO_QUERY );
        if( xLegendShape.is())
            xLegendShape->setPosition( maLegendPos );
    }

    // #102413# BuildChart to manifest legend position
    if( xDoc->hasControllersLocked())
        xDoc->unlockControllers();

    // AF: No more BuildCharts until Initialize is called (by Draw or SaveAs).

    // BM: There should be no further BuildCharts, and it is very dangerous to
    // leave the lock status on hoping that it is changed in Draw or SaveAs
    // (OLE-Clone?).  At least it isn't for the writer flat XML filter.  So,
    // leave Controllers unlocked from now on, as this is the last line of code
    // that the Chart XML import routine will call
}

SvXMLImportContext* SchXMLChartContext::CreateChildContext(
    USHORT 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,
                                                  maSeriesAddresses, msCategoriesAddress,
                                                  msChartAddress, msTableNumberList );
            break;

        case XML_TOK_CHART_TITLE:
            if( xDoc.is())
            {
                if( xProp.is())
                {
                    uno::Any aTrueBool;
                    aTrueBool <<= (sal_Bool)(sal_True);
                    xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasMainTitle" ), aTrueBool );

                    SCH_BUILDCHART( xDoc );
                }
                uno::Reference< drawing::XShape > xTitleShape( xDoc->getTitle(), uno::UNO_QUERY );
                pContext = new SchXMLTitleContext( mrImportHelper, GetImport(),
                                                   rLocalName, maMainTitle, xTitleShape, maMainTitlePos, mbSetMainTitlePos );
            }
            break;

        case XML_TOK_CHART_SUBTITLE:
            if( xDoc.is())
            {
                if( xProp.is())
                {
                    xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasSubTitle" ), aTrueBool );
                    SCH_BUILDCHART( xDoc );
                }
                uno::Reference< drawing::XShape > xTitleShape( xDoc->getSubTitle(), uno::UNO_QUERY );
                pContext = new SchXMLTitleContext( mrImportHelper, GetImport(),
                                                   rLocalName, maSubTitle, xTitleShape, maSubTitlePos, mbSetSubTitlePos );
            }
            break;

        case XML_TOK_CHART_LEGEND:
            pContext = new SchXMLLegendContext( mrImportHelper, GetImport(), rLocalName, maLegendPos, mbSetLegendPos );
            mbHasLegend =sal_True;
            break;

        case XML_TOK_CHART_TABLE:
            pContext = new SchXMLTableContext( mrImportHelper, GetImport(), rLocalName, maTable );
            if( pContext )
            {
                mbHasOwnTable = sal_True;
                if( xProp.is())
                    try
                    {
                        xProp->setPropertyValue( ::rtl::OUString::createFromAscii( "ExportData" ), aTrueBool );
                    }
                    catch( uno::Exception )
                    {
                        DBG_ERRORFILE( "Property missing" );
                    }
            }
            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   (awt::Size aChartSize,
                                        sal_Bool bDomainForDefaultDataNeeded,
                                        rtl::OUString aServiceName,
                                        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 );
    if( xModel.is())
        xModel->lockControllers();

    //  Hide title, subtitle, and legend
    uno::Reference< beans::XPropertySet > xProp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
    if( xProp.is())
    {
        uno::Any aFalseBool;
        aFalseBool <<= (sal_Bool)(sal_False);
        try
        {
            xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasMainTitle" ), aFalseBool );
            xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasSubTitle" ), aFalseBool );
            xProp->setPropertyValue( rtl::OUString::createFromAscii( "HasLegend" ), aFalseBool );
        }
        catch( beans::UnknownPropertyException )
        {
            DBG_ERROR( "XML-Chart Import: Property not found" );
        }
    }

    //  Set the size of the draw page.
    uno::Reference< drawing::XDrawPageSupplier > xPageSupp( mrImportHelper.GetChartDocument(), uno::UNO_QUERY );
    if( xPageSupp.is())
    {
        uno::Reference< beans::XPropertySet > xPageProp( xPageSupp->getDrawPage(), uno::UNO_QUERY );
        if( xPageProp.is())
        {
            try
            {
                uno::Any aAny;
                aAny <<= (sal_Int32)( aChartSize.Width );
                xPageProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Width" )), aAny );

                aAny <<= (sal_Int32)( aChartSize.Height );
                xPageProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Height" )), aAny );
            }
            catch( beans::UnknownPropertyException )
            {
                DBG_ERROR( "Cannot set page size" );
            }
        }
    }

    //  We have to unlock the controllers and execute an implicit BuildChart because
    //  the following call to setData needs data structures created in a BuildChart.
    if( xModel.is())
        xModel->unlockControllers();

    //  Set a (logically) empty data set.  It will later be filled with the
    //  actual data.
    //  Because the chart does not work with a really empty data set a dummy data point
    //  and, if necessary, a dummy domain value (Not a number) are set.
    uno::Reference< chart::XChartDataArray > xArray( xDoc->getData(), uno::UNO_QUERY );
    if( xArray.is())
    {
        double fNan = 0.0;

        uno::Reference< chart::XChartData > xData( xDoc->getData(), uno::UNO_QUERY );
        if( xData.is())
            fNan = xData->getNotANumber();

        // attention: the data must at least be 1 x 1,
        // (or 2 x 2 for scatter charts)
        // otherwise BuildChart doesn't perform much.
        if( bDomainForDefaultDataNeeded )
        {
            uno::Sequence< uno::Sequence< double > > aAlmostEmptySeq( 2 );
            aAlmostEmptySeq[ 0 ].realloc( 2 );
            aAlmostEmptySeq[ 0 ][ 0 ] = 0.0;
            aAlmostEmptySeq[ 0 ][ 1 ] = fNan;

            aAlmostEmptySeq[ 1 ].realloc( 2 );
            aAlmostEmptySeq[ 1 ][ 0 ] = 0.0;
            aAlmostEmptySeq[ 1 ][ 1 ] = fNan;

            xArray->setData( aAlmostEmptySeq );
        }
        else
        {
            uno::Sequence< uno::Sequence< double > > aAlmostEmptySeq( 1 );
            aAlmostEmptySeq[ 0 ].realloc( 1 );
            aAlmostEmptySeq[ 0 ][ 0 ] = 0.0;

            xArray->setData( aAlmostEmptySeq );
        }
    }

    if( xModel.is())
        xModel->lockControllers();

    //  Set the chart type via setting the diagram.
    if( aServiceName.getLength() &&
        xDoc.is())
    {
        uno::Reference< lang::XMultiServiceFactory > xFact( xDoc, uno::UNO_QUERY );
        if( xFact.is())
        {
            uno::Reference< chart::XDiagram > xDia( xFact->createInstance( aServiceName ), uno::UNO_QUERY );
            if( xDia.is())
            {
                xDoc->setDiagram( xDia );

                // set data row source for pie charts to ROWS
                if( bSetSwitchData )
                {
                    uno::Reference< beans::XPropertySet > xDiaProp( xDia, uno::UNO_QUERY );
                    if( xDiaProp.is())
                    {
                        uno::Any aAny;
                        aAny <<= chart::ChartDataRowSource( chart::ChartDataRowSource_ROWS );
                        xDiaProp->setPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DataRowSource" )), aAny );
                    }
                }
            }
        }
    }

    if( xModel.is())
        xModel->unlockControllers();
}

uno::Sequence< sal_Int32 > SchXMLChartContext::GetNumberSequenceFromString( const ::rtl::OUString& rStr )
{
    const sal_Unicode aSpace( ' ' );

    // count number of entries
    ::std::vector< sal_Int32 > aVec;
    sal_Int32 nLastPos = 0;
    sal_Int32 nPos = 0;
    const sal_Int32 nSize = rStr.getLength();
    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 );
    sal_Int32* pSeqArr = aSeq.getArray();
    for( nPos = 0; nPos < nVecSize; ++nPos )
    {
        pSeqArr[ nPos ] = aVec[ nPos ];
    }
    return aSeq;
}

// ----------------------------------------

SchXMLTitleContext::SchXMLTitleContext( SchXMLImportHelper& rImpHelper, SvXMLImport& rImport,
                                        const rtl::OUString& rLocalName,
                                        rtl::OUString& rTitle,
                                        uno::Reference< drawing::XShape >& xTitleShape,
                                        awt::Point& rPosition,
                                        bool & rSetPosition ) :
        SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
        mrImportHelper( rImpHelper ),
        mrTitle( rTitle ),
        mxTitleShape( xTitleShape ),
        mrPosition( rPosition ),
        mrSetPosition( rSetPosition )
{
}

SchXMLTitleContext::~SchXMLTitleContext()
{}

void SchXMLTitleContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
{
    sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
    rtl::OUString aValue;

    if( mxTitleShape.is())
        mrPosition = mxTitleShape->getPosition();

    for( sal_Int16 i = 0; i < nAttrCount; i++ )
    {
        rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
        rtl::OUString aLocalName;
        rtl::OUString aValue = xAttrList->getValueByIndex( i );
        USHORT nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );

        if( nPrefix == XML_NAMESPACE_SVG )
        {
            if( IsXMLToken( aLocalName, XML_X ) )
            {
                GetImport().GetMM100UnitConverter().convertMeasure( mrPosition.X, aValue );
                mrSetPosition = true;
            }
            else if( IsXMLToken( aLocalName, XML_Y ) )
            {
                GetImport().GetMM100UnitConverter().convertMeasure( mrPosition.Y, aValue );
                mrSetPosition = true;
            }
        }
        else if( nPrefix == XML_NAMESPACE_CHART )
        {
            if( IsXMLToken( aLocalName, XML_STYLE_NAME ) )
                msAutoStyleName = aValue;
        }
    }

    if( mxTitleShape.is())
    {
        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(
    USHORT nPrefix,
    const rtl::OUString& rLocalName,
    const uno::Reference< xml::sax::XAttributeList >& xAttrList )
{
    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;
}

// ----------------------------------------

SchXMLLegendContext::SchXMLLegendContext( SchXMLImportHelper& rImpHelper,
                                          SvXMLImport& rImport, const rtl::OUString& rLocalName,
                                          com::sun::star::awt::Point& rPosition,
                                          bool & rSetPosition ) :
        SvXMLImportContext( rImport, XML_NAMESPACE_CHART, rLocalName ),
        mrImportHelper( rImpHelper ),
        mrPosition( rPosition ),
        mrSetPosition( rSetPosition )
{
}

void SchXMLLegendContext::StartElement( const uno::Reference< xml::sax::XAttributeList >& xAttrList )
{
    uno::Reference< chart::XChartDocument > xDoc = mrImportHelper.GetChartDocument();
    if( ! xDoc.is())
        return;

    // turn on legend
    uno::Reference< beans::XPropertySet > xDocProp( xDoc, uno::UNO_QUERY );
    if( xDocProp.is())
    {
        uno::Any aTrueBool;
        aTrueBool <<= (sal_Bool)(sal_True);
        try
        {
            xDocProp->setPropertyValue( rtl::OUString::createFromAscii( "HasLegend" ), aTrueBool );
            SCH_BUILDCHART( xDoc );

            // initialize position
            uno::Reference< drawing::XShape > xLegendShape( xDoc->getLegend(), uno::UNO_QUERY );
            if( xLegendShape.is())
                mrPosition = xLegendShape->getPosition();
        }
        catch( beans::UnknownPropertyException )
        {
            DBG_ERROR( "Property HasLegend not found" );
        }
    }

    // parse attributes
    sal_Int16 nAttrCount = xAttrList.is()? xAttrList->getLength(): 0;
    rtl::OUString aValue;
    const SvXMLTokenMap& rAttrTokenMap = mrImportHelper.GetLegendAttrTokenMap();

    awt::Point aPosition;
    uno::Reference< drawing::XShape > xLegendShape( xDoc->getLegend(), uno::UNO_QUERY );
    if( xLegendShape.is())
        aPosition = xLegendShape->getPosition();

    rtl::OUString sAutoStyleName;

    for( sal_Int16 i = 0; i < nAttrCount; i++ )
    {
        rtl::OUString sAttrName = xAttrList->getNameByIndex( i );
        rtl::OUString aLocalName;
        rtl::OUString aValue = xAttrList->getValueByIndex( i );
        USHORT nPrefix = GetImport().GetNamespaceMap().GetKeyByAttrName( sAttrName, &aLocalName );

        switch( rAttrTokenMap.Get( nPrefix, aLocalName ))
        {
            case XML_TOK_LEGEND_POSITION:
                {
                    // set anchor position
                    uno::Reference< beans::XPropertySet > xProp( xDoc->getLegend(), uno::UNO_QUERY );
                    if( xProp.is())
                    {
                        try
                        {
                            USHORT nEnumVal;
                            if( GetImport().GetMM100UnitConverter().convertEnum( nEnumVal, aValue, aXMLLegendAlignmentMap ))
                            {
                                uno::Any aAny;
                                aAny <<= (chart::ChartLegendPosition)(nEnumVal);
                                xProp->setPropertyValue( rtl::OUString::createFromAscii( "Alignment" ), aAny );
                            }
                        }
                        catch( beans::UnknownPropertyException )
                        {
                            DBG_ERROR( "Property Alignment (legend) not found" );
                        }
                    }
                }
                break;

            case XML_TOK_LEGEND_X:
                GetImport().GetMM100UnitConverter().convertMeasure( mrPosition.X, aValue );
                mrSetPosition = true;
                break;
            case XML_TOK_LEGEND_Y:
                GetImport().GetMM100UnitConverter().convertMeasure( mrPosition.Y, aValue );
                mrSetPosition = true;
                break;
            case XML_TOK_LEGEND_STYLE_NAME:
                sAutoStyleName = aValue;
        }
    }

    // set auto-styles for Area
    uno::Reference< beans::XPropertySet > xProp( xDoc->getLegend(), 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 );
        }
    }
}

SchXMLLegendContext::~SchXMLLegendContext()
{
}
