Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/chart2/source/controller/main/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 21 kB image not shown  

Quelle  SelectionHelper.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 <SelectionHelper.hxx>
#include <ObjectIdentifier.hxx>
#include <Diagram.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 = std::move(aLastChild);
                    }
                    else
                        m_aSelectedOID_selectOnlyIfNoDoubleClickIsFollowing = std::move(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>&&nbsp;xChartModel ) const
{
    return SelectionHelper::isRotateableObject( m_aSelectedOID.getObjectCID(), xChartModel );
}

bool Selection::isDragableObjectSelected() const
{
    return m_aSelectedOID.isDragableObject();
}

bool Selection::isTitleObjectSelected() const
{
    return m_aSelectedOID.getObjectType() == OBJECTTYPE_TITLE;
}

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 )
            {
                aRet = ObjectIdentifier::createClassifiedIdentifier( OBJECTTYPE_DIAGRAM, OUString::number( 0 ) );
            }
        }
    }

    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();
        ifauto 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<tools::Long>(aPoint.getX()), basegfx::fround<tools::Long>(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: */

92%


¤ Dauer der Verarbeitung: 0.8 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 ist noch experimentell.