summaryrefslogtreecommitdiffstats
path: root/chart2/source/controller/main/SelectionHelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'chart2/source/controller/main/SelectionHelper.cxx')
-rw-r--r--chart2/source/controller/main/SelectionHelper.cxx651
1 files changed, 651 insertions, 0 deletions
diff --git a/chart2/source/controller/main/SelectionHelper.cxx b/chart2/source/controller/main/SelectionHelper.cxx
new file mode 100644
index 0000000000..11fc5d9fae
--- /dev/null
+++ b/chart2/source/controller/main/SelectionHelper.cxx
@@ -0,0 +1,651 @@
+/* -*- 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 <SelectionHelper.hxx>
+#include <ObjectIdentifier.hxx>
+#include <DiagramHelper.hxx>
+#include <Diagram.hxx>
+#include <ChartModelHelper.hxx>
+#include <ChartModel.hxx>
+
+#include <svx/svdpage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/obj3d.hxx>
+#include <svx/svdopath.hxx>
+#include <vcl/svapp.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+#include <osl/diagnose.h>
+
+namespace chart
+{
+using namespace ::com::sun::star;
+
+namespace
+{
+
+OUString lcl_getObjectName( SdrObject const * pObj )
+{
+ if(pObj)
+ return pObj->GetName();
+ return OUString();
+}
+
+void impl_selectObject( SdrObject* pObjectToSelect, DrawViewWrapper& rDrawViewWrapper )
+{
+ SolarMutexGuard aSolarGuard;
+
+ if(pObjectToSelect)
+ {
+ SelectionHelper aSelectionHelper( pObjectToSelect );
+ SdrObject* pMarkObj = aSelectionHelper.getObjectToMark();
+ rDrawViewWrapper.setMarkHandleProvider(&aSelectionHelper);
+ rDrawViewWrapper.MarkObject(pMarkObj);
+ rDrawViewWrapper.setMarkHandleProvider(nullptr);
+ }
+}
+
+}//anonymous namespace
+
+bool Selection::hasSelection() const
+{
+ return m_aSelectedOID.isValid();
+}
+
+OUString const & Selection::getSelectedCID() const
+{
+ return m_aSelectedOID.getObjectCID();
+}
+
+uno::Reference< drawing::XShape > const & Selection::getSelectedAdditionalShape() const
+{
+ return m_aSelectedOID.getAdditionalShape();
+}
+
+bool Selection::setSelection( const OUString& rCID )
+{
+ if ( rCID != m_aSelectedOID.getObjectCID() )
+ {
+ m_aSelectedOID = ObjectIdentifier( rCID );
+ return true;
+ }
+ return false;
+}
+
+bool Selection::setSelection( const uno::Reference< drawing::XShape >& xShape )
+{
+ if ( !( xShape == m_aSelectedOID.getAdditionalShape() ) )
+ {
+ clearSelection();
+ m_aSelectedOID = ObjectIdentifier( xShape );
+ return true;
+ }
+ return false;
+}
+
+void Selection::clearSelection()
+{
+ m_aSelectedOID = ObjectIdentifier();
+ m_aSelectedOID_beforeMouseDown = ObjectIdentifier();
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+}
+
+bool Selection::maybeSwitchSelectionAfterSingleClickWasEnsured()
+{
+ if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid()
+ && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing != m_aSelectedOID )
+ {
+ m_aSelectedOID = m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing;
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+ return true;
+ }
+ return false;
+}
+
+void Selection::resetPossibleSelectionAfterSingleClickWasEnsured()
+{
+ if ( m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() )
+ {
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+ }
+}
+
+void Selection::remindSelectionBeforeMouseDown()
+{
+ m_aSelectedOID_beforeMouseDown = m_aSelectedOID;
+}
+
+bool Selection::isSelectionDifferentFromBeforeMouseDown() const
+{
+ return ( m_aSelectedOID != m_aSelectedOID_beforeMouseDown );
+}
+
+void Selection::applySelection( DrawViewWrapper* pDrawViewWrapper )
+{
+ if( !pDrawViewWrapper )
+ return;
+
+ {
+ SolarMutexGuard aSolarGuard;
+ pDrawViewWrapper->UnmarkAll();
+ }
+ SdrObject* pObjectToSelect = nullptr;
+ if ( m_aSelectedOID.isAutoGeneratedObject() )
+ {
+ pObjectToSelect = pDrawViewWrapper->getNamedSdrObject( m_aSelectedOID.getObjectCID() );
+ }
+ else if( m_aSelectedOID.isAdditionalShape() )
+ {
+ pObjectToSelect = DrawViewWrapper::getSdrObject( m_aSelectedOID.getAdditionalShape() );
+ }
+
+ impl_selectObject( pObjectToSelect, *pDrawViewWrapper );
+}
+
+void Selection::adaptSelectionToNewPos( const Point& rMousePos, DrawViewWrapper const * pDrawViewWrapper
+ , bool bIsRightMouse, bool bWaitingForDoubleClick )
+{
+ if( !pDrawViewWrapper )
+ return;
+
+ //do not toggle multiclick selection if right clicked on the selected object or waiting for double click
+ bool bAllowMultiClickSelectionChange = !bIsRightMouse && !bWaitingForDoubleClick;
+
+ ObjectIdentifier aLastSelectedObject( m_aSelectedOID );
+
+ SolarMutexGuard aSolarGuard;
+
+ //bAllowMultiClickSelectionChange==true -> a second click on the same object can lead to a changed selection (e.g. series -> single data point)
+
+ //get object to select:
+ {
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+
+ //the search for the object to select starts with the hit object deepest in the grouping hierarchy (a leaf in the tree)
+ //further we travel along the grouping hierarchy from child to parent
+ SdrObject* pNewObj = pDrawViewWrapper->getHitObject(rMousePos);
+ m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );//name of pNewObj
+
+ //ignore handle only objects for hit test
+ while( pNewObj && m_aSelectedOID.getObjectCID().match( "HandlesOnly" ) )
+ {
+ pNewObj->SetMarkProtect(true);
+ pNewObj = pDrawViewWrapper->getHitObject(rMousePos);
+ m_aSelectedOID = ObjectIdentifier( lcl_getObjectName( pNewObj ) );
+ }
+
+ //accept only named objects while searching for the object to select
+ //this call may change m_aSelectedOID
+ if ( SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, true ) )
+ {
+ //if the so far found object is a multi click object further steps are necessary
+ while( ObjectIdentifier::isMultiClickObject( m_aSelectedOID.getObjectCID() ) )
+ {
+ bool bSameObjectAsLastSelected = ( aLastSelectedObject == m_aSelectedOID );
+ if( bSameObjectAsLastSelected )
+ {
+ //if the same child is clicked again don't go up further
+ break;
+ }
+ if ( ObjectIdentifier::areSiblings( aLastSelectedObject.getObjectCID(), m_aSelectedOID.getObjectCID() ) )
+ {
+ //if a sibling of the last selected object is clicked don't go up further
+ break;
+ }
+ ObjectIdentifier aLastChild = m_aSelectedOID;
+ if ( !SelectionHelper::findNamedParent( pNewObj, m_aSelectedOID, false ) )
+ {
+ //take the one found so far
+ break;
+ }
+ //if the last selected object is found don't go up further
+ //but take the last child if selection change is allowed
+ if ( aLastSelectedObject == m_aSelectedOID )
+ {
+ if( bAllowMultiClickSelectionChange )
+ {
+ m_aSelectedOID = aLastChild;
+ }
+ else
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = aLastChild;
+ break;
+ }
+ }
+
+ OSL_ENSURE(m_aSelectedOID.isValid(), "somehow lost selected object");
+ }
+ else
+ {
+ //maybe an additional shape was hit
+ if ( pNewObj )
+ {
+ m_aSelectedOID = ObjectIdentifier( uno::Reference< drawing::XShape >( pNewObj->getUnoShape(), uno::UNO_QUERY ) );
+ }
+ else
+ {
+ m_aSelectedOID = ObjectIdentifier();
+ }
+ }
+
+ if ( !m_aSelectedOID.isAdditionalShape() )
+ {
+ OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );//@todo read CID from model
+
+ if ( !m_aSelectedOID.isAutoGeneratedObject() )
+ {
+ m_aSelectedOID = ObjectIdentifier( aPageCID );
+ }
+
+ //check whether the diagram was hit but not selected (e.g. because it has no filling):
+ OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
+ OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model
+ bool bBackGroundHit = m_aSelectedOID.getObjectCID() == aPageCID || m_aSelectedOID.getObjectCID() == aWallCID || !m_aSelectedOID.isAutoGeneratedObject();
+ if( bBackGroundHit )
+ {
+ //todo: if more than one diagram is available in future do check the list of all diagrams here
+ SdrObject* pDiagram = pDrawViewWrapper->getNamedSdrObject( aDiagramCID );
+ if( pDiagram )
+ {
+ if( DrawViewWrapper::IsObjectHit( pDiagram, rMousePos ) )
+ {
+ m_aSelectedOID = ObjectIdentifier( aDiagramCID );
+ }
+ }
+ }
+ //check whether the legend was hit but not selected (e.g. because it has no filling):
+ if( bBackGroundHit || m_aSelectedOID.getObjectCID() == aDiagramCID )
+ {
+ OUString aLegendCID( ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::createParticleForLegend(nullptr) ) );//@todo read CID from model
+ SdrObject* pLegend = pDrawViewWrapper->getNamedSdrObject( aLegendCID );
+ if( pLegend )
+ {
+ if( DrawViewWrapper::IsObjectHit( pLegend, rMousePos ) )
+ {
+ m_aSelectedOID = ObjectIdentifier( aLegendCID );
+ }
+ }
+ }
+ }
+ }
+
+ if ( bIsRightMouse && m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing.isValid() )
+ {
+ m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = ObjectIdentifier();
+ }
+}
+
+bool Selection::isResizeableObjectSelected() const
+{
+ ObjectType eObjectType = m_aSelectedOID.getObjectType();
+ switch( eObjectType )
+ {
+ case OBJECTTYPE_DIAGRAM:
+ case OBJECTTYPE_DIAGRAM_WALL:
+ case OBJECTTYPE_SHAPE:
+ case OBJECTTYPE_LEGEND:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Selection::isRotateableObjectSelected( const rtl::Reference<::chart::ChartModel>& xChartModel ) const
+{
+ return SelectionHelper::isRotateableObject( m_aSelectedOID.getObjectCID(), xChartModel );
+}
+
+bool Selection::isDragableObjectSelected() const
+{
+ return m_aSelectedOID.isDragableObject();
+}
+
+bool Selection::isAdditionalShapeSelected() const
+{
+ return m_aSelectedOID.isAdditionalShape();
+}
+
+bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject
+ , OUString& rOutName
+ , bool bGivenObjectMayBeResult )
+{
+ SolarMutexGuard aSolarGuard;
+ //find the deepest named group
+ SdrObject* pObj = pInOutObject;
+ OUString aName;
+ if( bGivenObjectMayBeResult )
+ aName = lcl_getObjectName( pObj );
+
+ while( pObj && !ObjectIdentifier::isCID( aName ) )
+ {
+ SdrObjList* pObjList = pObj->getParentSdrObjListFromSdrObject();
+ if( !pObjList )
+ return false;
+ SdrObject* pOwner = pObjList->getSdrObjectFromSdrObjList();
+ if( !pOwner )
+ return false;
+ pObj = pOwner;
+ aName = lcl_getObjectName( pObj );
+ }
+
+ if(!pObj)
+ return false;
+ if(aName.isEmpty())
+ return false;
+
+ pInOutObject = pObj;
+ rOutName = aName;
+ return true;
+}
+
+bool SelectionHelper::findNamedParent( SdrObject*& pInOutObject
+ , ObjectIdentifier& rOutObject
+ , bool bGivenObjectMayBeResult )
+{
+ OUString aName;
+ if ( findNamedParent( pInOutObject, aName, bGivenObjectMayBeResult ) )
+ {
+ rOutObject = ObjectIdentifier( aName );
+ return true;
+ }
+ return false;
+}
+
+bool SelectionHelper::isDragableObjectHitTwice( const Point& rMPos
+ , const OUString& rNameOfSelectedObject
+ , const DrawViewWrapper& rDrawViewWrapper )
+{
+ if(rNameOfSelectedObject.isEmpty())
+ return false;
+ if( !ObjectIdentifier::isDragableObject(rNameOfSelectedObject) )
+ return false;
+ SolarMutexGuard aSolarGuard;
+ SdrObject* pObj = rDrawViewWrapper.getNamedSdrObject( rNameOfSelectedObject );
+ return DrawViewWrapper::IsObjectHit( pObj, rMPos );
+}
+
+OUString SelectionHelper::getHitObjectCID(
+ const Point& rMPos,
+ DrawViewWrapper const & rDrawViewWrapper,
+ bool bGetDiagramInsteadOf_Wall )
+{
+ SolarMutexGuard aSolarGuard;
+ OUString aRet;
+
+ SdrObject* pNewObj = rDrawViewWrapper.getHitObject(rMPos);
+ aRet = lcl_getObjectName( pNewObj );//name of pNewObj
+
+ //ignore handle only objects for hit test
+ while( pNewObj && aRet.match("HandlesOnly") )
+ {
+ pNewObj->SetMarkProtect(true);
+ pNewObj = rDrawViewWrapper.getHitObject(rMPos);
+ aRet = lcl_getObjectName( pNewObj );
+ }
+
+ //accept only named objects while searching for the object to select
+ if( !findNamedParent( pNewObj, aRet, true ) )
+ {
+ aRet.clear();
+ }
+
+ OUString aPageCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_PAGE, u"" ) );//@todo read CID from model
+ //get page when nothing was hit
+ if( aRet.isEmpty() && !pNewObj )
+ {
+ aRet = aPageCID;
+ }
+
+ //get diagram instead wall or page if hit inside diagram
+ if( !aRet.isEmpty() )
+ {
+ if( aRet == aPageCID )
+ {
+ OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
+ //todo: if more than one diagram is available in future do check the list of all diagrams here
+ SdrObject* pDiagram = rDrawViewWrapper.getNamedSdrObject( aDiagramCID );
+ if( pDiagram )
+ {
+ if( DrawViewWrapper::IsObjectHit( pDiagram, rMPos ) )
+ {
+ aRet = aDiagramCID;
+ }
+ }
+ }
+ else if( bGetDiagramInsteadOf_Wall )
+ {
+ OUString aWallCID( ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM_WALL, u"" ) );//@todo read CID from model
+
+ if( aRet == aWallCID )
+ {
+ OUString aDiagramCID = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
+ aRet = aDiagramCID;
+ }
+ }
+ }
+
+ return aRet;
+ // \\- solar mutex
+}
+
+bool SelectionHelper::isRotateableObject( std::u16string_view rCID
+ , const rtl::Reference<::chart::ChartModel>& xChartModel )
+{
+ if( !ObjectIdentifier::isRotateableObject( rCID ) )
+ return false;
+
+ sal_Int32 nDimensionCount = xChartModel->getFirstChartDiagram()->getDimension();
+
+ return nDimensionCount == 3;
+}
+
+SelectionHelper::SelectionHelper( SdrObject* pSelectedObj )
+ : m_pSelectedObj( pSelectedObj ), m_pMarkObj(nullptr)
+{
+
+}
+SelectionHelper::~SelectionHelper()
+{
+}
+
+bool SelectionHelper::getFrameDragSingles()
+{
+ //true == green == surrounding handles
+ return DynCastE3dObject( m_pSelectedObj) == nullptr;
+}
+
+SdrObject* SelectionHelper::getMarkHandlesObject( SdrObject* pObj )
+{
+ if(!pObj)
+ return nullptr;
+ OUString aName( lcl_getObjectName( pObj ) );
+ if( aName.match("MarkHandles") || aName.match("HandlesOnly") )
+ return pObj;
+ if( !aName.isEmpty() )//don't get the markhandles of a different object
+ return nullptr;
+
+ //search for a child with name "MarkHandles" or "HandlesOnly"
+ SolarMutexGuard aSolarGuard;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if(pSubList)
+ {
+ SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
+ while (aIterator.IsMore())
+ {
+ SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() );
+ if( pMarkHandles )
+ return pMarkHandles;
+ }
+ }
+ return nullptr;
+}
+
+SdrObject* SelectionHelper::getObjectToMark()
+{
+ //return the selected object itself
+ //or a specific other object if that exists
+ SdrObject* pObj = m_pSelectedObj;
+ m_pMarkObj = pObj;
+
+ //search for a child with name "MarkHandles" or "HandlesOnly"
+ if(pObj)
+ {
+ SolarMutexGuard aSolarGuard;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if(pSubList)
+ {
+ SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
+ while (aIterator.IsMore())
+ {
+ SdrObject* pMarkHandles = SelectionHelper::getMarkHandlesObject( aIterator.Next() );
+ if( pMarkHandles )
+ {
+ m_pMarkObj = pMarkHandles;
+ break;
+ }
+ }
+ }
+ }
+ return m_pMarkObj;
+}
+
+E3dScene* SelectionHelper::getSceneToRotate( SdrObject* pObj )
+{
+ //search whether the object or one of its children is a 3D object
+ //if so, return the accessory 3DScene
+
+ E3dObject* pRotateable = nullptr;
+
+ if(pObj)
+ {
+ pRotateable = DynCastE3dObject(pObj);
+ if( !pRotateable )
+ {
+ SolarMutexGuard aSolarGuard;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if(pSubList)
+ {
+ SdrObjListIter aIterator(pSubList, SdrIterMode::DeepWithGroups);
+ while( aIterator.IsMore() && !pRotateable )
+ {
+ pRotateable = DynCastE3dObject(aIterator.Next());
+ }
+ }
+ }
+ }
+
+ E3dScene* pScene(nullptr);
+
+ if(pRotateable)
+ {
+ SolarMutexGuard aSolarGuard;
+ pScene = pRotateable->getRootE3dSceneFromE3dObject();
+ }
+
+ return pScene;
+}
+
+bool SelectionHelper::getMarkHandles( SdrHdlList& rHdlList )
+{
+ SolarMutexGuard aSolarGuard;
+
+ //@todo -> more flexible handle creation
+ //2 scenarios possible:
+ //1. add an additional invisible shape as a child to the selected object
+ //this child needs to be named somehow and handles need to be generated there from...
+ //or 2. offer a central service per view where renderer and so can register for handle creation for a special shape
+ //.. or 3. feature from drawinglayer to create handles for each shape... (bad performance... ?) ?
+
+ //scenario 1 is now used:
+ //if a child with name MarkHandles exists
+ //this child is marked instead of the logical selected object
+
+/*
+ //if a special mark object was found
+ //that object should be used for marking only
+ if( m_pMarkObj != m_pSelectedObj)
+ return false;
+*/
+ //if a special mark object was found
+ //that object should be used to create handles from
+ if( m_pMarkObj && m_pMarkObj != m_pSelectedObj)
+ {
+ rHdlList.Clear();
+ if( auto pPathObj = dynamic_cast<const SdrPathObj*>( m_pMarkObj) )
+ {
+ //if th object is a polygon
+ //from each point a handle is generated
+ const ::basegfx::B2DPolyPolygon& rPolyPolygon = pPathObj->GetPathPoly();
+ for( sal_uInt32 nN = 0; nN < rPolyPolygon.count(); nN++)
+ {
+ const ::basegfx::B2DPolygon& aPolygon(rPolyPolygon.getB2DPolygon(nN));
+ for( sal_uInt32 nM = 0; nM < aPolygon.count(); nM++)
+ {
+ const ::basegfx::B2DPoint aPoint(aPolygon.getB2DPoint(nM));
+ rHdlList.AddHdl(std::make_unique<SdrHdl>(Point(basegfx::fround(aPoint.getX()), basegfx::fround(aPoint.getY())), SdrHdlKind::Poly));
+ }
+ }
+ return true;
+ }
+ else
+ return false; //use the special MarkObject for marking
+ }
+
+ //@todo:
+ //add and document good marking defaults ...
+
+ rHdlList.Clear();
+
+ SdrObject* pObj = m_pSelectedObj;
+ if(!pObj)
+ return false;
+ SdrObjList* pSubList = pObj->GetSubList();
+ if( !pSubList )//no group object !pObj->IsGroupObject()
+ return false;
+
+ OUString aName( lcl_getObjectName( pObj ) );
+ ObjectType eObjectType( ObjectIdentifier::getObjectType( aName ) );
+ if( eObjectType == OBJECTTYPE_DATA_POINT
+ || eObjectType == OBJECTTYPE_DATA_LABEL
+ || eObjectType == OBJECTTYPE_LEGEND_ENTRY
+ || eObjectType == OBJECTTYPE_AXIS_UNITLABEL )
+ {
+ return false;
+ }
+
+ SdrObjListIter aIterator(pSubList, SdrIterMode::Flat);
+
+ while (aIterator.IsMore())
+ {
+ SdrObject* pSubObj = aIterator.Next();
+ if( eObjectType == OBJECTTYPE_DATA_SERIES )
+ {
+ OUString aSubName( lcl_getObjectName( pSubObj ) );
+ ObjectType eSubObjectType( ObjectIdentifier::getObjectType( aSubName ) );
+ if( eSubObjectType!=OBJECTTYPE_DATA_POINT )
+ return false;
+ }
+
+ Point aPos = pSubObj->GetCurrentBoundRect().Center();
+ rHdlList.AddHdl(std::make_unique<SdrHdl>(aPos,SdrHdlKind::Poly));
+ }
+ return true;
+}
+
+} //namespace chart
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */