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 <svx/svdedtv.hxx>
21 #include <svx/svdundo.hxx>
22 #include <svx/svdogrp.hxx>
23 #include <svx/svdoutl.hxx>
24 #include <svx/svdopath.hxx>
25 #include <svx/svdpage.hxx>
26 #include <svx/svdpagv.hxx>
27 #include <svx/svditer.hxx>
28 #include <svx/svdograf.hxx>
29 #include <svx/svdoole2.hxx>
30 #include <svx/dialmgr.hxx>
31 #include <svx/sdooitm.hxx>
32 #include <svx/sdshitm.hxx>
33 #include <svx/xfillit0.hxx>
34 #include <svx/xlineit0.hxx>
35 #include <svx/xtextit0.hxx>
36 #include "svdfmtf.hxx"
38 #include <svx/svdetc.hxx>
39 #include <editeng/outlobj.hxx>
40 #include <editeng/eeitem.hxx>
41 #include <basegfx/polygon/b2dpolypolygon.hxx>
42 #include <basegfx/polygon/b2dpolypolygontools.hxx>
43 #include <svx/strings.hrc>
44 #include <svx/svdoashp.hxx>
45 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
46 #include <i18nutil/unicode.hxx>
47 #include <sal/log.hxx>
48 #include <tools/debug.hxx>
51 #include <vcl/graph.hxx>
52 #include <svx/svxids.hrc>
53 #include <dstribut_enum.hxx>
54 #include <osl/diagnose.h>
56 using namespace com::sun::star
;
58 SdrObject
* SdrEditView::GetMaxToTopObj(SdrObject
* /*pObj*/) const
63 SdrObject
* SdrEditView::GetMaxToBtmObj(SdrObject
* /*pObj*/) const
68 void SdrEditView::ObjOrderChanged(SdrObject
* /*pObj*/, size_t /*nOldPos*/, size_t /*nNewPos*/)
72 void SdrEditView::MovMarkedToTop()
74 const size_t nCount
=GetMarkedObjectCount();
78 const bool bUndo
= IsUndoEnabled();
81 BegUndo(SvxResId(STR_EditMovToTop
),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::MoveToTop
);
84 for (size_t nm
=0; nm
<nCount
; ++nm
)
85 { // All Ordnums have to be correct!
86 GetMarkedObjectByIndex(nm
)->GetOrdNum();
89 SdrObjList
* pOL0
=nullptr;
91 for (size_t nm
=nCount
; nm
>0;)
94 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
95 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
96 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
99 nNewPos
= pOL
->GetObjCount()-1;
102 const size_t nNowPos
= pObj
->GetOrdNumDirect();
103 const tools::Rectangle
& rBR
=pObj
->GetCurrentBoundRect();
104 size_t nCmpPos
= nNowPos
+1;
105 SdrObject
* pMaxObj
=GetMaxToTopObj(pObj
);
106 if (pMaxObj
!=nullptr)
108 size_t nMaxPos
=pMaxObj
->GetOrdNum();
112 nNewPos
=nMaxPos
; // neither go faster...
114 nNewPos
=nNowPos
; // nor go in the other direction
117 while (nCmpPos
<nNewPos
&& !bEnd
)
119 SdrObject
* pCmpObj
=pOL
->GetObj(nCmpPos
);
120 if (pCmpObj
==nullptr)
122 OSL_FAIL("MovMarkedToTop(): Reference object not found.");
125 else if (pCmpObj
==pMaxObj
)
131 else if (rBR
.Overlaps(pCmpObj
->GetCurrentBoundRect()))
141 if (nNowPos
!=nNewPos
)
144 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
146 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
147 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
156 MarkListHasChanged();
159 void SdrEditView::MovMarkedToBtm()
161 const size_t nCount
=GetMarkedObjectCount();
165 const bool bUndo
= IsUndoEnabled();
168 BegUndo(SvxResId(STR_EditMovToBtm
),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::MoveToBottom
);
171 for (size_t nm
=0; nm
<nCount
; ++nm
)
172 { // All Ordnums have to be correct!
173 GetMarkedObjectByIndex(nm
)->GetOrdNum();
177 SdrObjList
* pOL0
=nullptr;
179 for (size_t nm
=0; nm
<nCount
; ++nm
)
181 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
182 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
183 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
189 const size_t nNowPos
= pObj
->GetOrdNumDirect();
190 const tools::Rectangle
& rBR
=pObj
->GetCurrentBoundRect();
191 size_t nCmpPos
= nNowPos
;
194 SdrObject
* pMaxObj
=GetMaxToBtmObj(pObj
);
195 if (pMaxObj
!=nullptr)
197 const size_t nMinPos
=pMaxObj
->GetOrdNum()+1;
199 nNewPos
=nMinPos
; // neither go faster...
201 nNewPos
=nNowPos
; // nor go in the other direction
204 // nNewPos in this case is the "maximum" position
205 // the object may reach without going faster than the object before
206 // it (multiple selection).
207 while (nCmpPos
>nNewPos
&& !bEnd
)
209 SdrObject
* pCmpObj
=pOL
->GetObj(nCmpPos
);
210 if (pCmpObj
==nullptr)
212 OSL_FAIL("MovMarkedToBtm(): Reference object not found.");
215 else if (pCmpObj
==pMaxObj
)
221 else if (rBR
.Overlaps(pCmpObj
->GetCurrentBoundRect()))
231 if (nNowPos
!=nNewPos
)
234 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
236 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
237 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
246 MarkListHasChanged();
249 void SdrEditView::PutMarkedToTop()
251 PutMarkedInFrontOfObj(nullptr);
254 void SdrEditView::PutMarkedInFrontOfObj(const SdrObject
* pRefObj
)
256 const size_t nCount
=GetMarkedObjectCount();
260 const bool bUndo
= IsUndoEnabled();
262 BegUndo(SvxResId(STR_EditPutToTop
),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::PutToTop
);
266 if (pRefObj
!=nullptr)
268 // Make "in front of the object" work, even if the
269 // selected objects are already in front of the other object
270 const size_t nRefMark
=TryToFindMarkedObject(pRefObj
);
272 if (nRefMark
!=SAL_MAX_SIZE
)
274 aRefMark
=*GetSdrMarkByIndex(nRefMark
);
275 GetMarkedObjectListWriteAccess().DeleteMark(nRefMark
);
278 if (nRefMark
!=SAL_MAX_SIZE
)
280 GetMarkedObjectListWriteAccess().InsertEntry(aRefMark
);
284 for (size_t nm
=0; nm
<nCount
; ++nm
)
285 { // All Ordnums have to be correct!
286 GetMarkedObjectByIndex(nm
)->GetOrdNum();
289 SdrObjList
* pOL0
=nullptr;
291 for (size_t nm
=nCount
; nm
>0;)
294 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
295 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
298 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
301 nNewPos
=pOL
->GetObjCount()-1;
304 const size_t nNowPos
=pObj
->GetOrdNumDirect();
305 SdrObject
* pMaxObj
=GetMaxToTopObj(pObj
);
306 if (pMaxObj
!=nullptr)
308 size_t nMaxOrd
=pMaxObj
->GetOrdNum(); // sadly doesn't work any other way
312 nNewPos
=nMaxOrd
; // neither go faster...
314 nNewPos
=nNowPos
; // nor go into the other direction
316 if (pRefObj
!=nullptr)
318 if (pRefObj
->getParentSdrObjListFromSdrObject()==pObj
->getParentSdrObjListFromSdrObject())
320 const size_t nMaxOrd
=pRefObj
->GetOrdNum(); // sadly doesn't work any other way
322 nNewPos
=nMaxOrd
; // neither go faster...
324 nNewPos
=nNowPos
; // nor go into the other direction
328 nNewPos
=nNowPos
; // different PageView, so don't change
331 if (nNowPos
!=nNewPos
)
334 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
336 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
337 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
340 } // if (pObj!=pRefObj)
341 } // for loop over all selected objects
347 MarkListHasChanged();
350 void SdrEditView::PutMarkedToBtm()
352 PutMarkedBehindObj(nullptr);
355 void SdrEditView::PutMarkedBehindObj(const SdrObject
* pRefObj
)
357 const size_t nCount
=GetMarkedObjectCount();
361 const bool bUndo
= IsUndoEnabled();
364 BegUndo(SvxResId(STR_EditPutToBtm
),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::PutToBottom
);
367 if (pRefObj
!=nullptr)
369 // Make "behind the object" work, even if the
370 // selected objects are already behind the other object
371 const size_t nRefMark
=TryToFindMarkedObject(pRefObj
);
373 if (nRefMark
!=SAL_MAX_SIZE
)
375 aRefMark
=*GetSdrMarkByIndex(nRefMark
);
376 GetMarkedObjectListWriteAccess().DeleteMark(nRefMark
);
379 if (nRefMark
!=SAL_MAX_SIZE
)
381 GetMarkedObjectListWriteAccess().InsertEntry(aRefMark
);
385 for (size_t nm
=0; nm
<nCount
; ++nm
) { // All Ordnums have to be correct!
386 GetMarkedObjectByIndex(nm
)->GetOrdNum();
389 SdrObjList
* pOL0
=nullptr;
391 for (size_t nm
=0; nm
<nCount
; ++nm
) {
392 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
393 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
395 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
400 const size_t nNowPos
=pObj
->GetOrdNumDirect();
401 SdrObject
* pMinObj
=GetMaxToBtmObj(pObj
);
402 if (pMinObj
!=nullptr) {
403 const size_t nMinOrd
=pMinObj
->GetOrdNum()+1; // sadly doesn't work any differently
404 if (nNewPos
<nMinOrd
) nNewPos
=nMinOrd
; // neither go faster...
405 if (nNewPos
>nNowPos
) nNewPos
=nNowPos
; // nor go into the other direction
407 if (pRefObj
!=nullptr) {
408 if (pRefObj
->getParentSdrObjListFromSdrObject()==pObj
->getParentSdrObjListFromSdrObject()) {
409 const size_t nMinOrd
=pRefObj
->GetOrdNum(); // sadly doesn't work any differently
410 if (nNewPos
<nMinOrd
) nNewPos
=nMinOrd
; // neither go faster...
411 if (nNewPos
>nNowPos
) nNewPos
=nNowPos
; // nor go into the other direction
413 nNewPos
=nNowPos
; // different PageView, so don't change
416 if (nNowPos
!=nNewPos
) {
418 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
420 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
421 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
424 } // if (pObj!=pRefObj)
425 } // for loop over all selected objects
431 MarkListHasChanged();
435 void SdrEditView::ReverseOrderOfMarked()
438 const size_t nMarkCount
=GetMarkedObjectCount();
444 bool bUndo
= IsUndoEnabled();
446 BegUndo(SvxResId(STR_EditRevOrder
),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ReverseOrder
);
450 // take into account selection across multiple PageViews
452 while (b
<nMarkCount
&& GetSdrPageViewOfMarkedByIndex(b
) == GetSdrPageViewOfMarkedByIndex(a
)) ++b
;
454 SdrObjList
* pOL
=GetSdrPageViewOfMarkedByIndex(a
)->GetObjList();
456 if (a
<c
) { // make sure OrdNums aren't dirty
457 GetMarkedObjectByIndex(a
)->GetOrdNum();
460 SdrObject
* pObj1
=GetMarkedObjectByIndex(a
);
461 SdrObject
* pObj2
=GetMarkedObjectByIndex(c
);
462 const size_t nOrd1
=pObj1
->GetOrdNumDirect();
463 const size_t nOrd2
=pObj2
->GetOrdNumDirect();
466 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1
,nOrd1
,nOrd2
));
467 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2
,nOrd2
-1,nOrd1
));
469 pOL
->SetObjectOrdNum(nOrd1
,nOrd2
);
470 // Obj 2 has moved forward by one position, so now nOrd2-1
471 pOL
->SetObjectOrdNum(nOrd2
-1,nOrd1
);
472 // use Replace instead of SetOrdNum for performance reasons (recalculation of Ordnums)
478 } while (a
<nMarkCount
);
484 MarkListHasChanged();
487 void SdrEditView::ImpCheckToTopBtmPossible()
489 const size_t nCount
=GetMarkedObjectCount();
493 { // special-casing for single selection
494 SdrObject
* pObj
=GetMarkedObjectByIndex(0);
495 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
496 SAL_WARN_IF(!pOL
, "svx", "Object somehow has no ObjList");
497 size_t nMax
= pOL
? pOL
->GetObjCount() : 0;
499 const size_t nObjNum
=pObj
->GetOrdNum();
500 SdrObject
* pRestrict
=GetMaxToTopObj(pObj
);
501 if (pRestrict
!=nullptr) {
502 const size_t nRestrict
=pRestrict
->GetOrdNum();
503 if (nRestrict
<nMax
) nMax
=nRestrict
;
505 pRestrict
=GetMaxToBtmObj(pObj
);
506 if (pRestrict
!=nullptr) {
507 const size_t nRestrict
=pRestrict
->GetOrdNum();
508 if (nRestrict
>nMin
) nMin
=nRestrict
;
510 m_bToTopPossible
=nObjNum
<nMax
-1;
511 m_bToBtmPossible
=nObjNum
>nMin
;
512 } else { // multiple selection
513 SdrObjList
* pOL0
=nullptr;
515 for (size_t nm
= 0; !m_bToBtmPossible
&& nm
<nCount
; ++nm
) { // check 'send to background'
516 SdrObject
* pObj
=GetMarkedObjectByIndex(nm
);
517 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
522 const size_t nPos
= pObj
->GetOrdNum();
523 m_bToBtmPossible
= nPos
&& (nPos
-1 > nPos0
);
528 nPos0
= SAL_MAX_SIZE
;
529 for (size_t nm
=nCount
; !m_bToTopPossible
&& nm
>0; ) { // check 'bring to front'
531 SdrObject
* pObj
=GetMarkedObjectByIndex(nm
);
532 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
534 nPos0
=pOL
->GetObjCount();
537 const size_t nPos
= pObj
->GetOrdNum();
538 m_bToTopPossible
= nPos
+1 < nPos0
;
548 void SdrEditView::ImpCopyAttributes(const SdrObject
* pSource
, SdrObject
* pDest
) const
550 if (pSource
!=nullptr) {
551 SdrObjList
* pOL
=pSource
->GetSubList();
552 if (pOL
!=nullptr && !pSource
->Is3DObj()) { // get first non-group object from group
553 SdrObjListIter
aIter(pOL
,SdrIterMode::DeepNoGroups
);
554 pSource
=aIter
.Next();
558 if(!(pSource
&& pDest
))
561 SfxItemSetFixed
<SDRATTR_START
, SDRATTR_NOTPERSIST_FIRST
-1,
562 SDRATTR_NOTPERSIST_LAST
+1, SDRATTR_END
,
563 EE_ITEMS_START
, EE_ITEMS_END
> aSet(GetModel().GetItemPool());
565 aSet
.Put(pSource
->GetMergedItemSet());
567 pDest
->ClearMergedItem();
568 pDest
->SetMergedItemSet(aSet
);
570 pDest
->NbcSetLayer(pSource
->GetLayer());
571 pDest
->NbcSetStyleSheet(pSource
->GetStyleSheet(), true);
574 bool SdrEditView::ImpCanConvertForCombine1(const SdrObject
* pObj
)
576 // new condition IsLine() to be able to combine simple Lines
579 const SdrPathObj
* pPath
= dynamic_cast< const SdrPathObj
*>( pObj
);
583 bIsLine
= pPath
->IsLine();
586 SdrObjTransformInfoRec aInfo
;
587 pObj
->TakeObjInfo(aInfo
);
589 return (aInfo
.bCanConvToPath
|| aInfo
.bCanConvToPoly
|| bIsLine
);
592 bool SdrEditView::ImpCanConvertForCombine(const SdrObject
* pObj
)
594 SdrObjList
* pOL
= pObj
->GetSubList();
596 if(pOL
&& !pObj
->Is3DObj())
598 SdrObjListIter
aIter(pOL
, SdrIterMode::DeepNoGroups
);
600 while(aIter
.IsMore())
602 SdrObject
* pObj1
= aIter
.Next();
604 // all members of a group have to be convertible
605 if(!ImpCanConvertForCombine1(pObj1
))
613 if(!ImpCanConvertForCombine1(pObj
))
622 basegfx::B2DPolyPolygon
SdrEditView::ImpGetPolyPolygon1(const SdrObject
* pObj
)
624 basegfx::B2DPolyPolygon aRetval
;
625 const SdrPathObj
* pPath
= dynamic_cast<const SdrPathObj
*>( pObj
);
627 if(pPath
&& !pObj
->GetOutlinerParaObject())
629 aRetval
= pPath
->GetPathPoly();
633 rtl::Reference
<SdrObject
> pConvObj
= pObj
->ConvertToPolyObj(true/*bCombine*/, false);
637 SdrObjList
* pOL
= pConvObj
->GetSubList();
641 SdrObjListIter
aIter(pOL
, SdrIterMode::DeepNoGroups
);
643 while(aIter
.IsMore())
645 SdrObject
* pObj1
= aIter
.Next();
646 pPath
= dynamic_cast<SdrPathObj
*>( pObj1
);
650 aRetval
.append(pPath
->GetPathPoly());
656 pPath
= dynamic_cast<SdrPathObj
*>( pConvObj
.get() );
660 aRetval
= pPath
->GetPathPoly();
669 basegfx::B2DPolyPolygon
SdrEditView::ImpGetPolyPolygon(const SdrObject
* pObj
)
671 SdrObjList
* pOL
= pObj
->GetSubList();
673 if(pOL
&& !pObj
->Is3DObj())
675 basegfx::B2DPolyPolygon aRetval
;
676 SdrObjListIter
aIter(pOL
, SdrIterMode::DeepNoGroups
);
678 while(aIter
.IsMore())
680 SdrObject
* pObj1
= aIter
.Next();
681 aRetval
.append(ImpGetPolyPolygon1(pObj1
));
688 return ImpGetPolyPolygon1(pObj
);
692 basegfx::B2DPolygon
SdrEditView::ImpCombineToSinglePolygon(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
694 const sal_uInt32
nPolyCount(rPolyPolygon
.count());
698 return basegfx::B2DPolygon();
700 else if(1 == nPolyCount
)
702 return rPolyPolygon
.getB2DPolygon(0);
706 basegfx::B2DPolygon
aRetval(rPolyPolygon
.getB2DPolygon(0));
708 for(sal_uInt32
a(1); a
< nPolyCount
; a
++)
710 basegfx::B2DPolygon
aCandidate(rPolyPolygon
.getB2DPolygon(a
));
714 if(aCandidate
.count())
716 const basegfx::B2DPoint
aCA(aCandidate
.getB2DPoint(0));
717 const basegfx::B2DPoint
aCB(aCandidate
.getB2DPoint(aCandidate
.count() - 1));
718 const basegfx::B2DPoint
aRA(aRetval
.getB2DPoint(0));
719 const basegfx::B2DPoint
aRB(aRetval
.getB2DPoint(aRetval
.count() - 1));
721 const double fRACA(basegfx::B2DVector(aCA
- aRA
).getLength());
722 const double fRACB(basegfx::B2DVector(aCB
- aRA
).getLength());
723 const double fRBCA(basegfx::B2DVector(aCA
- aRB
).getLength());
724 const double fRBCB(basegfx::B2DVector(aCB
- aRB
).getLength());
726 const double fSmallestRA(std::min(fRACA
, fRACB
));
727 const double fSmallestRB(std::min(fRBCA
, fRBCB
));
729 if(fSmallestRA
< fSmallestRB
)
735 const double fSmallestCA(std::min(fRACA
, fRBCA
));
736 const double fSmallestCB(std::min(fRACB
, fRBCB
));
738 if(fSmallestCB
< fSmallestCA
)
744 // append candidate to retval
745 aRetval
.append(aCandidate
);
750 aRetval
= aCandidate
;
760 // for distribution dialog function
761 struct ImpDistributeEntry
770 typedef std::vector
<ImpDistributeEntry
> ImpDistributeEntryList
;
772 void SdrEditView::DistributeMarkedObjects(sal_uInt16 SlotID
)
774 const size_t nMark(GetMarkedObjectCount());
779 SvxDistributeHorizontal eHor
= SvxDistributeHorizontal::NONE
;
780 SvxDistributeVertical eVer
= SvxDistributeVertical::NONE
;
784 case SID_DISTRIBUTE_HLEFT
: eHor
= SvxDistributeHorizontal::Left
; break;
785 case SID_DISTRIBUTE_HCENTER
: eHor
= SvxDistributeHorizontal::Center
; break;
786 case SID_DISTRIBUTE_HDISTANCE
: eHor
= SvxDistributeHorizontal::Distance
; break;
787 case SID_DISTRIBUTE_HRIGHT
: eHor
= SvxDistributeHorizontal::Right
; break;
788 case SID_DISTRIBUTE_VTOP
: eVer
= SvxDistributeVertical::Top
; break;
789 case SID_DISTRIBUTE_VCENTER
: eVer
= SvxDistributeVertical::Center
; break;
790 case SID_DISTRIBUTE_VDISTANCE
: eVer
= SvxDistributeVertical::Distance
; break;
791 case SID_DISTRIBUTE_VBOTTOM
: eVer
= SvxDistributeVertical::Bottom
; break;
794 ImpDistributeEntryList aEntryList
;
795 ImpDistributeEntryList::iterator itEntryList
;
796 sal_uInt32 nFullLength
;
798 const bool bUndo
= IsUndoEnabled();
802 if(eHor
!= SvxDistributeHorizontal::NONE
)
804 // build sorted entry list
807 for( size_t a
= 0; a
< nMark
; ++a
)
809 SdrMark
* pMark
= GetSdrMarkByIndex(a
);
810 ImpDistributeEntry aNew
;
812 aNew
.mpObj
= pMark
->GetMarkedSdrObj();
816 case SvxDistributeHorizontal::Left
:
818 aNew
.mnPos
= aNew
.mpObj
->GetSnapRect().Left();
821 case SvxDistributeHorizontal::Center
:
823 aNew
.mnPos
= (aNew
.mpObj
->GetSnapRect().Right() + aNew
.mpObj
->GetSnapRect().Left()) / 2;
826 case SvxDistributeHorizontal::Distance
:
828 aNew
.mnLength
= aNew
.mpObj
->GetSnapRect().GetWidth() + 1;
829 nFullLength
+= aNew
.mnLength
;
830 aNew
.mnPos
= (aNew
.mpObj
->GetSnapRect().Right() + aNew
.mpObj
->GetSnapRect().Left()) / 2;
833 case SvxDistributeHorizontal::Right
:
835 aNew
.mnPos
= aNew
.mpObj
->GetSnapRect().Right();
841 itEntryList
= std::find_if(aEntryList
.begin(), aEntryList
.end(),
842 [&aNew
](const ImpDistributeEntry
& rEntry
) { return rEntry
.mnPos
>= aNew
.mnPos
; });
843 if ( itEntryList
< aEntryList
.end() )
844 aEntryList
.insert( itEntryList
, aNew
);
846 aEntryList
.push_back( aNew
);
849 if(eHor
== SvxDistributeHorizontal::Distance
)
851 // calculate room in-between
852 sal_Int32 nWidth
= GetAllMarkedBoundRect().GetWidth() + 1;
853 double fStepWidth
= (static_cast<double>(nWidth
) - static_cast<double>(nFullLength
)) / static_cast<double>(aEntryList
.size() - 1);
854 double fStepStart
= static_cast<double>(aEntryList
[ 0 ].mnPos
);
855 fStepStart
+= fStepWidth
+ static_cast<double>((aEntryList
[ 0 ].mnLength
+ aEntryList
[ 1 ].mnLength
) / 2);
857 // move entries 1..n-1
858 for( size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
860 ImpDistributeEntry
& rCurr
= aEntryList
[ i
];
861 ImpDistributeEntry
& rNext
= aEntryList
[ i
+ 1];
862 sal_Int32 nDelta
= static_cast<sal_Int32
>(fStepStart
+ 0.5) - rCurr
.mnPos
;
864 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*rCurr
.mpObj
));
865 rCurr
.mpObj
->Move(Size(nDelta
, 0));
866 fStepStart
+= fStepWidth
+ static_cast<double>((rCurr
.mnLength
+ rNext
.mnLength
) / 2);
871 // calculate distances
872 sal_Int32 nWidth
= aEntryList
[ aEntryList
.size() - 1 ].mnPos
- aEntryList
[ 0 ].mnPos
;
873 double fStepWidth
= static_cast<double>(nWidth
) / static_cast<double>(aEntryList
.size() - 1);
874 double fStepStart
= static_cast<double>(aEntryList
[ 0 ].mnPos
);
875 fStepStart
+= fStepWidth
;
877 // move entries 1..n-1
878 for( size_t i
= 1 ; i
< aEntryList
.size()-1 ; ++i
)
880 ImpDistributeEntry
& rCurr
= aEntryList
[ i
];
881 sal_Int32 nDelta
= static_cast<sal_Int32
>(fStepStart
+ 0.5) - rCurr
.mnPos
;
883 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*rCurr
.mpObj
));
884 rCurr
.mpObj
->Move(Size(nDelta
, 0));
885 fStepStart
+= fStepWidth
;
893 if(eVer
!= SvxDistributeVertical::NONE
)
895 // build sorted entry list
898 for( size_t a
= 0; a
< nMark
; ++a
)
900 SdrMark
* pMark
= GetSdrMarkByIndex(a
);
901 ImpDistributeEntry aNew
;
903 aNew
.mpObj
= pMark
->GetMarkedSdrObj();
907 case SvxDistributeVertical::Top
:
909 aNew
.mnPos
= aNew
.mpObj
->GetSnapRect().Top();
912 case SvxDistributeVertical::Center
:
914 aNew
.mnPos
= (aNew
.mpObj
->GetSnapRect().Bottom() + aNew
.mpObj
->GetSnapRect().Top()) / 2;
917 case SvxDistributeVertical::Distance
:
919 aNew
.mnLength
= aNew
.mpObj
->GetSnapRect().GetHeight() + 1;
920 nFullLength
+= aNew
.mnLength
;
921 aNew
.mnPos
= (aNew
.mpObj
->GetSnapRect().Bottom() + aNew
.mpObj
->GetSnapRect().Top()) / 2;
924 case SvxDistributeVertical::Bottom
:
926 aNew
.mnPos
= aNew
.mpObj
->GetSnapRect().Bottom();
932 itEntryList
= std::find_if(aEntryList
.begin(), aEntryList
.end(),
933 [&aNew
](const ImpDistributeEntry
& rEntry
) { return rEntry
.mnPos
>= aNew
.mnPos
; });
934 if ( itEntryList
< aEntryList
.end() )
935 aEntryList
.insert( itEntryList
, aNew
);
937 aEntryList
.push_back( aNew
);
940 if(eVer
== SvxDistributeVertical::Distance
)
942 // calculate room in-between
943 sal_Int32 nHeight
= GetAllMarkedBoundRect().GetHeight() + 1;
944 double fStepWidth
= (static_cast<double>(nHeight
) - static_cast<double>(nFullLength
)) / static_cast<double>(aEntryList
.size() - 1);
945 double fStepStart
= static_cast<double>(aEntryList
[ 0 ].mnPos
);
946 fStepStart
+= fStepWidth
+ static_cast<double>((aEntryList
[ 0 ].mnLength
+ aEntryList
[ 1 ].mnLength
) / 2);
948 // move entries 1..n-1
949 for( size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
951 ImpDistributeEntry
& rCurr
= aEntryList
[ i
];
952 ImpDistributeEntry
& rNext
= aEntryList
[ i
+ 1 ];
953 sal_Int32 nDelta
= static_cast<sal_Int32
>(fStepStart
+ 0.5) - rCurr
.mnPos
;
955 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*rCurr
.mpObj
));
956 rCurr
.mpObj
->Move(Size(0, nDelta
));
957 fStepStart
+= fStepWidth
+ static_cast<double>((rCurr
.mnLength
+ rNext
.mnLength
) / 2);
962 // calculate distances
963 sal_Int32 nHeight
= aEntryList
[ aEntryList
.size() - 1 ].mnPos
- aEntryList
[ 0 ].mnPos
;
964 double fStepWidth
= static_cast<double>(nHeight
) / static_cast<double>(aEntryList
.size() - 1);
965 double fStepStart
= static_cast<double>(aEntryList
[ 0 ].mnPos
);
966 fStepStart
+= fStepWidth
;
968 // move entries 1..n-1
969 for(size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
971 ImpDistributeEntry
& rCurr
= aEntryList
[ i
];
972 sal_Int32 nDelta
= static_cast<sal_Int32
>(fStepStart
+ 0.5) - rCurr
.mnPos
;
974 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*rCurr
.mpObj
));
975 rCurr
.mpObj
->Move(Size(0, nDelta
));
976 fStepStart
+= fStepWidth
;
984 // UNDO-Comment and end of UNDO
985 GetModel().SetUndoComment(SvxResId(STR_DistributeMarkedObjects
));
991 void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode
)
993 // #i73441# check content
994 if(!AreObjectsMarked())
1000 const bool bUndo
= IsUndoEnabled();
1005 size_t nInsPos
= SAL_MAX_SIZE
;
1006 const SdrObject
* pAttrObj
= nullptr;
1007 basegfx::B2DPolyPolygon aMergePolyPolygonA
;
1008 basegfx::B2DPolyPolygon aMergePolyPolygonB
;
1010 SdrObjList
* pInsOL
= nullptr;
1011 SdrPageView
* pInsPV
= nullptr;
1012 bool bFirstObjectComplete(false);
1014 // make sure selected objects are contour objects
1015 // since now basegfx::utils::adaptiveSubdivide() is used, it is no longer
1016 // necessary to use ConvertMarkedToPolyObj which will subdivide curves using the old
1017 // mechanisms. In a next step the polygon clipper will even be able to clip curves...
1018 // ConvertMarkedToPolyObj(true);
1019 ConvertMarkedToPathObj(true);
1020 OSL_ENSURE(AreObjectsMarked(), "no more objects selected after preparations (!)");
1022 for(size_t a
=0; a
<GetMarkedObjectCount(); ++a
)
1024 SdrMark
* pM
= GetSdrMarkByIndex(a
);
1025 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1027 if(ImpCanConvertForCombine(pObj
))
1032 nInsPos
= pObj
->GetOrdNum() + 1;
1033 pInsPV
= pM
->GetPageView();
1034 pInsOL
= pObj
->getParentSdrObjListFromSdrObject();
1036 // #i76891# use single iteration from SJ here which works on SdrObjects and takes
1037 // groups into account by itself
1038 SdrObjListIter
aIter(*pObj
, SdrIterMode::DeepWithGroups
);
1040 while(aIter
.IsMore())
1042 SdrObject
* pCandidate
= aIter
.Next();
1043 SdrPathObj
* pPathObj
= dynamic_cast<SdrPathObj
*>( pCandidate
);
1046 basegfx::B2DPolyPolygon
aTmpPoly(pPathObj
->GetPathPoly());
1048 // #i76891# unfortunately ConvertMarkedToPathObj has converted all
1049 // involved polygon data to curve segments, even if not necessary.
1050 // It is better to try to reduce to more simple polygons.
1051 aTmpPoly
= basegfx::utils::simplifyCurveSegments(aTmpPoly
);
1053 // for each part polygon as preparation, remove self-intersections
1054 // correct orientations and get rid of possible neutral polygons.
1055 aTmpPoly
= basegfx::utils::prepareForPolygonOperation(aTmpPoly
);
1057 if(!bFirstObjectComplete
)
1059 // #i111987# Also need to collect ORed source shape when more than
1060 // a single polygon is involved
1061 if(aMergePolyPolygonA
.count())
1063 aMergePolyPolygonA
= basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA
, aTmpPoly
);
1067 aMergePolyPolygonA
= aTmpPoly
;
1072 if(aMergePolyPolygonB
.count())
1074 // to topologically correctly collect the 2nd polygon
1075 // group it is necessary to OR the parts (each is seen as
1076 // XOR-FillRule polygon and they are drawn over each-other)
1077 aMergePolyPolygonB
= basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonB
, aTmpPoly
);
1081 aMergePolyPolygonB
= aTmpPoly
;
1087 // was there something added to the first polygon?
1088 if(!bFirstObjectComplete
&& aMergePolyPolygonA
.count())
1090 bFirstObjectComplete
= true;
1093 // move object to temporary delete list
1094 aRemove
.InsertEntry(SdrMark(pObj
, pM
->GetPageView()));
1100 case SdrMergeMode::Merge
:
1102 // merge all contained parts (OR)
1103 aMergePolyPolygonA
= basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA
, aMergePolyPolygonB
);
1106 case SdrMergeMode::Subtract
:
1108 // Subtract B from A
1109 aMergePolyPolygonA
= basegfx::utils::solvePolygonOperationDiff(aMergePolyPolygonA
, aMergePolyPolygonB
);
1112 case SdrMergeMode::Intersect
:
1115 aMergePolyPolygonA
= basegfx::utils::solvePolygonOperationAnd(aMergePolyPolygonA
, aMergePolyPolygonB
);
1120 // #i73441# check insert list before taking actions
1123 rtl::Reference
<SdrPathObj
> pPath
= new SdrPathObj(pAttrObj
->getSdrModelFromSdrObject(), SdrObjKind::PathFill
, std::move(aMergePolyPolygonA
));
1124 ImpCopyAttributes(pAttrObj
, pPath
.get());
1125 pInsOL
->InsertObject(pPath
.get(), nInsPos
);
1127 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath
));
1129 // #i124760# To have a correct selection with only the new object it is necessary to
1130 // unmark all objects first. If not doing so, there may remain invalid pointers to objects
1131 // TTTT:Not needed for aw080 (!)
1132 UnmarkAllObj(pInsPV
);
1134 MarkObj(pPath
.get(), pInsPV
, false, true);
1137 aRemove
.ForceSort();
1140 case SdrMergeMode::Merge
:
1143 SvxResId(STR_EditMergeMergePoly
),
1144 aRemove
.GetMarkDescription());
1147 case SdrMergeMode::Subtract
:
1150 SvxResId(STR_EditMergeSubstractPoly
),
1151 aRemove
.GetMarkDescription());
1154 case SdrMergeMode::Intersect
:
1157 SvxResId(STR_EditMergeIntersectPoly
),
1158 aRemove
.GetMarkDescription());
1162 DeleteMarkedList(aRemove
);
1168 void SdrEditView::EqualizeMarkedObjects(bool bWidth
)
1170 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1171 size_t nMarked
= rMarkList
.GetMarkCount();
1176 size_t nLastSelected
= 0;
1177 sal_Int64 nLastSelectedTime
= rMarkList
.GetMark(0)->getTimeStamp();
1178 for (size_t a
= 1; a
< nMarked
; ++a
)
1180 sal_Int64 nCandidateTime
= rMarkList
.GetMark(a
)->getTimeStamp();
1181 if (nCandidateTime
> nLastSelectedTime
)
1183 nLastSelectedTime
= nCandidateTime
;
1188 SdrObject
* pLastSelectedObj
= rMarkList
.GetMark(nLastSelected
)->GetMarkedSdrObj();
1189 Size
aLastRectSize(pLastSelectedObj
->GetLogicRect().GetSize());
1191 const bool bUndo
= IsUndoEnabled();
1196 for (size_t a
= 0; a
< nMarked
; ++a
)
1198 if (a
== nLastSelected
)
1200 SdrMark
* pM
= rMarkList
.GetMark(a
);
1201 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1202 tools::Rectangle
aLogicRect(pObj
->GetLogicRect());
1203 Size
aLogicRectSize(aLogicRect
.GetSize());
1205 aLogicRectSize
.setWidth( aLastRectSize
.Width() );
1207 aLogicRectSize
.setHeight( aLastRectSize
.Height() );
1208 aLogicRect
.SetSize(aLogicRectSize
);
1210 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj
));
1211 pObj
->SetLogicRect(aLogicRect
);
1215 SvxResId(bWidth
? STR_EqualizeWidthMarkedObjects
: STR_EqualizeHeightMarkedObjects
),
1216 rMarkList
.GetMarkDescription());
1222 void SdrEditView::CombineMarkedTextObjects()
1224 SdrPageView
* pPageView
= GetSdrPageView();
1225 if ( !pPageView
|| pPageView
->IsLayerLocked( GetActiveLayer() ) )
1228 bool bUndo
= IsUndoEnabled();
1230 // Undo-String will be set later
1234 SdrOutliner
& rDrawOutliner
= getSdrModelFromSdrView().GetDrawOutliner();
1236 SdrObjListIter
aIter( GetMarkedObjectList(), SdrIterMode::Flat
);
1237 while ( aIter
.IsMore() )
1239 SdrObject
* pObj
= aIter
.Next();
1240 SdrTextObj
* pTextObj
= DynCastSdrTextObj( pObj
);
1241 const OutlinerParaObject
* pOPO
= pTextObj
? pTextObj
->GetOutlinerParaObject() : nullptr;
1242 if ( pOPO
&& pTextObj
->IsTextFrame()
1243 && pTextObj
->GetObjIdentifier() == SdrObjKind::Text
// not callouts (OBJ_CAPTION)
1244 && !pTextObj
->IsOutlText() // not impress presentation objects
1245 && pTextObj
->GetMergedItem(XATTR_FORMTXTSTYLE
).GetValue() == XFormTextStyle::NONE
// not Fontwork
1248 // if the last paragraph does not end in paragraph-end punctuation (ignoring whitespace),
1249 // assume this text should be added to the end of the last paragraph, instead of starting a new paragraph.
1250 const sal_Int32 nPara
= rDrawOutliner
.GetParagraphCount();
1251 const OUString sLastPara
= nPara
? rDrawOutliner
.GetText( rDrawOutliner
.GetParagraph( nPara
- 1 ) ) : "";
1252 sal_Int32 n
= sLastPara
.getLength();
1253 while ( n
&& unicode::isWhiteSpace( sLastPara
[--n
] ) )
1255 //TODO: find way to use Locale to identify sentence final punctuation. Copied IsSentenceAtEnd() from autofmt.cxx
1256 const bool bAppend
= !n
|| ( sLastPara
[n
] != '.' && sLastPara
[n
] != '?' && sLastPara
[n
] != '!' );
1257 rDrawOutliner
.AddText( *pOPO
, bAppend
);
1261 // Unmark non-textboxes, because all marked objects are deleted at the end. AdjustMarkHdl later.
1262 MarkObj(pObj
, pPageView
, /*bUnmark=*/true, /*bImpNoSetMarkHdl=*/true);
1266 MarkListHasChanged();
1269 if ( GetMarkedObjectCount() > 1 )
1271 rtl::Reference
<SdrRectObj
> pReplacement
= new SdrRectObj( getSdrModelFromSdrView(), SdrObjKind::Text
);
1272 pReplacement
->SetOutlinerParaObject( rDrawOutliner
.CreateParaObject() );
1273 pReplacement
->SetSnapRect( GetMarkedObjRect() );
1275 const SdrInsertFlags nFlags
= SdrInsertFlags::DONTMARK
| SdrInsertFlags::SETDEFLAYER
;
1276 if ( InsertObjectAtView( pReplacement
.get(), *pPageView
, nFlags
) )
1286 void SdrEditView::CombineMarkedObjects(bool bNoPolyPoly
)
1288 // #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
1289 // create a 2nd Undo-action and Undo-Comment.
1291 bool bUndo
= IsUndoEnabled();
1293 // Undo-String will be set later
1295 BegUndo("", "", bNoPolyPoly
? SdrRepeatFunc::CombineOnePoly
: SdrRepeatFunc::CombinePolyPoly
);
1297 // #105899# First, guarantee that all objects are converted to polyobjects,
1298 // especially for SdrGrafObj with bitmap filling this is necessary to not
1299 // lose the bitmap filling.
1302 // ConvertMarkedToPolyObj was too strong here, it will lose quality and
1303 // information when curve objects are combined. This can be replaced by
1304 // using ConvertMarkedToPathObj without changing the previous fix.
1307 // Instead of simply passing true as LineToArea, use bNoPolyPoly as info
1308 // if this command is a 'Combine' or a 'Connect' command. On Connect it's true.
1309 // To not concert line segments with a set line width to polygons in that case,
1310 // use this info. Do not convert LineToArea on Connect commands.
1311 // ConvertMarkedToPathObj(!bNoPolyPoly);
1313 // This is used for Combine and Connect. In no case it is necessary to force
1314 // the content to curve, but it is also not good to force to polygons. Thus,
1315 // curve is the less information losing one. Remember: This place is not
1317 // LineToArea is never necessary, both commands are able to take over the
1318 // set line style and to display it correctly. Thus, i will use a
1319 // ConvertMarkedToPathObj with a false in any case. Only drawback is that
1320 // simple polygons will be changed to curves, but with no information loss.
1321 ConvertMarkedToPathObj(false /* bLineToArea */);
1323 // continue as before
1324 basegfx::B2DPolyPolygon aPolyPolygon
;
1325 SdrObjList
* pCurrentOL
= nullptr;
1326 SdrMarkList aRemoveBuffer
;
1328 SortMarkedObjects();
1329 size_t nInsPos
= SAL_MAX_SIZE
;
1330 SdrObjList
* pInsOL
= nullptr;
1331 SdrPageView
* pInsPV
= nullptr;
1332 const SdrObject
* pAttrObj
= nullptr;
1334 for(size_t a
= GetMarkedObjectCount(); a
; )
1337 SdrMark
* pM
= GetSdrMarkByIndex(a
);
1338 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1339 SdrObjList
* pThisOL
= pObj
->getParentSdrObjListFromSdrObject();
1341 if(pCurrentOL
!= pThisOL
)
1343 pCurrentOL
= pThisOL
;
1346 if(ImpCanConvertForCombine(pObj
))
1348 // remember objects to be able to copy attributes
1351 // unfortunately ConvertMarkedToPathObj has converted all
1352 // involved polygon data to curve segments, even if not necessary.
1353 // It is better to try to reduce to more simple polygons.
1354 basegfx::B2DPolyPolygon
aTmpPoly(basegfx::utils::simplifyCurveSegments(ImpGetPolyPolygon(pObj
)));
1355 aPolyPolygon
.insert(0, aTmpPoly
);
1359 nInsPos
= pObj
->GetOrdNum() + 1;
1360 pInsPV
= pM
->GetPageView();
1361 pInsOL
= pObj
->getParentSdrObjListFromSdrObject();
1364 aRemoveBuffer
.InsertEntry(SdrMark(pObj
, pM
->GetPageView()));
1370 basegfx::B2DPolygon
aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon
));
1371 aPolyPolygon
.clear();
1372 aPolyPolygon
.append(aCombinedPolygon
);
1375 const sal_uInt32
nPolyCount(aPolyPolygon
.count());
1377 if (nPolyCount
&& pAttrObj
)
1379 SdrObjKind eKind
= SdrObjKind::PathFill
;
1383 aPolyPolygon
.setClosed(true);
1387 // check for Polyline
1388 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0));
1389 const sal_uInt32
nPointCount(aPolygon
.count());
1391 if(nPointCount
<= 2)
1393 eKind
= SdrObjKind::PathLine
;
1397 if(!aPolygon
.isClosed())
1399 const basegfx::B2DPoint
aPointA(aPolygon
.getB2DPoint(0));
1400 const basegfx::B2DPoint
aPointB(aPolygon
.getB2DPoint(nPointCount
- 1));
1401 const double fDistance(basegfx::B2DVector(aPointB
- aPointA
).getLength());
1402 const double fJoinTolerance(10.0);
1404 if(fDistance
< fJoinTolerance
)
1406 aPolyPolygon
.setClosed(true);
1410 eKind
= SdrObjKind::PathLine
;
1416 rtl::Reference
<SdrPathObj
> pPath
= new SdrPathObj(pAttrObj
->getSdrModelFromSdrObject(), eKind
, std::move(aPolyPolygon
));
1418 // attributes of the lowest object
1419 ImpCopyAttributes(pAttrObj
, pPath
.get());
1421 // If LineStyle of pAttrObj is drawing::LineStyle_NONE force to drawing::LineStyle_SOLID to make visible.
1422 const drawing::LineStyle eLineStyle
= pAttrObj
->GetMergedItem(XATTR_LINESTYLE
).GetValue();
1423 const drawing::FillStyle eFillStyle
= pAttrObj
->GetMergedItem(XATTR_FILLSTYLE
).GetValue();
1425 // Take fill style/closed state of pAttrObj in account when deciding to change the line style
1426 bool bIsClosedPathObj
= false;
1427 if (auto pPathObj
= dynamic_cast<const SdrPathObj
*>(pAttrObj
))
1428 if (pPathObj
->IsClosed())
1429 bIsClosedPathObj
= true;
1431 if(drawing::LineStyle_NONE
== eLineStyle
&& (drawing::FillStyle_NONE
== eFillStyle
|| !bIsClosedPathObj
))
1433 pPath
->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID
));
1436 pInsOL
->InsertObject(pPath
.get(),nInsPos
);
1438 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath
));
1440 // Here was a severe error: Without UnmarkAllObj, the new object was marked
1441 // additionally to the two ones which are deleted below. As long as those are
1442 // in the UNDO there is no problem, but as soon as they get deleted, the
1443 // MarkList will contain deleted objects -> GPF.
1444 UnmarkAllObj(pInsPV
);
1445 MarkObj(pPath
.get(), pInsPV
, false, true);
1448 // build an UndoComment from the objects actually used
1449 aRemoveBuffer
.ForceSort(); // important for remove (see below)
1451 SetUndoComment(SvxResId(bNoPolyPoly
?STR_EditCombine_OnePoly
:STR_EditCombine_PolyPoly
),aRemoveBuffer
.GetMarkDescription());
1453 // remove objects actually used from the list
1454 DeleteMarkedList(aRemoveBuffer
);
1463 bool SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon
& rPpolyPolygon
, bool bMakeLines
)
1466 const sal_uInt32
nPolygonCount(rPpolyPolygon
.count());
1468 if(nPolygonCount
>= 2)
1470 // #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
1473 else if(bMakeLines
&& 1 == nPolygonCount
)
1475 // #i69172# ..or with at least 2 edges (curves or lines)
1476 const basegfx::B2DPolygon
& aPolygon(rPpolyPolygon
.getB2DPolygon(0));
1477 const sal_uInt32
nPointCount(aPolygon
.count());
1488 bool SdrEditView::ImpCanDismantle(const SdrObject
* pObj
, bool bMakeLines
)
1490 bool bOtherObjs(false); // true=objects other than PathObj's existent
1491 bool bMin1PolyPoly(false); // true=at least 1 tools::PolyPolygon with more than one Polygon existent
1492 SdrObjList
* pOL
= pObj
->GetSubList();
1496 // group object -- check all members if they're PathObjs
1497 SdrObjListIter
aIter(pOL
, SdrIterMode::DeepNoGroups
);
1499 while(aIter
.IsMore() && !bOtherObjs
)
1501 const SdrObject
* pObj1
= aIter
.Next();
1502 const SdrPathObj
* pPath
= dynamic_cast<const SdrPathObj
*>( pObj1
);
1506 if(ImpCanDismantle(pPath
->GetPathPoly(), bMakeLines
))
1508 bMin1PolyPoly
= true;
1511 SdrObjTransformInfoRec aInfo
;
1512 pObj1
->TakeObjInfo(aInfo
);
1514 if(!aInfo
.bCanConvToPath
)
1516 // happens e. g. in the case of FontWork
1528 const SdrPathObj
* pPath
= dynamic_cast<const SdrPathObj
*>(pObj
);
1529 const SdrObjCustomShape
* pCustomShape
= dynamic_cast<const SdrObjCustomShape
*>(pObj
);
1534 if(ImpCanDismantle(pPath
->GetPathPoly(),bMakeLines
))
1536 bMin1PolyPoly
= true;
1539 SdrObjTransformInfoRec aInfo
;
1540 pObj
->TakeObjInfo(aInfo
);
1542 // new condition IsLine() to be able to break simple Lines
1543 if(!(aInfo
.bCanConvToPath
|| aInfo
.bCanConvToPoly
) && !pPath
->IsLine())
1545 // happens e. g. in the case of FontWork
1549 else if(pCustomShape
)
1553 // allow break command
1554 bMin1PolyPoly
= true;
1562 return bMin1PolyPoly
&& !bOtherObjs
;
1565 void SdrEditView::ImpDismantleOneObject(const SdrObject
* pObj
, SdrObjList
& rOL
, size_t& rPos
, SdrPageView
* pPV
, bool bMakeLines
)
1567 const SdrPathObj
* pSrcPath
= dynamic_cast<const SdrPathObj
*>( pObj
);
1568 const SdrObjCustomShape
* pCustomShape
= dynamic_cast<const SdrObjCustomShape
*>( pObj
);
1570 const bool bUndo
= IsUndoEnabled();
1574 // #i74631# redesigned due to XpolyPolygon removal and explicit constructors
1575 SdrObject
* pLast
= nullptr; // to be able to apply OutlinerParaObject
1576 const basegfx::B2DPolyPolygon
& rPolyPolygon(pSrcPath
->GetPathPoly());
1577 const sal_uInt32
nPolyCount(rPolyPolygon
.count());
1579 for(sal_uInt32
a(0); a
< nPolyCount
; a
++)
1581 const basegfx::B2DPolygon
& rCandidate(rPolyPolygon
.getB2DPolygon(a
));
1582 const sal_uInt32
nPointCount(rCandidate
.count());
1584 if(!bMakeLines
|| nPointCount
< 2)
1586 rtl::Reference
<SdrPathObj
> pPath
= new SdrPathObj(
1587 pSrcPath
->getSdrModelFromSdrObject(),
1588 pSrcPath
->GetObjIdentifier(),
1589 basegfx::B2DPolyPolygon(rCandidate
));
1590 ImpCopyAttributes(pSrcPath
, pPath
.get());
1591 pLast
= pPath
.get();
1592 rOL
.InsertObject(pPath
.get(), rPos
);
1594 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath
, true));
1595 MarkObj(pPath
.get(), pPV
, false, true);
1600 const sal_uInt32
nLoopCount(rCandidate
.isClosed() ? nPointCount
: nPointCount
- 1);
1602 for(sal_uInt32
b(0); b
< nLoopCount
; b
++)
1604 SdrObjKind
eKind(SdrObjKind::PolyLine
);
1605 basegfx::B2DPolygon aNewPolygon
;
1606 const sal_uInt32
nNextIndex((b
+ 1) % nPointCount
);
1608 aNewPolygon
.append(rCandidate
.getB2DPoint(b
));
1610 if(rCandidate
.areControlPointsUsed())
1612 aNewPolygon
.appendBezierSegment(
1613 rCandidate
.getNextControlPoint(b
),
1614 rCandidate
.getPrevControlPoint(nNextIndex
),
1615 rCandidate
.getB2DPoint(nNextIndex
));
1616 eKind
= SdrObjKind::PathLine
;
1620 aNewPolygon
.append(rCandidate
.getB2DPoint(nNextIndex
));
1623 rtl::Reference
<SdrPathObj
> pPath
= new SdrPathObj(
1624 pSrcPath
->getSdrModelFromSdrObject(),
1626 basegfx::B2DPolyPolygon(aNewPolygon
));
1627 ImpCopyAttributes(pSrcPath
, pPath
.get());
1628 pLast
= pPath
.get();
1629 rOL
.InsertObject(pPath
.get(), rPos
);
1631 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath
, true));
1632 MarkObj(pPath
.get(), pPV
, false, true);
1638 if(pLast
&& pSrcPath
->GetOutlinerParaObject())
1640 pLast
->SetOutlinerParaObject(*pSrcPath
->GetOutlinerParaObject());
1643 else if(pCustomShape
)
1647 // break up custom shape
1648 const SdrObject
* pReplacement
= pCustomShape
->GetSdrObjectFromCustomShape();
1652 rtl::Reference
<SdrObject
> pCandidate(pReplacement
->CloneSdrObject(pReplacement
->getSdrModelFromSdrObject()));
1653 DBG_ASSERT(pCandidate
, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
1655 if(pCustomShape
->GetMergedItem(SDRATTR_SHADOW
).GetValue())
1657 if(dynamic_cast<const SdrObjGroup
*>( pReplacement
) != nullptr)
1659 pCandidate
->SetMergedItem(makeSdrShadowItem(true));
1663 rOL
.InsertObject(pCandidate
.get(), rPos
);
1665 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pCandidate
, true));
1666 MarkObj(pCandidate
.get(), pPV
, false, true);
1668 if(pCustomShape
->HasText() && !pCustomShape
->IsTextPath())
1670 // #i37011# also create a text object and add at rPos + 1
1671 rtl::Reference
<SdrObject
> pTextObj
= SdrObjFactory::MakeNewObject(
1672 pCustomShape
->getSdrModelFromSdrObject(),
1673 pCustomShape
->GetObjInventor(),
1676 // Copy text content
1677 OutlinerParaObject
* pParaObj
= pCustomShape
->GetOutlinerParaObject();
1680 pTextObj
->NbcSetOutlinerParaObject(*pParaObj
);
1683 // copy all attributes
1684 SfxItemSet
aTargetItemSet(pCustomShape
->GetMergedItemSet());
1686 // clear fill and line style
1687 aTargetItemSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
1688 aTargetItemSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
1690 // get the text bounds and set at text object
1691 tools::Rectangle aTextBounds
= pCustomShape
->GetSnapRect();
1692 if(pCustomShape
->GetTextBounds(aTextBounds
))
1694 pTextObj
->SetSnapRect(aTextBounds
);
1697 // if rotated, copy GeoStat, too.
1698 const GeoStat
& rSourceGeo
= pCustomShape
->GetGeoStat();
1699 if(rSourceGeo
.nRotationAngle
)
1701 pTextObj
->NbcRotate(
1702 pCustomShape
->GetSnapRect().Center(), rSourceGeo
.nRotationAngle
,
1703 rSourceGeo
.mfSinRotationAngle
, rSourceGeo
.mfCosRotationAngle
);
1706 // set modified ItemSet at text object
1707 pTextObj
->SetMergedItemSet(aTargetItemSet
);
1710 rOL
.InsertObject(pTextObj
.get(), rPos
+ 1);
1712 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pTextObj
, true));
1713 MarkObj(pTextObj
.get(), pPV
, false, true);
1720 void SdrEditView::DismantleMarkedObjects(bool bMakeLines
)
1722 // temporary MarkList
1723 SdrMarkList aRemoveBuffer
;
1725 SortMarkedObjects();
1727 const bool bUndo
= IsUndoEnabled();
1731 // comment is constructed later
1732 BegUndo("", "", bMakeLines
? SdrRepeatFunc::DismantleLines
: SdrRepeatFunc::DismantlePolys
);
1735 SdrObjList
* pOL0
=nullptr;
1736 const bool bWasLocked
= GetModel().isLocked();
1737 GetModel().setLock(true);
1738 for (size_t nm
=GetMarkedObjectCount(); nm
>0;) {
1740 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1741 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1742 SdrPageView
* pPV
=pM
->GetPageView();
1743 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
1744 if (pOL
!=pOL0
) { pOL0
=pOL
; pObj
->GetOrdNum(); } // make sure OrdNums are correct!
1745 if (ImpCanDismantle(pObj
,bMakeLines
)) {
1746 aRemoveBuffer
.InsertEntry(SdrMark(pObj
,pM
->GetPageView()));
1747 const size_t nPos0
=pObj
->GetOrdNumDirect();
1748 size_t nPos
=nPos0
+1;
1749 SdrObjList
* pSubList
=pObj
->GetSubList();
1750 if (pSubList
!=nullptr && !pObj
->Is3DObj()) {
1751 SdrObjListIter
aIter(pSubList
,SdrIterMode::DeepNoGroups
);
1752 while (aIter
.IsMore()) {
1753 const SdrObject
* pObj1
=aIter
.Next();
1754 ImpDismantleOneObject(pObj1
,*pOL
,nPos
,pPV
,bMakeLines
);
1757 ImpDismantleOneObject(pObj
,*pOL
,nPos
,pPV
,bMakeLines
);
1760 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj
,true));
1761 pOL
->RemoveObject(nPos0
);
1764 GetModel().setLock(bWasLocked
);
1768 // construct UndoComment from objects actually used
1769 SetUndoComment(SvxResId(bMakeLines
?STR_EditDismantle_Lines
:STR_EditDismantle_Polys
),aRemoveBuffer
.GetMarkDescription());
1770 // remove objects actually used from the list
1779 void SdrEditView::GroupMarked()
1781 if (!AreObjectsMarked())
1784 SortMarkedObjects();
1786 const bool bUndo
= IsUndoEnabled();
1789 BegUndo(SvxResId(STR_EditGroup
),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::Group
);
1791 for(size_t nm
= GetMarkedObjectCount(); nm
>0; )
1793 // add UndoActions for all affected objects
1795 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1796 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1797 AddUndoActions( CreateConnectorUndo( *pObj
) );
1798 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoRemoveObject( *pObj
));
1802 SdrMarkList aNewMark
;
1803 SdrPageView
* pPV
= GetSdrPageView();
1807 SdrObjList
* pCurrentLst
=pPV
->GetObjList();
1808 SdrObjList
* pSrcLst
=pCurrentLst
;
1809 SdrObjList
* pSrcLst0
=pSrcLst
;
1810 // make sure OrdNums are correct
1811 if (pSrcLst
->IsObjOrdNumsDirty())
1812 pSrcLst
->RecalcObjOrdNums();
1813 rtl::Reference
<SdrObject
> pGrp
;
1814 SdrObjList
* pDstLst
=nullptr;
1815 // if all selected objects come from foreign object lists.
1816 // the group object is the last one in the list.
1817 size_t nInsPos
=pSrcLst
->GetObjCount();
1818 bool bNeedInsPos
=true;
1819 for (size_t nm
=GetMarkedObjectCount(); nm
>0;)
1822 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1823 if (pM
->GetPageView()==pPV
)
1825 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1828 pGrp
= new SdrObjGroup(pObj
->getSdrModelFromSdrObject());
1829 pDstLst
=pGrp
->GetSubList();
1830 assert(pDstLst
&& "Alleged group object doesn't return object list.");
1832 pSrcLst
=pObj
->getParentSdrObjListFromSdrObject();
1833 if (pSrcLst
!=pSrcLst0
)
1835 if (pSrcLst
->IsObjOrdNumsDirty())
1836 pSrcLst
->RecalcObjOrdNums();
1838 bool bForeignList
=pSrcLst
!=pCurrentLst
;
1839 if (!bForeignList
&& bNeedInsPos
)
1841 nInsPos
=pObj
->GetOrdNum(); // this way, all ObjOrdNum of the page are set
1845 pSrcLst
->RemoveObject(pObj
->GetOrdNumDirect());
1847 nInsPos
--; // correct InsertPos
1848 pDstLst
->InsertObject(pObj
,0);
1849 GetMarkedObjectListWriteAccess().DeleteMark(nm
);
1855 assert(pDstLst
); // keep coverity happy
1856 aNewMark
.InsertEntry(SdrMark(pGrp
.get(),pPV
));
1857 const size_t nCount
=pDstLst
->GetObjCount();
1858 pCurrentLst
->InsertObject(pGrp
.get(),nInsPos
);
1861 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pGrp
,true)); // no recalculation!
1862 for (size_t no
=0; no
<nCount
; ++no
)
1864 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst
->GetObj(no
)));
1869 GetMarkedObjectListWriteAccess().Merge(aNewMark
);
1870 MarkListHasChanged();
1880 void SdrEditView::UnGroupMarked()
1882 SdrMarkList aNewMark
;
1884 const bool bUndo
= IsUndoEnabled();
1886 BegUndo("", "", SdrRepeatFunc::Ungroup
);
1892 for (size_t nm
=GetMarkedObjectCount(); nm
>0;) {
1894 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
1895 SdrObject
* pGrp
=pM
->GetMarkedSdrObj();
1896 SdrObjList
* pSrcLst
=pGrp
->GetSubList();
1897 if (pSrcLst
!=nullptr) {
1900 aName
= pGrp
->TakeObjNameSingul(); // retrieve name of group
1901 aName1
= pGrp
->TakeObjNamePlural(); // retrieve name of group
1904 if (nCount
==2) aName
=aName1
; // set plural name
1906 OUString
aStr(pGrp
->TakeObjNamePlural()); // retrieve name of group
1912 size_t nDstCnt
=pGrp
->GetOrdNum();
1913 SdrObjList
* pDstLst
=pM
->GetPageView()->GetObjList();
1914 size_t nObjCount
=pSrcLst
->GetObjCount();
1915 const bool bIsDiagram(pGrp
->isDiagram());
1917 // If the Group is a Diagram, it has a filler BG object to guarantee
1918 // the Diagam's dimensions. Identify that shape
1919 if(bIsDiagram
&& nObjCount
)
1921 SdrObject
* pObj(pSrcLst
->GetObj(0));
1923 if(nullptr != pObj
&& !pObj
->IsGroupObject() &&
1924 !pObj
->HasLineStyle() &&
1925 pObj
->IsMoveProtect() && pObj
->IsResizeProtect())
1927 if(pObj
->HasFillStyle())
1929 // If it has FillStyle it is a useful object representing that possible
1930 // defined fill from oox import. In this case, we should remove the
1931 // Move/Resize protection to allow seamless further processing.
1933 // Undo of these is handled by SdrUndoGeoObj which holds a SdrObjGeoData,
1936 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj
));
1938 pObj
->SetMoveProtect(false);
1939 pObj
->SetResizeProtect(false);
1943 // If it has no FillStyle it is not useful for any further processing
1944 // but only was used as a placeholder, get directly rid of it
1946 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj
));
1948 pSrcLst
->RemoveObject(0);
1950 nObjCount
= pSrcLst
->GetObjCount();
1955 // FIRST move contained objects to parent of group, so that
1956 // the contained objects are NOT migrated to the UNDO-ItemPool
1957 // when AddUndo(new SdrUndoDelObj(*pGrp)) is called.
1960 for (size_t no
=nObjCount
; no
>0;)
1963 SdrObject
* pObj
=pSrcLst
->GetObj(no
);
1964 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoRemoveObject(*pObj
));
1968 for (size_t no
=0; no
<nObjCount
; ++no
)
1970 rtl::Reference
<SdrObject
> pObj
=pSrcLst
->RemoveObject(0);
1971 pDstLst
->InsertObject(pObj
.get(),nDstCnt
);
1973 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoInsertObject(*pObj
,true));
1975 // No SortCheck when inserting into MarkList, because that would
1976 // provoke a RecalcOrdNums() each time because of pObj->GetOrdNum():
1977 aNewMark
.InsertEntry(SdrMark(pObj
.get(),pM
->GetPageView()),false);
1982 // Now it is safe to add the delete-UNDO which triggers the
1983 // MigrateItemPool now only for itself, not for the sub-objects.
1984 // nDstCnt is right, because previous inserts move group
1985 // object deeper and increase nDstCnt.
1986 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp
));
1988 pDstLst
->RemoveObject(nDstCnt
);
1990 GetMarkedObjectListWriteAccess().DeleteMark(nm
);
1996 aName
=SvxResId(STR_ObjNamePluralGRUP
); // Use the term "Group Objects," if different objects are grouped.
1997 SetUndoComment(SvxResId(STR_EditUngroup
),aName
);
2005 GetMarkedObjectListWriteAccess().Merge(aNewMark
,true); // Because of the sorting above, aNewMark is reversed
2006 MarkListHasChanged();
2014 rtl::Reference
<SdrObject
> SdrEditView::ImpConvertOneObj(SdrObject
* pObj
, bool bPath
, bool bLineToArea
)
2016 rtl::Reference
<SdrObject
> pNewObj
= pObj
->ConvertToPolyObj(bPath
, bLineToArea
);
2019 SdrObjList
* pOL
= pObj
->getParentSdrObjListFromSdrObject();
2020 const bool bUndo
= IsUndoEnabled();
2022 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoReplaceObject(*pObj
,*pNewObj
));
2024 pOL
->ReplaceObject(pNewObj
.get(), pObj
->GetOrdNum());
2029 void SdrEditView::ImpConvertTo(bool bPath
, bool bLineToArea
)
2031 if (!AreObjectsMarked()) return;
2033 bool bMrkChg
= false;
2034 const size_t nMarkCount
=GetMarkedObjectCount();
2035 TranslateId pDscrID
;
2039 pDscrID
= STR_EditConvToContour
;
2041 pDscrID
= STR_EditConvToContours
;
2043 BegUndo(SvxResId(pDscrID
), GetDescriptionOfMarkedObjects());
2048 if (nMarkCount
==1) pDscrID
=STR_EditConvToCurve
;
2049 else pDscrID
=STR_EditConvToCurves
;
2050 BegUndo(SvxResId(pDscrID
),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ConvertToPath
);
2052 if (nMarkCount
==1) pDscrID
=STR_EditConvToPoly
;
2053 else pDscrID
=STR_EditConvToPolys
;
2054 BegUndo(SvxResId(pDscrID
),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ConvertToPoly
);
2057 for (size_t nm
=nMarkCount
; nm
>0;) {
2059 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
2060 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
2061 SdrPageView
* pPV
=pM
->GetPageView();
2062 if (pObj
->IsGroupObject() && !pObj
->Is3DObj()) {
2063 SdrObject
* pGrp
=pObj
;
2064 SdrObjListIter
aIter(*pGrp
, SdrIterMode::DeepNoGroups
);
2065 while (aIter
.IsMore()) {
2067 ImpConvertOneObj(pObj
,bPath
,bLineToArea
);
2070 rtl::Reference
<SdrObject
> pNewObj
=ImpConvertOneObj(pObj
,bPath
,bLineToArea
);
2073 GetMarkedObjectListWriteAccess().ReplaceMark(SdrMark(pNewObj
.get(),pPV
),nm
);
2081 MarkListHasChanged();
2085 void SdrEditView::ConvertMarkedToPathObj(bool bLineToArea
)
2087 ImpConvertTo(true, bLineToArea
);
2090 void SdrEditView::ConvertMarkedToPolyObj()
2092 ImpConvertTo(false, false/*bLineToArea*/);
2097 GDIMetaFile
GetMetaFile(SdrGrafObj
const * pGraf
)
2099 if (pGraf
->HasGDIMetaFile())
2100 return pGraf
->GetTransformedGraphic(SdrGrafObjTransformsAttrs::MIRROR
).GetGDIMetaFile();
2101 assert(pGraf
->isEmbeddedVectorGraphicData());
2102 return pGraf
->getMetafileFromEmbeddedVectorGraphicData();
2107 void SdrEditView::DoImportMarkedMtf(SvdProgressInfo
*pProgrInfo
)
2109 const bool bUndo
= IsUndoEnabled();
2112 BegUndo("", "", SdrRepeatFunc::ImportMtf
);
2114 SortMarkedObjects();
2115 SdrMarkList aForTheDescription
;
2116 SdrMarkList aNewMarked
;
2117 for (size_t nm
=GetMarkedObjectCount(); nm
> 0; )
2119 // create Undo objects for all new objects
2120 // check for cancellation between the metafiles
2121 if (pProgrInfo
!= nullptr)
2123 pProgrInfo
->SetNextObject();
2124 if (!pProgrInfo
->ReportActions(0))
2129 SdrMark
* pM
=GetSdrMarkByIndex(nm
);
2130 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
2131 SdrPageView
* pPV
=pM
->GetPageView();
2132 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
2133 const size_t nInsPos
=pObj
->GetOrdNum()+1;
2135 tools::Rectangle aLogicRect
;
2137 SdrGrafObj
* pGraf
= dynamic_cast<SdrGrafObj
*>( pObj
);
2138 if (pGraf
!= nullptr)
2140 Graphic aGraphic
= pGraf
->GetGraphic();
2141 auto const & pVectorGraphicData
= aGraphic
.getVectorGraphicData();
2143 if (pVectorGraphicData
&& pVectorGraphicData
->getType() == VectorGraphicDataType::Pdf
)
2145 auto pPdfium
= vcl::pdf::PDFiumLibrary::get();
2148 aLogicRect
= pGraf
->GetLogicRect();
2149 ImpSdrPdfImport
aFilter(GetModel(), pObj
->GetLayer(), aLogicRect
, aGraphic
);
2150 if (aGraphic
.getPageNumber() < aFilter
.GetPageCount())
2152 nInsCnt
= aFilter
.DoImport(*pOL
, nInsPos
, aGraphic
.getPageNumber(), pProgrInfo
);
2156 else if (pGraf
->HasGDIMetaFile() || pGraf
->isEmbeddedVectorGraphicData() )
2158 GDIMetaFile
aMetaFile(GetMetaFile(pGraf
));
2159 if (aMetaFile
.GetActionSize())
2161 aLogicRect
= pGraf
->GetLogicRect();
2162 ImpSdrGDIMetaFileImport
aFilter(GetModel(), pObj
->GetLayer(), aLogicRect
);
2163 nInsCnt
= aFilter
.DoImport(aMetaFile
, *pOL
, nInsPos
, pProgrInfo
);
2168 SdrOle2Obj
* pOle2
= dynamic_cast<SdrOle2Obj
*>(pObj
);
2169 if (pOle2
!= nullptr && pOle2
->GetGraphic())
2171 aLogicRect
= pOle2
->GetLogicRect();
2172 ImpSdrGDIMetaFileImport
aFilter(GetModel(), pObj
->GetLayer(), aLogicRect
);
2173 nInsCnt
= aFilter
.DoImport(pOle2
->GetGraphic()->GetGDIMetaFile(), *pOL
, nInsPos
, pProgrInfo
);
2179 GeoStat
aGeoStat(pGraf
? pGraf
->GetGeoStat() : pOle2
->GetGeoStat());
2180 size_t nObj
= nInsPos
;
2182 if (aGeoStat
.nShearAngle
)
2183 aGeoStat
.RecalcTan();
2185 if (aGeoStat
.nRotationAngle
)
2186 aGeoStat
.RecalcSinCos();
2188 for (size_t i
= 0; i
< nInsCnt
; i
++)
2191 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pOL
->GetObj(nObj
)));
2193 // update new MarkList
2194 SdrObject
* pCandidate
= pOL
->GetObj(nObj
);
2196 // apply original transformation
2197 if (aGeoStat
.nShearAngle
)
2198 pCandidate
->NbcShear(aLogicRect
.TopLeft(), aGeoStat
.nShearAngle
, aGeoStat
.mfTanShearAngle
, false);
2200 if (aGeoStat
.nRotationAngle
)
2201 pCandidate
->NbcRotate(aLogicRect
.TopLeft(), aGeoStat
.nRotationAngle
, aGeoStat
.mfSinRotationAngle
, aGeoStat
.mfCosRotationAngle
);
2203 SdrMark
aNewMark(pCandidate
, pPV
);
2204 aNewMarked
.InsertEntry(aNewMark
);
2209 aForTheDescription
.InsertEntry(*pM
);
2212 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj
));
2214 // remove object from selection and delete
2215 GetMarkedObjectListWriteAccess().DeleteMark(TryToFindMarkedObject(pObj
));
2216 pOL
->RemoveObject(nInsPos
-1);
2220 if (aNewMarked
.GetMarkCount())
2222 // create new selection
2223 for (size_t a
= 0; a
< aNewMarked
.GetMarkCount(); ++a
)
2225 GetMarkedObjectListWriteAccess().InsertEntry(*aNewMarked
.GetMark(a
));
2228 SortMarkedObjects();
2233 SetUndoComment(SvxResId(STR_EditImportMtf
),aForTheDescription
.GetMarkDescription());
2238 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */