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/brdcst.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 );
120 SdrObject
* SdrMark::GetMarkedSdrObj() const
122 return mpSelectedSdrObject
;
125 SdrMark
& SdrMark::operator=(const SdrMark
& rMark
)
127 SetMarkedSdrObj(rMark
.mpSelectedSdrObject
);
128 mpPageView
= rMark
.mpPageView
;
129 mbCon1
= rMark
.mbCon1
;
130 mbCon2
= rMark
.mbCon2
;
131 mnUser
= rMark
.mnUser
;
145 mpPoints
= new SdrUShortCont(*rMark
.mpPoints
);
149 *mpPoints
= *rMark
.mpPoints
;
165 mpLines
= new SdrUShortCont(*rMark
.mpLines
);
169 *mpLines
= *rMark
.mpLines
;
173 if(!rMark
.mpGluePoints
)
185 mpGluePoints
= new SdrUShortCont(*rMark
.mpGluePoints
);
189 *mpGluePoints
= *rMark
.mpGluePoints
;
196 bool SdrMark::operator==(const SdrMark
& rMark
) const
198 bool bRet(mpSelectedSdrObject
== rMark
.mpSelectedSdrObject
&& mpPageView
== rMark
.mpPageView
&& mbCon1
== rMark
.mbCon1
&& mbCon2
== rMark
.mbCon2
&& mnUser
== rMark
.mnUser
);
200 if((mpPoints
!= 0L) != (rMark
.mpPoints
!= 0L))
203 if((mpLines
!= 0L) != (rMark
.mpLines
!= 0L))
206 if((mpGluePoints
!= 0L) != (rMark
.mpGluePoints
!= 0L))
209 if(bRet
&& mpPoints
&& *mpPoints
!= *rMark
.mpPoints
)
212 if(bRet
&& mpLines
&& *mpLines
!= *rMark
.mpLines
)
215 if(bRet
&& mpGluePoints
&& *mpGluePoints
!= *rMark
.mpGluePoints
)
223 static bool ImpSdrMarkListSorter(SdrMark
* const& lhs
, SdrMark
* const& rhs
)
225 SdrObject
* pObj1
= lhs
->GetMarkedSdrObj();
226 SdrObject
* pObj2
= rhs
->GetMarkedSdrObj();
227 SdrObjList
* pOL1
= (pObj1
) ? pObj1
->GetObjList() : 0L;
228 SdrObjList
* pOL2
= (pObj2
) ? pObj2
->GetObjList() : 0L;
232 // AF: Note that I reverted a change from sal_uInt32 to sal_uLong (made
233 // for 64bit compliance, #i78198#) because internally in SdrObject
234 // both nOrdNum and mnNavigationPosition are stored as sal_uInt32.
235 sal_uInt32
nObjOrd1((pObj1
) ? pObj1
->GetNavigationPosition() : 0);
236 sal_uInt32
nObjOrd2((pObj2
) ? pObj2
->GetNavigationPosition() : 0);
238 return nObjOrd1
< nObjOrd2
;
242 return (sal_IntPtr
)pOL1
< (sal_IntPtr
)pOL2
;
248 void SdrMarkList::ForceSort() const
252 ((SdrMarkList
*)this)->ImpForceSort();
256 void SdrMarkList::ImpForceSort()
261 sal_uLong nAnz
= maList
.size();
266 for(std::vector
<SdrMark
*>::iterator it
= maList
.begin(); it
!= maList
.end(); )
269 if(pAkt
->GetMarkedSdrObj() == 0)
271 it
= maList
.erase( it
);
277 nAnz
= maList
.size();
282 std::sort(maList
.begin(), maList
.end(), ImpSdrMarkListSorter
);
285 if(maList
.size() > 1)
287 SdrMark
* pAkt
= maList
.back();
288 int i
= maList
.size() - 2;
291 SdrMark
* pCmp
= maList
[i
];
292 if(pAkt
->GetMarkedSdrObj() == pCmp
->GetMarkedSdrObj() && pAkt
->GetMarkedSdrObj())
302 maList
.erase(maList
.begin() + i
);
318 void SdrMarkList::Clear()
320 for(sal_uLong
i(0L); i
< GetMarkCount(); i
++)
322 SdrMark
* pMark
= GetMark(i
);
330 void SdrMarkList::operator=(const SdrMarkList
& rLst
)
334 for(sal_uLong
i(0L); i
< rLst
.GetMarkCount(); i
++)
336 SdrMark
* pMark
= rLst
.GetMark(i
);
337 SdrMark
* pNeuMark
= new SdrMark(*pMark
);
338 maList
.push_back(pNeuMark
);
341 maMarkName
= rLst
.maMarkName
;
342 mbNameOk
= rLst
.mbNameOk
;
343 maPointName
= rLst
.maPointName
;
344 mbPointNameOk
= rLst
.mbPointNameOk
;
345 maGluePointName
= rLst
.maGluePointName
;
346 mbGluePointNameOk
= rLst
.mbGluePointNameOk
;
347 mbSorted
= rLst
.mbSorted
;
350 SdrMark
* SdrMarkList::GetMark(sal_uLong nNum
) const
352 return (nNum
< maList
.size()) ? maList
[nNum
] : NULL
;
355 sal_uLong
SdrMarkList::FindObject(const SdrObject
* pObj
) const
357 // Since relying on OrdNums is not allowed for the selection because objects in the
358 // selection may not be inserted in a list if they are e.g. modified ATM, i changed
359 // this loop to just look if the object pointer is in the selection.
361 // Problem is that GetOrdNum() which is const, internally casts to non-const and
362 // hardly sets the OrdNum member of the object (nOrdNum) to 0 (ZERO) if the object
363 // is not inserted in a object list.
364 // Since this may be by purpose and necessary somewhere else i decided that it is
365 // less dangerous to change this method then changing SdrObject::GetOrdNum().
366 if(pObj
&& !maList
.empty())
368 for(sal_uLong
a(0L); a
< maList
.size(); a
++)
370 if(maList
[a
]->GetMarkedSdrObj() == pObj
)
377 return CONTAINER_ENTRY_NOTFOUND
;
380 void SdrMarkList::InsertEntry(const SdrMark
& rMark
, bool bChkSort
)
383 sal_uLong
nAnz(maList
.size());
385 if(!bChkSort
|| !mbSorted
|| nAnz
== 0)
390 maList
.push_back(new SdrMark(rMark
));
394 SdrMark
* pLast
= GetMark(sal_uLong(nAnz
- 1));
395 const SdrObject
* pLastObj
= pLast
->GetMarkedSdrObj();
396 const SdrObject
* pNeuObj
= rMark
.GetMarkedSdrObj();
398 if(pLastObj
== pNeuObj
)
400 // This one already exists.
403 pLast
->SetCon1(true);
406 pLast
->SetCon2(true);
410 SdrMark
* pKopie
= new SdrMark(rMark
);
411 maList
.push_back(pKopie
);
413 // now check if the sort is ok
414 const SdrObjList
* pLastOL
= pLastObj
!=0L ? pLastObj
->GetObjList() : 0L;
415 const SdrObjList
* pNeuOL
= pNeuObj
!=0L ? pNeuObj
->GetObjList() : 0L;
417 if(pLastOL
== pNeuOL
)
419 const sal_uLong
nLastNum(pLastObj
!=0L ? pLastObj
->GetOrdNum() : 0);
420 const sal_uLong
nNeuNum(pNeuObj
!=0L ? pNeuObj
->GetOrdNum() : 0);
422 if(nNeuNum
< nLastNum
)
424 // at some point, we have to sort
430 // at some point, we have to sort
439 void SdrMarkList::DeleteMark(sal_uLong nNum
)
441 SdrMark
* pMark
= GetMark(nNum
);
442 DBG_ASSERT(pMark
!=0L,"DeleteMark: MarkEntry not found.");
446 maList
.erase(maList
.begin() + nNum
);
452 void SdrMarkList::ReplaceMark(const SdrMark
& rNewMark
, sal_uLong nNum
)
454 SdrMark
* pMark
= GetMark(nNum
);
455 DBG_ASSERT(pMark
!=0L,"ReplaceMark: MarkEntry not found.");
461 SdrMark
* pKopie
= new SdrMark(rNewMark
);
462 maList
[nNum
] = pKopie
;
467 void SdrMarkList::Merge(const SdrMarkList
& rSrcList
, bool bReverse
)
469 sal_uLong
nAnz(rSrcList
.maList
.size());
471 if(rSrcList
.mbSorted
)
473 // merge without forcing a Sort in rSrcList
479 for(sal_uLong
i(0L); i
< nAnz
; i
++)
481 SdrMark
* pM
= rSrcList
.maList
[i
];
487 for(sal_uLong
i(nAnz
); i
> 0;)
490 SdrMark
* pM
= rSrcList
.maList
[i
];
496 bool SdrMarkList::DeletePageView(const SdrPageView
& rPV
)
500 for(std::vector
<SdrMark
*>::iterator it
= maList
.begin(); it
!= maList
.end(); )
502 SdrMark
* pMark
= *it
;
504 if(pMark
->GetPageView()==&rPV
)
506 it
= maList
.erase(it
);
518 bool SdrMarkList::InsertPageView(const SdrPageView
& rPV
)
521 DeletePageView(rPV
); // delete all of them, then append the entire page
523 const SdrObjList
* pOL
= rPV
.GetObjList();
524 sal_uLong
nObjAnz(pOL
->GetObjCount());
526 for(sal_uLong
nO(0L); nO
< nObjAnz
; nO
++)
528 pObj
= pOL
->GetObj(nO
);
529 bool bDoIt(rPV
.IsObjMarkable(pObj
));
533 SdrMark
* pM
= new SdrMark(pObj
, (SdrPageView
*)&rPV
);
534 maList
.push_back(pM
);
543 const OUString
& SdrMarkList::GetMarkDescription() const
545 sal_uLong
nAnz(GetMarkCount());
547 if(mbNameOk
&& 1L == nAnz
)
549 // if it's a single selection, cache only text frame
550 const SdrObject
* pObj
= GetMark(0)->GetMarkedSdrObj();
551 const SdrTextObj
* pTextObj
= PTR_CAST(SdrTextObj
, pObj
);
553 if(!pTextObj
|| !pTextObj
->IsTextFrame())
555 ((SdrMarkList
*)(this))->mbNameOk
= false;
561 SdrMark
* pMark
= GetMark(0);
566 const_cast<SdrMarkList
*>(this)->maMarkName
= ImpGetResStr(STR_ObjNameNoObj
);
570 if(pMark
->GetMarkedSdrObj())
572 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNameSingul();
577 if(pMark
->GetMarkedSdrObj())
579 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNamePlural();
582 for(sal_uLong i
= 1; i
< GetMarkCount() && bEq
; i
++)
584 SdrMark
* pMark2
= GetMark(i
);
585 OUString
aStr1(pMark2
->GetMarkedSdrObj()->TakeObjNamePlural());
591 aNam
= ImpGetResStr(STR_ObjNamePlural
);
595 aNam
= OUString::number( nAnz
) + " " + aNam
;
598 const_cast<SdrMarkList
*>(this)->maMarkName
= aNam
;
599 const_cast<SdrMarkList
*>(this)->mbNameOk
= true;
605 const OUString
& SdrMarkList::GetPointMarkDescription(bool bGlue
) const
607 bool& rNameOk
= (bool&)(bGlue
? mbGluePointNameOk
: mbPointNameOk
);
608 OUString
& rName
= const_cast<OUString
&>(bGlue
? maGluePointName
: maPointName
);
609 sal_uLong
nMarkAnz(GetMarkCount());
610 sal_uLong
nMarkPtAnz(0L);
611 sal_uLong
nMarkPtObjAnz(0L);
612 sal_uLong
n1stMarkNum(ULONG_MAX
);
614 for(sal_uLong
nMarkNum(0L); nMarkNum
< nMarkAnz
; nMarkNum
++)
616 const SdrMark
* pMark
= GetMark(nMarkNum
);
617 const SdrUShortCont
* pPts
= bGlue
? pMark
->GetMarkedGluePoints() : pMark
->GetMarkedPoints();
618 sal_uLong
nAnz(pPts
? pPts
->size() : 0);
622 if(n1stMarkNum
== ULONG_MAX
)
624 n1stMarkNum
= nMarkNum
;
631 if(nMarkPtObjAnz
> 1 && rNameOk
)
633 // preliminary decision
638 if(rNameOk
&& 1L == nMarkPtObjAnz
)
640 // if it's a single selection, cache only text frame
641 const SdrObject
* pObj
= GetMark(0)->GetMarkedSdrObj();
642 const SdrTextObj
* pTextObj
= PTR_CAST(SdrTextObj
,pObj
);
644 if(!pTextObj
|| !pTextObj
->IsTextFrame())
657 const SdrMark
* pMark
= GetMark(n1stMarkNum
);
660 if(1L == nMarkPtObjAnz
)
662 if(pMark
->GetMarkedSdrObj())
664 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNameSingul();
669 if(pMark
->GetMarkedSdrObj())
671 aNam
= pMark
->GetMarkedSdrObj()->TakeObjNamePlural();
676 for(sal_uLong
i(n1stMarkNum
+ 1L); i
< GetMarkCount() && bEq
; i
++)
678 const SdrMark
* pMark2
= GetMark(i
);
679 const SdrUShortCont
* pPts
= bGlue
? pMark2
->GetMarkedGluePoints() : pMark2
->GetMarkedPoints();
681 if(pPts
&& !pPts
->empty() && pMark2
->GetMarkedSdrObj())
683 OUString
aStr1(pMark2
->GetMarkedSdrObj()->TakeObjNamePlural());
690 aNam
= ImpGetResStr(STR_ObjNamePlural
);
693 aNam
= OUString::number( nMarkPtObjAnz
) + " " + aNam
;
700 aStr1
= (ImpGetResStr(bGlue
? STR_ViewMarkedGluePoint
: STR_ViewMarkedPoint
));
704 aStr1
= (ImpGetResStr(bGlue
? STR_ViewMarkedGluePoints
: STR_ViewMarkedPoints
));
705 aStr1
= aStr1
.replaceFirst("%2", OUString::number( nMarkPtAnz
));
708 aStr1
= aStr1
.replaceFirst("%1", aNam
);
716 bool SdrMarkList::TakeBoundRect(SdrPageView
* pPV
, Rectangle
& rRect
) const
721 for(sal_uLong
i(0L); i
< GetMarkCount(); i
++)
723 SdrMark
* pMark
= GetMark(i
);
725 if(!pPV
|| pMark
->GetPageView() == pPV
)
727 if(pMark
->GetMarkedSdrObj())
729 aR
= pMark
->GetMarkedSdrObj()->GetCurrentBoundRect();
747 bool SdrMarkList::TakeSnapRect(SdrPageView
* pPV
, Rectangle
& rRect
) const
751 for(sal_uLong
i(0L); i
< GetMarkCount(); i
++)
753 SdrMark
* pMark
= GetMark(i
);
755 if(!pPV
|| pMark
->GetPageView() == pPV
)
757 if(pMark
->GetMarkedSdrObj())
759 Rectangle
aR(pMark
->GetMarkedSdrObj()->GetSnapRect());
781 ViewSelection::ViewSelection()
782 : mbEdgesOfMarkedNodesDirty(false)
786 void ViewSelection::SetEdgesOfMarkedNodesDirty()
788 if(!mbEdgesOfMarkedNodesDirty
)
790 mbEdgesOfMarkedNodesDirty
= true;
791 maEdgesOfMarkedNodes
.Clear();
792 maMarkedEdgesOfMarkedNodes
.Clear();
793 maAllMarkedObjects
.clear();
797 const SdrMarkList
& ViewSelection::GetEdgesOfMarkedNodes() const
799 if(mbEdgesOfMarkedNodesDirty
)
801 ((ViewSelection
*)this)->ImpForceEdgesOfMarkedNodes();
804 return maEdgesOfMarkedNodes
;
807 const SdrMarkList
& ViewSelection::GetMarkedEdgesOfMarkedNodes() const
809 if(mbEdgesOfMarkedNodesDirty
)
811 ((ViewSelection
*)this)->ImpForceEdgesOfMarkedNodes();
814 return maMarkedEdgesOfMarkedNodes
;
817 const std::vector
<SdrObject
*>& ViewSelection::GetAllMarkedObjects() const
819 if(mbEdgesOfMarkedNodesDirty
)
820 ((ViewSelection
*)this)->ImpForceEdgesOfMarkedNodes();
822 return maAllMarkedObjects
;
825 void ViewSelection::ImplCollectCompleteSelection(SdrObject
* pObj
)
829 bool bIsGroup(pObj
->IsGroupObject());
831 if(bIsGroup
&& pObj
->ISA(E3dObject
) && !pObj
->ISA(E3dScene
))
838 SdrObjList
* pList
= pObj
->GetSubList();
840 for(sal_uLong
a(0L); a
< pList
->GetObjCount(); a
++)
842 SdrObject
* pObj2
= pList
->GetObj(a
);
843 ImplCollectCompleteSelection(pObj2
);
847 maAllMarkedObjects
.push_back(pObj
);
851 void ViewSelection::ImpForceEdgesOfMarkedNodes()
853 if(mbEdgesOfMarkedNodesDirty
)
855 mbEdgesOfMarkedNodesDirty
= false;
856 maMarkedObjectList
.ForceSort();
857 maEdgesOfMarkedNodes
.Clear();
858 maMarkedEdgesOfMarkedNodes
.Clear();
859 maAllMarkedObjects
.clear();
861 // GetMarkCount after ForceSort
862 const sal_uLong
nMarkAnz(maMarkedObjectList
.GetMarkCount());
864 for(sal_uLong
a(0L); a
< nMarkAnz
; a
++)
866 SdrObject
* pCandidate
= maMarkedObjectList
.GetMark(a
)->GetMarkedSdrObj();
870 // build transitive hull
871 ImplCollectCompleteSelection(pCandidate
);
873 if(pCandidate
->IsNode())
875 // travel over broadcaster/listener to access edges connected to the selected object
876 const SfxBroadcaster
* pBC
= pCandidate
->GetBroadcaster();
880 sal_uInt16
nLstAnz(pBC
->GetListenerCount());
882 for(sal_uInt16
nl(0); nl
< nLstAnz
; nl
++)
884 SfxListener
* pLst
= pBC
->GetListener(nl
);
885 SdrEdgeObj
* pEdge
= PTR_CAST(SdrEdgeObj
, pLst
);
887 if(pEdge
&& pEdge
->IsInserted() && pEdge
->GetPage() == pCandidate
->GetPage())
889 SdrMark
aM(pEdge
, maMarkedObjectList
.GetMark(a
)->GetPageView());
891 if(pEdge
->GetConnectedNode(true) == pCandidate
)
896 if(pEdge
->GetConnectedNode(false) == pCandidate
)
901 if(CONTAINER_ENTRY_NOTFOUND
== maMarkedObjectList
.FindObject(pEdge
))
903 // check if it itself is selected
904 maEdgesOfMarkedNodes
.InsertEntry(aM
);
908 maMarkedEdgesOfMarkedNodes
.InsertEntry(aM
);
917 maEdgesOfMarkedNodes
.ForceSort();
918 maMarkedEdgesOfMarkedNodes
.ForceSort();
921 } // end of namespace sdr
923 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */