Quelle svdmark.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 <osl/time.h>
#include <svx/svdmark.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdpage.hxx>
#include <svx/svdpagv.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
#include <svl/SfxBroadcaster.hxx>
#include <svx/svdoedge.hxx>
#include <osl/diagnose.h>
#include <tools/debug.hxx>
#include <cassert>
void SdrMark::setTime()
{
TimeValue aNow;
osl_getSystemTime(&aNow);
mnTimeStamp = sal_Int64(aNow.Seconds) * 1000000000 + aNow.Nanosec;
}
SdrMark::SdrMark(SdrObject* pNewObj, SdrPageView* pNewPageView)
: mpSelectedSdrObject(pNewObj),
mpPageView(pNewPageView),
mbCon1(false ),
mbCon2(false ),
mnUser(0 )
{
if (mpSelectedSdrObject)
{
mpSelectedSdrObject->AddObjectUser( *this );
}
setTime();
}
SdrMark::SdrMark(const SdrMark& rMark)
: ObjectUser(),
mnTimeStamp(0 ),
mpSelectedSdrObject(nullptr),
mpPageView(nullptr),
mbCon1(false ),
mbCon2(false ),
mnUser(0 )
{
*this = rMark;
}
SdrMark::~SdrMark()
{
if (mpSelectedSdrObject)
{
mpSelectedSdrObject->RemoveObjectUser( *this );
}
}
void SdrMark::ObjectInDestruction(const SdrObject& rObject)
{
(void ) rObject; // avoid warnings
OSL_ENSURE(mpSelectedSdrObject && mpSelectedSdrObject == &rObject, "SdrMark::ObjectInDestruction: called from object different from hosted one (!)" );
OSL_ENSURE(mpSelectedSdrObject, "SdrMark::ObjectInDestruction: still selected SdrObject is deleted, deselect first (!)" );
mpSelectedSdrObject = nullptr;
}
void SdrMark::SetMarkedSdrObj(SdrObject* pNewObj)
{
if (mpSelectedSdrObject)
{
mpSelectedSdrObject->RemoveObjectUser( *this );
}
mpSelectedSdrObject = pNewObj;
if (mpSelectedSdrObject)
{
mpSelectedSdrObject->AddObjectUser( *this );
}
}
SdrMark& SdrMark::operator =(const SdrMark& rMark)
{
SetMarkedSdrObj(rMark.mpSelectedSdrObject);
mnTimeStamp = rMark.mnTimeStamp;
mpPageView = rMark.mpPageView;
mbCon1 = rMark.mbCon1;
mbCon2 = rMark.mbCon2;
mnUser = rMark.mnUser;
maPoints = rMark.maPoints;
maGluePoints = rMark.maGluePoints;
return *this ;
}
static bool ImpSdrMarkListSorter(std::unique_ptr<SdrMark> const & lhs, std::unique_ptr<SdrMark> const & rhs)
{
SdrObject* pObj1 = lhs->GetMarkedSdrObj();
SdrObject* pObj2 = rhs->GetMarkedSdrObj();
SdrObjList* pOL1 = pObj1 ? pObj1->getParentSdrObjListFromSdrObject() : nullptr;
SdrObjList* pOL2 = pObj2 ? pObj2->getParentSdrObjListFromSdrObject() : nullptr;
if (pOL1 == pOL2)
{
// AF: Note that I reverted a change from sal_uInt32 to sal_uLong (made
// for 64bit compliance, #i78198#) because internally in SdrObject
// both nOrdNum and mnNavigationPosition are stored as sal_uInt32.
sal_uInt32 nObjOrd1(pObj1 ? pObj1->GetNavigationPosition() : 0 );
sal_uInt32 nObjOrd2(pObj2 ? pObj2->GetNavigationPosition() : 0 );
return nObjOrd1 < nObjOrd2;
}
else
{
return pOL1 < pOL2;
}
}
void SdrMarkList::ForceSort() const
{
if (!mbSorted)
{
const_cast <SdrMarkList*>(this )->ImpForceSort();
}
}
void SdrMarkList::ImpForceSort()
{
if (mbSorted)
return ;
mbSorted = true ;
size_t nCount = maList.size();
// remove invalid
if (nCount > 0 )
{
std::erase_if(maList, [](std::unique_ptr<SdrMark>& rItem) { return rItem->GetMarkedSdrObj() == nullptr; });
nCount = maList.size();
}
if (nCount <= 1 )
return ;
std::sort(maList.begin(), maList.end(), ImpSdrMarkListSorter);
// remove duplicates
if (maList.size() <= 1 )
return ;
SdrMark* pCurrent = maList.back().get();
for (size_t count = maList.size() - 1 ; count; --count)
{
size_t i = count - 1 ;
SdrMark* pCmp = maList[i].get();
assert(pCurrent->GetMarkedSdrObj());
if (pCurrent->GetMarkedSdrObj() == pCmp->GetMarkedSdrObj())
{
// Con1/Con2 Merging
if (pCmp->IsCon1())
pCurrent->SetCon1(true );
if (pCmp->IsCon2())
pCurrent->SetCon2(true );
// delete pCmp
maList.erase(maList.begin() + i);
}
else
{
pCurrent = pCmp;
}
}
}
void SdrMarkList::Clear()
{
maList.clear();
mbSorted = true ; //we're empty, so can be considered sorted
SetNameDirty();
}
SdrMarkList& SdrMarkList::operator =(const SdrMarkList& rLst)
{
if (this != &rLst)
{
Clear();
for (size_t i = 0 ; i < rLst.GetMarkCount(); ++i)
{
SdrMark* pMark = rLst.GetMark(i);
maList.emplace_back(new SdrMark(*pMark));
}
maMarkName = rLst.maMarkName;
mbNameOk = rLst.mbNameOk;
maPointName = rLst.maPointName;
mbPointNameOk = rLst.mbPointNameOk;
maGluePointName = rLst.maGluePointName;
mbSorted = rLst.mbSorted;
}
return *this ;
}
SdrMark* SdrMarkList::GetMark(size_t nNum) const
{
return (nNum < maList.size()) ? maList[nNum].get() : nullptr;
}
size_t SdrMarkList::FindObject(const SdrObject* pObj) const
{
// Since relying on OrdNums is not allowed for the selection because objects in the
// selection may not be inserted in a list if they are e.g. modified ATM, i changed
// this loop to just look if the object pointer is in the selection.
// Problem is that GetOrdNum() which is const, internally casts to non-const and
// hardly sets the OrdNum member of the object (nOrdNum) to 0 (ZERO) if the object
// is not inserted in an object list.
// Since this may be by purpose and necessary somewhere else i decided that it is
// less dangerous to change this method then changing SdrObject::GetOrdNum().
if (pObj)
{
for (size_t a = 0 ; a < maList.size(); ++a)
{
if (maList[a]->GetMarkedSdrObj() == pObj)
{
return a;
}
}
}
return SAL_MAX_SIZE;
}
void SdrMarkList::InsertEntry(const SdrMark& rMark, bool bChkSort)
{
SetNameDirty();
const size_t nCount(maList.size());
if (!bChkSort || !mbSorted || nCount == 0 )
{
if (!bChkSort)
mbSorted = false ;
maList.emplace_back(new SdrMark(rMark));
}
else
{
SdrMark* pLast = GetMark(nCount - 1 );
const SdrObject* pLastObj = pLast->GetMarkedSdrObj();
const SdrObject* pNewObj = rMark.GetMarkedSdrObj();
if (pLastObj == pNewObj)
{
// This one already exists.
// Con1/Con2 Merging
if (rMark.IsCon1())
pLast->SetCon1(true );
if (rMark.IsCon2())
pLast->SetCon2(true );
}
else
{
maList.emplace_back(new SdrMark(rMark));
// now check if the sort is ok
const SdrObjList* pLastOL = pLastObj!=nullptr ? pLastObj->getParentSdrObjListFromSdrObject() : nullptr;
const SdrObjList* pNewOL = pNewObj !=nullptr ? pNewObj->getParentSdrObjListFromSdrObject() : nullptr;
if (pLastOL == pNewOL)
{
const sal_uInt32 nLastNum(pLastObj!=nullptr ? pLastObj->GetOrdNum() : 0 );
const sal_uInt32 nNewNum(pNewObj !=nullptr ? pNewObj ->GetOrdNum() : 0 );
if (nNewNum < nLastNum)
{
// at some point, we have to sort
mbSorted = false ;
}
}
else
{
// at some point, we have to sort
mbSorted = false ;
}
}
}
}
void SdrMarkList::DeleteMark(size_t nNum)
{
SdrMark* pMark = GetMark(nNum);
DBG_ASSERT(pMark!=nullptr,"DeleteMark: MarkEntry not found." );
if (pMark)
{
maList.erase(maList.begin() + nNum);
if (maList.empty())
mbSorted = true ; //we're empty, so can be considered sorted
SetNameDirty();
}
}
void SdrMarkList::ReplaceMark(const SdrMark& rNewMark, size_t nNum)
{
SdrMark* pMark = GetMark(nNum);
DBG_ASSERT(pMark!=nullptr,"ReplaceMark: MarkEntry not found." );
if (pMark)
{
SetNameDirty();
maList[nNum].reset(new SdrMark(rNewMark));
mbSorted = false ;
}
}
void SdrMarkList::Merge(const SdrMarkList& rSrcList, bool bReverse)
{
const size_t nCount(rSrcList.maList.size());
if (rSrcList.mbSorted)
{
// merge without forcing a Sort in rSrcList
bReverse = false ;
}
if (!bReverse)
{
for (size_t i = 0 ; i < nCount; ++i)
{
SdrMark* pM = rSrcList.maList[i].get();
InsertEntry(*pM);
}
}
else
{
for (size_t i = nCount; i > 0 ;)
{
--i;
SdrMark* pM = rSrcList.maList[i].get();
InsertEntry(*pM);
}
}
}
bool SdrMarkList::DeletePageView(const SdrPageView& rPV)
{
bool bChgd(false );
for (auto it = maList.begin(); it != maList.end(); )
{
SdrMark* pMark = it->get();
if (pMark->GetPageView()==&rPV)
{
it = maList.erase(it);
SetNameDirty();
bChgd = true ;
}
else
++it;
}
return bChgd;
}
bool SdrMarkList::InsertPageView(const SdrPageView& rPV)
{
bool bChgd(false );
DeletePageView(rPV); // delete all of them, then append the entire page
const SdrObjList* pOL = rPV.GetObjList();
for (const rtl::Reference<SdrObject>& pObj : *pOL)
{
bool bDoIt(rPV.IsObjMarkable(pObj.get()));
if (bDoIt)
{
maList.emplace_back(new SdrMark(pObj.get(), const_cast <SdrPageView*>(&rPV)));
SetNameDirty();
bChgd = true ;
}
}
return bChgd;
}
const OUString& SdrMarkList::GetMarkDescription() const
{
const size_t nCount(GetMarkCount());
if (mbNameOk && 1 == nCount)
{
// if it's a single selection, cache only text frame
const SdrObject* pObj = GetMark(0 )->GetMarkedSdrObj();
const SdrTextObj* pTextObj = DynCastSdrTextObj( pObj );
if (!pTextObj || !pTextObj->IsTextFrame())
{
const_cast <SdrMarkList*>(this )->mbNameOk = false ;
}
}
if (!mbNameOk)
{
SdrMark* pMark = GetMark(0 );
OUString aNam;
if (!nCount)
{
const_cast <SdrMarkList*>(this )->maMarkName = SvxResId(STR_ObjNameNoObj);
}
else if (1 == nCount)
{
if (pMark->GetMarkedSdrObj())
{
aNam = pMark->GetMarkedSdrObj()->TakeObjNameSingul();
}
}
else
{
if (pMark->GetMarkedSdrObj())
{
aNam = pMark->GetMarkedSdrObj()->TakeObjNamePlural();
bool bEq(true );
for (size_t i = 1 ; i < GetMarkCount() && bEq; ++i)
{
SdrMark* pMark2 = GetMark(i);
OUString aStr1(pMark2->GetMarkedSdrObj()->TakeObjNamePlural());
bEq = aNam == aStr1;
}
if (!bEq)
{
aNam = SvxResId(STR_ObjNamePlural);
}
}
aNam = OUString::number( nCount ) + " " + aNam;
}
const_cast <SdrMarkList*>(this )->maMarkName = aNam;
const_cast <SdrMarkList*>(this )->mbNameOk = true ;
}
return maMarkName;
}
const OUString& SdrMarkList::GetPointMarkDescription(bool bGlue) const
{
bool & rNameOk = const_cast <bool &>(bGlue ? mbGluePointNameOk : mbPointNameOk);
OUString& rName = const_cast <OUString&>(bGlue ? maGluePointName : maPointName);
const size_t nMarkCount(GetMarkCount());
size_t nMarkPtCnt(0 );
size_t nMarkPtObjCnt(0 );
size_t n1stMarkNum(SAL_MAX_SIZE);
for (size_t nMarkNum = 0 ; nMarkNum < nMarkCount; ++nMarkNum)
{
const SdrMark* pMark = GetMark(nMarkNum);
const SdrUShortCont& rPts = bGlue ? pMark->GetMarkedGluePoints() : pMark->GetMarkedPoints();
if (!rPts.empty())
{
if (n1stMarkNum == SAL_MAX_SIZE)
{
n1stMarkNum = nMarkNum;
}
nMarkPtCnt += rPts.size();
nMarkPtObjCnt++;
}
if (nMarkPtObjCnt > 1 && rNameOk)
{
// preliminary decision
return rName;
}
}
if (rNameOk && 1 == nMarkPtObjCnt)
{
// if it's a single selection, cache only text frame
const SdrObject* pObj = GetMark(0 )->GetMarkedSdrObj();
const SdrTextObj* pTextObj = DynCastSdrTextObj( pObj );
if (!pTextObj || !pTextObj->IsTextFrame())
{
rNameOk = false ;
}
}
if (!nMarkPtObjCnt)
{
rName.clear();
rNameOk = true ;
}
else if (!rNameOk)
{
const SdrMark* pMark = GetMark(n1stMarkNum);
OUString aNam;
if (1 == nMarkPtObjCnt)
{
if (pMark->GetMarkedSdrObj())
{
aNam = pMark->GetMarkedSdrObj()->TakeObjNameSingul();
}
}
else
{
if (pMark->GetMarkedSdrObj())
{
aNam = pMark->GetMarkedSdrObj()->TakeObjNamePlural();
}
bool bEq(true );
for (size_t i = n1stMarkNum + 1 ; i < GetMarkCount() && bEq; ++i)
{
const SdrMark* pMark2 = GetMark(i);
const SdrUShortCont& rPts = bGlue ? pMark2->GetMarkedGluePoints() : pMark2->GetMarkedPoints();
if (!rPts.empty() && pMark2->GetMarkedSdrObj())
{
OUString aStr1(pMark2->GetMarkedSdrObj()->TakeObjNamePlural());
bEq = aNam == aStr1;
}
}
if (!bEq)
{
aNam = SvxResId(STR_ObjNamePlural);
}
aNam = OUString::number( nMarkPtObjCnt ) + " " + aNam;
}
OUString aStr1;
if (1 == nMarkPtCnt)
{
aStr1 = SvxResId(bGlue ? STR_ViewMarkedGluePoint : STR_ViewMarkedPoint);
}
else
{
aStr1 = SvxResId(bGlue ? STR_ViewMarkedGluePoints : STR_ViewMarkedPoints);
aStr1 = aStr1.replaceFirst("%2" , OUString::number( nMarkPtCnt ));
}
aStr1 = aStr1.replaceFirst("%1" , aNam);
rName = aStr1;
rNameOk = true ;
}
return rName;
}
bool SdrMarkList::TakeBoundRect(SdrPageView const * pPV, tools::Rectangle& rRect) const
{
bool bFnd(false );
tools::Rectangle aR;
for (size_t i = 0 ; i < GetMarkCount(); ++i)
{
SdrMark* pMark = GetMark(i);
if (!pPV || pMark->GetPageView() == pPV)
{
if (pMark->GetMarkedSdrObj())
{
aR = pMark->GetMarkedSdrObj()->GetCurrentBoundRect();
if (bFnd)
{
rRect.Union (aR);
}
else
{
rRect = aR;
bFnd = true ;
}
}
}
}
return bFnd;
}
bool SdrMarkList::TakeSnapRect(SdrPageView const * pPV, tools::Rectangle& rRect) const
{
bool bFnd(false );
for (size_t i = 0 ; i < GetMarkCount(); ++i)
{
SdrMark* pMark = GetMark(i);
if (!pPV || pMark->GetPageView() == pPV)
{
if (pMark->GetMarkedSdrObj())
{
tools::Rectangle aR(pMark->GetMarkedSdrObj()->GetSnapRect());
if (bFnd)
{
rRect.Union (aR);
}
else
{
rRect = aR;
bFnd = true ;
}
}
}
}
return bFnd;
}
namespace sdr
{
ViewSelection::ViewSelection()
: mbEdgesOfMarkedNodesDirty(false )
{
}
void ViewSelection::SetEdgesOfMarkedNodesDirty()
{
if (!mbEdgesOfMarkedNodesDirty)
{
mbEdgesOfMarkedNodesDirty = true ;
maEdgesOfMarkedNodes.Clear();
maMarkedEdgesOfMarkedNodes.Clear();
maAllMarkedObjects.clear();
}
}
const SdrMarkList& ViewSelection::GetEdgesOfMarkedNodes() const
{
if (mbEdgesOfMarkedNodesDirty)
{
const_cast <ViewSelection*>(this )->ImpForceEdgesOfMarkedNodes();
}
return maEdgesOfMarkedNodes;
}
const SdrMarkList& ViewSelection::GetMarkedEdgesOfMarkedNodes() const
{
if (mbEdgesOfMarkedNodesDirty)
{
const_cast <ViewSelection*>(this )->ImpForceEdgesOfMarkedNodes();
}
return maMarkedEdgesOfMarkedNodes;
}
const std::vector<SdrObject*>& ViewSelection::GetAllMarkedObjects() const
{
if (mbEdgesOfMarkedNodesDirty)
const_cast <ViewSelection*>(this )->ImpForceEdgesOfMarkedNodes();
return maAllMarkedObjects;
}
void ViewSelection::ImplCollectCompleteSelection(SdrObject* pObj)
{
if (!pObj)
return ;
bool bIsGroup(pObj->IsGroupObject());
if (bIsGroup && DynCastE3dObject(pObj) != nullptr && DynCastE3dScene(pObj) == nullptr)
{
bIsGroup = false ;
}
if (bIsGroup)
{
SdrObjList* pList = pObj->GetSubList();
for (const rtl::Reference<SdrObject>& pObj2 : *pList)
ImplCollectCompleteSelection(pObj2.get());
}
maAllMarkedObjects.push_back(pObj);
}
void ViewSelection::ImpForceEdgesOfMarkedNodes()
{
if (!mbEdgesOfMarkedNodesDirty)
return ;
mbEdgesOfMarkedNodesDirty = false ;
maMarkedObjectList.ForceSort();
maEdgesOfMarkedNodes.Clear();
maMarkedEdgesOfMarkedNodes.Clear();
maAllMarkedObjects.clear();
// GetMarkCount after ForceSort
const size_t nMarkCount(maMarkedObjectList.GetMarkCount());
for (size_t a = 0 ; a < nMarkCount; ++a)
{
SdrObject* pCandidate = maMarkedObjectList.GetMark(a)->GetMarkedSdrObj();
if (!pCandidate)
continue ;
// build transitive hull
ImplCollectCompleteSelection(pCandidate);
// travel over broadcaster/listener to access edges connected to the selected object
const SfxBroadcaster* pBC = pCandidate->GetBroadcaster();
if (!pBC)
continue ;
pBC->ForAllListeners(
[this , &pCandidate, &a] (SfxListener* pLst)
{
SdrEdgeObj* pEdge = dynamic_cast <SdrEdgeObj*>( pLst );
if (pEdge && pEdge->IsInserted() && pEdge->getSdrPageFromSdrObject() == pCandidate->getSdrPageFromSdrObject())
{
SdrMark aM(pEdge, maMarkedObjectList.GetMark(a)->GetPageView());
if (pEdge->GetConnectedNode(true ) == pCandidate)
{
aM.SetCon1(true );
}
if (pEdge->GetConnectedNode(false ) == pCandidate)
{
aM.SetCon2(true );
}
if (SAL_MAX_SIZE == maMarkedObjectList.FindObject(pEdge))
{
// check if it itself is selected
maEdgesOfMarkedNodes.InsertEntry(aM);
}
else
{
maMarkedEdgesOfMarkedNodes.InsertEntry(aM);
}
}
return false ;
});
}
maEdgesOfMarkedNodes.ForceSort();
maMarkedEdgesOfMarkedNodes.ForceSort();
}
} // end of namespace sdr
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Messung V0.5 in Prozent C=94 H=100 G=96
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland
2026-10-11
Neuigkeiten
Aktuelles
Motto des Tages
Open Source Software
Jenseits des Üblichen ....
Besucherstatistik
Statistik
#Sources=1126864
#Domains=2039723