1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
23 #include <svx/svdmark.hxx>
24 #include <svx/svdobj.hxx>
25 #include <svx/svdpage.hxx>
26 #include <svx/svdpagv.hxx>
27 #include <svx/strings.hrc>
28 #include <svx/dialmgr.hxx>
31 #include <svx/obj3d.hxx>
32 #include <svx/scene3d.hxx>
33 #include <svl/SfxBroadcaster.hxx>
34 #include <svx/svdoedge.hxx>
38 void SdrMark::setTime()
41 osl_getSystemTime(&aNow
);
42 mnTimeStamp
= sal_Int64(aNow
.Seconds
) * 1000000000 + aNow
.Nanosec
;
45 SdrMark::SdrMark(SdrObject
* pNewObj
, SdrPageView
* pNewPageView
)
46 : mpSelectedSdrObject(pNewObj
),
47 mpPageView(pNewPageView
),
52 if(mpSelectedSdrObject
)
54 mpSelectedSdrObject
->AddObjectUser( *this );
59 SdrMark::SdrMark(const SdrMark
& rMark
)
62 mpSelectedSdrObject(nullptr),
73 if (mpSelectedSdrObject
)
75 mpSelectedSdrObject
->RemoveObjectUser( *this );
79 void SdrMark::ObjectInDestruction(const SdrObject
& rObject
)
81 (void) rObject
; // avoid warnings
82 OSL_ENSURE(mpSelectedSdrObject
&& mpSelectedSdrObject
== &rObject
, "SdrMark::ObjectInDestruction: called from object different from hosted one (!)");
83 OSL_ENSURE(mpSelectedSdrObject
, "SdrMark::ObjectInDestruction: still selected SdrObject is deleted, deselect first (!)");
84 mpSelectedSdrObject
= nullptr;
87 void SdrMark::SetMarkedSdrObj(SdrObject
* pNewObj
)
89 if(mpSelectedSdrObject
)
91 mpSelectedSdrObject
->RemoveObjectUser( *this );
94 mpSelectedSdrObject
= pNewObj
;
96 if(mpSelectedSdrObject
)
98 mpSelectedSdrObject
->AddObjectUser( *this );
102 SdrMark
& SdrMark::operator=(const SdrMark
& rMark
)
104 SetMarkedSdrObj(rMark
.mpSelectedSdrObject
);
106 mnTimeStamp
= rMark
.mnTimeStamp
;
107 mpPageView
= rMark
.mpPageView
;
108 mbCon1
= rMark
.mbCon1
;
109 mbCon2
= rMark
.mbCon2
;
110 mnUser
= rMark
.mnUser
;
111 maPoints
= rMark
.maPoints
;
112 maGluePoints
= rMark
.maGluePoints
;
117 static bool ImpSdrMarkListSorter(std::unique_ptr
<SdrMark
> const& lhs
, std::unique_ptr
<SdrMark
> const& rhs
)
119 SdrObject
* pObj1
= lhs
->GetMarkedSdrObj();
120 SdrObject
* pObj2
= rhs
->GetMarkedSdrObj();
121 SdrObjList
* pOL1
= pObj1
? pObj1
->getParentSdrObjListFromSdrObject() : nullptr;
122 SdrObjList
* pOL2
= pObj2
? pObj2
->getParentSdrObjListFromSdrObject() : nullptr;
126 // AF: Note that I reverted a change from sal_uInt32 to sal_uLong (made
127 // for 64bit compliance, #i78198#) because internally in SdrObject
128 // both nOrdNum and mnNavigationPosition are stored as sal_uInt32.
129 sal_uInt32
nObjOrd1(pObj1
? pObj1
->GetNavigationPosition() : 0);
130 sal_uInt32
nObjOrd2(pObj2
? pObj2
->GetNavigationPosition() : 0);
132 return nObjOrd1
< nObjOrd2
;
141 void SdrMarkList::ForceSort() const
145 const_cast<SdrMarkList
*>(this)->ImpForceSort();
149 void SdrMarkList::ImpForceSort()
155 size_t nCount
= maList
.size();
160 maList
.erase(std::remove_if(maList
.begin(), maList
.end(),
161 [](std::unique_ptr
<SdrMark
>& rItem
) { return rItem
->GetMarkedSdrObj() == nullptr; }),
163 nCount
= maList
.size();
169 std::sort(maList
.begin(), maList
.end(), ImpSdrMarkListSorter
);
172 if(maList
.size() <= 1)
175 SdrMark
* pCurrent
= maList
.back().get();
176 for (size_t count
= maList
.size() - 1; count
; --count
)
178 size_t i
= count
- 1;
179 SdrMark
* pCmp
= maList
[i
].get();
180 assert(pCurrent
->GetMarkedSdrObj());
181 if(pCurrent
->GetMarkedSdrObj() == pCmp
->GetMarkedSdrObj())
185 pCurrent
->SetCon1(true);
188 pCurrent
->SetCon2(true);
191 maList
.erase(maList
.begin() + i
);
200 void SdrMarkList::Clear()
203 mbSorted
= true; //we're empty, so can be considered sorted
207 SdrMarkList
& SdrMarkList::operator=(const SdrMarkList
& rLst
)
213 for(size_t i
= 0; i
< rLst
.GetMarkCount(); ++i
)
215 SdrMark
* pMark
= rLst
.GetMark(i
);
216 maList
.emplace_back(new SdrMark(*pMark
));
219 maMarkName
= rLst
.maMarkName
;
220 mbNameOk
= rLst
.mbNameOk
;
221 maPointName
= rLst
.maPointName
;
222 mbPointNameOk
= rLst
.mbPointNameOk
;
223 maGluePointName
= rLst
.maGluePointName
;
224 mbSorted
= rLst
.mbSorted
;
229 SdrMark
* SdrMarkList::GetMark(size_t nNum
) const
231 return (nNum
< maList
.size()) ? maList
[nNum
].get() : nullptr;
234 size_t SdrMarkList::FindObject(const SdrObject
* pObj
) const
236 // Since relying on OrdNums is not allowed for the selection because objects in the
237 // selection may not be inserted in a list if they are e.g. modified ATM, i changed
238 // this loop to just look if the object pointer is in the selection.
240 // Problem is that GetOrdNum() which is const, internally casts to non-const and
241 // hardly sets the OrdNum member of the object (nOrdNum) to 0 (ZERO) if the object
242 // is not inserted in an object list.
243 // Since this may be by purpose and necessary somewhere else i decided that it is
244 // less dangerous to change this method then changing SdrObject::GetOrdNum().
247 for(size_t a
= 0; a
< maList
.size(); ++a
)
249 if(maList
[a
]->GetMarkedSdrObj() == pObj
)
259 void SdrMarkList::InsertEntry(const SdrMark
& rMark
, bool bChkSort
)
262 const size_t nCount(maList
.size());
264 if(!bChkSort
|| !mbSorted
|| nCount
== 0)
269 maList
.emplace_back(new SdrMark(rMark
));
273 SdrMark
* pLast
= GetMark(nCount
- 1);
274 const SdrObject
* pLastObj
= pLast
->GetMarkedSdrObj();
275 const SdrObject
* pNewObj
= rMark
.GetMarkedSdrObj();
277 if(pLastObj
== pNewObj
)
279 // This one already exists.
282 pLast
->SetCon1(true);
285 pLast
->SetCon2(true);
289 maList
.emplace_back(new SdrMark(rMark
));
291 // now check if the sort is ok
292 const SdrObjList
* pLastOL
= pLastObj
!=nullptr ? pLastObj
->getParentSdrObjListFromSdrObject() : nullptr;
293 const SdrObjList
* pNewOL
= pNewObj
!=nullptr ? pNewObj
->getParentSdrObjListFromSdrObject() : nullptr;
295 if(pLastOL
== pNewOL
)
297 const sal_uLong
nLastNum(pLastObj
!=nullptr ? pLastObj
->GetOrdNum() : 0);
298 const sal_uLong
nNewNum(pNewObj
!=nullptr ? pNewObj
->GetOrdNum() : 0);
300 if(nNewNum
< nLastNum
)
302 // at some point, we have to sort
308 // at some point, we have to sort
315 void SdrMarkList::DeleteMark(size_t nNum
)
317 SdrMark
* pMark
= GetMark(nNum
);
318 DBG_ASSERT(pMark
!=nullptr,"DeleteMark: MarkEntry not found.");
322 maList
.erase(maList
.begin() + nNum
);
324 mbSorted
= true; //we're empty, so can be considered sorted
329 void SdrMarkList::ReplaceMark(const SdrMark
& rNewMark
, size_t nNum
)
331 SdrMark
* pMark
= GetMark(nNum
);
332 DBG_ASSERT(pMark
!=nullptr,"ReplaceMark: MarkEntry not found.");
337 maList
[nNum
].reset(new SdrMark(rNewMark
));
342 void SdrMarkList::Merge(const SdrMarkList
& rSrcList
, bool bReverse
)
344 const size_t nCount(rSrcList
.maList
.size());
346 if(rSrcList
.mbSorted
)
348 // merge without forcing a Sort in rSrcList
354 for(size_t i
= 0; i
< nCount
; ++i
)
356 SdrMark
* pM
= rSrcList
.maList
[i
].get();
362 for(size_t i
= nCount
; i
> 0;)
365 SdrMark
* pM
= rSrcList
.maList
[i
].get();
371 bool SdrMarkList::DeletePageView(const SdrPageView
& rPV
)
375 for(auto it
= maList
.begin(); it
!= maList
.end(); )
377 SdrMark
* pMark
= it
->get();
379 if(pMark
->GetPageView()==&rPV
)
381 it
= maList
.erase(it
);
392 bool SdrMarkList::InsertPageView(const SdrPageView
& rPV
)
395 DeletePageView(rPV
); // delete all of them, then append the entire page
396 const SdrObjList
* pOL
= rPV
.GetObjList();
397 const size_t nObjCount(pOL
->GetObjCount());
399 for(size_t nO
= 0; nO
< nObjCount
; ++nO
)
401 SdrObject
* pObj
= pOL
->GetObj(nO
);
402 bool bDoIt(rPV
.IsObjMarkable(pObj
));
406 maList
.emplace_back(new SdrMark(pObj
, const_cast<SdrPageView
*>(&rPV
)));
415 const OUString
& SdrMarkList::GetMarkDescription() const
417 const size_t nCount(GetMarkCount());
419 if(mbNameOk
&& 1 == nCount
)
421 // if it's a single selection, cache only text frame
422 const SdrObject
* pObj
= GetMark(0)->GetMarkedSdrObj();
423 const SdrTextObj
* pTextObj
= dynamic_cast<const SdrTextObj
*>( pObj
);
425 if(!pTextObj
|| !pTextObj
->IsTextFrame())
427 const_cast<SdrMarkList
*>(this)->mbNameOk
= false;
433 SdrMark
* pMark
= GetMark(0);
438 const_cast<SdrMarkList
*>(this)->maMarkName
= SvxResId(STR_ObjNameNoObj
);
442 if(pMark
->GetMarkedSdrObj())
444 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNameSingul();
449 if(pMark
->GetMarkedSdrObj())
451 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNamePlural();
454 for(size_t i
= 1; i
< GetMarkCount() && bEq
; ++i
)
456 SdrMark
* pMark2
= GetMark(i
);
457 OUString
aStr1(pMark2
->GetMarkedSdrObj()->TakeObjNamePlural());
463 aNam
= SvxResId(STR_ObjNamePlural
);
467 aNam
= OUString::number( nCount
) + " " + aNam
;
470 const_cast<SdrMarkList
*>(this)->maMarkName
= aNam
;
471 const_cast<SdrMarkList
*>(this)->mbNameOk
= true;
477 const OUString
& SdrMarkList::GetPointMarkDescription(bool bGlue
) const
479 bool& rNameOk
= const_cast<bool&>(bGlue
? mbGluePointNameOk
: mbPointNameOk
);
480 OUString
& rName
= const_cast<OUString
&>(bGlue
? maGluePointName
: maPointName
);
481 const size_t nMarkCount(GetMarkCount());
482 size_t nMarkPtCnt(0);
483 size_t nMarkPtObjCnt(0);
484 size_t n1stMarkNum(SAL_MAX_SIZE
);
486 for(size_t nMarkNum
= 0; nMarkNum
< nMarkCount
; ++nMarkNum
)
488 const SdrMark
* pMark
= GetMark(nMarkNum
);
489 const SdrUShortCont
& rPts
= bGlue
? pMark
->GetMarkedGluePoints() : pMark
->GetMarkedPoints();
493 if(n1stMarkNum
== SAL_MAX_SIZE
)
495 n1stMarkNum
= nMarkNum
;
498 nMarkPtCnt
+= rPts
.size();
502 if(nMarkPtObjCnt
> 1 && rNameOk
)
504 // preliminary decision
509 if(rNameOk
&& 1 == nMarkPtObjCnt
)
511 // if it's a single selection, cache only text frame
512 const SdrObject
* pObj
= GetMark(0)->GetMarkedSdrObj();
513 const SdrTextObj
* pTextObj
= dynamic_cast<const SdrTextObj
*>( pObj
);
515 if(!pTextObj
|| !pTextObj
->IsTextFrame())
528 const SdrMark
* pMark
= GetMark(n1stMarkNum
);
531 if(1 == nMarkPtObjCnt
)
533 if(pMark
->GetMarkedSdrObj())
535 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNameSingul();
540 if(pMark
->GetMarkedSdrObj())
542 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNamePlural();
547 for(size_t i
= n1stMarkNum
+ 1; i
< GetMarkCount() && bEq
; ++i
)
549 const SdrMark
* pMark2
= GetMark(i
);
550 const SdrUShortCont
& rPts
= bGlue
? pMark2
->GetMarkedGluePoints() : pMark2
->GetMarkedPoints();
552 if (!rPts
.empty() && pMark2
->GetMarkedSdrObj())
554 OUString
aStr1(pMark2
->GetMarkedSdrObj()->TakeObjNamePlural());
561 aNam
= SvxResId(STR_ObjNamePlural
);
564 aNam
= OUString::number( nMarkPtObjCnt
) + " " + aNam
;
571 aStr1
= SvxResId(bGlue
? STR_ViewMarkedGluePoint
: STR_ViewMarkedPoint
);
575 aStr1
= SvxResId(bGlue
? STR_ViewMarkedGluePoints
: STR_ViewMarkedPoints
);
576 aStr1
= aStr1
.replaceFirst("%2", OUString::number( nMarkPtCnt
));
579 aStr1
= aStr1
.replaceFirst("%1", aNam
);
587 bool SdrMarkList::TakeBoundRect(SdrPageView
const * pPV
, tools::Rectangle
& rRect
) const
592 for(size_t i
= 0; i
< GetMarkCount(); ++i
)
594 SdrMark
* pMark
= GetMark(i
);
596 if(!pPV
|| pMark
->GetPageView() == pPV
)
598 if(pMark
->GetMarkedSdrObj())
600 aR
= pMark
->GetMarkedSdrObj()->GetCurrentBoundRect();
618 bool SdrMarkList::TakeSnapRect(SdrPageView
const * pPV
, tools::Rectangle
& rRect
) const
622 for(size_t i
= 0; i
< GetMarkCount(); ++i
)
624 SdrMark
* pMark
= GetMark(i
);
626 if(!pPV
|| pMark
->GetPageView() == pPV
)
628 if(pMark
->GetMarkedSdrObj())
630 tools::Rectangle
aR(pMark
->GetMarkedSdrObj()->GetSnapRect());
651 ViewSelection::ViewSelection()
652 : mbEdgesOfMarkedNodesDirty(false)
656 void ViewSelection::SetEdgesOfMarkedNodesDirty()
658 if(!mbEdgesOfMarkedNodesDirty
)
660 mbEdgesOfMarkedNodesDirty
= true;
661 maEdgesOfMarkedNodes
.Clear();
662 maMarkedEdgesOfMarkedNodes
.Clear();
663 maAllMarkedObjects
.clear();
667 const SdrMarkList
& ViewSelection::GetEdgesOfMarkedNodes() const
669 if(mbEdgesOfMarkedNodesDirty
)
671 const_cast<ViewSelection
*>(this)->ImpForceEdgesOfMarkedNodes();
674 return maEdgesOfMarkedNodes
;
677 const SdrMarkList
& ViewSelection::GetMarkedEdgesOfMarkedNodes() const
679 if(mbEdgesOfMarkedNodesDirty
)
681 const_cast<ViewSelection
*>(this)->ImpForceEdgesOfMarkedNodes();
684 return maMarkedEdgesOfMarkedNodes
;
687 const std::vector
<SdrObject
*>& ViewSelection::GetAllMarkedObjects() const
689 if(mbEdgesOfMarkedNodesDirty
)
690 const_cast<ViewSelection
*>(this)->ImpForceEdgesOfMarkedNodes();
692 return maAllMarkedObjects
;
695 void ViewSelection::ImplCollectCompleteSelection(SdrObject
* pObj
)
700 bool bIsGroup(pObj
->IsGroupObject());
702 if(bIsGroup
&& dynamic_cast< const E3dObject
* >(pObj
) != nullptr && dynamic_cast< const E3dScene
* >(pObj
) == nullptr)
709 SdrObjList
* pList
= pObj
->GetSubList();
711 for(size_t a
= 0; a
< pList
->GetObjCount(); ++a
)
713 SdrObject
* pObj2
= pList
->GetObj(a
);
714 ImplCollectCompleteSelection(pObj2
);
718 maAllMarkedObjects
.push_back(pObj
);
721 void ViewSelection::ImpForceEdgesOfMarkedNodes()
723 if(!mbEdgesOfMarkedNodesDirty
)
726 mbEdgesOfMarkedNodesDirty
= false;
727 maMarkedObjectList
.ForceSort();
728 maEdgesOfMarkedNodes
.Clear();
729 maMarkedEdgesOfMarkedNodes
.Clear();
730 maAllMarkedObjects
.clear();
732 // GetMarkCount after ForceSort
733 const size_t nMarkCount(maMarkedObjectList
.GetMarkCount());
735 for(size_t a
= 0; a
< nMarkCount
; ++a
)
737 SdrObject
* pCandidate
= maMarkedObjectList
.GetMark(a
)->GetMarkedSdrObj();
741 // build transitive hull
742 ImplCollectCompleteSelection(pCandidate
);
744 // travel over broadcaster/listener to access edges connected to the selected object
745 const SfxBroadcaster
* pBC
= pCandidate
->GetBroadcaster();
749 const size_t nLstCnt(pBC
->GetSizeOfVector());
751 for(size_t nl
=0; nl
< nLstCnt
; ++nl
)
753 SfxListener
* pLst
= pBC
->GetListener(nl
);
754 SdrEdgeObj
* pEdge
= dynamic_cast<SdrEdgeObj
*>( pLst
);
756 if(pEdge
&& pEdge
->IsInserted() && pEdge
->getSdrPageFromSdrObject() == pCandidate
->getSdrPageFromSdrObject())
758 SdrMark
aM(pEdge
, maMarkedObjectList
.GetMark(a
)->GetPageView());
760 if(pEdge
->GetConnectedNode(true) == pCandidate
)
765 if(pEdge
->GetConnectedNode(false) == pCandidate
)
770 if(SAL_MAX_SIZE
== maMarkedObjectList
.FindObject(pEdge
))
772 // check if it itself is selected
773 maEdgesOfMarkedNodes
.InsertEntry(aM
);
777 maMarkedEdgesOfMarkedNodes
.InsertEntry(aM
);
785 maEdgesOfMarkedNodes
.ForceSort();
786 maMarkedEdgesOfMarkedNodes
.ForceSort();
788 } // end of namespace sdr
790 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */