/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#include <tools/debug.hxx>

#include <com/sun/star/text/PositionLayoutDir.hpp>
#include <com/sun/star/chart/XChartDocument.hpp>

#include "unointerfacetouniqueidentifiermapper.hxx"

#include <list>

#ifndef _XMLOFF_SHAPEIMPORT_HXX
#include <xmloff/shapeimport.hxx>
#endif
#include <xmloff/xmltkmap.hxx>
#include "xmloff/xmlnmspe.hxx"
#include <xmloff/xmltoken.hxx>
#include "ximpstyl.hxx"
#include "ximpshap.hxx"
#include "sdpropls.hxx"
#include <xmloff/xmlprmap.hxx>
#include "ximp3dscene.hxx"
#include "ximp3dobject.hxx"
#include "ximpgrp.hxx"
#include "ximplink.hxx"

#include <map>
#include <vector>

using ::rtl::OUString;
using ::rtl::OUStringBuffer;

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

//////////////////////////////////////////////////////////////////////////////

struct ltint32
{
  bool operator()(const sal_Int32 p, sal_Int32 q) const
  {
    return p < q;
  }
};

typedef std::map<sal_Int32,com::sun::star::uno::Reference< com::sun::star::drawing::XShape >,ltint32> IdShapeMap;

struct ConnectionHint
{
    com::sun::star::uno::Reference< com::sun::star::drawing::XShape > mxConnector;
    sal_Bool  bStart;
    OUString aDestShapeId;
    sal_Int32 nDestGlueId;
};

struct XShapeCompareHelper
{
  bool operator()(com::sun::star::uno::Reference < com::sun::star::drawing::XShape > x1,
                  com::sun::star::uno::Reference < com::sun::star::drawing::XShape > x2 ) const
  {
    return x1.get() < x2.get();
  }
};

/** this map store all glue point id mappings for shapes that had user defined glue points. This
    is needed because on insertion the glue points will get a new and unique id */
typedef std::map<sal_Int32,sal_Int32,ltint32> GluePointIdMap;
typedef std::map< com::sun::star::uno::Reference < com::sun::star::drawing::XShape >, GluePointIdMap, XShapeCompareHelper > ShapeGluePointsMap;

/** this struct is created for each startPage() call and stores information that is needed during
    import of shapes for one page. Since pages could be nested ( notes pages inside impress ) there
    is a pointer so one can build up a stack of this structs */
struct XMLShapeImportPageContextImpl
{
    ShapeGluePointsMap      maShapeGluePointsMap;

    uno::Reference < drawing::XShapes > mxShapes;

    struct XMLShapeImportPageContextImpl* mpNext;
};

/** this class is to enable adding members to the XMLShapeImportHelper without getting incompatible */
struct XMLShapeImportHelperImpl
{
    // context for sorting shapes
    ShapeSortContext*           mpSortContext;

    IdShapeMap                  maShapeIds;

    std::vector<ConnectionHint> maConnections;

    // #88546# possibility to swich progress bar handling on/off
    sal_Bool                    mbHandleProgressBar;

    // stores the capability of the current model to create presentation shapes
    sal_Bool                    mbIsPresentationShapesSupported;
};

//////////////////////////////////////////////////////////////////////////////

XMLShapeImportHelper::XMLShapeImportHelper(
        SvXMLImport& rImporter,
        const uno::Reference< frame::XModel>& rModel,
        SvXMLImportPropertyMapper *pExtMapper )
:   mpPageContext(NULL),
    mxModel(rModel),

    mpPropertySetMapper(0L),
    mpPresPagePropsMapper(0L),
    mpStylesContext(0L),
    mpAutoStylesContext(0L),
    mpGroupShapeElemTokenMap(0L),
    mpFrameShapeElemTokenMap(0L),
    mp3DSceneShapeElemTokenMap(0L),
    mp3DObjectAttrTokenMap(0L),
    mp3DPolygonBasedAttrTokenMap(0L),
    mp3DCubeObjectAttrTokenMap(0L),
    mp3DSphereObjectAttrTokenMap(0L),
    mp3DSceneShapeAttrTokenMap(0L),
    mp3DLightAttrTokenMap(0L),
    mpPathShapeAttrTokenMap(0L),
    mpPolygonShapeAttrTokenMap(0L),
    msStartShape(RTL_CONSTASCII_USTRINGPARAM("StartShape")),
    msEndShape(RTL_CONSTASCII_USTRINGPARAM("EndShape")),
    msStartGluePointIndex(RTL_CONSTASCII_USTRINGPARAM("StartGluePointIndex")),
    msEndGluePointIndex(RTL_CONSTASCII_USTRINGPARAM("EndGluePointIndex")),

    mrImporter( rImporter )
{
    mpImpl = new XMLShapeImportHelperImpl();
    mpImpl->mpSortContext = 0;

    // #88546# init to FALSE
    mpImpl->mbHandleProgressBar = sal_False;

    mpSdPropHdlFactory = new XMLSdPropHdlFactory( rModel, rImporter );

    // set lock to avoid deletion
    mpSdPropHdlFactory->acquire();

    // construct PropertySetMapper
    UniReference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper(mpSdPropHdlFactory);
    mpPropertySetMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
    // set lock to avoid deletion
    mpPropertySetMapper->acquire();

    if( pExtMapper )
    {
        UniReference < SvXMLImportPropertyMapper > xExtMapper( pExtMapper );
        mpPropertySetMapper->ChainImportMapper( xExtMapper );
    }

    // chain text attributes
    mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaExtPropMapper(rImporter));
    mpPropertySetMapper->ChainImportMapper(XMLTextImportHelper::CreateParaDefaultExtPropMapper(rImporter));

/*
    // chain form attributes
    const UniReference< SvXMLImportPropertyMapper> xFormMapper( rImporter.GetFormImport()->getStylePropertyMapper().getBodyPtr() );
    mpPropertySetMapper->ChainImportMapper(xFormMapper);
*/

    // construct PresPagePropsMapper
    xMapper = new XMLPropertySetMapper((XMLPropertyMapEntry*)aXMLSDPresPageProps, mpSdPropHdlFactory);
    mpPresPagePropsMapper = new SvXMLImportPropertyMapper( xMapper, rImporter );
    if(mpPresPagePropsMapper)
    {
        // set lock to avoid deletion
        mpPresPagePropsMapper->acquire();
    }

    uno::Reference< lang::XServiceInfo > xInfo( rImporter.GetModel(), uno::UNO_QUERY );
    const OUString aSName( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.presentation.PresentationDocument") );
    mpImpl->mbIsPresentationShapesSupported = xInfo.is() && xInfo->supportsService( aSName );
}

//////////////////////////////////////////////////////////////////////////////

XMLShapeImportHelper::~XMLShapeImportHelper()
{
    DBG_ASSERT( mpImpl->maConnections.empty(), "XMLShapeImportHelper::restoreConnections() was not called!" );

    // cleanup factory, decrease refcount. Should lead to destruction.
    if(mpSdPropHdlFactory)
    {
        mpSdPropHdlFactory->release();
        mpSdPropHdlFactory = 0L;
    }

    // cleanup mapper, decrease refcount. Should lead to destruction.
    if(mpPropertySetMapper)
    {
        mpPropertySetMapper->release();
        mpPropertySetMapper = 0L;
    }

    // cleanup presPage mapper, decrease refcount. Should lead to destruction.
    if(mpPresPagePropsMapper)
    {
        mpPresPagePropsMapper->release();
        mpPresPagePropsMapper = 0L;
    }

    if(mpGroupShapeElemTokenMap) delete mpGroupShapeElemTokenMap;
    if(mpFrameShapeElemTokenMap) delete mpFrameShapeElemTokenMap;
/*
    if(mpShapeAttrTokenMap) delete mpShapeAttrTokenMap;
    if(mpRectShapeAttrTokenMap) delete mpRectShapeAttrTokenMap;
    if(mpLineShapeAttrTokenMap) delete mpLineShapeAttrTokenMap;
    if(mpEllipseShapeAttrTokenMap) delete mpEllipseShapeAttrTokenMap;
    if(mpTextBoxShapeAttrTokenMap) delete mpTextBoxShapeAttrTokenMap;
    if(mpControlShapeAttrTokenMap) delete mpControlShapeAttrTokenMap;
    if(mpPageShapeAttrTokenMap) delete mpPageShapeAttrTokenMap;
    if(mpGraphicObjectShapeAttrTokenMap) delete mpGraphicObjectShapeAttrTokenMap;
*/
    if(mpPolygonShapeAttrTokenMap) delete mpPolygonShapeAttrTokenMap;
    if(mpPathShapeAttrTokenMap) delete mpPathShapeAttrTokenMap;
    if(mp3DSceneShapeElemTokenMap) delete mp3DSceneShapeElemTokenMap;
    if(mp3DObjectAttrTokenMap) delete mp3DObjectAttrTokenMap;
    if(mp3DPolygonBasedAttrTokenMap) delete mp3DPolygonBasedAttrTokenMap;
    if(mp3DCubeObjectAttrTokenMap) delete mp3DCubeObjectAttrTokenMap;
    if(mp3DSphereObjectAttrTokenMap) delete mp3DSphereObjectAttrTokenMap;
    if(mp3DSceneShapeAttrTokenMap) delete mp3DSceneShapeAttrTokenMap;
    if(mp3DLightAttrTokenMap) delete mp3DLightAttrTokenMap;

    // Styles or AutoStyles context?
    if(mpStylesContext)
    {
        mpStylesContext->Clear();
        mpStylesContext->ReleaseRef();
    }

    if(mpAutoStylesContext)
    {
        mpAutoStylesContext->Clear();
        mpAutoStylesContext->ReleaseRef();
    }

    delete mpImpl;
}

//////////////////////////////////////////////////////////////////////////////



const SvXMLTokenMap& XMLShapeImportHelper::GetGroupShapeElemTokenMap()
{
    if(!mpGroupShapeElemTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry aGroupShapeElemTokenMap[] =
{
    { XML_NAMESPACE_DRAW,           XML_G,              XML_TOK_GROUP_GROUP         },
    { XML_NAMESPACE_DRAW,           XML_RECT,           XML_TOK_GROUP_RECT          },
    { XML_NAMESPACE_DRAW,           XML_LINE,           XML_TOK_GROUP_LINE          },
    { XML_NAMESPACE_DRAW,           XML_CIRCLE,         XML_TOK_GROUP_CIRCLE        },
    { XML_NAMESPACE_DRAW,           XML_ELLIPSE,        XML_TOK_GROUP_ELLIPSE       },
    { XML_NAMESPACE_DRAW,           XML_POLYGON,        XML_TOK_GROUP_POLYGON       },
    { XML_NAMESPACE_DRAW,           XML_POLYLINE,       XML_TOK_GROUP_POLYLINE      },
    { XML_NAMESPACE_DRAW,           XML_PATH,           XML_TOK_GROUP_PATH          },

    { XML_NAMESPACE_DRAW,           XML_CONTROL,        XML_TOK_GROUP_CONTROL       },
    { XML_NAMESPACE_DRAW,           XML_CONNECTOR,      XML_TOK_GROUP_CONNECTOR     },
    { XML_NAMESPACE_DRAW,           XML_MEASURE,        XML_TOK_GROUP_MEASURE       },
    { XML_NAMESPACE_DRAW,           XML_PAGE_THUMBNAIL, XML_TOK_GROUP_PAGE          },
    { XML_NAMESPACE_DRAW,           XML_CAPTION,        XML_TOK_GROUP_CAPTION       },

    { XML_NAMESPACE_CHART,          XML_CHART,          XML_TOK_GROUP_CHART         },
    { XML_NAMESPACE_DR3D,           XML_SCENE,          XML_TOK_GROUP_3DSCENE       },

    { XML_NAMESPACE_DRAW,           XML_FRAME,          XML_TOK_GROUP_FRAME         },
    { XML_NAMESPACE_DRAW,           XML_CUSTOM_SHAPE,   XML_TOK_GROUP_CUSTOM_SHAPE  },

    { XML_NAMESPACE_DRAW,           XML_CUSTOM_SHAPE,   XML_TOK_GROUP_CUSTOM_SHAPE  },
    { XML_NAMESPACE_OFFICE,         XML_ANNOTATION,     XML_TOK_GROUP_ANNOTATION    },
    { XML_NAMESPACE_DRAW,           XML_A,              XML_TOK_GROUP_A             },

    XML_TOKEN_MAP_END
};

        mpGroupShapeElemTokenMap = new SvXMLTokenMap(aGroupShapeElemTokenMap);
    } // if(!mpGroupShapeElemTokenMap)

    return *mpGroupShapeElemTokenMap;
}

const SvXMLTokenMap& XMLShapeImportHelper::GetFrameShapeElemTokenMap()
{
    if(!mpFrameShapeElemTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry aFrameShapeElemTokenMap[] =
{
    { XML_NAMESPACE_DRAW,           XML_TEXT_BOX,       XML_TOK_FRAME_TEXT_BOX      },
    { XML_NAMESPACE_DRAW,           XML_IMAGE,          XML_TOK_FRAME_IMAGE         },
    { XML_NAMESPACE_DRAW,           XML_OBJECT,         XML_TOK_FRAME_OBJECT        },
    { XML_NAMESPACE_DRAW,           XML_OBJECT_OLE,     XML_TOK_FRAME_OBJECT_OLE    },
    { XML_NAMESPACE_DRAW,           XML_PLUGIN,         XML_TOK_FRAME_PLUGIN        },
    { XML_NAMESPACE_DRAW,           XML_FLOATING_FRAME, XML_TOK_FRAME_FLOATING_FRAME},
    { XML_NAMESPACE_DRAW,           XML_APPLET,         XML_TOK_FRAME_APPLET        },
    { XML_NAMESPACE_TABLE,          XML_TABLE,          XML_TOK_FRAME_TABLE         },
    XML_TOKEN_MAP_END
};

        mpFrameShapeElemTokenMap = new SvXMLTokenMap(aFrameShapeElemTokenMap);
    } // if(!mpFrameShapeElemTokenMap)

    return *mpFrameShapeElemTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::Get3DSceneShapeElemTokenMap()
{
    if(!mp3DSceneShapeElemTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry a3DSceneShapeElemTokenMap[] =
{
    { XML_NAMESPACE_DR3D,           XML_SCENE,      XML_TOK_3DSCENE_3DSCENE     },
    { XML_NAMESPACE_DR3D,           XML_CUBE,       XML_TOK_3DSCENE_3DCUBE      },
    { XML_NAMESPACE_DR3D,           XML_SPHERE,     XML_TOK_3DSCENE_3DSPHERE    },
    { XML_NAMESPACE_DR3D,           XML_ROTATE,     XML_TOK_3DSCENE_3DLATHE     },
    { XML_NAMESPACE_DR3D,           XML_EXTRUDE,    XML_TOK_3DSCENE_3DEXTRUDE   },
    XML_TOKEN_MAP_END
};

        mp3DSceneShapeElemTokenMap = new SvXMLTokenMap(a3DSceneShapeElemTokenMap);
    } // if(!mp3DSceneShapeElemTokenMap)

    return *mp3DSceneShapeElemTokenMap;
}

//////////////////////////////////////////////////////////////////////////////
/*

const SvXMLTokenMap& XMLShapeImportHelper::GetShapeAttrTokenMap()
{
    if(!mpShapeAttrTokenMap)
    {
    static __FAR_DATA SvXMLTokenMapEntry aShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_DRAW,           XML_NAME,               XML_TOK_SHAPE_NAME                          },
    { XML_NAMESPACE_DRAW,           XML_STYLE_NAME,         XML_TOK_SHAPE_DRAWSTYLE_NAME_GRAPHICS       },
    { XML_NAMESPACE_PRESENTATION,   XML_CLASS,              XML_TOK_SHAPE_PRESENTATION_CLASS            },
    { XML_NAMESPACE_PRESENTATION,   XML_STYLE_NAME,         XML_TOK_SHAPE_DRAWSTYLE_NAME_PRESENTATION   },
    { XML_NAMESPACE_SVG,            XML_TRANSFORM,          XML_TOK_SHAPE_TRANSFORM                     },
    { XML_NAMESPACE_PRESENTATION,   XML_PLACEHOLDER,        XML_TOK_SHAPE_IS_PLACEHOLDER                },
    { XML_NAMESPACE_PRESENTATION,   XML_USER_TRANSFORMED,   XML_TOK_SHAPE_IS_USER_TRANSFORMED           },
    XML_TOKEN_MAP_END
};

        mpShapeAttrTokenMap = new SvXMLTokenMap(aShapeAttrTokenMap);
        }

    return *mpShapeAttrTokenMap;
}
*/
//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::Get3DObjectAttrTokenMap()
{
    if(!mp3DObjectAttrTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry a3DObjectAttrTokenMap[] =
{
    { XML_NAMESPACE_DRAW,           XML_STYLE_NAME,         XML_TOK_3DOBJECT_DRAWSTYLE_NAME     },
    { XML_NAMESPACE_DR3D,           XML_TRANSFORM,          XML_TOK_3DOBJECT_TRANSFORM          },
    XML_TOKEN_MAP_END
};

        mp3DObjectAttrTokenMap = new SvXMLTokenMap(a3DObjectAttrTokenMap);
    } // if(!mp3DObjectAttrTokenMap)

    return *mp3DObjectAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::Get3DPolygonBasedAttrTokenMap()
{
    if(!mp3DPolygonBasedAttrTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry a3DPolygonBasedAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,            XML_VIEWBOX,            XML_TOK_3DPOLYGONBASED_VIEWBOX      },
    { XML_NAMESPACE_SVG,            XML_D,                  XML_TOK_3DPOLYGONBASED_D            },
    XML_TOKEN_MAP_END
};

        mp3DPolygonBasedAttrTokenMap = new SvXMLTokenMap(a3DPolygonBasedAttrTokenMap);
    } // if(!mp3DPolygonBasedAttrTokenMap)

    return *mp3DPolygonBasedAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::Get3DCubeObjectAttrTokenMap()
{
    if(!mp3DCubeObjectAttrTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry a3DCubeObjectAttrTokenMap[] =
{
    { XML_NAMESPACE_DR3D,           XML_MIN_EDGE,           XML_TOK_3DCUBEOBJ_MINEDGE   },
    { XML_NAMESPACE_DR3D,           XML_MAX_EDGE,           XML_TOK_3DCUBEOBJ_MAXEDGE   },
    XML_TOKEN_MAP_END
};

        mp3DCubeObjectAttrTokenMap = new SvXMLTokenMap(a3DCubeObjectAttrTokenMap);
    } // if(!mp3DCubeObjectAttrTokenMap)

    return *mp3DCubeObjectAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::Get3DSphereObjectAttrTokenMap()
{
    if(!mp3DSphereObjectAttrTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry a3DSphereObjectAttrTokenMap[] =
{
    { XML_NAMESPACE_DR3D,           XML_CENTER,             XML_TOK_3DSPHEREOBJ_CENTER  },
    { XML_NAMESPACE_DR3D,           XML_SIZE,               XML_TOK_3DSPHEREOBJ_SIZE    },
    XML_TOKEN_MAP_END
};

        mp3DSphereObjectAttrTokenMap = new SvXMLTokenMap(a3DSphereObjectAttrTokenMap);
    } // if(!mp3DSphereObjectAttrTokenMap)

    return *mp3DSphereObjectAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////
/*

const SvXMLTokenMap& XMLShapeImportHelper::GetRectShapeAttrTokenMap()
{
    if(!mpRectShapeAttrTokenMap)
    {
    static __FAR_DATA SvXMLTokenMapEntry aRectShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_X,                  XML_TOK_RECTSHAPE_X                 },
    { XML_NAMESPACE_SVG,    XML_Y,                  XML_TOK_RECTSHAPE_Y                 },
    { XML_NAMESPACE_SVG,    XML_WIDTH,              XML_TOK_RECTSHAPE_WIDTH             },
    { XML_NAMESPACE_SVG,    XML_HEIGHT,             XML_TOK_RECTSHAPE_HEIGHT            },
    { XML_NAMESPACE_DRAW,   XML_CORNER_RADIUS,      XML_TOK_RECTSHAPE_CORNER_RADIUS     },
    XML_TOKEN_MAP_END
};

        mpRectShapeAttrTokenMap = new SvXMLTokenMap(aRectShapeAttrTokenMap);
        }

    return *mpRectShapeAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::GetLineShapeAttrTokenMap()
{
    if(!mpLineShapeAttrTokenMap)
    {
    static __FAR_DATA SvXMLTokenMapEntry aLineShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_X1,             XML_TOK_LINESHAPE_X1                },
    { XML_NAMESPACE_SVG,    XML_Y1,             XML_TOK_LINESHAPE_Y1                },
    { XML_NAMESPACE_SVG,    XML_X2,             XML_TOK_LINESHAPE_X2                },
    { XML_NAMESPACE_SVG,    XML_Y2,             XML_TOK_LINESHAPE_Y2                },
    XML_TOKEN_MAP_END
};

        mpLineShapeAttrTokenMap = new SvXMLTokenMap(aLineShapeAttrTokenMap);
        }

    return *mpLineShapeAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::GetEllipseShapeAttrTokenMap()
{
    if(!mpEllipseShapeAttrTokenMap)
    {
    static __FAR_DATA SvXMLTokenMapEntry aEllipseShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_RX,             XML_TOK_ELLIPSESHAPE_RX             },
    { XML_NAMESPACE_SVG,    XML_RY,             XML_TOK_ELLIPSESHAPE_RY             },
    { XML_NAMESPACE_SVG,    XML_CX,             XML_TOK_ELLIPSESHAPE_CX             },
    { XML_NAMESPACE_SVG,    XML_CY,             XML_TOK_ELLIPSESHAPE_CY             },
    { XML_NAMESPACE_SVG,    XML_R,              XML_TOK_ELLIPSESHAPE_R              },
    XML_TOKEN_MAP_END
};

        mpEllipseShapeAttrTokenMap = new SvXMLTokenMap(aEllipseShapeAttrTokenMap);
        }

    return *mpEllipseShapeAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////
*/

const SvXMLTokenMap& XMLShapeImportHelper::GetPolygonShapeAttrTokenMap()
{
    if(!mpPolygonShapeAttrTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry aPolygonShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_VIEWBOX,            XML_TOK_POLYGONSHAPE_VIEWBOX        },
    { XML_NAMESPACE_DRAW,   XML_POINTS,             XML_TOK_POLYGONSHAPE_POINTS         },
    XML_TOKEN_MAP_END
};

        mpPolygonShapeAttrTokenMap = new SvXMLTokenMap(aPolygonShapeAttrTokenMap);
    } // if(!mpPolygonShapeAttrTokenMap)

    return *mpPolygonShapeAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::GetPathShapeAttrTokenMap()
{
    if(!mpPathShapeAttrTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry aPathShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_VIEWBOX,            XML_TOK_PATHSHAPE_VIEWBOX           },
    { XML_NAMESPACE_SVG,    XML_D,                  XML_TOK_PATHSHAPE_D                 },
    XML_TOKEN_MAP_END
};

        mpPathShapeAttrTokenMap = new SvXMLTokenMap(aPathShapeAttrTokenMap);
    } // if(!mpPathShapeAttrTokenMap)

    return *mpPathShapeAttrTokenMap;
}
/*
//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::GetTextBoxShapeAttrTokenMap()
{
    if(!mpTextBoxShapeAttrTokenMap)
    {
    static __FAR_DATA SvXMLTokenMapEntry aTextBoxShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_X,                  XML_TOK_TEXTBOXSHAPE_X              },
    { XML_NAMESPACE_SVG,    XML_Y,                  XML_TOK_TEXTBOXSHAPE_Y              },
    { XML_NAMESPACE_SVG,    XML_WIDTH,              XML_TOK_TEXTBOXSHAPE_WIDTH          },
    { XML_NAMESPACE_SVG,    XML_HEIGHT,             XML_TOK_TEXTBOXSHAPE_HEIGHT         },
    XML_TOKEN_MAP_END
};

        mpTextBoxShapeAttrTokenMap = new SvXMLTokenMap(aTextBoxShapeAttrTokenMap);
        }

    return *mpTextBoxShapeAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::GetControlShapeAttrTokenMap()
{
    if(!mpControlShapeAttrTokenMap)
    {
    static __FAR_DATA SvXMLTokenMapEntry aControlShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_X,                  XML_TOK_CONTROLSHAPE_X              },
    { XML_NAMESPACE_SVG,    XML_Y,                  XML_TOK_CONTROLSHAPE_Y              },
    { XML_NAMESPACE_SVG,    XML_WIDTH,              XML_TOK_CONTROLSHAPE_WIDTH          },
    { XML_NAMESPACE_SVG,    XML_HEIGHT,             XML_TOK_CONTROLSHAPE_HEIGHT         },
    XML_TOKEN_MAP_END
};

        mpControlShapeAttrTokenMap = new SvXMLTokenMap(aControlShapeAttrTokenMap);
        }

    return *mpControlShapeAttrTokenMap;
}
*/
//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::Get3DSceneShapeAttrTokenMap()
{
    if(!mp3DSceneShapeAttrTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry a3DSceneShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_DR3D,   XML_TRANSFORM,          XML_TOK_3DSCENESHAPE_TRANSFORM      },
    { XML_NAMESPACE_DR3D,   XML_VRP,                XML_TOK_3DSCENESHAPE_VRP            },
    { XML_NAMESPACE_DR3D,   XML_VPN,                XML_TOK_3DSCENESHAPE_VPN            },
    { XML_NAMESPACE_DR3D,   XML_VUP,                XML_TOK_3DSCENESHAPE_VUP            },
    { XML_NAMESPACE_DR3D,   XML_PROJECTION,         XML_TOK_3DSCENESHAPE_PROJECTION     },
    { XML_NAMESPACE_DR3D,   XML_DISTANCE,           XML_TOK_3DSCENESHAPE_DISTANCE       },
    { XML_NAMESPACE_DR3D,   XML_FOCAL_LENGTH,       XML_TOK_3DSCENESHAPE_FOCAL_LENGTH   },
    { XML_NAMESPACE_DR3D,   XML_SHADOW_SLANT,       XML_TOK_3DSCENESHAPE_SHADOW_SLANT   },
    { XML_NAMESPACE_DR3D,   XML_SHADE_MODE,         XML_TOK_3DSCENESHAPE_SHADE_MODE     },
    { XML_NAMESPACE_DR3D,   XML_AMBIENT_COLOR,      XML_TOK_3DSCENESHAPE_AMBIENT_COLOR  },
    { XML_NAMESPACE_DR3D,   XML_LIGHTING_MODE,      XML_TOK_3DSCENESHAPE_LIGHTING_MODE  },
    XML_TOKEN_MAP_END
};

        mp3DSceneShapeAttrTokenMap = new SvXMLTokenMap(a3DSceneShapeAttrTokenMap);
    } // if(!mp3DSceneShapeAttrTokenMap)

    return *mp3DSceneShapeAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::Get3DLightAttrTokenMap()
{
    if(!mp3DLightAttrTokenMap)
    {
        static __FAR_DATA SvXMLTokenMapEntry a3DLightAttrTokenMap[] =
{
    { XML_NAMESPACE_DR3D,   XML_DIFFUSE_COLOR,      XML_TOK_3DLIGHT_DIFFUSE_COLOR       },
    { XML_NAMESPACE_DR3D,   XML_DIRECTION,          XML_TOK_3DLIGHT_DIRECTION           },
    { XML_NAMESPACE_DR3D,   XML_ENABLED,            XML_TOK_3DLIGHT_ENABLED             },
    { XML_NAMESPACE_DR3D,   XML_SPECULAR,           XML_TOK_3DLIGHT_SPECULAR            },
    XML_TOKEN_MAP_END
};

        mp3DLightAttrTokenMap = new SvXMLTokenMap(a3DLightAttrTokenMap);
    } // if(!mp3DLightAttrTokenMap)

    return *mp3DLightAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////
/*

const SvXMLTokenMap& XMLShapeImportHelper::GetPageShapeAttrTokenMap()
{
    if(!mpPageShapeAttrTokenMap)
    {
    static __FAR_DATA SvXMLTokenMapEntry aPageShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_X,                  XML_TOK_PAGESHAPE_X             },
    { XML_NAMESPACE_SVG,    XML_Y,                  XML_TOK_PAGESHAPE_Y             },
    { XML_NAMESPACE_SVG,    XML_WIDTH,              XML_TOK_PAGESHAPE_WIDTH         },
    { XML_NAMESPACE_SVG,    XML_HEIGHT,             XML_TOK_PAGESHAPE_HEIGHT        },
    XML_TOKEN_MAP_END
};

        mpPageShapeAttrTokenMap = new SvXMLTokenMap(aPageShapeAttrTokenMap);
        }

    return *mpPageShapeAttrTokenMap;
}

//////////////////////////////////////////////////////////////////////////////


const SvXMLTokenMap& XMLShapeImportHelper::GetGraphicObjectShapeAttrTokenMap()
{
    if(!mpGraphicObjectShapeAttrTokenMap)
    {
    static __FAR_DATA SvXMLTokenMapEntry aGraphicObjectShapeAttrTokenMap[] =
{
    { XML_NAMESPACE_SVG,    XML_X,                  XML_TOK_GOSHAPE_X                   },
    { XML_NAMESPACE_SVG,    XML_Y,                  XML_TOK_GOSHAPE_Y                   },
    { XML_NAMESPACE_SVG,    XML_WIDTH,              XML_TOK_GOSHAPE_WIDTH               },
    { XML_NAMESPACE_SVG,    XML_HEIGHT,             XML_TOK_GOSHAPE_HEIGHT              },
    { XML_NAMESPACE_XLINK,  XML_HREF,               XML_TOK_GOSHAPE_URL                 },
    XML_TOKEN_MAP_END
};

        mpGraphicObjectShapeAttrTokenMap = new SvXMLTokenMap(aGraphicObjectShapeAttrTokenMap);
        }

    return *mpGraphicObjectShapeAttrTokenMap;
}
*/
//////////////////////////////////////////////////////////////////////////////

SvXMLShapeContext* XMLShapeImportHelper::Create3DSceneChildContext(
    SvXMLImport& rImport,
    USHORT p_nPrefix,
    const OUString& rLocalName,
    const uno::Reference< xml::sax::XAttributeList>& xAttrList,
    uno::Reference< drawing::XShapes >& rShapes)
{
    SdXMLShapeContext *pContext = 0L;

    if(rShapes.is())
    {
        const SvXMLTokenMap& rTokenMap = Get3DSceneShapeElemTokenMap();
        switch(rTokenMap.Get(p_nPrefix, rLocalName))
        {
            case XML_TOK_3DSCENE_3DSCENE:
            {
                // dr3d:3dscene inside dr3d:3dscene context
                pContext = new SdXML3DSceneShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False);
                break;
            }
            case XML_TOK_3DSCENE_3DCUBE:
            {
                // dr3d:3dcube inside dr3d:3dscene context
                pContext = new SdXML3DCubeObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False);
                break;
            }
            case XML_TOK_3DSCENE_3DSPHERE:
            {
                // dr3d:3dsphere inside dr3d:3dscene context
                pContext = new SdXML3DSphereObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False);
                break;
            }
            case XML_TOK_3DSCENE_3DLATHE:
            {
                // dr3d:3dlathe inside dr3d:3dscene context
                pContext = new SdXML3DLatheObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False);
                break;
            }
            case XML_TOK_3DSCENE_3DEXTRUDE:
            {
                // dr3d:3dextrude inside dr3d:3dscene context
                pContext = new SdXML3DExtrudeObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False);
                break;
            }
        }
    }

    // now parse the attribute list and call the child context for each unknown attribute
    sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
    for(sal_Int16 a(0); a < nAttrCount; a++)
    {
        const OUString& rAttrName = xAttrList->getNameByIndex(a);
        OUString aLocalName;
        sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
        const OUString aValue( xAttrList->getValueByIndex(a) );

        pContext->processAttribute( nPrefix, aLocalName, aValue );
    }

    return pContext;
}

//////////////////////////////////////////////////////////////////////////////

void XMLShapeImportHelper::SetStylesContext(SvXMLStylesContext* pNew)
{
    mpStylesContext = pNew;
    mpStylesContext->AddRef();
}

//////////////////////////////////////////////////////////////////////////////

void XMLShapeImportHelper::SetAutoStylesContext(SvXMLStylesContext* pNew)
{
    mpAutoStylesContext = pNew;
    mpAutoStylesContext->AddRef();
}

//////////////////////////////////////////////////////////////////////////////

SvXMLShapeContext* XMLShapeImportHelper::CreateGroupChildContext(
    SvXMLImport& rImport,
    USHORT p_nPrefix,
    const OUString& rLocalName,
    const uno::Reference< xml::sax::XAttributeList>& xAttrList,
    uno::Reference< drawing::XShapes >& rShapes,
    sal_Bool bTemporaryShape)
{
    SdXMLShapeContext *pContext = 0L;

    const SvXMLTokenMap& rTokenMap = GetGroupShapeElemTokenMap();
    sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;

    switch(rTokenMap.Get(p_nPrefix, rLocalName))
    {
        case XML_TOK_GROUP_GROUP:
        {
            // draw:g inside group context (RECURSIVE)
            pContext = new SdXMLGroupShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
            break;
        }
        case XML_TOK_GROUP_3DSCENE:
        {
            // dr3d:3dscene inside group context
            pContext = new SdXML3DSceneShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
            break;
        }
        case XML_TOK_GROUP_RECT:
        {
            // draw:rect inside group context
            pContext = new SdXMLRectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_LINE:
        {
            // draw:line inside group context
            pContext = new SdXMLLineShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_CIRCLE:
        case XML_TOK_GROUP_ELLIPSE:
        {
            // draw:circle or draw:ellipse inside group context
            pContext = new SdXMLEllipseShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_POLYGON:
        case XML_TOK_GROUP_POLYLINE:
        {
            // draw:polygon or draw:polyline inside group context
            pContext = new SdXMLPolygonShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes,
                rTokenMap.Get(p_nPrefix, rLocalName) == XML_TOK_GROUP_POLYGON ? TRUE : FALSE, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_PATH:
        {
            // draw:path inside group context
            pContext = new SdXMLPathShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape);
            break;
        }
        case XML_TOK_GROUP_FRAME:
        {
            // text:text-box inside group context
            pContext = new SdXMLFrameShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_CONTROL:
        {
            // draw:control inside group context
            pContext = new SdXMLControlShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_CONNECTOR:
        {
            // draw:connector inside group context
            pContext = new SdXMLConnectorShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_MEASURE:
        {
            // draw:measure inside group context
            pContext = new SdXMLMeasureShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_PAGE:
        {
            // draw:page inside group context
            pContext = new SdXMLPageShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_CAPTION:
        case XML_TOK_GROUP_ANNOTATION:
        {
            // draw:caption inside group context
            pContext = new SdXMLCaptionShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_CHART:
        {
            // chart:chart inside group context
            pContext = new SdXMLChartShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, bTemporaryShape );
            break;
        }
        case XML_TOK_GROUP_CUSTOM_SHAPE:
        {
            // draw:customshape
            pContext = new SdXMLCustomShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False );
            break;
        }
         case XML_TOK_GROUP_A:
         {
             return new SdXMLShapeLinkContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
         }
        // add other shapes here...
        default:
            return new SvXMLShapeContext( rImport, p_nPrefix, rLocalName, bTemporaryShape );
    }

    // now parse the attribute list and call the child context for each unknown attribute
    for(sal_Int16 a(0); a < nAttrCount; a++)
    {
        const OUString& rAttrName = xAttrList->getNameByIndex(a);
        OUString aLocalName;
        sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
        const OUString aValue( xAttrList->getValueByIndex(a) );

        pContext->processAttribute( nPrefix, aLocalName, aValue );
    }

    return pContext;
}

// This method is called from SdXMLFrameContext to create children of drawe:frame
SvXMLShapeContext* XMLShapeImportHelper::CreateFrameChildContext(
    SvXMLImport& rImport,
    USHORT p_nPrefix,
    const OUString& rLocalName,
    const uno::Reference< xml::sax::XAttributeList>& rAttrList,
    uno::Reference< drawing::XShapes >& rShapes,
    const uno::Reference< xml::sax::XAttributeList>& rFrameAttrList)
{
    SdXMLShapeContext *pContext = 0L;

    const SvXMLTokenMap& rTokenMap = GetFrameShapeElemTokenMap();

    SvXMLAttributeList *pAttrList = new SvXMLAttributeList( rAttrList );
    if( rFrameAttrList.is() )
        pAttrList->AppendAttributeList( rFrameAttrList );
    uno::Reference < xml::sax::XAttributeList > xAttrList = pAttrList;


    switch(rTokenMap.Get(p_nPrefix, rLocalName))
    {
        case XML_TOK_FRAME_TEXT_BOX:
        {
            // text:text-box inside group context
            pContext = new SdXMLTextBoxShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False );
            break;
        }
        case XML_TOK_FRAME_IMAGE:
        {
            // office:image inside group context
            pContext = new SdXMLGraphicObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False );
            break;
        }
        case XML_TOK_FRAME_OBJECT:
        case XML_TOK_FRAME_OBJECT_OLE:
        {
            // draw:object or draw:object_ole
            pContext = new SdXMLObjectShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False );
            break;
        }
        case XML_TOK_FRAME_TABLE:
        {
            // draw:object or draw:object_ole
            if( rImport.IsTableShapeSupported() )
                pContext = new SdXMLTableShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes );
            break;

        }
        case XML_TOK_FRAME_PLUGIN:
        {
            // draw:plugin
            pContext = new SdXMLPluginShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False );
            break;
        }
        case XML_TOK_FRAME_FLOATING_FRAME:
        {
            // draw:floating-frame
            pContext = new SdXMLFloatingFrameShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False );
            break;
        }
        case XML_TOK_FRAME_APPLET:
        {
            // draw:applet
            pContext = new SdXMLAppletShapeContext( rImport, p_nPrefix, rLocalName, xAttrList, rShapes, sal_False );
            break;
        }
        // add other shapes here...
        default:
            break;
    }

    if( pContext )
    {
        // now parse the attribute list and call the child context for each unknown attribute
        sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
        for(sal_Int16 a(0); a < nAttrCount; a++)
        {
            const OUString& rAttrName = xAttrList->getNameByIndex(a);
            OUString aLocalName;
            sal_uInt16 nPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(rAttrName, &aLocalName);
            const OUString aValue( xAttrList->getValueByIndex(a) );

            pContext->processAttribute( nPrefix, aLocalName, aValue );
        }
    }

    return pContext;
}

SvXMLImportContext *XMLShapeImportHelper::CreateFrameChildContext(
    SvXMLImportContext *pThisContext,
    USHORT nPrefix,
    const OUString& rLocalName,
    const uno::Reference< xml::sax::XAttributeList>& xAttrList )
{
    SvXMLImportContext * pContext = NULL;

    SdXMLFrameShapeContext *pFrameContext = PTR_CAST( SdXMLFrameShapeContext, pThisContext );
    if( pFrameContext )
        pContext = pFrameContext->CreateChildContext( nPrefix, rLocalName, xAttrList );

    return pContext;
}


/** this function is called whenever the implementation classes like to add this new
    shape to the given XShapes.
*/
void XMLShapeImportHelper::addShape( uno::Reference< drawing::XShape >& rShape,
                                     const uno::Reference< xml::sax::XAttributeList >&,
                                     uno::Reference< drawing::XShapes >& rShapes)
{
    if( rShape.is() && rShapes.is() )
    {
        // add new shape to parent
        rShapes->add( rShape );
    }
}

/** this function is called whenever the implementation classes have finished importing
    a shape to the given XShapes. The shape is already inserted into its XShapes and
    all properties and styles are set.
*/
void XMLShapeImportHelper::finishShape(
        com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& rShape,
        const com::sun::star::uno::Reference< com::sun::star::xml::sax::XAttributeList >&,
        com::sun::star::uno::Reference< com::sun::star::drawing::XShapes >&)
{
    // --> OD 2004-08-10 #i28749#, #i36248# - set property <PositionLayoutDir>
    // to <PositionInHoriL2R>, if it exists and the import states that
    // the shape positioning attributes are in horizontal left-to-right
    // layout. This is the case for the OpenOffice.org file format.
    // This setting is done for Writer documents, because the property
    // only exists at service com::sun::star::text::Shape - the Writer
    // UNO service for shapes.
    // The value indicates that the positioning attributes are given
    // in horizontal left-to-right layout. The property is evaluated
    // during the first positioning of the shape in order to convert
    // the shape position given in the OpenOffice.org file format to
    // the one for the OASIS Open Office file format.
    uno::Reference< beans::XPropertySet > xPropSet(rShape, uno::UNO_QUERY);
    if ( xPropSet.is() )
    {
        if ( mrImporter.IsShapePositionInHoriL2R() &&
             xPropSet->getPropertySetInfo()->hasPropertyByName(
                OUString(RTL_CONSTASCII_USTRINGPARAM("PositionLayoutDir"))) )
        {
            uno::Any aPosLayoutDir;
            aPosLayoutDir <<= text::PositionLayoutDir::PositionInHoriL2R;
            xPropSet->setPropertyValue(
                OUString(RTL_CONSTASCII_USTRINGPARAM("PositionLayoutDir")),
                aPosLayoutDir );
        }
    }
    // <--
}

// helper functions for z-order sorting
struct ZOrderHint
{
    sal_Int32 nIs;
    sal_Int32 nShould;

    int operator<(const ZOrderHint& rComp) const { return nShould < rComp.nShould; }
};

class ShapeSortContext
{
public:
    uno::Reference< drawing::XShapes > mxShapes;
    list<ZOrderHint>              maZOrderList;
    list<ZOrderHint>              maUnsortedList;

    sal_Int32                     mnCurrentZ;
    ShapeSortContext*             mpParentContext;
    const OUString                msZOrder;

    ShapeSortContext( uno::Reference< drawing::XShapes >& rShapes, ShapeSortContext* pParentContext = NULL );

    void moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos );
};

ShapeSortContext::ShapeSortContext( uno::Reference< drawing::XShapes >& rShapes, ShapeSortContext* pParentContext )
:   mxShapes( rShapes ), mnCurrentZ( 0 ), mpParentContext( pParentContext ),
    msZOrder(RTL_CONSTASCII_USTRINGPARAM("ZOrder"))
{
}

void ShapeSortContext::moveShape( sal_Int32 nSourcePos, sal_Int32 nDestPos )
{
    uno::Any aAny( mxShapes->getByIndex( nSourcePos ) );
    uno::Reference< beans::XPropertySet > xPropSet;
    aAny >>= xPropSet;

    if( xPropSet.is() && xPropSet->getPropertySetInfo()->hasPropertyByName( msZOrder ) )
    {
        aAny <<= nDestPos;
        xPropSet->setPropertyValue( msZOrder, aAny );

        list<ZOrderHint>::iterator aIter = maZOrderList.begin();
        list<ZOrderHint>::iterator aEnd = maZOrderList.end();

        while( aIter != aEnd )
        {
            if( (*aIter).nIs < nSourcePos )
            {
                DBG_ASSERT( (*aIter).nIs >= nDestPos, "Shape sorting failed" );
                (*aIter).nIs++;
            }
            aIter++;
        }

        aIter = maUnsortedList.begin();
        aEnd = maUnsortedList.end();

        while( aIter != aEnd )
        {
            if( (*aIter).nIs < nSourcePos )
            {
                DBG_ASSERT( (*aIter).nIs >= nDestPos, "shape sorting failed" );
                (*aIter).nIs++;
            }
            aIter++;
        }
    }
}

