tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / svx / source / svdraw / svdmark.cxx
blobfc5d815ab9a26ff0ae8f6a7d06bd6a1acfd8697e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <osl/time.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 <svl/SfxBroadcaster.hxx>
32 #include <svx/svdoedge.hxx>
33 #include <osl/diagnose.h>
34 #include <tools/debug.hxx>
36 #include <cassert>
38 void SdrMark::setTime()
40 TimeValue aNow;
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),
48 mbCon1(false),
49 mbCon2(false),
50 mnUser(0)
52 if(mpSelectedSdrObject)
54 mpSelectedSdrObject->AddObjectUser( *this );
56 setTime();
59 SdrMark::SdrMark(const SdrMark& rMark)
60 : ObjectUser(),
61 mnTimeStamp(0),
62 mpSelectedSdrObject(nullptr),
63 mpPageView(nullptr),
64 mbCon1(false),
65 mbCon2(false),
66 mnUser(0)
68 *this = rMark;
71 SdrMark::~SdrMark()
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;
114 return *this;
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;
124 if (pOL1 == pOL2)
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;
134 else
136 return pOL1 < pOL2;
141 void SdrMarkList::ForceSort() const
143 if(!mbSorted)
145 const_cast<SdrMarkList*>(this)->ImpForceSort();
149 void SdrMarkList::ImpForceSort()
151 if(mbSorted)
152 return;
154 mbSorted = true;
155 size_t nCount = maList.size();
157 // remove invalid
158 if(nCount > 0 )
160 std::erase_if(maList, [](std::unique_ptr<SdrMark>& rItem) { return rItem->GetMarkedSdrObj() == nullptr; });
161 nCount = maList.size();
164 if(nCount <= 1)
165 return;
167 std::sort(maList.begin(), maList.end(), ImpSdrMarkListSorter);
169 // remove duplicates
170 if(maList.size() <= 1)
171 return;
173 SdrMark* pCurrent = maList.back().get();
174 for (size_t count = maList.size() - 1; count; --count)
176 size_t i = count - 1;
177 SdrMark* pCmp = maList[i].get();
178 assert(pCurrent->GetMarkedSdrObj());
179 if(pCurrent->GetMarkedSdrObj() == pCmp->GetMarkedSdrObj())
181 // Con1/Con2 Merging
182 if(pCmp->IsCon1())
183 pCurrent->SetCon1(true);
185 if(pCmp->IsCon2())
186 pCurrent->SetCon2(true);
188 // delete pCmp
189 maList.erase(maList.begin() + i);
191 else
193 pCurrent = pCmp;
198 void SdrMarkList::Clear()
200 maList.clear();
201 mbSorted = true; //we're empty, so can be considered sorted
202 SetNameDirty();
205 SdrMarkList& SdrMarkList::operator=(const SdrMarkList& rLst)
207 if (this != &rLst)
209 Clear();
211 for(size_t i = 0; i < rLst.GetMarkCount(); ++i)
213 SdrMark* pMark = rLst.GetMark(i);
214 maList.emplace_back(new SdrMark(*pMark));
217 maMarkName = rLst.maMarkName;
218 mbNameOk = rLst.mbNameOk;
219 maPointName = rLst.maPointName;
220 mbPointNameOk = rLst.mbPointNameOk;
221 maGluePointName = rLst.maGluePointName;
222 mbSorted = rLst.mbSorted;
224 return *this;
227 SdrMark* SdrMarkList::GetMark(size_t nNum) const
229 return (nNum < maList.size()) ? maList[nNum].get() : nullptr;
232 size_t SdrMarkList::FindObject(const SdrObject* pObj) const
234 // Since relying on OrdNums is not allowed for the selection because objects in the
235 // selection may not be inserted in a list if they are e.g. modified ATM, i changed
236 // this loop to just look if the object pointer is in the selection.
238 // Problem is that GetOrdNum() which is const, internally casts to non-const and
239 // hardly sets the OrdNum member of the object (nOrdNum) to 0 (ZERO) if the object
240 // is not inserted in an object list.
241 // Since this may be by purpose and necessary somewhere else i decided that it is
242 // less dangerous to change this method then changing SdrObject::GetOrdNum().
243 if(pObj)
245 for(size_t a = 0; a < maList.size(); ++a)
247 if(maList[a]->GetMarkedSdrObj() == pObj)
249 return a;
254 return SAL_MAX_SIZE;
257 void SdrMarkList::InsertEntry(const SdrMark& rMark, bool bChkSort)
259 SetNameDirty();
260 const size_t nCount(maList.size());
262 if(!bChkSort || !mbSorted || nCount == 0)
264 if(!bChkSort)
265 mbSorted = false;
267 maList.emplace_back(new SdrMark(rMark));
269 else
271 SdrMark* pLast = GetMark(nCount - 1);
272 const SdrObject* pLastObj = pLast->GetMarkedSdrObj();
273 const SdrObject* pNewObj = rMark.GetMarkedSdrObj();
275 if(pLastObj == pNewObj)
277 // This one already exists.
278 // Con1/Con2 Merging
279 if(rMark.IsCon1())
280 pLast->SetCon1(true);
282 if(rMark.IsCon2())
283 pLast->SetCon2(true);
285 else
287 maList.emplace_back(new SdrMark(rMark));
289 // now check if the sort is ok
290 const SdrObjList* pLastOL = pLastObj!=nullptr ? pLastObj->getParentSdrObjListFromSdrObject() : nullptr;
291 const SdrObjList* pNewOL = pNewObj !=nullptr ? pNewObj->getParentSdrObjListFromSdrObject() : nullptr;
293 if(pLastOL == pNewOL)
295 const sal_uInt32 nLastNum(pLastObj!=nullptr ? pLastObj->GetOrdNum() : 0);
296 const sal_uInt32 nNewNum(pNewObj !=nullptr ? pNewObj ->GetOrdNum() : 0);
298 if(nNewNum < nLastNum)
300 // at some point, we have to sort
301 mbSorted = false;
304 else
306 // at some point, we have to sort
307 mbSorted = false;
313 void SdrMarkList::DeleteMark(size_t nNum)
315 SdrMark* pMark = GetMark(nNum);
316 DBG_ASSERT(pMark!=nullptr,"DeleteMark: MarkEntry not found.");
318 if(pMark)
320 maList.erase(maList.begin() + nNum);
321 if (maList.empty())
322 mbSorted = true; //we're empty, so can be considered sorted
323 SetNameDirty();
327 void SdrMarkList::ReplaceMark(const SdrMark& rNewMark, size_t nNum)
329 SdrMark* pMark = GetMark(nNum);
330 DBG_ASSERT(pMark!=nullptr,"ReplaceMark: MarkEntry not found.");
332 if(pMark)
334 SetNameDirty();
335 maList[nNum].reset(new SdrMark(rNewMark));
336 mbSorted = false;
340 void SdrMarkList::Merge(const SdrMarkList& rSrcList, bool bReverse)
342 const size_t nCount(rSrcList.maList.size());
344 if(rSrcList.mbSorted)
346 // merge without forcing a Sort in rSrcList
347 bReverse = false;
350 if(!bReverse)
352 for(size_t i = 0; i < nCount; ++i)
354 SdrMark* pM = rSrcList.maList[i].get();
355 InsertEntry(*pM);
358 else
360 for(size_t i = nCount; i > 0;)
362 --i;
363 SdrMark* pM = rSrcList.maList[i].get();
364 InsertEntry(*pM);
369 bool SdrMarkList::DeletePageView(const SdrPageView& rPV)
371 bool bChgd(false);
373 for(auto it = maList.begin(); it != maList.end(); )
375 SdrMark* pMark = it->get();
377 if(pMark->GetPageView()==&rPV)
379 it = maList.erase(it);
380 SetNameDirty();
381 bChgd = true;
383 else
384 ++it;
387 return bChgd;
390 bool SdrMarkList::InsertPageView(const SdrPageView& rPV)
392 bool bChgd(false);
393 DeletePageView(rPV); // delete all of them, then append the entire page
394 const SdrObjList* pOL = rPV.GetObjList();
396 for (const rtl::Reference<SdrObject>& pObj : *pOL)
398 bool bDoIt(rPV.IsObjMarkable(pObj.get()));
400 if(bDoIt)
402 maList.emplace_back(new SdrMark(pObj.get(), const_cast<SdrPageView*>(&rPV)));
403 SetNameDirty();
404 bChgd = true;
408 return bChgd;
411 const OUString& SdrMarkList::GetMarkDescription() const
413 const size_t nCount(GetMarkCount());
415 if(mbNameOk && 1 == nCount)
417 // if it's a single selection, cache only text frame
418 const SdrObject* pObj = GetMark(0)->GetMarkedSdrObj();
419 const SdrTextObj* pTextObj = DynCastSdrTextObj( pObj );
421 if(!pTextObj || !pTextObj->IsTextFrame())
423 const_cast<SdrMarkList*>(this)->mbNameOk = false;
427 if(!mbNameOk)
429 SdrMark* pMark = GetMark(0);
430 OUString aNam;
432 if(!nCount)
434 const_cast<SdrMarkList*>(this)->maMarkName = SvxResId(STR_ObjNameNoObj);
436 else if(1 == nCount)
438 if(pMark->GetMarkedSdrObj())
440 aNam = pMark->GetMarkedSdrObj()->TakeObjNameSingul();
443 else
445 if(pMark->GetMarkedSdrObj())
447 aNam = pMark->GetMarkedSdrObj()->TakeObjNamePlural();
448 bool bEq(true);
450 for(size_t i = 1; i < GetMarkCount() && bEq; ++i)
452 SdrMark* pMark2 = GetMark(i);
453 OUString aStr1(pMark2->GetMarkedSdrObj()->TakeObjNamePlural());
454 bEq = aNam == aStr1;
457 if(!bEq)
459 aNam = SvxResId(STR_ObjNamePlural);
463 aNam = OUString::number( nCount ) + " " + aNam;
466 const_cast<SdrMarkList*>(this)->maMarkName = aNam;
467 const_cast<SdrMarkList*>(this)->mbNameOk = true;
470 return maMarkName;
473 const OUString& SdrMarkList::GetPointMarkDescription(bool bGlue) const
475 bool& rNameOk = const_cast<bool&>(bGlue ? mbGluePointNameOk : mbPointNameOk);
476 OUString& rName = const_cast<OUString&>(bGlue ? maGluePointName : maPointName);
477 const size_t nMarkCount(GetMarkCount());
478 size_t nMarkPtCnt(0);
479 size_t nMarkPtObjCnt(0);
480 size_t n1stMarkNum(SAL_MAX_SIZE);
482 for(size_t nMarkNum = 0; nMarkNum < nMarkCount; ++nMarkNum)
484 const SdrMark* pMark = GetMark(nMarkNum);
485 const SdrUShortCont& rPts = bGlue ? pMark->GetMarkedGluePoints() : pMark->GetMarkedPoints();
487 if (!rPts.empty())
489 if(n1stMarkNum == SAL_MAX_SIZE)
491 n1stMarkNum = nMarkNum;
494 nMarkPtCnt += rPts.size();
495 nMarkPtObjCnt++;
498 if(nMarkPtObjCnt > 1 && rNameOk)
500 // preliminary decision
501 return rName;
505 if(rNameOk && 1 == nMarkPtObjCnt)
507 // if it's a single selection, cache only text frame
508 const SdrObject* pObj = GetMark(0)->GetMarkedSdrObj();
509 const SdrTextObj* pTextObj = DynCastSdrTextObj( pObj );
511 if(!pTextObj || !pTextObj->IsTextFrame())
513 rNameOk = false;
517 if(!nMarkPtObjCnt)
519 rName.clear();
520 rNameOk = true;
522 else if(!rNameOk)
524 const SdrMark* pMark = GetMark(n1stMarkNum);
525 OUString aNam;
527 if(1 == nMarkPtObjCnt)
529 if(pMark->GetMarkedSdrObj())
531 aNam = pMark->GetMarkedSdrObj()->TakeObjNameSingul();
534 else
536 if(pMark->GetMarkedSdrObj())
538 aNam = pMark->GetMarkedSdrObj()->TakeObjNamePlural();
541 bool bEq(true);
543 for(size_t i = n1stMarkNum + 1; i < GetMarkCount() && bEq; ++i)
545 const SdrMark* pMark2 = GetMark(i);
546 const SdrUShortCont& rPts = bGlue ? pMark2->GetMarkedGluePoints() : pMark2->GetMarkedPoints();
548 if (!rPts.empty() && pMark2->GetMarkedSdrObj())
550 OUString aStr1(pMark2->GetMarkedSdrObj()->TakeObjNamePlural());
551 bEq = aNam == aStr1;
555 if(!bEq)
557 aNam = SvxResId(STR_ObjNamePlural);
560 aNam = OUString::number( nMarkPtObjCnt ) + " " + aNam;
563 OUString aStr1;
565 if(1 == nMarkPtCnt)
567 aStr1 = SvxResId(bGlue ? STR_ViewMarkedGluePoint : STR_ViewMarkedPoint);
569 else
571 aStr1 = SvxResId(bGlue ? STR_ViewMarkedGluePoints : STR_ViewMarkedPoints);
572 aStr1 = aStr1.replaceFirst("%2", OUString::number( nMarkPtCnt ));
575 aStr1 = aStr1.replaceFirst("%1", aNam);
576 rName = aStr1;
577 rNameOk = true;
580 return rName;
583 bool SdrMarkList::TakeBoundRect(SdrPageView const * pPV, tools::Rectangle& rRect) const
585 bool bFnd(false);
586 tools::Rectangle aR;
588 for(size_t i = 0; i < GetMarkCount(); ++i)
590 SdrMark* pMark = GetMark(i);
592 if(!pPV || pMark->GetPageView() == pPV)
594 if(pMark->GetMarkedSdrObj())
596 aR = pMark->GetMarkedSdrObj()->GetCurrentBoundRect();
598 if(bFnd)
600 rRect.Union(aR);
602 else
604 rRect = aR;
605 bFnd = true;
611 return bFnd;
614 bool SdrMarkList::TakeSnapRect(SdrPageView const * pPV, tools::Rectangle& rRect) const
616 bool bFnd(false);
618 for(size_t i = 0; i < GetMarkCount(); ++i)
620 SdrMark* pMark = GetMark(i);
622 if(!pPV || pMark->GetPageView() == pPV)
624 if(pMark->GetMarkedSdrObj())
626 tools::Rectangle aR(pMark->GetMarkedSdrObj()->GetSnapRect());
628 if(bFnd)
630 rRect.Union(aR);
632 else
634 rRect = aR;
635 bFnd = true;
641 return bFnd;
645 namespace sdr
647 ViewSelection::ViewSelection()
648 : mbEdgesOfMarkedNodesDirty(false)
652 void ViewSelection::SetEdgesOfMarkedNodesDirty()
654 if(!mbEdgesOfMarkedNodesDirty)
656 mbEdgesOfMarkedNodesDirty = true;
657 maEdgesOfMarkedNodes.Clear();
658 maMarkedEdgesOfMarkedNodes.Clear();
659 maAllMarkedObjects.clear();
663 const SdrMarkList& ViewSelection::GetEdgesOfMarkedNodes() const
665 if(mbEdgesOfMarkedNodesDirty)
667 const_cast<ViewSelection*>(this)->ImpForceEdgesOfMarkedNodes();
670 return maEdgesOfMarkedNodes;
673 const SdrMarkList& ViewSelection::GetMarkedEdgesOfMarkedNodes() const
675 if(mbEdgesOfMarkedNodesDirty)
677 const_cast<ViewSelection*>(this)->ImpForceEdgesOfMarkedNodes();
680 return maMarkedEdgesOfMarkedNodes;
683 const std::vector<SdrObject*>& ViewSelection::GetAllMarkedObjects() const
685 if(mbEdgesOfMarkedNodesDirty)
686 const_cast<ViewSelection*>(this)->ImpForceEdgesOfMarkedNodes();
688 return maAllMarkedObjects;
691 void ViewSelection::ImplCollectCompleteSelection(SdrObject* pObj)
693 if(!pObj)
694 return;
696 bool bIsGroup(pObj->IsGroupObject());
698 if(bIsGroup && DynCastE3dObject(pObj) != nullptr && DynCastE3dScene(pObj) == nullptr)
700 bIsGroup = false;
703 if(bIsGroup)
705 SdrObjList* pList = pObj->GetSubList();
707 for (const rtl::Reference<SdrObject>& pObj2 : *pList)
708 ImplCollectCompleteSelection(pObj2.get());
711 maAllMarkedObjects.push_back(pObj);
714 void ViewSelection::ImpForceEdgesOfMarkedNodes()
716 if(!mbEdgesOfMarkedNodesDirty)
717 return;
719 mbEdgesOfMarkedNodesDirty = false;
720 maMarkedObjectList.ForceSort();
721 maEdgesOfMarkedNodes.Clear();
722 maMarkedEdgesOfMarkedNodes.Clear();
723 maAllMarkedObjects.clear();
725 // GetMarkCount after ForceSort
726 const size_t nMarkCount(maMarkedObjectList.GetMarkCount());
728 for(size_t a = 0; a < nMarkCount; ++a)
730 SdrObject* pCandidate = maMarkedObjectList.GetMark(a)->GetMarkedSdrObj();
731 if(!pCandidate)
732 continue;
734 // build transitive hull
735 ImplCollectCompleteSelection(pCandidate);
737 // travel over broadcaster/listener to access edges connected to the selected object
738 const SfxBroadcaster* pBC = pCandidate->GetBroadcaster();
739 if(!pBC)
740 continue;
742 pBC->ForAllListeners(
743 [this, &pCandidate, &a] (SfxListener* pLst)
745 SdrEdgeObj* pEdge = dynamic_cast<SdrEdgeObj*>( pLst );
747 if(pEdge && pEdge->IsInserted() && pEdge->getSdrPageFromSdrObject() == pCandidate->getSdrPageFromSdrObject())
749 SdrMark aM(pEdge, maMarkedObjectList.GetMark(a)->GetPageView());
751 if(pEdge->GetConnectedNode(true) == pCandidate)
753 aM.SetCon1(true);
756 if(pEdge->GetConnectedNode(false) == pCandidate)
758 aM.SetCon2(true);
761 if(SAL_MAX_SIZE == maMarkedObjectList.FindObject(pEdge))
763 // check if it itself is selected
764 maEdgesOfMarkedNodes.InsertEntry(aM);
766 else
768 maMarkedEdgesOfMarkedNodes.InsertEntry(aM);
771 return false;
774 maEdgesOfMarkedNodes.ForceSort();
775 maMarkedEdgesOfMarkedNodes.ForceSort();
777 } // end of namespace sdr
779 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */