Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sc/source/ui/unoobj/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 55 kB image not shown  

Quelle  shapeuno.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <sal/config.h>

#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequence.hxx>
#include <svtools/unoevent.hxx>
#include <svtools/unoimap.hxx>
#include <svx/svdobj.hxx>
#include <svx/ImageMapInfo.hxx>
#include <vcl/dropcache.hxx>
#include <vcl/svapp.hxx>
#include <vcl/unohelp.hxx>
#include <sfx2/event.hxx>
#include <editeng/unofield.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <cppuhelper/implbase.hxx>
#include <cppuhelper/supportsservice.hxx>
#include <comphelper/diagnose_ex.hxx>

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

#include <shapeuno.hxx>
#include <cellsuno.hxx>
#include <textuno.hxx>
#include <fielduno.hxx>
#include <docsh.hxx>
#include <drwlayer.hxx>
#include <userdat.hxx>
#include <unonames.hxx>
#include <styleuno.hxx>

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

static std::span<const SfxItemPropertyMapEntry> lcl_GetShapeMap()
{
    static const SfxItemPropertyMapEntry aShapeMap_Impl[] =
    {
        { SC_UNONAME_ANCHOR, 0, cppu::UnoType<uno::XInterface>::get(), 0, 0 },
        { SC_UNONAME_RESIZE_WITH_CELL, 0, cppu::UnoType<sal_Bool>::get(), 0, 0 },
        { SC_UNONAME_HORIPOS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
        { SC_UNONAME_IMAGEMAP, 0, cppu::UnoType<container::XIndexContainer>::get(), 0, 0 },
        { SC_UNONAME_VERTPOS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
        { SC_UNONAME_MOVEPROTECT, 0, cppu::UnoType<sal_Bool>::get(), 0, 0 },
        { SC_UNONAME_HYPERLINK, 0, cppu::UnoType<OUString>::get(), 0, 0 },
        { SC_UNONAME_URL, 0, cppu::UnoType<OUString>::get(), 0, 0 },
        { SC_UNONAME_STYLE, 0, cppu::UnoType<style::XStyle>::get(), css::beans::PropertyAttribute::MAYBEVOID, 0 },
    };
    return aShapeMap_Impl;
}

const SvEventDescription* ScShapeObj::GetSupportedMacroItems()
{
    static const SvEventDescription aMacroDescriptionsImpl[] =
    {
        { SvMacroItemId::NONE, nullptr }
    };
    return aMacroDescriptionsImpl;
}
ScMacroInfo* ScShapeObj_getShapeHyperMacroInfo( const ScShapeObj* pShape, bool bCreate false )
{
        if( pShape )
            if( SdrObject* pObj = pShape->GetSdrObject() )
                return ScDrawLayer::GetMacroInfo( pObj, bCreate );
        return nullptr;
}

ScShapeObj::ScShapeObj( uno::Reference<drawing::XShape>& xShape ) :
      pShapePropertySet(nullptr),
      pShapePropertyState(nullptr),
      bIsTextShape(false),
      bIsNoteCaption(false)
{
    osl_atomic_increment( &m_refCount );

    {
        mxShapeAgg.set( xShape, uno::UNO_QUERY );
        // extra block to force deletion of the temporary before setDelegator
    }

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

        mxShapeAgg->setDelegator( getXWeak() );

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

        bIsTextShape = ( comphelper::getFromUnoTunnel<SvxUnoTextBase>( mxShapeAgg ) != nullptr );
    }

    {
        SdrObject* pObj = GetSdrObject();
        if ( pObj )
        {
            bIsNoteCaption = ScDrawLayer::IsNoteCaption( pObj );
        }
    }

    osl_atomic_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 )
{
    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() noexcept
{
        OWeakObject::acquire();
}

void SAL_CALL ScShapeObj::release() noexcept
{
        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( cppu::UnoType<beans::XPropertySet>::get()) >>= 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( cppu::UnoType<beans::XPropertyState>::get()) >>= xState;
        pShapePropertyState = xState.get();
    }
}

static uno::Reference<lang::XComponent> lcl_GetComponent( const uno::Reference<uno::XAggregation>& xAgg )
{
    uno::Reference<lang::XComponent> xRet;
    if ( xAgg.is() )
        xAgg->queryAggregation( cppu::UnoType<lang::XComponent>::get()) >>= xRet;
    return xRet;
}

static uno::Reference<text::XText> lcl_GetText( const uno::Reference<uno::XAggregation>&&nbsp;xAgg )
{
    uno::Reference<text::XText> xRet;
    if ( xAgg.is() )
        xAgg->queryAggregation( cppu::UnoType<text::XText>::get()) >>= xRet;
    return xRet;
}

static uno::Reference<text::XSimpleText> lcl_GetSimpleText( const uno::Reference<uno::XAggregation>& xAgg )
{
    uno::Reference<text::XSimpleText> xRet;
    if ( xAgg.is() )
        xAgg->queryAggregation( cppu::UnoType<text::XSimpleText>::get()) >>= xRet;
    return xRet;
}

static uno::Reference<text::XTextRange> lcl_GetTextRange( const uno::Reference<uno::XAggregation>& xAgg )
{
    uno::Reference<text::XTextRange> xRet;
    if ( xAgg.is() )
        xAgg->queryAggregation( cppu::UnoType<text::XTextRange>::get()) >>= xRet;
    return xRet;
}

namespace {

struct PropertySetInfoCache : public CacheOwner
{
    uno::Reference<beans::XPropertySetInfo> getPropertySetInfo(const uno::Reference<beans::XPropertySetInfo>& rxPropSetInfo)
    {
        std::unique_lock l(gCacheMutex);
        // prevent memory leaks, possibly we could use an LRU map here.
        if (gCacheMap.size() > 100)
            gCacheMap.clear();
        auto it = gCacheMap.find(rxPropSetInfo);
        if (it != gCacheMap.end())
            return it->second;
        uno::Reference<beans::XPropertySetInfo> xCombined = new SfxExtItemPropertySetInfo( lcl_GetShapeMap(), rxPropSetInfo->getProperties() );
        gCacheMap.emplace(rxPropSetInfo, xCombined);
        return xCombined;
    }

private:
    virtual void dropCaches() override
    {
        std::unique_lock l(gCacheMutex);
        gCacheMap.clear();
    }

    virtual void dumpState(rtl::OStringBuffer& rState) override
    {
        THREAD_UNSAFE_DUMP_BEGIN
        rState.append("\nPropertySetInfoCache:\t");
        rState.append(static_cast<sal_Int32>(gCacheMap.size()));
        THREAD_UNSAFE_DUMP_END
    }

    std::mutex gCacheMutex;
    std::unordered_map<uno::Reference<beans::XPropertySetInfo>, uno::Reference<beans::XPropertySetInfo>> gCacheMap;
};

}

/**
 * If there are lots of shapes, the cost of allocating the XPropertySetInfo structures adds up.
 * But we have a static set of properties, and most of the underlying types have one static
 * set per class. So we can cache the combination of them, which dramatically reduces the number
 * of these we need to allocate.
 */

static uno::Reference<beans::XPropertySetInfo> getPropertySetInfoFromCache(const uno::Reference<beans::XPropertySetInfo>& rxPropSetInfo)
{
    static PropertySetInfoCache aCache;
    return aCache.getPropertySetInfo(rxPropSetInfo);
}

//  XPropertySet

uno::Reference<beans::XPropertySetInfo> SAL_CALL ScShapeObj::getPropertySetInfo()
{
    SolarMutexGuard 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());
            mxPropSetInfo = getPropertySetInfoFromCache(xAggInfo);
        }
    }
    return mxPropSetInfo;
}