void XMLShapeImportHelper::pushGroupForSorting( uno::Reference< drawing::XShapes >& rShapes )
{
    mpImpl->mpSortContext = new ShapeSortContext( rShapes, mpImpl->mpSortContext );
}

void XMLShapeImportHelper::popGroupAndSort()
{
    DBG_ASSERT( mpImpl->mpSortContext, "No context to sort!" );
    if( mpImpl->mpSortContext == NULL )
        return;

    try
    {
        list<ZOrderHint>& rZList = mpImpl->mpSortContext->maZOrderList;
        list<ZOrderHint>& rUnsortedList = mpImpl->mpSortContext->maUnsortedList;

        // sort shapes
        if( !rZList.empty() )
        {
            // only do something if we have shapes to sort

            // check if there are more shapes than inserted with ::shapeWithZIndexAdded()
            // This can happen if there where already shapes on the page before import
            // Since the writer may delete some of this shapes during import, we need
            // to do this here and not in our c'tor anymore

            // check if we have more shapes than we know of
            sal_Int32 nCount = mpImpl->mpSortContext->mxShapes->getCount();

            nCount -= rZList.size();
            nCount -= rUnsortedList.size();


            if( nCount > 0 )
            {
                // first update offsets of added shapes
                list<ZOrderHint>::iterator aIter( rZList.begin() );
                while( aIter != rZList.end() )
                    (*aIter++).nIs += nCount;

                aIter = rUnsortedList.begin();
                while( aIter != rUnsortedList.end() )
                    (*aIter++).nIs += nCount;

                // second add the already existing shapes in the unsorted list
                ZOrderHint aNewHint;

                do
                {
                    nCount--;

                    aNewHint.nIs = nCount;
                    aNewHint.nShould = -1;

                    rUnsortedList.insert(rUnsortedList.begin(), aNewHint);
                }
                while( nCount );
            }

            // sort z ordered shapes
            rZList.sort();

            // this is the current index, all shapes before that
            // index are finished
            sal_Int32 nIndex = 0;
            while( !rZList.empty() )
            {
                list<ZOrderHint>::iterator aIter( rZList.begin() );

                while( nIndex < (*aIter).nShould && !rUnsortedList.empty() )
                {
                    ZOrderHint aGapHint( *rUnsortedList.begin() );
                    rUnsortedList.pop_front();

                    mpImpl->mpSortContext->moveShape( aGapHint.nIs, nIndex++ );
                }

                if( (*aIter).nIs != nIndex )
                    mpImpl->mpSortContext->moveShape( (*aIter).nIs, nIndex );

                rZList.pop_front();
                nIndex++;
            }
        }
    }
    catch( uno::Exception& )
    {
        DBG_ERROR("exception while sorting shapes, sorting failed!");
    }

    // put parent on top and delete current context, were done
    ShapeSortContext* pContext = mpImpl->mpSortContext;
    mpImpl->mpSortContext = pContext->mpParentContext;
    delete pContext;
}

void XMLShapeImportHelper::shapeWithZIndexAdded( com::sun::star::uno::Reference< com::sun::star::drawing::XShape >&, sal_Int32 nZIndex )
{
    if( mpImpl->mpSortContext)
    {
        ZOrderHint aNewHint;
        aNewHint.nIs = mpImpl->mpSortContext->mnCurrentZ++;
        aNewHint.nShould = nZIndex;

        if( nZIndex == -1 )
        {
            // don't care, so add to unsorted list
            mpImpl->mpSortContext->maUnsortedList.push_back(aNewHint);
        }
        else
        {
            // insert into sort list
            mpImpl->mpSortContext->maZOrderList.push_back(aNewHint);
        }
    }
}

void XMLShapeImportHelper::addShapeConnection( com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& rConnectorShape,
                         sal_Bool bStart,
                         const rtl::OUString& rDestShapeId,
                         sal_Int32 nDestGlueId )
{
    ConnectionHint aHint;
    aHint.mxConnector = rConnectorShape;
    aHint.bStart = bStart;
    aHint.aDestShapeId = rDestShapeId;
    aHint.nDestGlueId = nDestGlueId;

    mpImpl->maConnections.push_back( aHint );
}

void XMLShapeImportHelper::restoreConnections()
{
    if( !mpImpl->maConnections.empty() )
    {
        uno::Any aAny;

        const vector<ConnectionHint>::size_type nCount = mpImpl->maConnections.size();
        for( vector<ConnectionHint>::size_type i = 0; i < nCount; i++ )
        {
            ConnectionHint& rHint = mpImpl->maConnections[i];
            uno::Reference< beans::XPropertySet > xConnector( rHint.mxConnector, uno::UNO_QUERY );
            if( xConnector.is() )
            {
                // #86637# remember line deltas
                uno::Any aLine1Delta;
                uno::Any aLine2Delta;
                uno::Any aLine3Delta;
                OUString aStr1(RTL_CONSTASCII_USTRINGPARAM("EdgeLine1Delta"));
                OUString aStr2(RTL_CONSTASCII_USTRINGPARAM("EdgeLine2Delta"));
                OUString aStr3(RTL_CONSTASCII_USTRINGPARAM("EdgeLine3Delta"));
                aLine1Delta = xConnector->getPropertyValue(aStr1);
                aLine2Delta = xConnector->getPropertyValue(aStr2);
                aLine3Delta = xConnector->getPropertyValue(aStr3);

                // #86637# simply setting these values WILL force the connector to do
                // an new layout promptly. So the line delta values have to be rescued
                // and restored around connector changes.
                uno::Reference< drawing::XShape > xShape(
                    mrImporter.getInterfaceToIdentifierMapper().getReference( rHint.aDestShapeId ), uno::UNO_QUERY );
                if( xShape.is() )
                {
                    aAny <<= xShape;
                    xConnector->setPropertyValue( rHint.bStart ? msStartShape : msEndShape, aAny );

                    sal_Int32 nGlueId = rHint.nDestGlueId < 4 ? rHint.nDestGlueId : getGluePointId( xShape, rHint.nDestGlueId );
                    aAny <<= nGlueId;
                    xConnector->setPropertyValue( rHint.bStart ? msStartGluePointIndex : msEndGluePointIndex, aAny );
                }

                // #86637# restore line deltas
                xConnector->setPropertyValue(aStr1, aLine1Delta );
                xConnector->setPropertyValue(aStr2, aLine2Delta );
                xConnector->setPropertyValue(aStr3, aLine3Delta );
            }
        }
        mpImpl->maConnections.clear();
    }
}

SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
{
    UniReference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rModel, rImport );
    UniReference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory );
    SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );

    // chain text attributes
    pResult->ChainImportMapper( XMLTextImportHelper::CreateParaExtPropMapper( rImport ) );
    return pResult;
}

/** creates a shape property set mapper that can be used for non shape elements.
    Only current feature is that the ShapeUserDefinedAttributes property is not included in this one. */
SvXMLImportPropertyMapper* XMLShapeImportHelper::CreateExternalShapePropMapper( const uno::Reference< frame::XModel>& rModel, SvXMLImport& rImport )
{
    UniReference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rModel, rImport );
    UniReference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, 1 );
    SvXMLImportPropertyMapper* pResult = new SvXMLImportPropertyMapper( xMapper, rImport );

    // chain text attributes
    pResult->ChainImportMapper( XMLTextImportHelper::CreateParaExtPropMapper( rImport ) );
    return pResult;
}

/** adds a mapping for a glue point identifier from an xml file to the identifier created after inserting
    the new glue point into the core. The saved mappings can be retrieved by getGluePointId() */
void XMLShapeImportHelper::addGluePointMapping( com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape,
                          sal_Int32 nSourceId, sal_Int32 nDestinnationId )
{
    if( mpPageContext )
        mpPageContext->maShapeGluePointsMap[xShape][nSourceId] = nDestinnationId;
}

/** moves all current DestinationId's by n */
void XMLShapeImportHelper::moveGluePointMapping( const com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape, const sal_Int32 n )
{
    if( mpPageContext )
    {
        ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
        if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
        {
            GluePointIdMap::iterator aShapeIdIter = (*aShapeIter).second.begin();
            GluePointIdMap::iterator aShapeIdEnd  = (*aShapeIter).second.end();
            while ( aShapeIdIter != aShapeIdEnd )
            {
                if ( (*aShapeIdIter).second != -1 )
                    (*aShapeIdIter).second += n;
                aShapeIdIter++;
            }
        }
    }
}

/** retrieves a mapping for a glue point identifier from the current xml file to the identifier created after
    inserting the new glue point into the core. The mapping must be initialized first with addGluePointMapping() */
sal_Int32 XMLShapeImportHelper::getGluePointId( com::sun::star::uno::Reference< com::sun::star::drawing::XShape >& xShape, sal_Int32 nSourceId )
{
    if( mpPageContext )
    {
        ShapeGluePointsMap::iterator aShapeIter( mpPageContext->maShapeGluePointsMap.find( xShape ) );
        if( aShapeIter != mpPageContext->maShapeGluePointsMap.end() )
        {
            GluePointIdMap::iterator aIdIter = (*aShapeIter).second.find(nSourceId);
            if( aIdIter != (*aShapeIter).second.end() )
                return (*aIdIter).second;
        }
    }

    return -1;
}

/** this method must be calling before the first shape is imported for the given page */
void XMLShapeImportHelper::startPage( com::sun::star::uno::Reference< com::sun::star::drawing::XShapes >& rShapes )
{
    XMLShapeImportPageContextImpl* pOldContext = mpPageContext;
    mpPageContext = new XMLShapeImportPageContextImpl();
    mpPageContext->mpNext = pOldContext;
    mpPageContext->mxShapes = rShapes;
}

/** this method must be calling after the last shape is imported for the given page */
void XMLShapeImportHelper::endPage( com::sun::star::uno::Reference< com::sun::star::drawing::XShapes >&
#ifdef DBG_UTIL
rShapes
#endif
)
{
    DBG_ASSERT( mpPageContext && (mpPageContext->mxShapes == rShapes), "wrong call to endPage(), no startPage called or wrong page" );
    if( NULL == mpPageContext )
        return;

    restoreConnections();

    XMLShapeImportPageContextImpl* pNextContext = mpPageContext->mpNext;
    delete mpPageContext;
    mpPageContext = pNextContext;
}

// #88546#
/** defines if the import should increment the progress bar or not */
void XMLShapeImportHelper::enableHandleProgressBar( sal_Bool bEnable )
{
    mpImpl->mbHandleProgressBar = bEnable;
}

sal_Bool XMLShapeImportHelper::IsHandleProgressBarEnabled() const
{
    return mpImpl->mbHandleProgressBar;
}

/** queries the capability of the current model to create presentation shapes */
sal_Bool XMLShapeImportHelper::IsPresentationShapesSupported()
{
    return mpImpl->mbIsPresentationShapesSupported;
}

const rtl::Reference< XMLTableImport >& XMLShapeImportHelper::GetShapeTableImport()
{
    if( !mxShapeTableImport.is() )
    {
        rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrImporter.GetModel(), mrImporter ) );
        rtl::Reference< XMLPropertySetMapper > xPropertySetMapper( new XMLShapePropertySetMapper( xFactory.get() ) );
        mxShapeTableImport = new XMLTableImport( mrImporter, xPropertySetMapper, xFactory );
    }

    return mxShapeTableImport;
}

void SvXMLShapeContext::setHyperlink( const OUString& rHyperlink )
{
    msHyperlink = rHyperlink;
}