/*************************************************************************
 *
 * 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_sc.hxx"

#include <tools/debug.hxx>
#include <comphelper/uno3.hxx>
#include <comphelper/stl_types.hxx>
#include <svtools/unoevent.hxx>
#include <svtools/unoimap.hxx>
#include <svx/svdobj.hxx>
#include <svx/unoshape.hxx>
#include <editeng/unofield.hxx>
#include <svx/shapepropertynotifier.hxx>
#include <toolkit/helper/convert.hxx>
#include <cppuhelper/implbase2.hxx>

#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/beans/PropertyAttribute.hpp>

#include "shapeuno.hxx"
#include "miscuno.hxx"
#include "cellsuno.hxx"
#include "textuno.hxx"
#include "fielduno.hxx"
#include "docsh.hxx"
#include "drwlayer.hxx"
#include "userdat.hxx"
#include "unonames.hxx"
#include "unoguard.hxx"

using namespace ::com::sun::star;

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

DECLARE_STL_USTRINGACCESS_MAP( uno::Sequence< sal_Int8 > *,  ScShapeImplementationIdMap );

static ScShapeImplementationIdMap aImplementationIdMap;

const SfxItemPropertyMapEntry* lcl_GetShapeMap()
{
    static SfxItemPropertyMapEntry aShapeMap_Impl[] =
	{
        {MAP_CHAR_LEN(SC_UNONAME_ANCHOR), 0, &getCppuType((uno::Reference<uno::XInterface>*)0), 0, 0 },
        {MAP_CHAR_LEN(SC_UNONAME_HORIPOS), 0, &getCppuType((sal_Int32*)0), 0, 0 },
		{MAP_CHAR_LEN(SC_UNONAME_IMAGEMAP),	0, &getCppuType((uno::Reference<container::XIndexContainer>*)0), 0, 0 },
		{MAP_CHAR_LEN(SC_UNONAME_VERTPOS), 0, &getCppuType((sal_Int32*)0), 0, 0 },
        {0,0,0,0,0,0}
	};
	return aShapeMap_Impl;
}

// static
const SvEventDescription* ScShapeObj::GetSupportedMacroItems()
{
	static const SvEventDescription aMacroDescriptionsImpl[] =
	{
		{ 0, NULL }
	};
	return aMacroDescriptionsImpl;
}

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

namespace
{
    void lcl_initializeNotifier( SdrObject& _rSdrObj, ::cppu::OWeakObject& _rShape )
    {
        ::svx::PPropertyValueProvider pProvider( new ::svx::PropertyValueProvider( _rShape, "Anchor" ) );
        _rSdrObj.getShapePropertyChangeNotifier().registerProvider( ::svx::eSpreadsheetAnchor, pProvider );
    }
}

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

ScShapeObj::ScShapeObj( uno::Reference<drawing::XShape>& xShape ) :
      pShapePropertySet(NULL),
      pShapePropertyState(NULL),
      pImplementationId(NULL),
      bIsTextShape(false),
      bIsNoteCaption(false),
      bInitializedNotifier(false)
{
	comphelper::increment( m_refCount );

	{
		mxShapeAgg = uno::Reference<uno::XAggregation>( xShape, uno::UNO_QUERY );
		// extra block to force deletion of the temporary before setDelegator
	}

	if (mxShapeAgg.is())
	{
		xShape = NULL;		// during setDelegator, mxShapeAgg must be the only ref

		mxShapeAgg->setDelegator( (cppu::OWeakObject*)this );

		xShape.set(uno::Reference<drawing::XShape>( mxShapeAgg, uno::UNO_QUERY ));

		bIsTextShape = ( SvxUnoTextBase::getImplementation( mxShapeAgg ) != NULL );
	}

    {
        SdrObject* pObj = GetSdrObject();
        if ( pObj )
        {
            bIsNoteCaption = ScDrawLayer::IsNoteCaption( pObj );
            lcl_initializeNotifier( *pObj, *this );
            bInitializedNotifier = true;
        }
    }

	comphelper::decrement( m_refCount );
}

ScShapeObj::~ScShapeObj()
{
//	if (mxShapeAgg.is())
//		mxShapeAgg->setDelegator(uno::Reference<uno::XInterface>());
}

// XInterface

uno::Any SAL_CALL ScShapeObj::queryInterface( const uno::Type& rType )
												throw(uno::RuntimeException)
{
    uno::Any aRet = ScShapeObj_Base::queryInterface( rType );

    if ( !aRet.hasValue() && bIsTextShape )
        aRet = ScShapeObj_TextBase::queryInterface( rType );

    if ( !aRet.hasValue() && bIsNoteCaption )
        aRet = ScShapeObj_ChildBase::queryInterface( rType );

	if ( !aRet.hasValue() && mxShapeAgg.is() )
		aRet = mxShapeAgg->queryAggregation( rType );

	return aRet;
}

void SAL_CALL ScShapeObj::acquire() throw()
{
        OWeakObject::acquire();
}

void SAL_CALL ScShapeObj::release() throw()
{
        OWeakObject::release();
}

void ScShapeObj::GetShapePropertySet()
{
    // #i61908# Store the result of queryAggregation in a member.
    // The reference in mxShapeAgg is kept for this object's lifetime, so the pointer is always valid.

    if (!pShapePropertySet)
    {
        uno::Reference<beans::XPropertySet> xProp;
        if ( mxShapeAgg.is() )
            mxShapeAgg->queryAggregation( getCppuType((uno::Reference<beans::XPropertySet>*) 0) ) >>= xProp;
        pShapePropertySet = xProp.get();
    }
}

void ScShapeObj::GetShapePropertyState()
{
    // #i61908# Store the result of queryAggregation in a member.
    // The reference in mxShapeAgg is kept for this object's lifetime, so the pointer is always valid.

    if (!pShapePropertyState)
    {
        uno::Reference<beans::XPropertyState> xState;
        if ( mxShapeAgg.is() )
            mxShapeAgg->queryAggregation( getCppuType((uno::Reference<beans::XPropertyState>*) 0) ) >>= xState;
        pShapePropertyState = xState.get();
    }
}

uno::Reference<lang::XComponent> lcl_GetComponent( const uno::Reference<uno::XAggregation>& xAgg )
{
	uno::Reference<lang::XComponent> xRet;
	if ( xAgg.is() )
		xAgg->queryAggregation( getCppuType((uno::Reference<lang::XComponent>*) 0) ) >>= xRet;
	return xRet;
}

uno::Reference<text::XText> lcl_GetText( const uno::Reference<uno::XAggregation>& xAgg )
{
	uno::Reference<text::XText> xRet;
	if ( xAgg.is() )
		xAgg->queryAggregation( getCppuType((uno::Reference<text::XText>*) 0) ) >>= xRet;
	return xRet;
}

uno::Reference<text::XSimpleText> lcl_GetSimpleText( const uno::Reference<uno::XAggregation>& xAgg )
{
	uno::Reference<text::XSimpleText> xRet;
	if ( xAgg.is() )
		xAgg->queryAggregation( getCppuType((uno::Reference<text::XSimpleText>*) 0) ) >>= xRet;
	return xRet;
}

uno::Reference<text::XTextRange> lcl_GetTextRange( const uno::Reference<uno::XAggregation>& xAgg )
{
	uno::Reference<text::XTextRange> xRet;
	if ( xAgg.is() )
		xAgg->queryAggregation( getCppuType((uno::Reference<text::XTextRange>*) 0) ) >>= xRet;
	return xRet;
}

//	XPropertySet

uno::Reference<beans::XPropertySetInfo> SAL_CALL ScShapeObj::getPropertySetInfo()
														throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

    // #i61527# cache property set info for this object
    if ( !mxPropSetInfo.is() )
    {
        //	mix own and aggregated properties:
        GetShapePropertySet();
        if (pShapePropertySet)
        {
            uno::Reference<beans::XPropertySetInfo> xAggInfo(pShapePropertySet->getPropertySetInfo());
            const uno::Sequence<beans::Property> aPropSeq(xAggInfo->getProperties());
            mxPropSetInfo.set(new SfxExtItemPropertySetInfo( lcl_GetShapeMap(), aPropSeq ));
        }
    }
	return mxPropSetInfo;
}

sal_Bool lcl_GetPageNum( SdrPage* pPage, SdrModel& rModel, SCTAB& rNum )
{
	sal_uInt16 nCount = rModel.GetPageCount();
	for (sal_uInt16 i=0; i<nCount; i++)
		if ( rModel.GetPage(i) == pPage )
		{
			rNum = static_cast<SCTAB>(i);
			return sal_True;
		}

	return sal_False;
}

sal_Bool lcl_GetCaptionPoint( uno::Reference< drawing::XShape >& xShape, awt::Point& rCaptionPoint )
{
    sal_Bool bReturn = sal_False;
    rtl::OUString sType(xShape->getShapeType());
    sal_Bool bCaptionShape(sType.equalsAscii("com.sun.star.drawing.CaptionShape"));
    if (bCaptionShape)
    {
        uno::Reference < beans::XPropertySet > xShapeProp (xShape, uno::UNO_QUERY);
        if (xShapeProp.is())
        {
            xShapeProp->getPropertyValue( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "CaptionPoint" )) ) >>= rCaptionPoint;
            bReturn = sal_True;
        }
    }
    return bReturn;
}

ScRange lcl_GetAnchorCell( uno::Reference< drawing::XShape >& xShape, ScDocument* pDoc, SCTAB nTab,
                          awt::Point& rUnoPoint, awt::Size& rUnoSize, awt::Point& rCaptionPoint )
{
    ScRange aReturn;
    rUnoPoint = xShape->getPosition();
    rtl::OUString sType(xShape->getShapeType());
    sal_Bool bCaptionShape(lcl_GetCaptionPoint(xShape, rCaptionPoint));
    if (pDoc->IsNegativePage(nTab))
    {
        rUnoSize = xShape->getSize();
        rUnoPoint.X += rUnoSize.Width; // the right top point is base
        if (bCaptionShape)
        {
            if (rCaptionPoint.X > 0 && rCaptionPoint.X > rUnoSize.Width)
                rUnoPoint.X += rCaptionPoint.X - rUnoSize.Width;
            if (rCaptionPoint.Y < 0)
                rUnoPoint.Y += rCaptionPoint.Y;
        }
        aReturn = pDoc->GetRange( nTab, Rectangle( VCLPoint(rUnoPoint), VCLPoint(rUnoPoint) ));
    }
    else
    {
        if (bCaptionShape)
        {
            if (rCaptionPoint.X < 0)
                rUnoPoint.X += rCaptionPoint.X;
            if (rCaptionPoint.Y < 0)
                rUnoPoint.Y += rCaptionPoint.Y;
        }
        aReturn = pDoc->GetRange( nTab, Rectangle( VCLPoint(rUnoPoint), VCLPoint(rUnoPoint) ));
    }

    return aReturn;
}

awt::Point lcl_GetRelativePos( uno::Reference< drawing::XShape >& xShape, ScDocument* pDoc, SCTAB nTab, ScRange& rRange,
                              awt::Size& rUnoSize, awt::Point& rCaptionPoint)
{
    awt::Point aUnoPoint;
    rRange = lcl_GetAnchorCell(xShape, pDoc, nTab, aUnoPoint, rUnoSize, rCaptionPoint);
    if (pDoc->IsNegativePage(nTab))
    {
        Rectangle aRect(pDoc->GetMMRect( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab() ));
        Point aPoint(aRect.TopRight());
        aUnoPoint.X -= aPoint.X();
        aUnoPoint.Y -= aPoint.Y();
    }
    else
    {
        ScRange aRange = pDoc->GetRange( nTab, Rectangle( VCLPoint(aUnoPoint), VCLPoint(aUnoPoint) ));
        Rectangle aRect(pDoc->GetMMRect( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab() ));
        Point aPoint(aRect.TopLeft());
        aUnoPoint.X -= aPoint.X();
        aUnoPoint.Y -= aPoint.Y();
    }

    return aUnoPoint;
}

void SAL_CALL ScShapeObj::setPropertyValue(
						const rtl::OUString& aPropertyName, const uno::Any& aValue )
				throw(beans::UnknownPropertyException, beans::PropertyVetoException,
						lang::IllegalArgumentException, lang::WrappedTargetException,
						uno::RuntimeException)
{
	ScUnoGuard aGuard;
	String aNameString(aPropertyName);

	if ( aNameString.EqualsAscii( SC_UNONAME_ANCHOR ) )
    {
        uno::Reference<sheet::XCellRangeAddressable> xRangeAdd(aValue, uno::UNO_QUERY);
        if (xRangeAdd.is())
        {
            SdrObject *pObj = GetSdrObject();
		    if (pObj)
		    {
		        ScDrawLayer* pModel = (ScDrawLayer*)pObj->GetModel();
		        SdrPage* pPage = pObj->GetPage();
		        if ( pModel && pPage )
		        {
			        ScDocument* pDoc = pModel->GetDocument();
			        if ( pDoc )
			        {
				        SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
				        if ( pObjSh && pObjSh->ISA(ScDocShell) )
				        {
					        ScDocShell* pDocSh = (ScDocShell*)pObjSh;

					        SCTAB nTab = 0;
					        if ( lcl_GetPageNum( pPage, *pModel, nTab ) )
					        {
                                table::CellRangeAddress aAddress = xRangeAdd->getRangeAddress();
                                if (nTab == aAddress.Sheet)
                                {
                                    if (aAddress.StartRow != aAddress.EndRow) //should be a Spreadsheet
                                    {
                                        DBG_ASSERT(aAddress.StartRow == 0 && aAddress.EndRow == MAXROW &&
                                            aAddress.StartColumn == 0 && aAddress.EndColumn == MAXCOL, "here should be a XSpreadsheet");
			                            ScDrawLayer::SetAnchor(pObj, SCA_PAGE);
                                    }
                                    else
                                    {
                                        DBG_ASSERT(aAddress.StartRow == aAddress.EndRow &&
                                            aAddress.StartColumn == aAddress.EndColumn, "here should be a XCell");
			                            ScDrawLayer::SetAnchor(pObj, SCA_CELL);
                                    }
                                    Rectangle aRect(pDoc->GetMMRect( static_cast<SCCOL>(aAddress.StartColumn), static_cast<SCROW>(aAddress.StartRow),
                                        static_cast<SCCOL>(aAddress.EndColumn), static_cast<SCROW>(aAddress.EndRow), aAddress.Sheet ));
                                    uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                                    if (xShape.is())
                                    {
                                        Point aPoint;
                                        Point aEndPoint;
                                        if (pDoc->IsNegativePage(nTab))
                                        {
                                            aPoint = aRect.TopRight();
                                            aEndPoint = aRect.BottomLeft();
                                        }
                                        else
                                        {
                                            aPoint = aRect.TopLeft();
                                            aEndPoint = aRect.BottomRight();
                                        }
                                        awt::Size aUnoSize;
                                        awt::Point aCaptionPoint;
                                        ScRange aRange;
                                        awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));

                                        aUnoPoint.X += aPoint.X();
                                        aUnoPoint.Y += aPoint.Y();

                                        if ( aUnoPoint.Y > aEndPoint.Y() )
                                            aUnoPoint.Y = aEndPoint.Y() - 2;
                                        if (pDoc->IsNegativePage(nTab))
                                        {
                                            if ( aUnoPoint.X < aEndPoint.X() )
                                                aUnoPoint.X = aEndPoint.X() + 2;
                                            aUnoPoint.X -= aUnoSize.Width;
                                            // remove difference to caption point
                                            if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
                                                aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
                                        }
                                        else
                                        {
                                            if ( aUnoPoint.X > aEndPoint.X() )
                                                aUnoPoint.X = aEndPoint.X() - 2;
                                            if (aCaptionPoint.X < 0)
                                                aUnoPoint.X -= aCaptionPoint.X;
                                        }
                                        if (aCaptionPoint.Y < 0)
                                            aUnoPoint.Y -= aCaptionPoint.Y;

                                        xShape->setPosition(aUnoPoint);
                                        pDocSh->SetModified();
                                    }
                                }
					        }
				        }
                    }
                }
            }
        }
        else
            throw lang::IllegalArgumentException(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("only XCell or XSpreadsheet objects allowed")), static_cast<cppu::OWeakObject*>(this), 0);
    }
    else if ( aNameString.EqualsAscii( SC_UNONAME_IMAGEMAP ) )
	{
		SdrObject* pObj = GetSdrObject();
		if ( pObj )
		{
			ImageMap aImageMap;
            uno::Reference< uno::XInterface > xImageMapInt(aValue, uno::UNO_QUERY);

			if( !xImageMapInt.is() || !SvUnoImageMap_fillImageMap( xImageMapInt, aImageMap ) )
				throw lang::IllegalArgumentException();

			ScIMapInfo* pIMapInfo = ScDrawLayer::GetIMapInfo(pObj);
			if( pIMapInfo )
			{
				// replace existing image map
				pIMapInfo->SetImageMap( aImageMap );
			}
			else
			{
				// insert new user data with image map
				pObj->InsertUserData(new ScIMapInfo(aImageMap) );
			}
		}
	}
    else if ( aNameString.EqualsAscii( SC_UNONAME_HORIPOS ) )
    {
        sal_Int32 nPos = 0;
        if (aValue >>= nPos)
        {
            SdrObject *pObj = GetSdrObject();
		    if (pObj)
		    {
		        ScDrawLayer* pModel = (ScDrawLayer*)pObj->GetModel();
		        SdrPage* pPage = pObj->GetPage();
		        if ( pModel && pPage )
		        {
					SCTAB nTab = 0;
					if ( lcl_GetPageNum( pPage, *pModel, nTab ) )
					{
			            ScDocument* pDoc = pModel->GetDocument();
			            if ( pDoc )
			            {
				            SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
				            if ( pObjSh && pObjSh->ISA(ScDocShell) )
				            {
					            ScDocShell* pDocSh = (ScDocShell*)pObjSh;
                                uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                                if (xShape.is())
                                {
                                    if (ScDrawLayer::GetAnchor(pObj) == SCA_PAGE)
                                    {
                                        awt::Point aPoint(xShape->getPosition());
                                        awt::Size aSize(xShape->getSize());
                                        awt::Point aCaptionPoint;
                                        if (pDoc->IsNegativePage(nTab))
                                        {
                                            nPos *= -1;
                                            nPos -= aSize.Width;
                                        }
                                        if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
                                        {
                                            if (pDoc->IsNegativePage(nTab))
                                            {
                                                if (aCaptionPoint.X > 0 && aCaptionPoint.X > aSize.Width)
                                                    nPos -= aCaptionPoint.X - aSize.Width;
                                            }
                                            else
                                            {
                                                if (aCaptionPoint.X < 0)
                                                    nPos -= aCaptionPoint.X;
                                            }
                                        }
                                        aPoint.X = nPos;
                                        xShape->setPosition(aPoint);
                                        pDocSh->SetModified();
                                    }
                                    else if (ScDrawLayer::GetAnchor(pObj) == SCA_CELL)
                                    {
                                        awt::Size aUnoSize;
                                        awt::Point aCaptionPoint;
                                        ScRange aRange;
                                        awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
                                        Rectangle aRect(pDoc->GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ));
                                        if (pDoc->IsNegativePage(nTab))
                                        {
                                            aUnoPoint.X = -nPos;
                                            Point aPoint(aRect.TopRight());
                                            Point aEndPoint(aRect.BottomLeft());
                                            aUnoPoint.X += aPoint.X();
                                            if (aUnoPoint.X < aEndPoint.X())
                                                aUnoPoint.X = aEndPoint.X() + 2;
                                            aUnoPoint.X -= aUnoSize.Width;
                                            if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
                                                aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
                                        }
                                        else
                                        {
                                            aUnoPoint.X = nPos;
                                            Point aPoint(aRect.TopLeft());
                                            Point aEndPoint(aRect.BottomRight());
                                            aUnoPoint.X += aPoint.X();
                                            if (aUnoPoint.X > aEndPoint.X())
                                                aUnoPoint.X = aEndPoint.X() - 2;
                                            if (aCaptionPoint.X < 0)
                                                aUnoPoint.X -= aCaptionPoint.X;
                                        }
                                        aUnoPoint.Y = xShape->getPosition().Y;
                                        xShape->setPosition(aUnoPoint);
                                        pDocSh->SetModified();
                                    }
                                    else
                                    {
                                        DBG_ERROR("unknown anchor type");
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    else if ( aNameString.EqualsAscii( SC_UNONAME_VERTPOS ) )
    {
        sal_Int32 nPos = 0;
        if (aValue >>= nPos)
        {
            SdrObject *pObj = GetSdrObject();
		    if (pObj)
		    {
		        ScDrawLayer* pModel = (ScDrawLayer*)pObj->GetModel();
		        SdrPage* pPage = pObj->GetPage();
		        if ( pModel && pPage )
		        {
					SCTAB nTab = 0;
					if ( lcl_GetPageNum( pPage, *pModel, nTab ) )
					{
			            ScDocument* pDoc = pModel->GetDocument();
			            if ( pDoc )
			            {
				            SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
				            if ( pObjSh && pObjSh->ISA(ScDocShell) )
				            {
					            ScDocShell* pDocSh = (ScDocShell*)pObjSh;
                                uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                                if (xShape.is())
                                {
                                    if (ScDrawLayer::GetAnchor(pObj) == SCA_PAGE)
                                    {
                                        awt::Point aPoint = xShape->getPosition();
                                        awt::Point aCaptionPoint;
                                        if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
                                        {
                                            if (aCaptionPoint.Y < 0)
                                                nPos -= aCaptionPoint.Y;
                                        }
                                        aPoint.Y = nPos;
                                        xShape->setPosition(aPoint);
                                        pDocSh->SetModified();
                                    }
                                    else if (ScDrawLayer::GetAnchor(pObj) == SCA_CELL)
                                    {
                                        awt::Size aUnoSize;
                                        awt::Point aCaptionPoint;
                                        ScRange aRange;
                                        awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
                                        Rectangle aRect(pDoc->GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ));
                                        Point aPoint(aRect.TopRight());
                                        Point aEndPoint(aRect.BottomLeft());
                                        aUnoPoint.Y = nPos;
                                        aUnoPoint.Y += aPoint.Y();
                                        if (aUnoPoint.Y > aEndPoint.Y())
                                            aUnoPoint.Y = aEndPoint.Y() - 2;
                                        if (aCaptionPoint.Y < 0)
                                            aUnoPoint.Y -= aCaptionPoint.Y;
                                        aUnoPoint.X = xShape->getPosition().X;
                                        xShape->setPosition(aUnoPoint);
                                        pDocSh->SetModified();
                                    }
                                    else
                                    {
                                        DBG_ERROR("unknown anchor type");
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
	else
	{
        GetShapePropertySet();
        if (pShapePropertySet)
            pShapePropertySet->setPropertyValue( aPropertyName, aValue );
	}
}

uno::Any SAL_CALL ScShapeObj::getPropertyValue( const rtl::OUString& aPropertyName )
				throw(beans::UnknownPropertyException, lang::WrappedTargetException,
						uno::RuntimeException)
{
	ScUnoGuard aGuard;
	String aNameString = aPropertyName;

	uno::Any aAny;
	if ( aNameString.EqualsAscii( SC_UNONAME_ANCHOR ) )
    {
		SdrObject *pObj = GetSdrObject();
		if (pObj)
		{
		    ScDrawLayer* pModel = (ScDrawLayer*)pObj->GetModel();
		    SdrPage* pPage = pObj->GetPage();
		    if ( pModel && pPage )
		    {
			    ScDocument* pDoc = pModel->GetDocument();
			    if ( pDoc )
			    {
					SCTAB nTab = 0;
					if ( lcl_GetPageNum( pPage, *pModel, nTab ) )
					{
				        SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
				        if ( pObjSh && pObjSh->ISA(ScDocShell) )
				        {
					        ScDocShell* pDocSh = (ScDocShell*)pObjSh;
                		    uno::Reference< uno::XInterface > xAnchor;
			                if (ScDrawLayer::GetAnchor(pObj) == SCA_CELL)
                            {
                                uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                                if (xShape.is())
                                {
                                    awt::Size aUnoSize;
                                    awt::Point aCaptionPoint;
                                    ScRange aRange;
                                    awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));

    						        xAnchor.set(static_cast<cppu::OWeakObject*>(new ScCellObj( pDocSh, aRange.aStart )));
                                }
                            }
                            else
                            {
    						    xAnchor.set(static_cast<cppu::OWeakObject*>(new ScTableSheetObj( pDocSh, nTab )));
                            }
                            aAny <<= xAnchor;
                        }
					}
                }
            }
        }
    }
    else if ( aNameString.EqualsAscii( SC_UNONAME_IMAGEMAP ) )
	{
		uno::Reference< uno::XInterface > xImageMap;
		SdrObject* pObj = GetSdrObject();
		if ( pObj )
		{
			ScIMapInfo* pIMapInfo = ScDrawLayer::GetIMapInfo(GetSdrObject());
			if( pIMapInfo )
			{
				const ImageMap& rIMap = pIMapInfo->GetImageMap();
				xImageMap.set(SvUnoImageMap_createInstance( rIMap, GetSupportedMacroItems() ));
			}
			else
				xImageMap = SvUnoImageMap_createInstance( GetSupportedMacroItems() );
		}
		aAny <<= uno::Reference< container::XIndexContainer >::query( xImageMap );
	}
    else if ( aNameString.EqualsAscii( SC_UNONAME_HORIPOS ) )
    {
		SdrObject *pObj = GetSdrObject();
		if (pObj)
		{
		    ScDrawLayer* pModel = (ScDrawLayer*)pObj->GetModel();
		    SdrPage* pPage = pObj->GetPage();
		    if ( pModel && pPage )
		    {
			    ScDocument* pDoc = pModel->GetDocument();
			    if ( pDoc )
			    {
					SCTAB nTab = 0;
					if ( lcl_GetPageNum( pPage, *pModel, nTab ) )
					{
                        uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                        if (xShape.is())
                        {
			                if (ScDrawLayer::GetAnchor(pObj) == SCA_CELL)
                            {
                                awt::Size aUnoSize;
                                awt::Point aCaptionPoint;
                                ScRange aRange;
                                awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
                                if (pDoc->IsNegativePage(nTab))
                                    aUnoPoint.X *= -1;
                                aAny <<= aUnoPoint.X;
                            }
                            else
                            {
                                awt::Point aCaptionPoint;
                                awt::Point aUnoPoint(xShape->getPosition());
                                awt::Size aUnoSize(xShape->getSize());
                                if (pDoc->IsNegativePage(nTab))
                                {
                                    aUnoPoint.X *= -1;
                                    aUnoPoint.X -= aUnoSize.Width;
                                }
                                if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
                                {
                                    if (pDoc->IsNegativePage(nTab))
                                    {
                                        if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
                                            aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
                                    }
                                    else
                                    {
                                        if (aCaptionPoint.X < 0)
                                            aUnoPoint.X += aCaptionPoint.X;
                                    }
                                }
                                aAny <<= aUnoPoint.X;
                            }
                        }
					}
                }
            }
        }
    }
    else if ( aNameString.EqualsAscii( SC_UNONAME_VERTPOS ) )
    {
		SdrObject *pObj = GetSdrObject();
		if (pObj)
		{
		    ScDrawLayer* pModel = (ScDrawLayer*)pObj->GetModel();
		    SdrPage* pPage = pObj->GetPage();
		    if ( pModel && pPage )
		    {
			    ScDocument* pDoc = pModel->GetDocument();
			    if ( pDoc )
			    {
					SCTAB nTab = 0;
					if ( lcl_GetPageNum( pPage, *pModel, nTab ) )
					{
                        uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                        if (xShape.is())
                        {
                		    uno::Reference< uno::XInterface > xAnchor;
			                if (ScDrawLayer::GetAnchor(pObj) == SCA_CELL)
                            {
                                awt::Size aUnoSize;
                                awt::Point aCaptionPoint;
                                ScRange aRange;
                                awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));

                                aAny <<= aUnoPoint.Y;
                            }
                            else
                            {
                                awt::Point aUnoPoint(xShape->getPosition());
                                awt::Point aCaptionPoint;
                                if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
                                {
                                    if (aCaptionPoint.Y < 0)
                                        aUnoPoint.Y += aCaptionPoint.Y;
                                }
                                aAny <<= aUnoPoint.Y;
                            }
                        }
					}
                }
            }
        }
    }
	else
	{
        GetShapePropertySet();
        if (pShapePropertySet)
            aAny = pShapePropertySet->getPropertyValue( aPropertyName );
	}

	return aAny;
}

void SAL_CALL ScShapeObj::addPropertyChangeListener( const rtl::OUString& aPropertyName,
							const uno::Reference<beans::XPropertyChangeListener>& aListener)
							throw(beans::UnknownPropertyException,
									lang::WrappedTargetException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

    GetShapePropertySet();
    if (pShapePropertySet)
        pShapePropertySet->addPropertyChangeListener( aPropertyName, aListener );

    if ( !bInitializedNotifier )
    {
        // here's the latest chance to initialize the property notification at the SdrObject
        // (in the ctor, where we also attempt to do this, we do not necessarily have
        // and SdrObject, yet)
        SdrObject* pObj = GetSdrObject();
        OSL_ENSURE( pObj, "ScShapeObj::addPropertyChangeListener: no SdrObject -> no property change notification!" );
        if ( pObj )
            lcl_initializeNotifier( *pObj, *this );
        bInitializedNotifier = true;
    }
}

void SAL_CALL ScShapeObj::removePropertyChangeListener( const rtl::OUString& aPropertyName,
							const uno::Reference<beans::XPropertyChangeListener>& aListener)
							throw(beans::UnknownPropertyException,
									lang::WrappedTargetException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

    GetShapePropertySet();
    if (pShapePropertySet)
        pShapePropertySet->removePropertyChangeListener( aPropertyName, aListener );
}

void SAL_CALL ScShapeObj::addVetoableChangeListener( const rtl::OUString& aPropertyName,
							const uno::Reference<beans::XVetoableChangeListener>& aListener)
							throw(beans::UnknownPropertyException,
								lang::WrappedTargetException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

    GetShapePropertySet();
    if (pShapePropertySet)
        pShapePropertySet->addVetoableChangeListener( aPropertyName, aListener );
}

void SAL_CALL ScShapeObj::removeVetoableChangeListener( const rtl::OUString& aPropertyName,
							const uno::Reference<beans::XVetoableChangeListener>& aListener)
							throw(beans::UnknownPropertyException,
								lang::WrappedTargetException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

    GetShapePropertySet();
    if (pShapePropertySet)
        pShapePropertySet->removeVetoableChangeListener( aPropertyName, aListener );
}

//	XPropertyState

beans::PropertyState SAL_CALL ScShapeObj::getPropertyState( const rtl::OUString& aPropertyName )
								throw(beans::UnknownPropertyException, uno::RuntimeException)
{
	ScUnoGuard aGuard;
	String aNameString(aPropertyName);

	beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
	if ( aNameString.EqualsAscii( SC_UNONAME_IMAGEMAP ) )
	{
		// ImageMap is always "direct"
	}
    else if ( aNameString.EqualsAscii( SC_UNONAME_ANCHOR ) )
	{
		// Anchor is always "direct"
	}
    else if ( aNameString.EqualsAscii( SC_UNONAME_HORIPOS ) )
	{
		// HoriPos is always "direct"
	}
    else if ( aNameString.EqualsAscii( SC_UNONAME_VERTPOS ) )
	{
		// VertPos is always "direct"
	}
	else
	{
        GetShapePropertyState();
        if (pShapePropertyState)
            eRet = pShapePropertyState->getPropertyState( aPropertyName );
	}

	return eRet;
}

uno::Sequence<beans::PropertyState> SAL_CALL ScShapeObj::getPropertyStates(
								const uno::Sequence<rtl::OUString>& aPropertyNames )
							throw(beans::UnknownPropertyException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

	//	simple loop to get own and aggregated states

	const rtl::OUString* pNames = aPropertyNames.getConstArray();
	uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
	beans::PropertyState* pStates = aRet.getArray();
	for(sal_Int32 i = 0; i < aPropertyNames.getLength(); i++)
		pStates[i] = getPropertyState(pNames[i]);
	return aRet;
}

void SAL_CALL ScShapeObj::setPropertyToDefault( const rtl::OUString& aPropertyName )
							throw(beans::UnknownPropertyException, uno::RuntimeException)
{
	ScUnoGuard aGuard;
	String aNameString(aPropertyName);

	if ( aNameString.EqualsAscii( SC_UNONAME_IMAGEMAP ) )
	{
		SdrObject* pObj = GetSdrObject();
		if ( pObj )
		{
			ScIMapInfo* pIMapInfo = ScDrawLayer::GetIMapInfo(pObj);
			if( pIMapInfo )
			{
				ImageMap aEmpty;
				pIMapInfo->SetImageMap( aEmpty );	// replace with empty image map
			}
			else
			{
				// nothing to do (no need to insert user data for an empty map)
			}
		}
	}
	else
	{
        GetShapePropertyState();
        if (pShapePropertyState)
            pShapePropertyState->setPropertyToDefault( aPropertyName );
	}
}

uno::Any SAL_CALL ScShapeObj::getPropertyDefault( const rtl::OUString& aPropertyName )
								throw(beans::UnknownPropertyException, lang::WrappedTargetException,
										uno::RuntimeException)
{
	ScUnoGuard aGuard;
	String aNameString = aPropertyName;

	uno::Any aAny;
	if ( aNameString.EqualsAscii( SC_UNONAME_IMAGEMAP ) )
	{
		//	default: empty ImageMap
		uno::Reference< uno::XInterface > xImageMap(SvUnoImageMap_createInstance( GetSupportedMacroItems() ));
		aAny <<= uno::Reference< container::XIndexContainer >::query( xImageMap );
	}
	else
	{
        GetShapePropertyState();
        if (pShapePropertyState)
            aAny = pShapePropertyState->getPropertyDefault( aPropertyName );
	}

	return aAny;
}

// XTextContent

void SAL_CALL ScShapeObj::attach( const uno::Reference<text::XTextRange>& /* xTextRange */ )
								throw(lang::IllegalArgumentException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

	throw lang::IllegalArgumentException();		// anchor cannot be changed
}

uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getAnchor() throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<text::XTextRange> xRet;

	SdrObject* pObj = GetSdrObject();
	if( pObj )
	{
		ScDrawLayer* pModel = (ScDrawLayer*)pObj->GetModel();
		SdrPage* pPage = pObj->GetPage();
		if ( pModel )
		{
			ScDocument* pDoc = pModel->GetDocument();
			if ( pDoc )
			{
				SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
				if ( pObjSh && pObjSh->ISA(ScDocShell) )
				{
					ScDocShell* pDocSh = (ScDocShell*)pObjSh;

					SCTAB nTab = 0;
					if ( lcl_GetPageNum( pPage, *pModel, nTab ) )
					{
						Point aPos(pObj->GetCurrentBoundRect().TopLeft());
						ScRange aRange(pDoc->GetRange( nTab, Rectangle( aPos, aPos ) ));

						//	anchor is always the cell

						xRet.set(new ScCellObj( pDocSh, aRange.aStart ));
					}
				}
			}
		}
	}

	return xRet;
}

// XComponent

void SAL_CALL ScShapeObj::dispose() throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
	if ( xAggComp.is() )
		xAggComp->dispose();
}

void SAL_CALL ScShapeObj::addEventListener(
						const uno::Reference<lang::XEventListener>& xListener )
													throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
	if ( xAggComp.is() )
		xAggComp->addEventListener(xListener);
}

void SAL_CALL ScShapeObj::removeEventListener(
						const uno::Reference<lang::XEventListener>& xListener )
													throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
	if ( xAggComp.is() )
		xAggComp->removeEventListener(xListener);
}

// XText
// (special handling for ScCellFieldObj)

void lcl_CopyOneProperty( beans::XPropertySet& rDest, beans::XPropertySet& rSource, const sal_Char* pName )
{
	rtl::OUString aNameStr(rtl::OUString::createFromAscii(pName));
	try
	{
		rDest.setPropertyValue( aNameStr, rSource.getPropertyValue( aNameStr ) );
	}
	catch (uno::Exception&)
	{
		DBG_ERROR("Exception in text field");
	}
}

void SAL_CALL ScShapeObj::insertTextContent( const uno::Reference<text::XTextRange>& xRange,
												const uno::Reference<text::XTextContent>& xContent,
												sal_Bool bAbsorb )
									throw(lang::IllegalArgumentException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<text::XTextContent> xEffContent;

	ScCellFieldObj* pCellField = ScCellFieldObj::getImplementation( xContent );
	if ( pCellField )
	{
		//	#105585# createInstance("TextField.URL") from the document creates a ScCellFieldObj.
		//	To insert it into drawing text, a SvxUnoTextField is needed instead.
		//	The ScCellFieldObj object is left in non-inserted state.

		SvxUnoTextField* pDrawField = new SvxUnoTextField( ID_URLFIELD );
		xEffContent.set(pDrawField);
		lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_URL );
		lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_REPR );
		lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_TARGET );
	}
	else
		xEffContent.set(xContent);

	uno::Reference<text::XText> xAggText(lcl_GetText(mxShapeAgg));
	if ( xAggText.is() )
		xAggText->insertTextContent( xRange, xEffContent, bAbsorb );
}

void SAL_CALL ScShapeObj::removeTextContent( const uno::Reference<text::XTextContent>& xContent )
								throw(container::NoSuchElementException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

	//	ScCellFieldObj can't be used here.

	uno::Reference<text::XText> xAggText(lcl_GetText(mxShapeAgg));
	if ( xAggText.is() )
		xAggText->removeTextContent( xContent );
}

// XSimpleText (parent of XText)
// Use own SvxUnoTextCursor subclass - everything is just passed to aggregated object

uno::Reference<text::XTextCursor> SAL_CALL ScShapeObj::createTextCursor()
													throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	if ( mxShapeAgg.is() )
	{
		//	ScDrawTextCursor must be used to ensure the ScShapeObj is returned by getText

		SvxUnoTextBase* pText = SvxUnoTextBase::getImplementation( mxShapeAgg );
		if (pText)
			return new ScDrawTextCursor( this, *pText );
	}

	return uno::Reference<text::XTextCursor>();
}

uno::Reference<text::XTextCursor> SAL_CALL ScShapeObj::createTextCursorByRange(
									const uno::Reference<text::XTextRange>& aTextPosition )
													throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	if ( mxShapeAgg.is() && aTextPosition.is() )
	{
		//	ScDrawTextCursor must be used to ensure the ScShapeObj is returned by getText

		SvxUnoTextBase* pText = SvxUnoTextBase::getImplementation( mxShapeAgg );
		SvxUnoTextRangeBase* pRange = SvxUnoTextRangeBase::getImplementation( aTextPosition );
		if ( pText && pRange )
		{
			SvxUnoTextCursor* pCursor = new ScDrawTextCursor( this, *pText );
			uno::Reference<text::XTextCursor> xCursor( pCursor );
			pCursor->SetSelection( pRange->GetSelection() );
			return xCursor;
		}
	}

	return uno::Reference<text::XTextCursor>();
}

void SAL_CALL ScShapeObj::insertString( const uno::Reference<text::XTextRange>& xRange,
										const rtl::OUString& aString, sal_Bool bAbsorb )
									throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<text::XSimpleText> xAggSimpleText(lcl_GetSimpleText(mxShapeAgg));
	if ( xAggSimpleText.is() )
		xAggSimpleText->insertString( xRange, aString, bAbsorb );
	else
		throw uno::RuntimeException();
}

void SAL_CALL ScShapeObj::insertControlCharacter( const uno::Reference<text::XTextRange>& xRange,
												sal_Int16 nControlCharacter, sal_Bool bAbsorb )
									throw(lang::IllegalArgumentException, uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<text::XSimpleText> xAggSimpleText(lcl_GetSimpleText(mxShapeAgg));
	if ( xAggSimpleText.is() )
		xAggSimpleText->insertControlCharacter( xRange, nControlCharacter, bAbsorb );
	else
		throw uno::RuntimeException();
}

// XTextRange
// (parent of XSimpleText)

uno::Reference<text::XText> SAL_CALL ScShapeObj::getText() throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;
	return this;
}

uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getStart() throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
	if ( xAggTextRange.is() )
		return xAggTextRange->getStart();
	else
		throw uno::RuntimeException();

//    return uno::Reference<text::XTextRange>();
}

uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getEnd() throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
	if ( xAggTextRange.is() )
		return xAggTextRange->getEnd();
	else
		throw uno::RuntimeException();

//    return uno::Reference<text::XTextRange>();
}

rtl::OUString SAL_CALL ScShapeObj::getString() throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
	if ( xAggTextRange.is() )
		return xAggTextRange->getString();
	else
		throw uno::RuntimeException();

//    return rtl::OUString();
}

void SAL_CALL ScShapeObj::setString( const rtl::OUString& aText ) throw(uno::RuntimeException)
{
	ScUnoGuard aGuard;

	uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
	if ( xAggTextRange.is() )
		xAggTextRange->setString( aText );
	else
		throw uno::RuntimeException();
}

// XChild

uno::Reference< uno::XInterface > SAL_CALL ScShapeObj::getParent() throw (uno::RuntimeException)
{
	ScUnoGuard aGuard;

    // receive cell position from caption object (parent of a note caption is the note cell)
	SdrObject* pObj = GetSdrObject();
	if( pObj )
	{
		ScDrawLayer* pModel = (ScDrawLayer*)pObj->GetModel();
		SdrPage* pPage = pObj->GetPage();
		if ( pModel )
		{
			ScDocument* pDoc = pModel->GetDocument();
			if ( pDoc )
			{
				SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
				if ( pObjSh && pObjSh->ISA(ScDocShell) )
				{
					ScDocShell* pDocSh = (ScDocShell*)pObjSh;

					SCTAB nTab = 0;
					if ( lcl_GetPageNum( pPage, *pModel, nTab ) )
					{
                        const ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObj, nTab );
                        if( pCaptData )
                            return static_cast< ::cppu::OWeakObject* >( new ScCellObj( pDocSh, pCaptData->maStart ) );
                    }
                }
            }
        }
    }

	return 0;
}

void SAL_CALL ScShapeObj::setParent( const uno::Reference< uno::XInterface >& ) throw (lang::NoSupportException, uno::RuntimeException)
{
    throw lang::NoSupportException();
}

// XTypeProvider

uno::Sequence<uno::Type> SAL_CALL ScShapeObj::getTypes() throw(uno::RuntimeException)
{
    uno::Sequence< uno::Type > aBaseTypes( ScShapeObj_Base::getTypes() );

    uno::Sequence< uno::Type > aTextTypes;
    if ( bIsTextShape )
        aTextTypes = ScShapeObj_TextBase::getTypes();

	uno::Reference<lang::XTypeProvider> xBaseProvider;
	if ( mxShapeAgg.is() )
		mxShapeAgg->queryAggregation( getCppuType((uno::Reference<lang::XTypeProvider>*) 0) ) >>= xBaseProvider;
	DBG_ASSERT( xBaseProvider.is(), "ScShapeObj: No XTypeProvider from aggregated shape!" );

    uno::Sequence< uno::Type > aAggTypes;
	if( xBaseProvider.is() )
		aAggTypes = xBaseProvider->getTypes();

    return ::comphelper::concatSequences( aBaseTypes, aTextTypes, aAggTypes );
}

uno::Sequence<sal_Int8> SAL_CALL ScShapeObj::getImplementationId()
													throw(uno::RuntimeException)
{
    ScUnoGuard aGuard;
	// do we need to compute the implementation id for this instance?
    if( !pImplementationId && mxShapeAgg.is())
	{
        uno::Reference< drawing::XShape > xAggShape;
        mxShapeAgg->queryAggregation( ::getCppuType((uno::Reference< drawing::XShape >*)0) ) >>= xAggShape;

        if( xAggShape.is() )
		{
            const rtl::OUString aShapeType( xAggShape->getShapeType() );
            // did we already compute an implementation id for the agregated shape type?
            ScShapeImplementationIdMap::iterator aIter( aImplementationIdMap.find(aShapeType ) );
			if( aIter == aImplementationIdMap.end() )
			{
				// we need to create a new implementation id for this
				// note: this memory is not free'd until application exists
				//		 but since we have a fixed set of shapetypes and the
				//		 memory will be reused this is ok.
                pImplementationId = new uno::Sequence< sal_Int8 >( 16 );
                rtl_createUuid( (sal_uInt8 *) pImplementationId->getArray(), 0, sal_True );
                aImplementationIdMap[ aShapeType ] = pImplementationId;
			}
			else
			{
				// use the already computed implementation id
                pImplementationId = (*aIter).second;
			}
		}
	}
    if( NULL == pImplementationId )
	{
        DBG_ERROR( "Could not create an implementation id for a ScXShape!" );
        return uno::Sequence< sal_Int8 > ();
	}
	else
	{
        return *pImplementationId;
	}
}

SdrObject* ScShapeObj::GetSdrObject() const throw()
{
	if(mxShapeAgg.is())
	{
		SvxShape* pShape = SvxShape::getImplementation( mxShapeAgg );
		if(pShape)
			return pShape->GetSdrObject();
	}

	return NULL;
}

#define SC_EVENTACC_ONCLICK     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OnClick" ) )
#ifdef ISSUE66550_HLINK_FOR_SHAPES
#define SC_EVENTACC_ONACTION    ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OnAction" ) )
#define SC_EVENTACC_URL         ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URL" ) )
#define SC_EVENTACC_ACTION      ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Action" ) )
#endif
#define SC_EVENTACC_SCRIPT      ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Script" ) )
#define SC_EVENTACC_EVENTTYPE   ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EventType" ) )

typedef ::cppu::WeakImplHelper1< container::XNameReplace > ShapeUnoEventAcess_BASE;
class ShapeUnoEventAccessImpl : public ShapeUnoEventAcess_BASE
{
private:
	ScShapeObj* mpShape;

    ScMacroInfo* getInfo( sal_Bool bCreate = sal_False )
	{
        if( mpShape )
            if( SdrObject* pObj = mpShape->GetSdrObject() )
                return ScDrawLayer::GetMacroInfo( pObj, bCreate );
        return 0;
	}

public:
	ShapeUnoEventAccessImpl( ScShapeObj* pShape ): mpShape( pShape )
	{
	}

	// XNameReplace
	virtual void SAL_CALL replaceByName( const rtl::OUString& aName, const uno::Any& aElement ) throw(lang::IllegalArgumentException, container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
	{
        if ( !hasByName( aName ) )
			throw container::NoSuchElementException();
		uno::Sequence< beans::PropertyValue > aProperties;
		aElement >>= aProperties;
		const beans::PropertyValue* pProperties = aProperties.getConstArray();
		const sal_Int32 nCount = aProperties.getLength();
		sal_Int32 nIndex;
		bool isEventType = false;
		for( nIndex = 0; nIndex < nCount; nIndex++, pProperties++ )
		{
            if ( pProperties->Name.equals( SC_EVENTACC_EVENTTYPE ) )
			{
				isEventType = true;
				continue;
			}
#ifdef ISSUE66550_HLINK_FOR_SHAPES
            if ( isEventType && ((pProperties->Name == SC_EVENTACC_SCRIPT) || (pProperties->Name == SC_EVENTACC_URL)) )
#else
            if ( isEventType && (pProperties->Name == SC_EVENTACC_SCRIPT) )
#endif
			{
                rtl::OUString sValue;
                if ( pProperties->Value >>= sValue )
                {
                    ScMacroInfo* pInfo = getInfo( sal_True );
                    DBG_ASSERT( pInfo, "shape macro info could not be created!" );
                    if ( !pInfo )
                        break;
                    if ( pProperties->Name == SC_EVENTACC_SCRIPT )
                        pInfo->SetMacro( sValue );
#ifdef ISSUE66550_HLINK_FOR_SHAPES
                    else
                        pInfo->SetHlink( sValue );
#endif
                }
			}
		}
	}

	// XNameAccess
	virtual uno::Any SAL_CALL getByName( const rtl::OUString& aName ) throw(container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException)
	{
        uno::Sequence< beans::PropertyValue > aProperties;
        ScMacroInfo* pInfo = getInfo();

        if ( aName == SC_EVENTACC_ONCLICK )
        {
            if ( pInfo && (pInfo->GetMacro().getLength() > 0) )
            {
                aProperties.realloc( 2 );
                aProperties[ 0 ].Name = SC_EVENTACC_EVENTTYPE;
                aProperties[ 0 ].Value <<= SC_EVENTACC_SCRIPT;
                aProperties[ 1 ].Name = SC_EVENTACC_SCRIPT;
                aProperties[ 1 ].Value <<= pInfo->GetMacro();
            }
        }
#ifdef ISSUE66550_HLINK_FOR_SHAPES
        else if( aName == SC_EVENTACC_ONACTION )
        {
            if ( pInfo && (pInfo->GetHlink().getLength() > 0) )
            {
                aProperties.realloc( 2 );
                aProperties[ 0 ].Name = SC_EVENTACC_EVENTTYPE;
                aProperties[ 0 ].Value <<= SC_EVENTACC_ACTION;
                aProperties[ 1 ].Name = SC_EVENTACC_URL;
                aProperties[ 1 ].Value <<= pInfo->GetHlink();
            }
        }
#endif
        else
        {
            throw container::NoSuchElementException();
        }

        return uno::Any( aProperties );
	}

    virtual uno::Sequence< rtl::OUString > SAL_CALL getElementNames() throw(uno::RuntimeException)
	{
#ifdef ISSUE66550_HLINK_FOR_SHAPES
        uno::Sequence< rtl::OUString > aSeq( 2 );
#else
        uno::Sequence< rtl::OUString > aSeq( 1 );
#endif
        aSeq[ 0 ] = SC_EVENTACC_ONCLICK;
#ifdef ISSUE66550_HLINK_FOR_SHAPES
        aSeq[ 1 ] = SC_EVENTACC_ONACTION;
#endif
        return aSeq;
	}

	virtual sal_Bool SAL_CALL hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
	{
#ifdef ISSUE66550_HLINK_FOR_SHAPES
        return (aName == SC_EVENTACC_ONCLICK) || (aName == SC_EVENTACC_ONACTION);
#else
        return aName == SC_EVENTACC_ONCLICK;
#endif
	}

	// XElementAccess
    virtual uno::Type SAL_CALL getElementType() throw(uno::RuntimeException)
	{
		return *SEQTYPE(::getCppuType((const uno::Sequence< beans::PropertyValue >*)0));
	}

    virtual sal_Bool SAL_CALL hasElements() throw(uno::RuntimeException)
	{
        // elements are always present (but contained property sequences may be empty)
        return sal_True;
	}
};

::uno::Reference< container::XNameReplace > SAL_CALL
ScShapeObj::getEvents(  ) throw(uno::RuntimeException)
{
	return new ShapeUnoEventAccessImpl( this );
}

::rtl::OUString SAL_CALL ScShapeObj::getImplementationName(  ) throw (uno::RuntimeException)
{
    return ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.sc.ScShapeObj" ) );
}

::sal_Bool SAL_CALL ScShapeObj::supportsService( const ::rtl::OUString& _ServiceName ) throw (uno::RuntimeException)
{
    uno::Sequence< ::rtl::OUString > aSupported( getSupportedServiceNames() );
    for ( const ::rtl::OUString* pSupported = aSupported.getConstArray();
          pSupported != aSupported.getConstArray() + aSupported.getLength();
          ++pSupported
        )
        if ( _ServiceName == *pSupported )
            return sal_True;
    return sal_False;
}

uno::Sequence< ::rtl::OUString > SAL_CALL ScShapeObj::getSupportedServiceNames(  ) throw (uno::RuntimeException)
{
    uno::Reference<lang::XServiceInfo> xSI;
    if ( mxShapeAgg.is() )
        mxShapeAgg->queryAggregation( lang::XServiceInfo::static_type() ) >>= xSI;

    uno::Sequence< ::rtl::OUString > aSupported;
    if ( xSI.is() )
        aSupported = xSI->getSupportedServiceNames();

    aSupported.realloc( aSupported.getLength() + 1 );
    aSupported[ aSupported.getLength() - 1 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.Shape" ) );
    
    if( bIsNoteCaption )
    {
        aSupported.realloc( aSupported.getLength() + 1 );
        aSupported[ aSupported.getLength() - 1 ] = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.sheet.CellAnnotationShape" ) );
    }

    return aSupported;
}