static bool lcl_GetPageNum( const 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 true;
        }

    return false;
}

static bool lcl_GetCaptionPoint( const uno::Reference< drawing::XShape >& xShape, awt::Point& rCaptionPoint )
{
    bool bReturn = false;
    OUString sType(xShape->getShapeType());
    bool bCaptionShape( sType == "com.sun.star.drawing.CaptionShape" );
    if (bCaptionShape)
    {
        uno::Reference < beans::XPropertySet > xShapeProp (xShape, uno::UNO_QUERY);
        if (xShapeProp.is())
        {
            xShapeProp->getPropertyValue(u"CaptionPoint"_ustr) >>= rCaptionPoint;
            bReturn = true;
        }
    }
    return bReturn;
}

static ScRange lcl_GetAnchorCell( const uno::Reference< drawing::XShape >& xShape, const ScDocument* pDoc, SCTAB nTab,
                          awt::Point& rUnoPoint, awt::Size& rUnoSize, awt::Point& rCaptionPoint )
{
    ScRange aReturn;
    rUnoPoint = xShape->getPosition();
    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, tools::Rectangle(vcl::unohelper::ConvertToVCLPoint(rUnoPoint),
                                                    vcl::unohelper::ConvertToVCLPoint(rUnoPoint)));
    }
    else
    {
        if (bCaptionShape)
        {
            if (rCaptionPoint.X < 0)
                rUnoPoint.X += rCaptionPoint.X;
            if (rCaptionPoint.Y < 0)
                rUnoPoint.Y += rCaptionPoint.Y;
        }
        aReturn
            = pDoc->GetRange(nTab, tools::Rectangle(vcl::unohelper::ConvertToVCLPoint(rUnoPoint),
                                                    vcl::unohelper::ConvertToVCLPoint(rUnoPoint)));
    }

    return aReturn;
}

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

void SAL_CALL ScShapeObj::setPropertyValue(const OUString& aPropertyName, const uno::Any& aValue)
{
    SolarMutexGuard aGuard;

    if ( aPropertyName == SC_UNONAME_ANCHOR )
    {
        uno::Reference<sheet::XCellRangeAddressable> xRangeAdd(aValue, uno::UNO_QUERY);
        if (!xRangeAdd.is())
            throw lang::IllegalArgumentException(u"only XCell or XSpreadsheet objects allowed"_ustr, getXWeak(), 0);

        SdrObject *pObj = GetSdrObject();
        if (pObj)
        {
            ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
            SdrPage* pPage(pObj->getSdrPageFromSdrObject());

            if ( pPage )
            {
                ScDocument* pDoc(rModel.GetDocument());

                if ( pDoc )
                {
                    if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
                    {
                        SCTAB nTab = 0;
                        if ( lcl_GetPageNum( pPage, rModel, nTab ) )
                        {
                            table::CellRangeAddress aAddress = xRangeAdd->getRangeAddress();
                            if (nTab == aAddress.Sheet)
                            {
                                tools::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 ));
                                awt::Point aRelPoint;
                                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;
                                    aRelPoint = lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint );
                                    awt::Point aUnoPoint(aRelPoint);

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

                                if (aAddress.StartRow != aAddress.EndRow) //should be a Spreadsheet
                                {
                                    OSL_ENSURE(aAddress.StartRow == 0 && aAddress.EndRow == pDoc->MaxRow() &&
                                        aAddress.StartColumn == 0 && aAddress.EndColumn == pDoc->MaxCol(), "here should be a XSpreadsheet");
                                    ScDrawLayer::SetPageAnchored(*pObj);
                                }
                                else
                                {
                                    OSL_ENSURE(aAddress.StartRow == aAddress.EndRow &&
                                        aAddress.StartColumn == aAddress.EndColumn, "here should be a XCell");
                                    ScDrawObjData aAnchor;
                                    aAnchor.maStart = ScAddress(aAddress.StartColumn, aAddress.StartRow, aAddress.Sheet);
                                    aAnchor.maStartOffset = Point(aRelPoint.X, aRelPoint.Y);
                                    ScDrawObjData* pDrawObjData = ScDrawLayer::GetObjData(pObj);
                                    if (pDrawObjData)
                                        aAnchor.mbResizeWithCell = pDrawObjData->mbResizeWithCell;
                                    //Uno sets the Anchor in terms of the unrotated shape, not much we can do
                                    //about that since uno also displays the shape geometry in terms of the unrotated
                                    //shape. #TODO think about changing the anchoring behaviour here too
                                    //Currently we've only got a start anchor, not an end-anchor, so generate that now
                                    ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, aAnchor, *pDoc, aAddress.Sheet);
                                    ScDrawLayer::SetCellAnchored(*pObj, aAnchor);
                                }
                            }
                        }
                    }
                }
            }
        }

    }
    else if ( aPropertyName == SC_UNONAME_RESIZE_WITH_CELL )
    {
        SdrObject* pObj = GetSdrObject();
        if (!pObj)
            return;
        ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj);

        // Nothing to do if anchored to page
        if (aAnchorType == SCA_PAGE)
            return;

        ScDrawObjData* pDrawObjData = ScDrawLayer::GetObjData(pObj);
        if (!pDrawObjData)
            return;

        aValue >>= pDrawObjData->mbResizeWithCell;
        ScDrawLayer::SetCellAnchored(*pObj, *pDrawObjData);
    }
    else if ( aPropertyName == 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();

            SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(pObj);
            if( pIMapInfo )
            {
                // replace existing image map
                pIMapInfo->SetImageMap( aImageMap );
            }
            else
            {
                // insert new user data with image map
                pObj->AppendUserData(std::unique_ptr<SdrObjUserData>(new SvxIMapInfo(aImageMap) ));
            }
        }
    }
    else if ( aPropertyName == SC_UNONAME_HORIPOS )
    {
        sal_Int32 nPos = 0;
        if (aValue >>= nPos)
        {
            SdrObject *pObj = GetSdrObject();
            if (pObj)
            {
                ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
                SdrPage* pPage(pObj->getSdrPageFromSdrObject());

                if ( pPage )
                {
                    SCTAB nTab = 0;
                    if ( lcl_GetPageNum( pPage, rModel, nTab ) )
                    {
                        ScDocument* pDoc = rModel.GetDocument();
                        if ( pDoc )
                        {
                            if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
                            {
                                uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                                if (xShape.is())
                                {
                                    if (ScDrawLayer::GetAnchorType(*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::GetAnchorType(*pObj) == SCA_CELL
                                             || ScDrawLayer::GetAnchorType(*pObj)
                                                    == SCA_CELL_RESIZE)
                                    {
                                        awt::Size aUnoSize;
                                        awt::Point aCaptionPoint;
                                        ScRange aRange;
                                        awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
                                        tools::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
                                    {
                                        OSL_FAIL("unknown anchor type");
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    else if ( aPropertyName == SC_UNONAME_VERTPOS )
    {
        sal_Int32 nPos = 0;
        if (aValue >>= nPos)
        {
            SdrObject *pObj = GetSdrObject();
            if (pObj)
            {
                ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
                SdrPage* pPage(pObj->getSdrPageFromSdrObject());

                if ( pPage )
                {
                    SCTAB nTab = 0;
                    if ( lcl_GetPageNum( pPage, rModel, nTab ) )
                    {
                        ScDocument* pDoc = rModel.GetDocument();
                        if ( pDoc )
                        {
                            if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
                            {
                                uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                                if (xShape.is())
                                {
                                    if (ScDrawLayer::GetAnchorType(*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::GetAnchorType(*pObj) == SCA_CELL
                                             || ScDrawLayer::GetAnchorType(*pObj)
                                                    == SCA_CELL_RESIZE)
                                    {
                                        awt::Size aUnoSize;
                                        awt::Point aCaptionPoint;
                                        ScRange aRange;
                                        awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
                                        tools::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
                                    {
                                        OSL_FAIL("unknown anchor type");
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    else if  ( aPropertyName == SC_UNONAME_HYPERLINK ||
               aPropertyName == SC_UNONAME_URL )
    {
        OUString sHyperlink;
        SdrObject* pObj = GetSdrObject();
        if (pObj && (aValue >>= sHyperlink))
            pObj->setHyperlink(sHyperlink);
    }
    else if ( aPropertyName == SC_UNONAME_MOVEPROTECT )
    {
        if( SdrObject* pObj = GetSdrObject() )
        {
            bool aProt = false;
            if( aValue >>= aProt )
                pObj->SetMoveProtect( aProt );
        }
    }
    else if ( aPropertyName == SC_UNONAME_STYLE )
    {
        if (SdrObject* pObj = GetSdrObject())
        {
            uno::Reference<style::XStyle> xStyle(aValue, uno::UNO_QUERY);
            auto pStyleSheetObj = dynamic_cast<ScStyleObj*>(xStyle.get());
            if (!pStyleSheetObj)
                throw lang::IllegalArgumentException();

            auto pStyleSheet = pStyleSheetObj->GetStyle_Impl();
            auto pOldStyleSheet = pObj->GetStyleSheet();

            if (pStyleSheet != pOldStyleSheet)
                pObj->SetStyleSheet(static_cast<SfxStyleSheet*>(pStyleSheet), false);
        }
    }
    else
    {
        GetShapePropertySet();
        if (pShapePropertySet)
            pShapePropertySet->setPropertyValue( aPropertyName, aValue );
    }
}

uno::Any SAL_CALL ScShapeObj::getPropertyValue( const OUString& aPropertyName )
{
    SolarMutexGuard aGuard;

    uno::Any aAny;
    if ( aPropertyName == SC_UNONAME_ANCHOR )
    {
        SdrObject *pObj = GetSdrObject();
        if (pObj)
        {
            ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
            SdrPage* pPage(pObj->getSdrPageFromSdrObject());

            if ( pPage )
            {
                ScDocument* pDoc = rModel.GetDocument();
                if ( pDoc )
                {
                    SCTAB nTab = 0;
                    if ( lcl_GetPageNum( pPage, rModel, nTab ) )
                    {
                        if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
                        {
                            uno::Reference< uno::XInterface > xAnchor;
                            if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjDataTab(pObj, nTab))
                                xAnchor.set(cppu::getXWeak(new ScCellObj( pDocSh, pAnchor->maStart)));
                            else
                                xAnchor.set(cppu::getXWeak(new ScTableSheetObj( pDocSh, nTab )));
                            aAny <<= xAnchor;
                        }
                    }
                }
            }
        }
    }
    else if (aPropertyName == SC_UNONAME_RESIZE_WITH_CELL)
    {
        bool bIsResizeWithCell = false;
        SdrObject* pObj = GetSdrObject();
        if (pObj)
        {
            ScAnchorType anchorType = ScDrawLayer::GetAnchorType(*pObj);
            bIsResizeWithCell = (anchorType == SCA_CELL_RESIZE);
        }
        aAny <<= bIsResizeWithCell;
    }
    else if ( aPropertyName == SC_UNONAME_IMAGEMAP )
    {
        uno::Reference< uno::XInterface > xImageMap;
        SdrObject* pObj = GetSdrObject();
        if ( pObj )
        {
            SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(GetSdrObject());
            if( pIMapInfo )
            {
                const ImageMap& rIMap = pIMapInfo->GetImageMap();
                xImageMap.set(SvUnoImageMap_createInstance( rIMap, GetSupportedMacroItems() ));
            }
            else
                xImageMap = SvUnoImageMap_createInstance();
        }
        aAny <<= uno::Reference< container::XIndexContainer >::query( xImageMap );
    }
    else if ( aPropertyName == SC_UNONAME_HORIPOS )
    {
        SdrObject *pObj = GetSdrObject();
        if (pObj)
        {
            ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
            SdrPage* pPage(pObj->getSdrPageFromSdrObject());

            if ( pPage )
            {
                ScDocument* pDoc = rModel.GetDocument();
                if ( pDoc )
                {
                    SCTAB nTab = 0;
                    if ( lcl_GetPageNum( pPage, rModel, nTab ) )
                    {
                        uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                        if (xShape.is())
                        {
                            if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
                                || ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL_RESIZE)
                            {
                                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 ( aPropertyName ==  SC_UNONAME_VERTPOS )
    {
        SdrObject *pObj = GetSdrObject();
        if (pObj)
        {
            ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
            SdrPage* pPage(pObj->getSdrPageFromSdrObject());

            if ( pPage )
            {
                ScDocument* pDoc = rModel.GetDocument();
                if ( pDoc )
                {
                    SCTAB nTab = 0;
                    if ( lcl_GetPageNum( pPage, rModel, nTab ) )
                    {
                        uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
                        if (xShape.is())
                        {
                            if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
                                || ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL_RESIZE)
                            {
                                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 if ( aPropertyName == SC_UNONAME_HYPERLINK ||
              aPropertyName == SC_UNONAME_URL )
    {
        OUString sHlink;
        if (SdrObject* pObj = GetSdrObject())
            sHlink = pObj->getHyperlink();
        aAny <<= sHlink;
    }
    else if ( aPropertyName == SC_UNONAME_MOVEPROTECT )
    {
        bool aProt = false;
        if ( SdrObject* pObj = GetSdrObject() )
            aProt = pObj->IsMoveProtect();
        aAny <<= aProt;
    }
    else if ( aPropertyName == SC_UNONAME_STYLE )
    {
        if (SdrObject* pObj = GetSdrObject())
        {
            if (auto pStyleSheet = pObj->GetStyleSheet())
            {
                ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
                ScDocument* pDoc = rModel.GetDocument();
                aAny <<= uno::Reference<style::XStyle>(new ScStyleObj(
                    pDoc ? pDoc->GetDocumentShell() : nullptr,
                    SfxStyleFamily::Frame, pStyleSheet->GetName()));
            }
        }
    }
    else
    {
        if(!pShapePropertySet) //performance consideration
            GetShapePropertySet();
        if (pShapePropertySet)
            aAny = pShapePropertySet->getPropertyValue( aPropertyName );
    }

    return aAny;
}

void SAL_CALL ScShapeObj::addPropertyChangeListener( const OUString& aPropertyName,
                            const uno::Reference<beans::XPropertyChangeListener>& aListener)
{
    SolarMutexGuard aGuard;

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

void SAL_CALL ScShapeObj::removePropertyChangeListener( const OUString& aPropertyName,
                            const uno::Reference<beans::XPropertyChangeListener>& aListener)
{
    SolarMutexGuard aGuard;

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

void SAL_CALL ScShapeObj::addVetoableChangeListener( const OUString& aPropertyName,
                            const uno::Reference<beans::XVetoableChangeListener>& aListener)
{
    SolarMutexGuard aGuard;

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

void SAL_CALL ScShapeObj::removeVetoableChangeListener( const OUString& aPropertyName,
                            const uno::Reference<beans::XVetoableChangeListener>& aListener)
{
    SolarMutexGuard aGuard;

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

//  XPropertyState

beans::PropertyState SAL_CALL ScShapeObj::getPropertyState( const OUString& aPropertyName )
{
    SolarMutexGuard aGuard;

    beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
    if ( aPropertyName == SC_UNONAME_IMAGEMAP )
    {
        // ImageMap is always "direct"
    }
    else if ( aPropertyName == SC_UNONAME_ANCHOR )
    {
        // Anchor is always "direct"
    }
    else if ( aPropertyName == SC_UNONAME_HORIPOS )
    {
        // HoriPos is always "direct"
    }
    else if ( aPropertyName == 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<OUString>& aPropertyNames )
{
    SolarMutexGuard aGuard;

    //  simple loop to get own and aggregated states

    uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
    std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
        [this](const OUString& rName) -> beans::PropertyState { return getPropertyState(rName); });
    return aRet;
}

void SAL_CALL ScShapeObj::setPropertyToDefault( const OUString& aPropertyName )
{
    SolarMutexGuard aGuard;

    if ( aPropertyName == SC_UNONAME_IMAGEMAP )
    {
        SdrObject* pObj = GetSdrObject();
        if ( pObj )
        {
            SvxIMapInfo* pIMapInfo = SvxIMapInfo::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 OUString& aPropertyName )
{
    SolarMutexGuard aGuard;

    uno::Any aAny;
    if ( aPropertyName == SC_UNONAME_IMAGEMAP )
    {
        //  default: empty ImageMap
        uno::Reference< uno::XInterface > xImageMap(SvUnoImageMap_createInstance());
        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();     // anchor cannot be changed
}

uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getAnchor()
{
    SolarMutexGuard aGuard;

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

    SdrObject* pObj = GetSdrObject();
    if( pObj )
    {
        ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
        SdrPage* pPage(pObj->getSdrPageFromSdrObject());
        ScDocument* pDoc = rModel.GetDocument();

        if ( pPage && pDoc )
        {
            if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
            {
                SCTAB nTab = 0;
                if ( lcl_GetPageNum( pPage, rModel, nTab ) )
                {
                    Point aPos(pObj->GetCurrentBoundRect().TopLeft());
                    ScRange aRange(pDoc->GetRange( nTab, tools::Rectangle( aPos, aPos ) ));

                    //  anchor is always the cell

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

    return xRet;
}

// XComponent

void SAL_CALL ScShapeObj::dispose()
{
    SolarMutexGuard 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 )
{
    SolarMutexGuard 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 )
{
    SolarMutexGuard aGuard;

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

// XText
// (special handling for ScCellFieldObj)

static void lcl_CopyOneProperty( beans::XPropertySet& rDest, beans::XPropertySet&&nbsp;rSource, const OUString& aNameStr )
{
    try
    {
        rDest.setPropertyValue( aNameStr, rSource.getPropertyValue( aNameStr ) );
    }
    catch (uno::Exception&)
    {
        TOOLS_WARN_EXCEPTION( "sc""Exception in text field");
    }
}

void SAL_CALL ScShapeObj::insertTextContent( const uno::Reference<text::XTextRange>&&nbsp;xRange,
                                                const uno::Reference<text::XTextContent>& xContent,
                                                sal_Bool bAbsorb )
{
    SolarMutexGuard aGuard;

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

    ScEditFieldObj* pCellField = dynamic_cast<ScEditFieldObj*>( xContent.get() );
    if ( pCellField )
    {
        //  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.

        rtl::Reference<SvxUnoTextField> pDrawField = new SvxUnoTextField( text::textfield::Type::URL );
        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>&&nbsp;xContent )
{
    SolarMutexGuard 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()
{
    SolarMutexGuard aGuard;

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

        SvxUnoTextBase* pText = comphelper::getFromUnoTunnel<SvxUnoTextBase>( 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 )
{
    SolarMutexGuard aGuard;

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

        SvxUnoTextBase* pText = comphelper::getFromUnoTunnel<SvxUnoTextBase>( mxShapeAgg );
        SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( aTextPosition );
        if ( pText && pRange )
        {
            rtl::Reference<SvxUnoTextCursor> pCursor = new ScDrawTextCursor( this, *pText );
            pCursor->SetSelection( pRange->GetSelection() );
            return pCursor;
        }
    }

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

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

    uno::Reference<text::XSimpleText> xAggSimpleText(lcl_GetSimpleText(mxShapeAgg));
    if ( !xAggSimpleText.is() )
        throw uno::RuntimeException();

    xAggSimpleText->insertString( xRange, aString, bAbsorb );
}

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

    uno::Reference<text::XSimpleText> xAggSimpleText(lcl_GetSimpleText(mxShapeAgg));
    if ( !xAggSimpleText.is() )
        throw uno::RuntimeException();

    xAggSimpleText->insertControlCharacter( xRange, nControlCharacter, bAbsorb );
}

// XTextRange
// (parent of XSimpleText)

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

uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getStart()
{
    SolarMutexGuard aGuard;

    uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
    if ( !xAggTextRange.is() )
        throw uno::RuntimeException();

    return xAggTextRange->getStart();
}

uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getEnd()
{
    SolarMutexGuard aGuard;

    uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
    if ( !xAggTextRange.is() )
        throw uno::RuntimeException();

    return xAggTextRange->getEnd();
}

OUString SAL_CALL ScShapeObj::getString()
{
    SolarMutexGuard aGuard;

    uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
    if ( !xAggTextRange.is() )
        throw uno::RuntimeException();

    return xAggTextRange->getString();
}

void SAL_CALL ScShapeObj::setString( const OUString& aText )
{
    SolarMutexGuard aGuard;

    uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
    if ( !xAggTextRange.is() )
        throw uno::RuntimeException();

    xAggTextRange->setString( aText );
}

// XChild

uno::Reference< uno::XInterface > SAL_CALL ScShapeObj::getParent()
{
    SolarMutexGuard aGuard;

    // receive cell position from caption object (parent of a note caption is the note cell)
    SdrObject* pObj = GetSdrObject();
    if( pObj )
    {
        ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
        SdrPage* pPage(pObj->getSdrPageFromSdrObject());
        ScDocument* pDoc = rModel.GetDocument();

        if ( pPage && pDoc )
        {
            if ( ScDocShell* pDocSh = pDoc->GetDocumentShell() )
            {
                SCTAB nTab = 0;
                if ( lcl_GetPageNum( pPage, rModel, nTab ) )
                {
                    const ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObj, nTab );
                    if( pCaptData )
                        return cppu::getXWeak( new ScCellObj( pDocSh, pCaptData->maStart ) );
                }
            }
        }
    }

    return nullptr;
}

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

// XTypeProvider

uno::Sequence<uno::Type> SAL_CALL ScShapeObj::getTypes()
{
    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( cppu::UnoType<lang::XTypeProvider>::get()) >>= xBaseProvider;
    OSL_ENSURE( 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()
{
    return css::uno::Sequence<sal_Int8>();
}

SdrObject* ScShapeObj::GetSdrObject() const noexcept
{
    if(mxShapeAgg.is())
        return SdrObject::getSdrObjectFromXShape( mxShapeAgg );
    return nullptr;
}

constexpr OUString SC_EVENTACC_ONCLICK = u"OnClick"_ustr;
constexpr OUString SC_EVENTACC_SCRIPT = u"Script"_ustr;
constexpr OUString SC_EVENTACC_EVENTTYPE = u"EventType"_ustr;

class ShapeUnoEventAccessImpl : public ::cppu::WeakImplHelper< container::XNameReplace >
{
private:
    ScShapeObj* mpShape;

    ScMacroInfo* getInfo( bool bCreate )
    {
        return ScShapeObj_getShapeHyperMacroInfo( mpShape, bCreate );
    }

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

    // XNameReplace
    virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override
    {
        if ( !hasByName( aName ) )
            throw container::NoSuchElementException();
        uno::Sequence< beans::PropertyValue > aProperties;
        aElement >>= aProperties;
        bool isEventType = false;
        for (const beans::PropertyValue& rProperty : aProperties)
        {
            if ( rProperty.Name == SC_EVENTACC_EVENTTYPE )
            {
                isEventType = true;
                continue;
            }
            if ( isEventType && (rProperty.Name == SC_EVENTACC_SCRIPT) )
            {
                OUString sValue;
                if ( rProperty.Value >>= sValue )
                {
                    ScMacroInfo* pInfo = getInfo( true );
                    OSL_ENSURE( pInfo, "shape macro info could not be created!" );
                    if ( !pInfo )
                        break;
                    pInfo->SetMacro( sValue );
                }
            }
        }
    }

    // XNameAccess
    virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
    {
        uno::Sequence< beans::PropertyValue > aProperties;
        ScMacroInfo* pInfo = getInfo(false);

        if ( aName != SC_EVENTACC_ONCLICK )
        {
            throw container::NoSuchElementException();
        }

        if ( pInfo && !pInfo->GetMacro().isEmpty() )
        {
            aProperties = { comphelper::makePropertyValue(SC_EVENTACC_EVENTTYPE,
                                                          SC_EVENTACC_SCRIPT),
                            comphelper::makePropertyValue(SC_EVENTACC_SCRIPT, pInfo->GetMacro()) };
        }

        return uno::Any( aProperties );
    }

    virtual uno::Sequence< OUString > SAL_CALL getElementNames() override
    {
        uno::Sequence<OUString> aSeq { SC_EVENTACC_ONCLICK };
        return aSeq;
    }

    virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
    {
        return aName == SC_EVENTACC_ONCLICK;
    }

    // XElementAccess
    virtual uno::Type SAL_CALL getElementType() override
    {
        return cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get();
    }

    virtual sal_Bool SAL_CALL hasElements() override
    {
        // elements are always present (but contained property sequences may be empty)
        return true;
    }
};

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

OUString SAL_CALL ScShapeObj::getImplementationName(  )
{
    return u"com.sun.star.comp.sc.ScShapeObj"_ustr;
}

sal_Bool SAL_CALL ScShapeObj::supportsService( const OUString& ServiceName )
{
    return cppu::supportsService(this, ServiceName);
}

uno::Sequence< OUString > SAL_CALL ScShapeObj::getSupportedServiceNames(  )
{
    uno::Reference<lang::XServiceInfo> xSI;
    if ( mxShapeAgg.is() )
        mxShapeAgg->queryAggregation( cppu::UnoType<lang::XServiceInfo>::get() ) >>= xSI;

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

    aSupported.realloc( aSupported.getLength() + 1 );
    aSupported.getArray()[ aSupported.getLength() - 1 ] = "com.sun.star.sheet.Shape";

    if( bIsNoteCaption )
    {
        aSupported.realloc( aSupported.getLength() + 1 );
        aSupported.getArray()[ aSupported.getLength() - 1 ] = "com.sun.star.sheet.CellAnnotationShape";
    }

    return aSupported;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=97 H=98 G=97

¤ Dauer der Verarbeitung: 0.21 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.