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 .
23 #include <svx/svdmark.hxx>
24 #include <svx/svdetc.hxx>
25 #include <svx/svdobj.hxx>
26 #include <svx/svdpage.hxx>
27 #include "svx/svditer.hxx"
28 #include <svx/svdpagv.hxx>
29 #include <svx/svdopath.hxx>
30 #include <svx/svdogrp.hxx>
31 #include <svx/svdorect.hxx>
32 #include "svx/svdstr.hrc"
33 #include "svdglob.hxx"
36 #include <svx/obj3d.hxx>
37 #include <svx/scene3d.hxx>
38 #include <svl/SfxBroadcaster.hxx>
39 #include <svx/svdoedge.hxx>
44 SdrMark::SdrMark(SdrObject
* pNewObj
, SdrPageView
* pNewPageView
)
45 : mpSelectedSdrObject(pNewObj
),
46 mpPageView(pNewPageView
),
54 if(mpSelectedSdrObject
)
56 mpSelectedSdrObject
->AddObjectUser( *this );
60 SdrMark::SdrMark(const SdrMark
& rMark
)
62 mpSelectedSdrObject(0L),
76 if(mpSelectedSdrObject
)
78 mpSelectedSdrObject
->RemoveObjectUser( *this );
97 void SdrMark::ObjectInDestruction(const SdrObject
& rObject
)
99 (void) rObject
; // avoid warnings
100 OSL_ENSURE(mpSelectedSdrObject
&& mpSelectedSdrObject
== &rObject
, "SdrMark::ObjectInDestruction: called form object different from hosted one (!)");
101 OSL_ENSURE(mpSelectedSdrObject
, "SdrMark::ObjectInDestruction: still selected SdrObject is deleted, deselect first (!)");
102 mpSelectedSdrObject
= 0L;
105 void SdrMark::SetMarkedSdrObj(SdrObject
* pNewObj
)
107 if(mpSelectedSdrObject
)
109 mpSelectedSdrObject
->RemoveObjectUser( *this );
112 mpSelectedSdrObject
= pNewObj
;
114 if(mpSelectedSdrObject
)
116 mpSelectedSdrObject
->AddObjectUser( *this );
121 SdrMark
& SdrMark::operator=(const SdrMark
& rMark
)
123 SetMarkedSdrObj(rMark
.mpSelectedSdrObject
);
124 mpPageView
= rMark
.mpPageView
;
125 mbCon1
= rMark
.mbCon1
;
126 mbCon2
= rMark
.mbCon2
;
127 mnUser
= rMark
.mnUser
;
141 mpPoints
= new SdrUShortCont(*rMark
.mpPoints
);
145 *mpPoints
= *rMark
.mpPoints
;
161 mpLines
= new SdrUShortCont(*rMark
.mpLines
);
165 *mpLines
= *rMark
.mpLines
;
169 if(!rMark
.mpGluePoints
)
181 mpGluePoints
= new SdrUShortCont(*rMark
.mpGluePoints
);
185 *mpGluePoints
= *rMark
.mpGluePoints
;
192 bool SdrMark::operator==(const SdrMark
& rMark
) const
194 bool bRet(mpSelectedSdrObject
== rMark
.mpSelectedSdrObject
&& mpPageView
== rMark
.mpPageView
&& mbCon1
== rMark
.mbCon1
&& mbCon2
== rMark
.mbCon2
&& mnUser
== rMark
.mnUser
);
196 if((mpPoints
!= 0L) != (rMark
.mpPoints
!= 0L))
199 if((mpLines
!= 0L) != (rMark
.mpLines
!= 0L))
202 if((mpGluePoints
!= 0L) != (rMark
.mpGluePoints
!= 0L))
205 if(bRet
&& mpPoints
&& *mpPoints
!= *rMark
.mpPoints
)
208 if(bRet
&& mpLines
&& *mpLines
!= *rMark
.mpLines
)
211 if(bRet
&& mpGluePoints
&& *mpGluePoints
!= *rMark
.mpGluePoints
)
219 static bool ImpSdrMarkListSorter(SdrMark
* const& lhs
, SdrMark
* const& rhs
)
221 SdrObject
* pObj1
= lhs
->GetMarkedSdrObj();
222 SdrObject
* pObj2
= rhs
->GetMarkedSdrObj();
223 SdrObjList
* pOL1
= (pObj1
) ? pObj1
->GetObjList() : 0L;
224 SdrObjList
* pOL2
= (pObj2
) ? pObj2
->GetObjList() : 0L;
228 // AF: Note that I reverted a change from sal_uInt32 to sal_uLong (made
229 // for 64bit compliance, #i78198#) because internally in SdrObject
230 // both nOrdNum and mnNavigationPosition are stored as sal_uInt32.
231 sal_uInt32
nObjOrd1((pObj1
) ? pObj1
->GetNavigationPosition() : 0);
232 sal_uInt32
nObjOrd2((pObj2
) ? pObj2
->GetNavigationPosition() : 0);
234 return nObjOrd1
< nObjOrd2
;
244 void SdrMarkList::ForceSort() const
248 const_cast<SdrMarkList
*>(this)->ImpForceSort();
252 void SdrMarkList::ImpForceSort()
257 size_t nCount
= maList
.size();
262 for(std::vector
<SdrMark
*>::iterator it
= maList
.begin(); it
!= maList
.end(); )
265 if(pAkt
->GetMarkedSdrObj() == 0)
267 it
= maList
.erase( it
);
273 nCount
= maList
.size();
278 std::sort(maList
.begin(), maList
.end(), ImpSdrMarkListSorter
);
281 if(maList
.size() > 1)
283 SdrMark
* pAkt
= maList
.back();
284 for (size_t i
= maList
.size() - 2; i
; --i
)
286 SdrMark
* pCmp
= maList
[i
];
287 if(pAkt
->GetMarkedSdrObj() == pCmp
->GetMarkedSdrObj() && pAkt
->GetMarkedSdrObj())
297 maList
.erase(maList
.begin() + i
);
311 void SdrMarkList::Clear()
313 for(size_t i
= 0; i
< GetMarkCount(); ++i
)
315 SdrMark
* pMark
= GetMark(i
);
323 void SdrMarkList::operator=(const SdrMarkList
& rLst
)
327 for(size_t i
= 0; i
< rLst
.GetMarkCount(); ++i
)
329 SdrMark
* pMark
= rLst
.GetMark(i
);
330 SdrMark
* pNeuMark
= new SdrMark(*pMark
);
331 maList
.push_back(pNeuMark
);
334 maMarkName
= rLst
.maMarkName
;
335 mbNameOk
= rLst
.mbNameOk
;
336 maPointName
= rLst
.maPointName
;
337 mbPointNameOk
= rLst
.mbPointNameOk
;
338 maGluePointName
= rLst
.maGluePointName
;
339 mbGluePointNameOk
= rLst
.mbGluePointNameOk
;
340 mbSorted
= rLst
.mbSorted
;
343 SdrMark
* SdrMarkList::GetMark(size_t nNum
) const
345 return (nNum
< maList
.size()) ? maList
[nNum
] : NULL
;
348 size_t SdrMarkList::FindObject(const SdrObject
* pObj
) const
350 // Since relying on OrdNums is not allowed for the selection because objects in the
351 // selection may not be inserted in a list if they are e.g. modified ATM, i changed
352 // this loop to just look if the object pointer is in the selection.
354 // Problem is that GetOrdNum() which is const, internally casts to non-const and
355 // hardly sets the OrdNum member of the object (nOrdNum) to 0 (ZERO) if the object
356 // is not inserted in a object list.
357 // Since this may be by purpose and necessary somewhere else i decided that it is
358 // less dangerous to change this method then changing SdrObject::GetOrdNum().
359 if(pObj
&& !maList
.empty())
361 for(size_t a
= 0; a
< maList
.size(); ++a
)
363 if(maList
[a
]->GetMarkedSdrObj() == pObj
)
373 void SdrMarkList::InsertEntry(const SdrMark
& rMark
, bool bChkSort
)
376 const size_t nCount(maList
.size());
378 if(!bChkSort
|| !mbSorted
|| nCount
== 0)
383 maList
.push_back(new SdrMark(rMark
));
387 SdrMark
* pLast
= GetMark(nCount
- 1);
388 const SdrObject
* pLastObj
= pLast
->GetMarkedSdrObj();
389 const SdrObject
* pNeuObj
= rMark
.GetMarkedSdrObj();
391 if(pLastObj
== pNeuObj
)
393 // This one already exists.
396 pLast
->SetCon1(true);
399 pLast
->SetCon2(true);
403 SdrMark
* pKopie
= new SdrMark(rMark
);
404 maList
.push_back(pKopie
);
406 // now check if the sort is ok
407 const SdrObjList
* pLastOL
= pLastObj
!=0L ? pLastObj
->GetObjList() : 0L;
408 const SdrObjList
* pNeuOL
= pNeuObj
!=0L ? pNeuObj
->GetObjList() : 0L;
410 if(pLastOL
== pNeuOL
)
412 const sal_uLong
nLastNum(pLastObj
!=0L ? pLastObj
->GetOrdNum() : 0);
413 const sal_uLong
nNeuNum(pNeuObj
!=0L ? pNeuObj
->GetOrdNum() : 0);
415 if(nNeuNum
< nLastNum
)
417 // at some point, we have to sort
423 // at some point, we have to sort
432 void SdrMarkList::DeleteMark(size_t nNum
)
434 SdrMark
* pMark
= GetMark(nNum
);
435 DBG_ASSERT(pMark
!=0L,"DeleteMark: MarkEntry not found.");
439 maList
.erase(maList
.begin() + nNum
);
445 void SdrMarkList::ReplaceMark(const SdrMark
& rNewMark
, size_t nNum
)
447 SdrMark
* pMark
= GetMark(nNum
);
448 DBG_ASSERT(pMark
!=0L,"ReplaceMark: MarkEntry not found.");
454 SdrMark
* pKopie
= new SdrMark(rNewMark
);
455 maList
[nNum
] = pKopie
;
460 void SdrMarkList::Merge(const SdrMarkList
& rSrcList
, bool bReverse
)
462 const size_t nCount(rSrcList
.maList
.size());
464 if(rSrcList
.mbSorted
)
466 // merge without forcing a Sort in rSrcList
472 for(size_t i
= 0; i
< nCount
; ++i
)
474 SdrMark
* pM
= rSrcList
.maList
[i
];
480 for(size_t i
= nCount
; i
> 0;)
483 SdrMark
* pM
= rSrcList
.maList
[i
];
489 bool SdrMarkList::DeletePageView(const SdrPageView
& rPV
)
493 for(std::vector
<SdrMark
*>::iterator it
= maList
.begin(); it
!= maList
.end(); )
495 SdrMark
* pMark
= *it
;
497 if(pMark
->GetPageView()==&rPV
)
499 it
= maList
.erase(it
);
511 bool SdrMarkList::InsertPageView(const SdrPageView
& rPV
)
514 DeletePageView(rPV
); // delete all of them, then append the entire page
515 const SdrObjList
* pOL
= rPV
.GetObjList();
516 const size_t nObjAnz(pOL
->GetObjCount());
518 for(size_t nO
= 0; nO
< nObjAnz
; ++nO
)
520 SdrObject
* pObj
= pOL
->GetObj(nO
);
521 bool bDoIt(rPV
.IsObjMarkable(pObj
));
525 SdrMark
* pM
= new SdrMark(pObj
, const_cast<SdrPageView
*>(&rPV
));
526 maList
.push_back(pM
);
535 const OUString
& SdrMarkList::GetMarkDescription() const
537 const size_t nCount(GetMarkCount());
539 if(mbNameOk
&& 1L == nCount
)
541 // if it's a single selection, cache only text frame
542 const SdrObject
* pObj
= GetMark(0)->GetMarkedSdrObj();
543 const SdrTextObj
* pTextObj
= PTR_CAST(SdrTextObj
, pObj
);
545 if(!pTextObj
|| !pTextObj
->IsTextFrame())
547 const_cast<SdrMarkList
*>(this)->mbNameOk
= false;
553 SdrMark
* pMark
= GetMark(0);
558 const_cast<SdrMarkList
*>(this)->maMarkName
= ImpGetResStr(STR_ObjNameNoObj
);
560 else if(1L == nCount
)
562 if(pMark
->GetMarkedSdrObj())
564 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNameSingul();
569 if(pMark
->GetMarkedSdrObj())
571 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNamePlural();
574 for(size_t i
= 1; i
< GetMarkCount() && bEq
; ++i
)
576 SdrMark
* pMark2
= GetMark(i
);
577 OUString
aStr1(pMark2
->GetMarkedSdrObj()->TakeObjNamePlural());
583 aNam
= ImpGetResStr(STR_ObjNamePlural
);
587 aNam
= OUString::number( nCount
) + " " + aNam
;
590 const_cast<SdrMarkList
*>(this)->maMarkName
= aNam
;
591 const_cast<SdrMarkList
*>(this)->mbNameOk
= true;
597 const OUString
& SdrMarkList::GetPointMarkDescription(bool bGlue
) const
599 bool& rNameOk
= (bool&)(bGlue
? mbGluePointNameOk
: mbPointNameOk
);
600 OUString
& rName
= const_cast<OUString
&>(bGlue
? maGluePointName
: maPointName
);
601 const size_t nMarkCount(GetMarkCount());
602 size_t nMarkPtAnz(0);
603 size_t nMarkPtObjAnz(0);
604 size_t n1stMarkNum(SAL_MAX_SIZE
);
606 for(size_t nMarkNum
= 0; nMarkNum
< nMarkCount
; ++nMarkNum
)
608 const SdrMark
* pMark
= GetMark(nMarkNum
);
609 const SdrUShortCont
* pPts
= bGlue
? pMark
->GetMarkedGluePoints() : pMark
->GetMarkedPoints();
610 const size_t nCount(pPts
? pPts
->size() : 0);
614 if(n1stMarkNum
== SAL_MAX_SIZE
)
616 n1stMarkNum
= nMarkNum
;
619 nMarkPtAnz
+= nCount
;
623 if(nMarkPtObjAnz
> 1 && rNameOk
)
625 // preliminary decision
630 if(rNameOk
&& 1 == nMarkPtObjAnz
)
632 // if it's a single selection, cache only text frame
633 const SdrObject
* pObj
= GetMark(0)->GetMarkedSdrObj();
634 const SdrTextObj
* pTextObj
= PTR_CAST(SdrTextObj
,pObj
);
636 if(!pTextObj
|| !pTextObj
->IsTextFrame())
649 const SdrMark
* pMark
= GetMark(n1stMarkNum
);
652 if(1L == nMarkPtObjAnz
)
654 if(pMark
->GetMarkedSdrObj())
656 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNameSingul();
661 if(pMark
->GetMarkedSdrObj())
663 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNamePlural();
668 for(size_t i
= n1stMarkNum
+ 1; i
< GetMarkCount() && bEq
; ++i
)
670 const SdrMark
* pMark2
= GetMark(i
);
671 const SdrUShortCont
* pPts
= bGlue
? pMark2
->GetMarkedGluePoints() : pMark2
->GetMarkedPoints();
673 if(pPts
&& !pPts
->empty() && pMark2
->GetMarkedSdrObj())
675 OUString
aStr1(pMark2
->GetMarkedSdrObj()->TakeObjNamePlural());
682 aNam
= ImpGetResStr(STR_ObjNamePlural
);
685 aNam
= OUString::number( nMarkPtObjAnz
) + " " + aNam
;
692 aStr1
= (ImpGetResStr(bGlue
? STR_ViewMarkedGluePoint
: STR_ViewMarkedPoint
));
696 aStr1
= (ImpGetResStr(bGlue
? STR_ViewMarkedGluePoints
: STR_ViewMarkedPoints
));
697 aStr1
= aStr1
.replaceFirst("%2", OUString::number( nMarkPtAnz
));
700 aStr1
= aStr1
.replaceFirst("%1", aNam
);
708 bool SdrMarkList::TakeBoundRect(SdrPageView
* pPV
, Rectangle
& rRect
) const
713 for(size_t i
= 0; i
< GetMarkCount(); ++i
)
715 SdrMark
* pMark
= GetMark(i
);
717 if(!pPV
|| pMark
->GetPageView() == pPV
)
719 if(pMark
->GetMarkedSdrObj())
721 aR
= pMark
->GetMarkedSdrObj()->GetCurrentBoundRect();
739 bool SdrMarkList::TakeSnapRect(SdrPageView
* pPV
, Rectangle
& rRect
) const
743 for(size_t i
= 0; i
< GetMarkCount(); ++i
)
745 SdrMark
* pMark
= GetMark(i
);
747 if(!pPV
|| pMark
->GetPageView() == pPV
)
749 if(pMark
->GetMarkedSdrObj())
751 Rectangle
aR(pMark
->GetMarkedSdrObj()->GetSnapRect());
773 ViewSelection::ViewSelection()
774 : mbEdgesOfMarkedNodesDirty(false)
778 void ViewSelection::SetEdgesOfMarkedNodesDirty()
780 if(!mbEdgesOfMarkedNodesDirty
)
782 mbEdgesOfMarkedNodesDirty
= true;
783 maEdgesOfMarkedNodes
.Clear();
784 maMarkedEdgesOfMarkedNodes
.Clear();
785 maAllMarkedObjects
.clear();
789 const SdrMarkList
& ViewSelection::GetEdgesOfMarkedNodes() const
791 if(mbEdgesOfMarkedNodesDirty
)
793 const_cast<ViewSelection
*>(this)->ImpForceEdgesOfMarkedNodes();
796 return maEdgesOfMarkedNodes
;
799 const SdrMarkList
& ViewSelection::GetMarkedEdgesOfMarkedNodes() const
801 if(mbEdgesOfMarkedNodesDirty
)
803 const_cast<ViewSelection
*>(this)->ImpForceEdgesOfMarkedNodes();
806 return maMarkedEdgesOfMarkedNodes
;
809 const std::vector
<SdrObject
*>& ViewSelection::GetAllMarkedObjects() const
811 if(mbEdgesOfMarkedNodesDirty
)
812 const_cast<ViewSelection
*>(this)->ImpForceEdgesOfMarkedNodes();
814 return maAllMarkedObjects
;
817 void ViewSelection::ImplCollectCompleteSelection(SdrObject
* pObj
)
821 bool bIsGroup(pObj
->IsGroupObject());
823 if(bIsGroup
&& pObj
->ISA(E3dObject
) && !pObj
->ISA(E3dScene
))
830 SdrObjList
* pList
= pObj
->GetSubList();
832 for(size_t a
= 0; a
< pList
->GetObjCount(); ++a
)
834 SdrObject
* pObj2
= pList
->GetObj(a
);
835 ImplCollectCompleteSelection(pObj2
);
839 maAllMarkedObjects
.push_back(pObj
);
843 void ViewSelection::ImpForceEdgesOfMarkedNodes()
845 if(mbEdgesOfMarkedNodesDirty
)
847 mbEdgesOfMarkedNodesDirty
= false;
848 maMarkedObjectList
.ForceSort();
849 maEdgesOfMarkedNodes
.Clear();
850 maMarkedEdgesOfMarkedNodes
.Clear();
851 maAllMarkedObjects
.clear();
853 // GetMarkCount after ForceSort
854 const size_t nMarkCount(maMarkedObjectList
.GetMarkCount());
856 for(size_t a
= 0; a
< nMarkCount
; ++a
)
858 SdrObject
* pCandidate
= maMarkedObjectList
.GetMark(a
)->GetMarkedSdrObj();
862 // build transitive hull
863 ImplCollectCompleteSelection(pCandidate
);
865 if(pCandidate
->IsNode())
867 // travel over broadcaster/listener to access edges connected to the selected object
868 const SfxBroadcaster
* pBC
= pCandidate
->GetBroadcaster();
872 const size_t nLstAnz(pBC
->GetSizeOfVector());
874 for(size_t nl
=0; nl
< nLstAnz
; ++nl
)
876 SfxListener
* pLst
= pBC
->GetListener(nl
);
877 SdrEdgeObj
* pEdge
= PTR_CAST(SdrEdgeObj
, pLst
);
879 if(pEdge
&& pEdge
->IsInserted() && pEdge
->GetPage() == pCandidate
->GetPage())
881 SdrMark
aM(pEdge
, maMarkedObjectList
.GetMark(a
)->GetPageView());
883 if(pEdge
->GetConnectedNode(true) == pCandidate
)
888 if(pEdge
->GetConnectedNode(false) == pCandidate
)
893 if(SAL_MAX_SIZE
== maMarkedObjectList
.FindObject(pEdge
))
895 // check if it itself is selected
896 maEdgesOfMarkedNodes
.InsertEntry(aM
);
900 maMarkedEdgesOfMarkedNodes
.InsertEntry(aM
);
909 maEdgesOfMarkedNodes
.ForceSort();
910 maMarkedEdgesOfMarkedNodes
.ForceSort();
913 } // end of namespace sdr
915 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */