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 SdrMarkList
& rMarkList
= GetMarkedObjectList();
75 const size_t nCount
=rMarkList
.GetMarkCount();
79 const bool bUndo
= IsUndoEnabled();
82 BegUndo(SvxResId(STR_EditMovToTop
),rMarkList
.GetMarkDescription(),SdrRepeatFunc::MoveToTop
);
84 rMarkList
.ForceSort();
85 for (size_t nm
=0; nm
<nCount
; ++nm
)
86 { // All Ordnums have to be correct!
87 rMarkList
.GetMark(nm
)->GetMarkedSdrObj()->GetOrdNum();
90 SdrObjList
* pOL0
=nullptr;
92 for (size_t nm
=nCount
; nm
>0;)
95 SdrMark
* pM
=rMarkList
.GetMark(nm
);
96 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
97 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
100 nNewPos
= pOL
->GetObjCount()-1;
103 const size_t nNowPos
= pObj
->GetOrdNumDirect();
104 const tools::Rectangle
& rBR
=pObj
->GetCurrentBoundRect();
105 size_t nCmpPos
= nNowPos
+1;
106 SdrObject
* pMaxObj
=GetMaxToTopObj(pObj
);
107 if (pMaxObj
!=nullptr)
109 size_t nMaxPos
=pMaxObj
->GetOrdNum();
113 nNewPos
=nMaxPos
; // neither go faster...
115 nNewPos
=nNowPos
; // nor go in the other direction
118 while (nCmpPos
<nNewPos
&& !bEnd
)
121 SdrObject
* pCmpObj
=pOL
->GetObj(nCmpPos
);
122 if (pCmpObj
==nullptr)
124 OSL_FAIL("MovMarkedToTop(): Reference object not found.");
127 else if (pCmpObj
==pMaxObj
)
133 else if (rBR
.Overlaps(pCmpObj
->GetCurrentBoundRect()))
143 if (nNowPos
!=nNewPos
)
146 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
148 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
149 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
158 MarkListHasChanged();
161 void SdrEditView::MovMarkedToBtm()
163 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
164 const size_t nCount
=rMarkList
.GetMarkCount();
168 const bool bUndo
= IsUndoEnabled();
171 BegUndo(SvxResId(STR_EditMovToBtm
),rMarkList
.GetMarkDescription(),SdrRepeatFunc::MoveToBottom
);
173 rMarkList
.ForceSort();
174 for (size_t nm
=0; nm
<nCount
; ++nm
)
175 { // All Ordnums have to be correct!
176 rMarkList
.GetMark(nm
)->GetMarkedSdrObj()->GetOrdNum();
180 SdrObjList
* pOL0
=nullptr;
182 for (size_t nm
=0; nm
<nCount
; ++nm
)
184 SdrMark
* pM
=rMarkList
.GetMark(nm
);
185 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
186 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
192 const size_t nNowPos
= pObj
->GetOrdNumDirect();
193 const tools::Rectangle
& rBR
=pObj
->GetCurrentBoundRect();
194 size_t nCmpPos
= nNowPos
;
197 SdrObject
* pMaxObj
=GetMaxToBtmObj(pObj
);
198 if (pMaxObj
!=nullptr)
200 const size_t nMinPos
=pMaxObj
->GetOrdNum()+1;
202 nNewPos
=nMinPos
; // neither go faster...
204 nNewPos
=nNowPos
; // nor go in the other direction
207 // nNewPos in this case is the "maximum" position
208 // the object may reach without going faster than the object before
209 // it (multiple selection).
210 while (nCmpPos
>nNewPos
&& !bEnd
)
213 SdrObject
* pCmpObj
=pOL
->GetObj(nCmpPos
);
214 if (pCmpObj
==nullptr)
216 OSL_FAIL("MovMarkedToBtm(): Reference object not found.");
219 else if (pCmpObj
==pMaxObj
)
225 else if (rBR
.Overlaps(pCmpObj
->GetCurrentBoundRect()))
235 if (nNowPos
!=nNewPos
)
238 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
240 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
241 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
250 MarkListHasChanged();
253 void SdrEditView::PutMarkedToTop()
255 PutMarkedInFrontOfObj(nullptr);
258 void SdrEditView::PutMarkedInFrontOfObj(const SdrObject
* pRefObj
)
260 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
261 const size_t nCount
=rMarkList
.GetMarkCount();
265 const bool bUndo
= IsUndoEnabled();
267 BegUndo(SvxResId(STR_EditPutToTop
),rMarkList
.GetMarkDescription(),SdrRepeatFunc::PutToTop
);
269 rMarkList
.ForceSort();
271 if (pRefObj
!=nullptr)
273 // Make "in front of the object" work, even if the
274 // selected objects are already in front of the other object
275 const size_t nRefMark
=rMarkList
.FindObject(pRefObj
);
277 if (nRefMark
!=SAL_MAX_SIZE
)
279 aRefMark
=*rMarkList
.GetMark(nRefMark
);
280 GetMarkedObjectListWriteAccess().DeleteMark(nRefMark
);
283 if (nRefMark
!=SAL_MAX_SIZE
)
285 GetMarkedObjectListWriteAccess().InsertEntry(aRefMark
);
286 rMarkList
.ForceSort();
289 for (size_t nm
=0; nm
<nCount
; ++nm
)
290 { // All Ordnums have to be correct!
291 rMarkList
.GetMark(nm
)->GetMarkedSdrObj()->GetOrdNum();
294 SdrObjList
* pOL0
=nullptr;
296 for (size_t nm
=nCount
; nm
>0;)
299 SdrMark
* pM
=rMarkList
.GetMark(nm
);
300 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
303 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
306 nNewPos
=pOL
->GetObjCount()-1;
309 const size_t nNowPos
=pObj
->GetOrdNumDirect();
310 SdrObject
* pMaxObj
=GetMaxToTopObj(pObj
);
311 if (pMaxObj
!=nullptr)
313 size_t nMaxOrd
=pMaxObj
->GetOrdNum(); // sadly doesn't work any other way
317 nNewPos
=nMaxOrd
; // neither go faster...
319 nNewPos
=nNowPos
; // nor go into the other direction
321 if (pRefObj
!=nullptr)
323 if (pRefObj
->getParentSdrObjListFromSdrObject()==pObj
->getParentSdrObjListFromSdrObject())
325 const size_t nMaxOrd
=pRefObj
->GetOrdNum(); // sadly doesn't work any other way
327 nNewPos
=nMaxOrd
; // neither go faster...
329 nNewPos
=nNowPos
; // nor go into the other direction
333 nNewPos
=nNowPos
; // different PageView, so don't change
336 if (nNowPos
!=nNewPos
)
339 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
341 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
342 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
345 } // if (pObj!=pRefObj)
346 } // for loop over all selected objects
352 MarkListHasChanged();
355 void SdrEditView::PutMarkedToBtm()
357 PutMarkedBehindObj(nullptr);
360 void SdrEditView::PutMarkedBehindObj(const SdrObject
* pRefObj
)
362 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
363 const size_t nCount
=rMarkList
.GetMarkCount();
367 const bool bUndo
= IsUndoEnabled();
370 BegUndo(SvxResId(STR_EditPutToBtm
),rMarkList
.GetMarkDescription(),SdrRepeatFunc::PutToBottom
);
372 rMarkList
.ForceSort();
373 if (pRefObj
!=nullptr)
375 // Make "behind the object" work, even if the
376 // selected objects are already behind the other object
377 const size_t nRefMark
=rMarkList
.FindObject(pRefObj
);
379 if (nRefMark
!=SAL_MAX_SIZE
)
381 aRefMark
=*rMarkList
.GetMark(nRefMark
);
382 GetMarkedObjectListWriteAccess().DeleteMark(nRefMark
);
385 if (nRefMark
!=SAL_MAX_SIZE
)
387 GetMarkedObjectListWriteAccess().InsertEntry(aRefMark
);
388 rMarkList
.ForceSort();
391 for (size_t nm
=0; nm
<nCount
; ++nm
) { // All Ordnums have to be correct!
392 rMarkList
.GetMark(nm
)->GetMarkedSdrObj()->GetOrdNum();
395 SdrObjList
* pOL0
=nullptr;
397 for (size_t nm
=0; nm
<nCount
; ++nm
) {
398 SdrMark
* pM
=rMarkList
.GetMark(nm
);
399 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
401 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
406 const size_t nNowPos
=pObj
->GetOrdNumDirect();
407 SdrObject
* pMinObj
=GetMaxToBtmObj(pObj
);
408 if (pMinObj
!=nullptr) {
409 const size_t nMinOrd
=pMinObj
->GetOrdNum()+1; // 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 if (pRefObj
!=nullptr) {
414 if (pRefObj
->getParentSdrObjListFromSdrObject()==pObj
->getParentSdrObjListFromSdrObject()) {
415 const size_t nMinOrd
=pRefObj
->GetOrdNum(); // sadly doesn't work any differently
416 if (nNewPos
<nMinOrd
) nNewPos
=nMinOrd
; // neither go faster...
417 if (nNewPos
>nNowPos
) nNewPos
=nNowPos
; // nor go into the other direction
419 nNewPos
=nNowPos
; // different PageView, so don't change
422 if (nNowPos
!=nNewPos
) {
424 pOL
->SetObjectOrdNum(nNowPos
,nNewPos
);
426 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj
,nNowPos
,nNewPos
));
427 ObjOrderChanged(pObj
,nNowPos
,nNewPos
);
430 } // if (pObj!=pRefObj)
431 } // for loop over all selected objects
437 MarkListHasChanged();
441 void SdrEditView::ReverseOrderOfMarked()
443 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
444 rMarkList
.ForceSort();
445 const size_t nMarkCount
=rMarkList
.GetMarkCount();
451 bool bUndo
= IsUndoEnabled();
453 BegUndo(SvxResId(STR_EditRevOrder
),rMarkList
.GetMarkDescription(),SdrRepeatFunc::ReverseOrder
);
457 // take into account selection across multiple PageViews
459 while (b
<nMarkCount
&& rMarkList
.GetMark(b
)->GetPageView() == rMarkList
.GetMark(a
)->GetPageView()) ++b
;
461 SdrObjList
* pOL
=rMarkList
.GetMark(a
)->GetPageView()->GetObjList();
463 if (a
<c
) { // make sure OrdNums aren't dirty
464 rMarkList
.GetMark(a
)->GetMarkedSdrObj()->GetOrdNum();
467 SdrObject
* pObj1
=rMarkList
.GetMark(a
)->GetMarkedSdrObj();
468 SdrObject
* pObj2
=rMarkList
.GetMark(c
)->GetMarkedSdrObj();
469 const size_t nOrd1
=pObj1
->GetOrdNumDirect();
470 const size_t nOrd2
=pObj2
->GetOrdNumDirect();
473 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1
,nOrd1
,nOrd2
));
474 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2
,nOrd2
-1,nOrd1
));
476 pOL
->SetObjectOrdNum(nOrd1
,nOrd2
);
477 // Obj 2 has moved forward by one position, so now nOrd2-1
478 pOL
->SetObjectOrdNum(nOrd2
-1,nOrd1
);
479 // use Replace instead of SetOrdNum for performance reasons (recalculation of Ordnums)
485 } while (a
<nMarkCount
);
491 MarkListHasChanged();
494 void SdrEditView::ImpCheckToTopBtmPossible()
496 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
497 const size_t nCount
=rMarkList
.GetMarkCount();
501 { // special-casing for single selection
502 SdrObject
* pObj
=rMarkList
.GetMark(0)->GetMarkedSdrObj();
503 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
504 SAL_WARN_IF(!pOL
, "svx", "Object somehow has no ObjList");
505 size_t nMax
= pOL
? pOL
->GetObjCount() : 0;
507 const size_t nObjNum
=pObj
->GetOrdNum();
508 SdrObject
* pRestrict
=GetMaxToTopObj(pObj
);
509 if (pRestrict
!=nullptr) {
510 const size_t nRestrict
=pRestrict
->GetOrdNum();
511 if (nRestrict
<nMax
) nMax
=nRestrict
;
513 pRestrict
=GetMaxToBtmObj(pObj
);
514 if (pRestrict
!=nullptr) {
515 const size_t nRestrict
=pRestrict
->GetOrdNum();
516 if (nRestrict
>nMin
) nMin
=nRestrict
;
518 m_bToTopPossible
= nObjNum
+1 < nMax
;
519 m_bToBtmPossible
= nObjNum
> nMin
;
520 } else { // multiple selection
521 SdrObjList
* pOL0
=nullptr;
523 for (size_t nm
= 0; !m_bToBtmPossible
&& nm
<nCount
; ++nm
) { // check 'send to background'
524 SdrObject
* pObj
=rMarkList
.GetMark(nm
)->GetMarkedSdrObj();
525 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
530 const size_t nPos
= pObj
->GetOrdNum();
531 m_bToBtmPossible
= nPos
&& (nPos
-1 > nPos0
);
536 nPos0
= SAL_MAX_SIZE
;
537 for (size_t nm
=nCount
; !m_bToTopPossible
&& nm
>0; ) { // check 'bring to front'
539 SdrObject
* pObj
=rMarkList
.GetMark(nm
)->GetMarkedSdrObj();
540 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
542 nPos0
=pOL
->GetObjCount();
545 const size_t nPos
= pObj
->GetOrdNum();
546 m_bToTopPossible
= nPos
+1 < nPos0
;
556 void SdrEditView::ImpCopyAttributes(const SdrObject
* pSource
, SdrObject
* pDest
) const
558 if (pSource
!=nullptr) {
559 SdrObjList
* pOL
=pSource
->GetSubList();
560 if (pOL
!=nullptr && !pSource
->Is3DObj()) { // get first non-group object from group
561 SdrObjListIter
aIter(pOL
,SdrIterMode::DeepNoGroups
);
562 pSource
=aIter
.Next();
566 if(!(pSource
&& pDest
))
569 SfxItemSetFixed
<SDRATTR_START
, SDRATTR_NOTPERSIST_FIRST
-1,
570 SDRATTR_NOTPERSIST_LAST
+1, SDRATTR_END
,
571 EE_ITEMS_START
, EE_ITEMS_END
> aSet(GetModel().GetItemPool());
573 aSet
.Put(pSource
->GetMergedItemSet());
575 pDest
->ClearMergedItem();
576 pDest
->SetMergedItemSet(aSet
);
578 pDest
->NbcSetLayer(pSource
->GetLayer());
579 pDest
->NbcSetStyleSheet(pSource
->GetStyleSheet(), true);
582 bool SdrEditView::ImpCanConvertForCombine1(const SdrObject
* pObj
)
584 // new condition IsLine() to be able to combine simple Lines
587 const SdrPathObj
* pPath
= dynamic_cast< const SdrPathObj
*>( pObj
);
591 bIsLine
= pPath
->IsLine();
594 SdrObjTransformInfoRec aInfo
;
595 pObj
->TakeObjInfo(aInfo
);
597 return (aInfo
.bCanConvToPath
|| aInfo
.bCanConvToPoly
|| bIsLine
);
600 bool SdrEditView::ImpCanConvertForCombine(const SdrObject
* pObj
)
602 SdrObjList
* pOL
= pObj
->GetSubList();
604 if(pOL
&& !pObj
->Is3DObj())
606 SdrObjListIter
aIter(pOL
, SdrIterMode::DeepNoGroups
);
608 while(aIter
.IsMore())
610 SdrObject
* pObj1
= aIter
.Next();
612 // all members of a group have to be convertible
613 if(!ImpCanConvertForCombine1(pObj1
))
621 if(!ImpCanConvertForCombine1(pObj
))
630 basegfx::B2DPolyPolygon
SdrEditView::ImpGetPolyPolygon1(const SdrObject
* pObj
)
632 basegfx::B2DPolyPolygon aRetval
;
633 const SdrPathObj
* pPath
= dynamic_cast<const SdrPathObj
*>( pObj
);
635 if(pPath
&& !pObj
->GetOutlinerParaObject())
637 aRetval
= pPath
->GetPathPoly();
641 rtl::Reference
<SdrObject
> pConvObj
= pObj
->ConvertToPolyObj(true/*bCombine*/, false);
645 SdrObjList
* pOL
= pConvObj
->GetSubList();
649 SdrObjListIter
aIter(pOL
, SdrIterMode::DeepNoGroups
);
651 while(aIter
.IsMore())
653 SdrObject
* pObj1
= aIter
.Next();
654 pPath
= dynamic_cast<SdrPathObj
*>( pObj1
);
658 aRetval
.append(pPath
->GetPathPoly());
664 pPath
= dynamic_cast<SdrPathObj
*>( pConvObj
.get() );
668 aRetval
= pPath
->GetPathPoly();
677 basegfx::B2DPolyPolygon
SdrEditView::ImpGetPolyPolygon(const SdrObject
* pObj
)
679 SdrObjList
* pOL
= pObj
->GetSubList();
681 if(pOL
&& !pObj
->Is3DObj())
683 basegfx::B2DPolyPolygon aRetval
;
684 SdrObjListIter
aIter(pOL
, SdrIterMode::DeepNoGroups
);
686 while(aIter
.IsMore())
688 SdrObject
* pObj1
= aIter
.Next();
689 aRetval
.append(ImpGetPolyPolygon1(pObj1
));
696 return ImpGetPolyPolygon1(pObj
);
700 basegfx::B2DPolygon
SdrEditView::ImpCombineToSinglePolygon(const basegfx::B2DPolyPolygon
& rPolyPolygon
)
702 const sal_uInt32
nPolyCount(rPolyPolygon
.count());
706 return basegfx::B2DPolygon();
708 else if(1 == nPolyCount
)
710 return rPolyPolygon
.getB2DPolygon(0);
714 basegfx::B2DPolygon
aRetval(rPolyPolygon
.getB2DPolygon(0));
716 for(sal_uInt32
a(1); a
< nPolyCount
; a
++)
718 basegfx::B2DPolygon
aCandidate(rPolyPolygon
.getB2DPolygon(a
));
722 if(aCandidate
.count())
724 const basegfx::B2DPoint
aCA(aCandidate
.getB2DPoint(0));
725 const basegfx::B2DPoint
aCB(aCandidate
.getB2DPoint(aCandidate
.count() - 1));
726 const basegfx::B2DPoint
aRA(aRetval
.getB2DPoint(0));
727 const basegfx::B2DPoint
aRB(aRetval
.getB2DPoint(aRetval
.count() - 1));
729 const double fRACA(basegfx::B2DVector(aCA
- aRA
).getLength());
730 const double fRACB(basegfx::B2DVector(aCB
- aRA
).getLength());
731 const double fRBCA(basegfx::B2DVector(aCA
- aRB
).getLength());
732 const double fRBCB(basegfx::B2DVector(aCB
- aRB
).getLength());
734 const double fSmallestRA(std::min(fRACA
, fRACB
));
735 const double fSmallestRB(std::min(fRBCA
, fRBCB
));
737 if(fSmallestRA
< fSmallestRB
)
743 const double fSmallestCA(std::min(fRACA
, fRBCA
));
744 const double fSmallestCB(std::min(fRACB
, fRBCB
));
746 if(fSmallestCB
< fSmallestCA
)
752 // append candidate to retval
753 aRetval
.append(aCandidate
);
758 aRetval
= std::move(aCandidate
);
768 // for distribution dialog function
769 struct ImpDistributeEntry
778 typedef std::vector
<ImpDistributeEntry
> ImpDistributeEntryList
;
780 void SdrEditView::DistributeMarkedObjects(sal_uInt16 SlotID
)
782 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
783 const size_t nMark(rMarkList
.GetMarkCount());
788 SvxDistributeHorizontal eHor
= SvxDistributeHorizontal::NONE
;
789 SvxDistributeVertical eVer
= SvxDistributeVertical::NONE
;
793 case SID_DISTRIBUTE_HLEFT
: eHor
= SvxDistributeHorizontal::Left
; break;
794 case SID_DISTRIBUTE_HCENTER
: eHor
= SvxDistributeHorizontal::Center
; break;
795 case SID_DISTRIBUTE_HDISTANCE
: eHor
= SvxDistributeHorizontal::Distance
; break;
796 case SID_DISTRIBUTE_HRIGHT
: eHor
= SvxDistributeHorizontal::Right
; break;
797 case SID_DISTRIBUTE_VTOP
: eVer
= SvxDistributeVertical::Top
; break;
798 case SID_DISTRIBUTE_VCENTER
: eVer
= SvxDistributeVertical::Center
; break;
799 case SID_DISTRIBUTE_VDISTANCE
: eVer
= SvxDistributeVertical::Distance
; break;
800 case SID_DISTRIBUTE_VBOTTOM
: eVer
= SvxDistributeVertical::Bottom
; break;
803 ImpDistributeEntryList aEntryList
;
804 ImpDistributeEntryList::iterator itEntryList
;
805 sal_uInt32 nFullLength
;
807 const bool bUndo
= IsUndoEnabled();
811 if(eHor
!= SvxDistributeHorizontal::NONE
)
813 // build sorted entry list
816 for( size_t a
= 0; a
< nMark
; ++a
)
818 SdrMark
* pMark
= rMarkList
.GetMark(a
);
819 ImpDistributeEntry aNew
;
821 aNew
.mpObj
= pMark
->GetMarkedSdrObj();
825 case SvxDistributeHorizontal::Left
:
827 aNew
.mnPos
= aNew
.mpObj
->GetSnapRect().Left();
830 case SvxDistributeHorizontal::Center
:
832 aNew
.mnPos
= (aNew
.mpObj
->GetSnapRect().Right() + aNew
.mpObj
->GetSnapRect().Left()) / 2;
835 case SvxDistributeHorizontal::Distance
:
837 aNew
.mnLength
= aNew
.mpObj
->GetSnapRect().GetWidth() + 1;
838 nFullLength
+= aNew
.mnLength
;
839 aNew
.mnPos
= (aNew
.mpObj
->GetSnapRect().Right() + aNew
.mpObj
->GetSnapRect().Left()) / 2;
842 case SvxDistributeHorizontal::Right
:
844 aNew
.mnPos
= aNew
.mpObj
->GetSnapRect().Right();
850 itEntryList
= std::find_if(aEntryList
.begin(), aEntryList
.end(),
851 [&aNew
](const ImpDistributeEntry
& rEntry
) { return rEntry
.mnPos
>= aNew
.mnPos
; });
852 if ( itEntryList
< aEntryList
.end() )
853 aEntryList
.insert( itEntryList
, aNew
);
855 aEntryList
.push_back( aNew
);
858 if(eHor
== SvxDistributeHorizontal::Distance
)
860 // calculate room in-between
861 sal_Int32 nWidth
= GetAllMarkedBoundRect().GetWidth() + 1;
862 double fStepWidth
= (static_cast<double>(nWidth
) - static_cast<double>(nFullLength
)) / static_cast<double>(aEntryList
.size() - 1);
863 double fStepStart
= static_cast<double>(aEntryList
[ 0 ].mnPos
);
864 fStepStart
+= fStepWidth
+ static_cast<double>((aEntryList
[ 0 ].mnLength
+ aEntryList
[ 1 ].mnLength
) / 2);
866 // move entries 1..n-1
867 for( size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
869 ImpDistributeEntry
& rCurr
= aEntryList
[ i
];
870 ImpDistributeEntry
& rNext
= aEntryList
[ i
+ 1];
871 sal_Int32 nDelta
= static_cast<sal_Int32
>(fStepStart
+ 0.5) - rCurr
.mnPos
;
873 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*rCurr
.mpObj
));
874 rCurr
.mpObj
->Move(Size(nDelta
, 0));
875 fStepStart
+= fStepWidth
+ static_cast<double>((rCurr
.mnLength
+ rNext
.mnLength
) / 2);
880 // calculate distances
881 sal_Int32 nWidth
= aEntryList
[ aEntryList
.size() - 1 ].mnPos
- aEntryList
[ 0 ].mnPos
;
882 double fStepWidth
= static_cast<double>(nWidth
) / static_cast<double>(aEntryList
.size() - 1);
883 double fStepStart
= static_cast<double>(aEntryList
[ 0 ].mnPos
);
884 fStepStart
+= fStepWidth
;
886 // move entries 1..n-1
887 for( size_t i
= 1 ; i
< aEntryList
.size()-1 ; ++i
)
889 ImpDistributeEntry
& rCurr
= aEntryList
[ i
];
890 sal_Int32 nDelta
= static_cast<sal_Int32
>(fStepStart
+ 0.5) - rCurr
.mnPos
;
892 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*rCurr
.mpObj
));
893 rCurr
.mpObj
->Move(Size(nDelta
, 0));
894 fStepStart
+= fStepWidth
;
902 if(eVer
!= SvxDistributeVertical::NONE
)
904 // build sorted entry list
907 for( size_t a
= 0; a
< nMark
; ++a
)
909 SdrMark
* pMark
= rMarkList
.GetMark(a
);
910 ImpDistributeEntry aNew
;
912 aNew
.mpObj
= pMark
->GetMarkedSdrObj();
916 case SvxDistributeVertical::Top
:
918 aNew
.mnPos
= aNew
.mpObj
->GetSnapRect().Top();
921 case SvxDistributeVertical::Center
:
923 aNew
.mnPos
= (aNew
.mpObj
->GetSnapRect().Bottom() + aNew
.mpObj
->GetSnapRect().Top()) / 2;
926 case SvxDistributeVertical::Distance
:
928 aNew
.mnLength
= aNew
.mpObj
->GetSnapRect().GetHeight() + 1;
929 nFullLength
+= aNew
.mnLength
;
930 aNew
.mnPos
= (aNew
.mpObj
->GetSnapRect().Bottom() + aNew
.mpObj
->GetSnapRect().Top()) / 2;
933 case SvxDistributeVertical::Bottom
:
935 aNew
.mnPos
= aNew
.mpObj
->GetSnapRect().Bottom();
941 itEntryList
= std::find_if(aEntryList
.begin(), aEntryList
.end(),
942 [&aNew
](const ImpDistributeEntry
& rEntry
) { return rEntry
.mnPos
>= aNew
.mnPos
; });
943 if ( itEntryList
< aEntryList
.end() )
944 aEntryList
.insert( itEntryList
, aNew
);
946 aEntryList
.push_back( aNew
);
949 if(eVer
== SvxDistributeVertical::Distance
)
951 // calculate room in-between
952 sal_Int32 nHeight
= GetAllMarkedBoundRect().GetHeight() + 1;
953 double fStepWidth
= (static_cast<double>(nHeight
) - static_cast<double>(nFullLength
)) / static_cast<double>(aEntryList
.size() - 1);
954 double fStepStart
= static_cast<double>(aEntryList
[ 0 ].mnPos
);
955 fStepStart
+= fStepWidth
+ static_cast<double>((aEntryList
[ 0 ].mnLength
+ aEntryList
[ 1 ].mnLength
) / 2);
957 // move entries 1..n-1
958 for( size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
960 ImpDistributeEntry
& rCurr
= aEntryList
[ i
];
961 ImpDistributeEntry
& rNext
= aEntryList
[ i
+ 1 ];
962 sal_Int32 nDelta
= static_cast<sal_Int32
>(fStepStart
+ 0.5) - rCurr
.mnPos
;
964 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*rCurr
.mpObj
));
965 rCurr
.mpObj
->Move(Size(0, nDelta
));
966 fStepStart
+= fStepWidth
+ static_cast<double>((rCurr
.mnLength
+ rNext
.mnLength
) / 2);
971 // calculate distances
972 sal_Int32 nHeight
= aEntryList
[ aEntryList
.size() - 1 ].mnPos
- aEntryList
[ 0 ].mnPos
;
973 double fStepWidth
= static_cast<double>(nHeight
) / static_cast<double>(aEntryList
.size() - 1);
974 double fStepStart
= static_cast<double>(aEntryList
[ 0 ].mnPos
);
975 fStepStart
+= fStepWidth
;
977 // move entries 1..n-1
978 for(size_t i
= 1, n
= aEntryList
.size()-1; i
< n
; ++i
)
980 ImpDistributeEntry
& rCurr
= aEntryList
[ i
];
981 sal_Int32 nDelta
= static_cast<sal_Int32
>(fStepStart
+ 0.5) - rCurr
.mnPos
;
983 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*rCurr
.mpObj
));
984 rCurr
.mpObj
->Move(Size(0, nDelta
));
985 fStepStart
+= fStepWidth
;
993 // UNDO-Comment and end of UNDO
994 GetModel().SetUndoComment(SvxResId(STR_DistributeMarkedObjects
));
1000 void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode
)
1002 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1003 // #i73441# check content
1004 if(rMarkList
.GetMarkCount() == 0)
1007 SdrMarkList aRemove
;
1008 rMarkList
.ForceSort();
1010 const bool bUndo
= IsUndoEnabled();
1015 size_t nInsPos
= SAL_MAX_SIZE
;
1016 const SdrObject
* pAttrObj
= nullptr;
1017 basegfx::B2DPolyPolygon aMergePolyPolygonA
;
1018 basegfx::B2DPolyPolygon aMergePolyPolygonB
;
1020 SdrObjList
* pInsOL
= nullptr;
1021 SdrPageView
* pInsPV
= nullptr;
1022 bool bFirstObjectComplete(false);
1024 // make sure selected objects are contour objects
1025 // since now basegfx::utils::adaptiveSubdivide() is used, it is no longer
1026 // necessary to use ConvertMarkedToPolyObj which will subdivide curves using the old
1027 // mechanisms. In a next step the polygon clipper will even be able to clip curves...
1028 // ConvertMarkedToPolyObj(true);
1029 ConvertMarkedToPathObj(true);
1030 OSL_ENSURE(rMarkList
.GetMarkCount() != 0, "no more objects selected after preparations (!)");
1032 for(size_t a
=0; a
<rMarkList
.GetMarkCount(); ++a
)
1034 SdrMark
* pM
= rMarkList
.GetMark(a
);
1035 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1037 if(ImpCanConvertForCombine(pObj
))
1042 nInsPos
= pObj
->GetOrdNum() + 1;
1043 pInsPV
= pM
->GetPageView();
1044 pInsOL
= pObj
->getParentSdrObjListFromSdrObject();
1046 // #i76891# use single iteration from SJ here which works on SdrObjects and takes
1047 // groups into account by itself
1048 SdrObjListIter
aIter(*pObj
, SdrIterMode::DeepWithGroups
);
1050 while(aIter
.IsMore())
1052 SdrObject
* pCandidate
= aIter
.Next();
1053 SdrPathObj
* pPathObj
= dynamic_cast<SdrPathObj
*>( pCandidate
);
1056 basegfx::B2DPolyPolygon
aTmpPoly(pPathObj
->GetPathPoly());
1058 // #i76891# unfortunately ConvertMarkedToPathObj has converted all
1059 // involved polygon data to curve segments, even if not necessary.
1060 // It is better to try to reduce to more simple polygons.
1061 aTmpPoly
= basegfx::utils::simplifyCurveSegments(aTmpPoly
);
1063 // for each part polygon as preparation, remove self-intersections
1064 // correct orientations and get rid of possible neutral polygons.
1065 aTmpPoly
= basegfx::utils::prepareForPolygonOperation(aTmpPoly
);
1067 if(!bFirstObjectComplete
)
1069 // #i111987# Also need to collect ORed source shape when more than
1070 // a single polygon is involved
1071 if(aMergePolyPolygonA
.count())
1073 aMergePolyPolygonA
= basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA
, aTmpPoly
);
1077 aMergePolyPolygonA
= std::move(aTmpPoly
);
1082 if(aMergePolyPolygonB
.count())
1084 // to topologically correctly collect the 2nd polygon
1085 // group it is necessary to OR the parts (each is seen as
1086 // XOR-FillRule polygon and they are drawn over each-other)
1087 aMergePolyPolygonB
= basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonB
, aTmpPoly
);
1091 aMergePolyPolygonB
= std::move(aTmpPoly
);
1097 // was there something added to the first polygon?
1098 if(!bFirstObjectComplete
&& aMergePolyPolygonA
.count())
1100 bFirstObjectComplete
= true;
1103 // move object to temporary delete list
1104 aRemove
.InsertEntry(SdrMark(pObj
, pM
->GetPageView()));
1110 case SdrMergeMode::Merge
:
1112 // merge all contained parts (OR)
1113 aMergePolyPolygonA
= basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA
, aMergePolyPolygonB
);
1116 case SdrMergeMode::Subtract
:
1118 // Subtract B from A
1119 aMergePolyPolygonA
= basegfx::utils::solvePolygonOperationDiff(aMergePolyPolygonA
, aMergePolyPolygonB
);
1122 case SdrMergeMode::Intersect
:
1125 aMergePolyPolygonA
= basegfx::utils::solvePolygonOperationAnd(aMergePolyPolygonA
, aMergePolyPolygonB
);
1130 // #i73441# check insert list before taking actions
1133 rtl::Reference
<SdrPathObj
> pPath
= new SdrPathObj(pAttrObj
->getSdrModelFromSdrObject(), SdrObjKind::PathFill
, std::move(aMergePolyPolygonA
));
1134 ImpCopyAttributes(pAttrObj
, pPath
.get());
1135 pInsOL
->InsertObject(pPath
.get(), nInsPos
);
1137 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath
));
1139 // #i124760# To have a correct selection with only the new object it is necessary to
1140 // unmark all objects first. If not doing so, there may remain invalid pointers to objects
1141 // TTTT:Not needed for aw080 (!)
1142 UnmarkAllObj(pInsPV
);
1144 MarkObj(pPath
.get(), pInsPV
, false, true);
1147 aRemove
.ForceSort();
1150 case SdrMergeMode::Merge
:
1153 SvxResId(STR_EditMergeMergePoly
),
1154 aRemove
.GetMarkDescription());
1157 case SdrMergeMode::Subtract
:
1160 SvxResId(STR_EditMergeSubstractPoly
),
1161 aRemove
.GetMarkDescription());
1164 case SdrMergeMode::Intersect
:
1167 SvxResId(STR_EditMergeIntersectPoly
),
1168 aRemove
.GetMarkDescription());
1172 DeleteMarkedList(aRemove
);
1178 void SdrEditView::EqualizeMarkedObjects(bool bWidth
)
1180 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1181 size_t nMarked
= rMarkList
.GetMarkCount();
1186 size_t nLastSelected
= 0;
1187 sal_Int64 nLastSelectedTime
= rMarkList
.GetMark(0)->getTimeStamp();
1188 for (size_t a
= 1; a
< nMarked
; ++a
)
1190 sal_Int64 nCandidateTime
= rMarkList
.GetMark(a
)->getTimeStamp();
1191 if (nCandidateTime
> nLastSelectedTime
)
1193 nLastSelectedTime
= nCandidateTime
;
1198 SdrObject
* pLastSelectedObj
= rMarkList
.GetMark(nLastSelected
)->GetMarkedSdrObj();
1199 Size
aLastRectSize(pLastSelectedObj
->GetLogicRect().GetSize());
1201 const bool bUndo
= IsUndoEnabled();
1206 for (size_t a
= 0; a
< nMarked
; ++a
)
1208 if (a
== nLastSelected
)
1210 SdrMark
* pM
= rMarkList
.GetMark(a
);
1211 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1212 tools::Rectangle
aLogicRect(pObj
->GetLogicRect());
1213 Size
aLogicRectSize(aLogicRect
.GetSize());
1215 aLogicRectSize
.setWidth( aLastRectSize
.Width() );
1217 aLogicRectSize
.setHeight( aLastRectSize
.Height() );
1218 aLogicRect
.SetSize(aLogicRectSize
);
1220 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj
));
1221 pObj
->SetLogicRect(aLogicRect
);
1225 SvxResId(bWidth
? STR_EqualizeWidthMarkedObjects
: STR_EqualizeHeightMarkedObjects
),
1226 rMarkList
.GetMarkDescription());
1232 void SdrEditView::CombineMarkedTextObjects()
1234 SdrPageView
* pPageView
= GetSdrPageView();
1235 if ( !pPageView
|| pPageView
->IsLayerLocked( GetActiveLayer() ) )
1238 bool bUndo
= IsUndoEnabled();
1240 // Undo-String will be set later
1244 SdrOutliner
& rDrawOutliner
= getSdrModelFromSdrView().GetDrawOutliner();
1246 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1247 SdrObjListIter
aIter( rMarkList
, SdrIterMode::Flat
);
1248 while ( aIter
.IsMore() )
1250 SdrObject
* pObj
= aIter
.Next();
1251 SdrTextObj
* pTextObj
= DynCastSdrTextObj( pObj
);
1252 const OutlinerParaObject
* pOPO
= pTextObj
? pTextObj
->GetOutlinerParaObject() : nullptr;
1253 if ( pOPO
&& pTextObj
->IsTextFrame()
1254 && pTextObj
->GetObjIdentifier() == SdrObjKind::Text
// not callouts (OBJ_CAPTION)
1255 && !pTextObj
->IsOutlText() // not impress presentation objects
1256 && pTextObj
->GetMergedItem(XATTR_FORMTXTSTYLE
).GetValue() == XFormTextStyle::NONE
// not Fontwork
1259 // if the last paragraph does not end in paragraph-end punctuation (ignoring whitespace),
1260 // assume this text should be added to the end of the last paragraph, instead of starting a new paragraph.
1261 const sal_Int32 nPara
= rDrawOutliner
.GetParagraphCount();
1262 const OUString sLastPara
= nPara
? rDrawOutliner
.GetText( rDrawOutliner
.GetParagraph( nPara
- 1 ) ) : u
""_ustr
;
1263 sal_Int32 n
= sLastPara
.getLength();
1264 while ( n
&& unicode::isWhiteSpace( sLastPara
[--n
] ) )
1266 //TODO: find way to use Locale to identify sentence final punctuation. Copied IsSentenceAtEnd() from autofmt.cxx
1267 const bool bAppend
= !n
|| ( sLastPara
[n
] != '.' && sLastPara
[n
] != '?' && sLastPara
[n
] != '!' );
1268 rDrawOutliner
.AddText( *pOPO
, bAppend
);
1272 // Unmark non-textboxes, because all marked objects are deleted at the end. AdjustMarkHdl later.
1273 MarkObj(pObj
, pPageView
, /*bUnmark=*/true, /*bImpNoSetMarkHdl=*/true);
1277 MarkListHasChanged();
1280 if ( rMarkList
.GetMarkCount() > 1 )
1282 rtl::Reference
<SdrRectObj
> pReplacement
= new SdrRectObj( getSdrModelFromSdrView(), SdrObjKind::Text
);
1283 pReplacement
->SetOutlinerParaObject( rDrawOutliner
.CreateParaObject() );
1284 pReplacement
->SetSnapRect( GetMarkedObjRect() );
1286 const SdrInsertFlags nFlags
= SdrInsertFlags::DONTMARK
| SdrInsertFlags::SETDEFLAYER
;
1287 if ( InsertObjectAtView( pReplacement
.get(), *pPageView
, nFlags
) )
1297 void SdrEditView::CombineMarkedObjects(bool bNoPolyPoly
)
1299 // #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
1300 // create a 2nd Undo-action and Undo-Comment.
1302 bool bUndo
= IsUndoEnabled();
1304 // Undo-String will be set later
1306 BegUndo(u
""_ustr
, u
""_ustr
, bNoPolyPoly
? SdrRepeatFunc::CombineOnePoly
: SdrRepeatFunc::CombinePolyPoly
);
1308 // #105899# First, guarantee that all objects are converted to polyobjects,
1309 // especially for SdrGrafObj with bitmap filling this is necessary to not
1310 // lose the bitmap filling.
1313 // ConvertMarkedToPolyObj was too strong here, it will lose quality and
1314 // information when curve objects are combined. This can be replaced by
1315 // using ConvertMarkedToPathObj without changing the previous fix.
1318 // Instead of simply passing true as LineToArea, use bNoPolyPoly as info
1319 // if this command is a 'Combine' or a 'Connect' command. On Connect it's true.
1320 // To not concert line segments with a set line width to polygons in that case,
1321 // use this info. Do not convert LineToArea on Connect commands.
1322 // ConvertMarkedToPathObj(!bNoPolyPoly);
1324 // This is used for Combine and Connect. In no case it is necessary to force
1325 // the content to curve, but it is also not good to force to polygons. Thus,
1326 // curve is the less information losing one. Remember: This place is not
1328 // LineToArea is never necessary, both commands are able to take over the
1329 // set line style and to display it correctly. Thus, i will use a
1330 // ConvertMarkedToPathObj with a false in any case. Only drawback is that
1331 // simple polygons will be changed to curves, but with no information loss.
1332 ConvertMarkedToPathObj(false /* bLineToArea */);
1334 // continue as before
1335 basegfx::B2DPolyPolygon aPolyPolygon
;
1336 SdrObjList
* pCurrentOL
= nullptr;
1337 SdrMarkList aRemoveBuffer
;
1339 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1340 rMarkList
.ForceSort();
1341 size_t nInsPos
= SAL_MAX_SIZE
;
1342 SdrObjList
* pInsOL
= nullptr;
1343 SdrPageView
* pInsPV
= nullptr;
1344 const SdrObject
* pAttrObj
= nullptr;
1346 for(size_t a
= rMarkList
.GetMarkCount(); a
; )
1349 SdrMark
* pM
= rMarkList
.GetMark(a
);
1350 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1351 SdrObjList
* pThisOL
= pObj
->getParentSdrObjListFromSdrObject();
1353 if(pCurrentOL
!= pThisOL
)
1355 pCurrentOL
= pThisOL
;
1358 if(ImpCanConvertForCombine(pObj
))
1360 // remember objects to be able to copy attributes
1363 // unfortunately ConvertMarkedToPathObj has converted all
1364 // involved polygon data to curve segments, even if not necessary.
1365 // It is better to try to reduce to more simple polygons.
1366 basegfx::B2DPolyPolygon
aTmpPoly(basegfx::utils::simplifyCurveSegments(ImpGetPolyPolygon(pObj
)));
1367 aPolyPolygon
.insert(0, aTmpPoly
);
1371 nInsPos
= pObj
->GetOrdNum() + 1;
1372 pInsPV
= pM
->GetPageView();
1373 pInsOL
= pObj
->getParentSdrObjListFromSdrObject();
1376 aRemoveBuffer
.InsertEntry(SdrMark(pObj
, pM
->GetPageView()));
1382 basegfx::B2DPolygon
aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon
));
1383 aPolyPolygon
.clear();
1384 aPolyPolygon
.append(aCombinedPolygon
);
1387 const sal_uInt32
nPolyCount(aPolyPolygon
.count());
1389 if (nPolyCount
&& pAttrObj
)
1391 SdrObjKind eKind
= SdrObjKind::PathFill
;
1395 aPolyPolygon
.setClosed(true);
1399 // check for Polyline
1400 const basegfx::B2DPolygon
aPolygon(aPolyPolygon
.getB2DPolygon(0));
1401 const sal_uInt32
nPointCount(aPolygon
.count());
1403 if(nPointCount
<= 2)
1405 eKind
= SdrObjKind::PathLine
;
1409 if(!aPolygon
.isClosed())
1411 const basegfx::B2DPoint
aPointA(aPolygon
.getB2DPoint(0));
1412 const basegfx::B2DPoint
aPointB(aPolygon
.getB2DPoint(nPointCount
- 1));
1413 const double fDistance(basegfx::B2DVector(aPointB
- aPointA
).getLength());
1414 const double fJoinTolerance(10.0);
1416 if(fDistance
< fJoinTolerance
)
1418 aPolyPolygon
.setClosed(true);
1422 eKind
= SdrObjKind::PathLine
;
1428 rtl::Reference
<SdrPathObj
> pPath
= new SdrPathObj(pAttrObj
->getSdrModelFromSdrObject(), eKind
, std::move(aPolyPolygon
));
1430 // attributes of the lowest object
1431 ImpCopyAttributes(pAttrObj
, pPath
.get());
1433 // If LineStyle of pAttrObj is drawing::LineStyle_NONE force to drawing::LineStyle_SOLID to make visible.
1434 const drawing::LineStyle eLineStyle
= pAttrObj
->GetMergedItem(XATTR_LINESTYLE
).GetValue();
1435 const drawing::FillStyle eFillStyle
= pAttrObj
->GetMergedItem(XATTR_FILLSTYLE
).GetValue();
1437 // Take fill style/closed state of pAttrObj in account when deciding to change the line style
1438 bool bIsClosedPathObj
= false;
1439 if (auto pPathObj
= dynamic_cast<const SdrPathObj
*>(pAttrObj
))
1440 if (pPathObj
->IsClosed())
1441 bIsClosedPathObj
= true;
1443 if(drawing::LineStyle_NONE
== eLineStyle
&& (drawing::FillStyle_NONE
== eFillStyle
|| !bIsClosedPathObj
))
1445 pPath
->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID
));
1448 pInsOL
->InsertObject(pPath
.get(),nInsPos
);
1450 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath
));
1452 // Here was a severe error: Without UnmarkAllObj, the new object was marked
1453 // additionally to the two ones which are deleted below. As long as those are
1454 // in the UNDO there is no problem, but as soon as they get deleted, the
1455 // MarkList will contain deleted objects -> GPF.
1456 UnmarkAllObj(pInsPV
);
1457 MarkObj(pPath
.get(), pInsPV
, false, true);
1460 // build an UndoComment from the objects actually used
1461 aRemoveBuffer
.ForceSort(); // important for remove (see below)
1463 SetUndoComment(SvxResId(bNoPolyPoly
?STR_EditCombine_OnePoly
:STR_EditCombine_PolyPoly
),aRemoveBuffer
.GetMarkDescription());
1465 // remove objects actually used from the list
1466 DeleteMarkedList(aRemoveBuffer
);
1475 bool SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon
& rPpolyPolygon
, bool bMakeLines
)
1478 const sal_uInt32
nPolygonCount(rPpolyPolygon
.count());
1480 if(nPolygonCount
>= 2)
1482 // #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
1485 else if(bMakeLines
&& 1 == nPolygonCount
)
1487 // #i69172# ..or with at least 2 edges (curves or lines)
1488 const basegfx::B2DPolygon
& aPolygon(rPpolyPolygon
.getB2DPolygon(0));
1489 const sal_uInt32
nPointCount(aPolygon
.count());
1500 bool SdrEditView::ImpCanDismantle(const SdrObject
* pObj
, bool bMakeLines
)
1502 bool bOtherObjs(false); // true=objects other than PathObj's existent
1503 bool bMin1PolyPoly(false); // true=at least 1 tools::PolyPolygon with more than one Polygon existent
1504 SdrObjList
* pOL
= pObj
->GetSubList();
1508 // group object -- check all members if they're PathObjs
1509 SdrObjListIter
aIter(pOL
, SdrIterMode::DeepNoGroups
);
1511 while(aIter
.IsMore() && !bOtherObjs
)
1513 const SdrObject
* pObj1
= aIter
.Next();
1514 const SdrPathObj
* pPath
= dynamic_cast<const SdrPathObj
*>( pObj1
);
1518 if(ImpCanDismantle(pPath
->GetPathPoly(), bMakeLines
))
1520 bMin1PolyPoly
= true;
1523 SdrObjTransformInfoRec aInfo
;
1524 pObj1
->TakeObjInfo(aInfo
);
1526 if(!aInfo
.bCanConvToPath
)
1528 // happens e. g. in the case of FontWork
1540 const SdrPathObj
* pPath
= dynamic_cast<const SdrPathObj
*>(pObj
);
1541 const SdrObjCustomShape
* pCustomShape
= dynamic_cast<const SdrObjCustomShape
*>(pObj
);
1546 if(ImpCanDismantle(pPath
->GetPathPoly(),bMakeLines
))
1548 bMin1PolyPoly
= true;
1551 SdrObjTransformInfoRec aInfo
;
1552 pObj
->TakeObjInfo(aInfo
);
1554 // new condition IsLine() to be able to break simple Lines
1555 if(!(aInfo
.bCanConvToPath
|| aInfo
.bCanConvToPoly
) && !pPath
->IsLine())
1557 // happens e. g. in the case of FontWork
1561 else if(pCustomShape
)
1565 // allow break command
1566 bMin1PolyPoly
= true;
1574 return bMin1PolyPoly
&& !bOtherObjs
;
1577 void SdrEditView::ImpDismantleOneObject(const SdrObject
* pObj
, SdrObjList
& rOL
, size_t& rPos
, SdrPageView
* pPV
, bool bMakeLines
)
1579 const SdrPathObj
* pSrcPath
= dynamic_cast<const SdrPathObj
*>( pObj
);
1580 const SdrObjCustomShape
* pCustomShape
= dynamic_cast<const SdrObjCustomShape
*>( pObj
);
1582 const bool bUndo
= IsUndoEnabled();
1586 // #i74631# redesigned due to XpolyPolygon removal and explicit constructors
1587 SdrObject
* pLast
= nullptr; // to be able to apply OutlinerParaObject
1588 const basegfx::B2DPolyPolygon
& rPolyPolygon(pSrcPath
->GetPathPoly());
1589 const sal_uInt32
nPolyCount(rPolyPolygon
.count());
1591 for(sal_uInt32
a(0); a
< nPolyCount
; a
++)
1593 const basegfx::B2DPolygon
& rCandidate(rPolyPolygon
.getB2DPolygon(a
));
1594 const sal_uInt32
nPointCount(rCandidate
.count());
1596 if(!bMakeLines
|| nPointCount
< 2)
1598 rtl::Reference
<SdrPathObj
> pPath
= new SdrPathObj(
1599 pSrcPath
->getSdrModelFromSdrObject(),
1600 pSrcPath
->GetObjIdentifier(),
1601 basegfx::B2DPolyPolygon(rCandidate
));
1602 ImpCopyAttributes(pSrcPath
, pPath
.get());
1603 pLast
= pPath
.get();
1604 rOL
.InsertObject(pPath
.get(), rPos
);
1606 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath
, true));
1607 MarkObj(pPath
.get(), pPV
, false, true);
1612 const sal_uInt32
nLoopCount(rCandidate
.isClosed() ? nPointCount
: nPointCount
- 1);
1614 for(sal_uInt32
b(0); b
< nLoopCount
; b
++)
1616 SdrObjKind
eKind(SdrObjKind::PolyLine
);
1617 basegfx::B2DPolygon aNewPolygon
;
1618 const sal_uInt32
nNextIndex((b
+ 1) % nPointCount
);
1620 aNewPolygon
.append(rCandidate
.getB2DPoint(b
));
1622 if(rCandidate
.areControlPointsUsed())
1624 aNewPolygon
.appendBezierSegment(
1625 rCandidate
.getNextControlPoint(b
),
1626 rCandidate
.getPrevControlPoint(nNextIndex
),
1627 rCandidate
.getB2DPoint(nNextIndex
));
1628 eKind
= SdrObjKind::PathLine
;
1632 aNewPolygon
.append(rCandidate
.getB2DPoint(nNextIndex
));
1635 rtl::Reference
<SdrPathObj
> pPath
= new SdrPathObj(
1636 pSrcPath
->getSdrModelFromSdrObject(),
1638 basegfx::B2DPolyPolygon(aNewPolygon
));
1639 ImpCopyAttributes(pSrcPath
, pPath
.get());
1640 pLast
= pPath
.get();
1641 rOL
.InsertObject(pPath
.get(), rPos
);
1643 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pPath
, true));
1644 MarkObj(pPath
.get(), pPV
, false, true);
1650 if(pLast
&& pSrcPath
->GetOutlinerParaObject())
1652 pLast
->SetOutlinerParaObject(*pSrcPath
->GetOutlinerParaObject());
1655 else if(pCustomShape
)
1659 // break up custom shape
1660 const SdrObject
* pReplacement
= pCustomShape
->GetSdrObjectFromCustomShape();
1664 rtl::Reference
<SdrObject
> pCandidate(pReplacement
->CloneSdrObject(pReplacement
->getSdrModelFromSdrObject()));
1665 DBG_ASSERT(pCandidate
, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
1667 if(pCustomShape
->GetMergedItem(SDRATTR_SHADOW
).GetValue())
1669 if(dynamic_cast<const SdrObjGroup
*>( pReplacement
) != nullptr)
1671 pCandidate
->SetMergedItem(makeSdrShadowItem(true));
1675 rOL
.InsertObject(pCandidate
.get(), rPos
);
1677 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pCandidate
, true));
1678 MarkObj(pCandidate
.get(), pPV
, false, true);
1680 if(pCustomShape
->HasText() && !pCustomShape
->IsTextPath())
1682 // #i37011# also create a text object and add at rPos + 1
1683 rtl::Reference
<SdrObject
> pTextObj
= SdrObjFactory::MakeNewObject(
1684 pCustomShape
->getSdrModelFromSdrObject(),
1685 pCustomShape
->GetObjInventor(),
1688 // Copy text content
1689 OutlinerParaObject
* pParaObj
= pCustomShape
->GetOutlinerParaObject();
1692 pTextObj
->NbcSetOutlinerParaObject(*pParaObj
);
1695 // copy all attributes
1696 SfxItemSet
aTargetItemSet(pCustomShape
->GetMergedItemSet());
1698 // clear fill and line style
1699 aTargetItemSet
.Put(XLineStyleItem(drawing::LineStyle_NONE
));
1700 aTargetItemSet
.Put(XFillStyleItem(drawing::FillStyle_NONE
));
1702 // get the text bounds and set at text object
1703 tools::Rectangle aTextBounds
= pCustomShape
->GetSnapRect();
1704 if(pCustomShape
->GetTextBounds(aTextBounds
))
1706 pTextObj
->SetSnapRect(aTextBounds
);
1709 // if rotated, copy GeoStat, too.
1710 const GeoStat
& rSourceGeo
= pCustomShape
->GetGeoStat();
1711 if(rSourceGeo
.m_nRotationAngle
)
1713 pTextObj
->NbcRotate(
1714 pCustomShape
->GetSnapRect().Center(), rSourceGeo
.m_nRotationAngle
,
1715 rSourceGeo
.mfSinRotationAngle
, rSourceGeo
.mfCosRotationAngle
);
1718 // set modified ItemSet at text object
1719 pTextObj
->SetMergedItemSet(aTargetItemSet
);
1722 rOL
.InsertObject(pTextObj
.get(), rPos
+ 1);
1724 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pTextObj
, true));
1725 MarkObj(pTextObj
.get(), pPV
, false, true);
1732 void SdrEditView::DismantleMarkedObjects(bool bMakeLines
)
1734 // temporary MarkList
1735 SdrMarkList aRemoveBuffer
;
1737 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1738 rMarkList
.ForceSort();
1740 const bool bUndo
= IsUndoEnabled();
1744 // comment is constructed later
1745 BegUndo(u
""_ustr
, u
""_ustr
, bMakeLines
? SdrRepeatFunc::DismantleLines
: SdrRepeatFunc::DismantlePolys
);
1748 SdrObjList
* pOL0
=nullptr;
1749 const bool bWasLocked
= GetModel().isLocked();
1750 GetModel().setLock(true);
1751 for (size_t nm
=rMarkList
.GetMarkCount(); nm
>0;) {
1753 SdrMark
* pM
=rMarkList
.GetMark(nm
);
1754 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1755 SdrPageView
* pPV
=pM
->GetPageView();
1756 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
1757 if (pOL
!=pOL0
) { pOL0
=pOL
; pObj
->GetOrdNum(); } // make sure OrdNums are correct!
1758 if (ImpCanDismantle(pObj
,bMakeLines
)) {
1760 aRemoveBuffer
.InsertEntry(SdrMark(pObj
,pM
->GetPageView()));
1761 const size_t nPos0
=pObj
->GetOrdNumDirect();
1762 size_t nPos
=nPos0
+1;
1763 SdrObjList
* pSubList
=pObj
->GetSubList();
1764 if (pSubList
!=nullptr && !pObj
->Is3DObj()) {
1765 SdrObjListIter
aIter(pSubList
,SdrIterMode::DeepNoGroups
);
1766 while (aIter
.IsMore()) {
1767 const SdrObject
* pObj1
=aIter
.Next();
1768 ImpDismantleOneObject(pObj1
,*pOL
,nPos
,pPV
,bMakeLines
);
1771 ImpDismantleOneObject(pObj
,*pOL
,nPos
,pPV
,bMakeLines
);
1774 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj
,true));
1775 pOL
->RemoveObject(nPos0
);
1778 GetModel().setLock(bWasLocked
);
1782 // construct UndoComment from objects actually used
1783 SetUndoComment(SvxResId(bMakeLines
?STR_EditDismantle_Lines
:STR_EditDismantle_Polys
),aRemoveBuffer
.GetMarkDescription());
1784 // remove objects actually used from the list
1793 void SdrEditView::GroupMarked()
1795 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1796 if (rMarkList
.GetMarkCount() == 0)
1799 rMarkList
.ForceSort();
1801 const bool bUndo
= IsUndoEnabled();
1804 BegUndo(SvxResId(STR_EditGroup
),rMarkList
.GetMarkDescription(),SdrRepeatFunc::Group
);
1806 for(size_t nm
= rMarkList
.GetMarkCount(); nm
>0; )
1808 // add UndoActions for all affected objects
1810 SdrMark
* pM
=rMarkList
.GetMark(nm
);
1811 SdrObject
* pObj
= pM
->GetMarkedSdrObj();
1812 AddUndoActions( CreateConnectorUndo( *pObj
) );
1813 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoRemoveObject( *pObj
));
1817 SdrMarkList aNewMark
;
1818 SdrPageView
* pPV
= GetSdrPageView();
1822 SdrObjList
* pCurrentLst
=pPV
->GetObjList();
1823 SdrObjList
* pSrcLst
=pCurrentLst
;
1824 SdrObjList
* pSrcLst0
=pSrcLst
;
1825 // make sure OrdNums are correct
1826 if (pSrcLst
->IsObjOrdNumsDirty())
1827 pSrcLst
->RecalcObjOrdNums();
1828 rtl::Reference
<SdrObject
> pGrp
;
1829 SdrObjList
* pDstLst
=nullptr;
1830 // if all selected objects come from foreign object lists.
1831 // the group object is the last one in the list.
1832 size_t nInsPos
=pSrcLst
->GetObjCount();
1833 bool bNeedInsPos
=true;
1834 for (size_t nm
=rMarkList
.GetMarkCount(); nm
>0;)
1837 SdrMark
* pM
=rMarkList
.GetMark(nm
);
1838 if (pM
->GetPageView()==pPV
)
1840 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
1843 pGrp
= new SdrObjGroup(pObj
->getSdrModelFromSdrObject());
1844 pDstLst
=pGrp
->GetSubList();
1845 assert(pDstLst
&& "Alleged group object doesn't return object list.");
1847 pSrcLst
=pObj
->getParentSdrObjListFromSdrObject();
1848 if (pSrcLst
!=pSrcLst0
)
1850 if (pSrcLst
->IsObjOrdNumsDirty())
1851 pSrcLst
->RecalcObjOrdNums();
1853 bool bForeignList
=pSrcLst
!=pCurrentLst
;
1854 if (!bForeignList
&& bNeedInsPos
)
1856 nInsPos
=pObj
->GetOrdNum(); // this way, all ObjOrdNum of the page are set
1860 pSrcLst
->RemoveObject(pObj
->GetOrdNumDirect());
1862 nInsPos
--; // correct InsertPos
1863 pDstLst
->InsertObject(pObj
,0);
1864 GetMarkedObjectListWriteAccess().DeleteMark(nm
);
1870 assert(pDstLst
); // keep coverity happy
1871 aNewMark
.InsertEntry(SdrMark(pGrp
.get(),pPV
));
1872 const size_t nCount
=pDstLst
->GetObjCount();
1873 pCurrentLst
->InsertObject(pGrp
.get(),nInsPos
);
1876 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pGrp
,true)); // no recalculation!
1877 for (size_t no
=0; no
<nCount
; ++no
)
1879 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst
->GetObj(no
)));
1884 GetMarkedObjectListWriteAccess().Merge(aNewMark
);
1885 MarkListHasChanged();
1895 void SdrEditView::UnGroupMarked()
1897 SdrMarkList aNewMark
;
1899 const bool bUndo
= IsUndoEnabled();
1901 BegUndo(u
""_ustr
, u
""_ustr
, SdrRepeatFunc::Ungroup
);
1907 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
1908 for (size_t nm
=rMarkList
.GetMarkCount(); nm
>0;) {
1910 SdrMark
* pM
=rMarkList
.GetMark(nm
);
1911 SdrObject
* pGrp
=pM
->GetMarkedSdrObj();
1912 SdrObjList
* pSrcLst
=pGrp
->GetSubList();
1913 if (pSrcLst
!=nullptr) {
1916 aName
= pGrp
->TakeObjNameSingul(); // retrieve name of group
1917 aName1
= pGrp
->TakeObjNamePlural(); // retrieve name of group
1920 if (nCount
==2) aName
=aName1
; // set plural name
1922 OUString
aStr(pGrp
->TakeObjNamePlural()); // retrieve name of group
1928 size_t nDstCnt
=pGrp
->GetOrdNum();
1929 SdrObjList
* pDstLst
=pM
->GetPageView()->GetObjList();
1930 size_t nObjCount
=pSrcLst
->GetObjCount();
1931 const bool bIsDiagram(pGrp
->isDiagram());
1933 // If the Group is a Diagram, it has a filler BG object to guarantee
1934 // the Diagam's dimensions. Identify that shape
1935 if(bIsDiagram
&& nObjCount
)
1937 SdrObject
* pObj(pSrcLst
->GetObj(0));
1939 if(nullptr != pObj
&& !pObj
->IsGroupObject() &&
1940 !pObj
->HasLineStyle() &&
1941 pObj
->IsMoveProtect() && pObj
->IsResizeProtect())
1943 if(pObj
->HasFillStyle())
1945 // If it has FillStyle it is a useful object representing that possible
1946 // defined fill from oox import. In this case, we should remove the
1947 // Move/Resize protection to allow seamless further processing.
1949 // Undo of these is handled by SdrUndoGeoObj which holds a SdrObjGeoData,
1952 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj
));
1954 pObj
->SetMoveProtect(false);
1955 pObj
->SetResizeProtect(false);
1959 // If it has no FillStyle it is not useful for any further processing
1960 // but only was used as a placeholder, get directly rid of it
1962 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj
));
1964 pSrcLst
->RemoveObject(0);
1966 nObjCount
= pSrcLst
->GetObjCount();
1971 // FIRST move contained objects to parent of group, so that
1972 // the contained objects are NOT migrated to the UNDO-ItemPool
1973 // when AddUndo(new SdrUndoDelObj(*pGrp)) is called.
1976 for (size_t no
=nObjCount
; no
>0;)
1979 SdrObject
* pObj
=pSrcLst
->GetObj(no
);
1980 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoRemoveObject(*pObj
));
1984 for (size_t no
=0; no
<nObjCount
; ++no
)
1986 rtl::Reference
<SdrObject
> pObj
=pSrcLst
->RemoveObject(0);
1987 pDstLst
->InsertObject(pObj
.get(),nDstCnt
);
1989 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoInsertObject(*pObj
,true));
1991 // No SortCheck when inserting into MarkList, because that would
1992 // provoke a RecalcOrdNums() each time because of pObj->GetOrdNum():
1993 aNewMark
.InsertEntry(SdrMark(pObj
.get(),pM
->GetPageView()),false);
1998 // Now it is safe to add the delete-UNDO which triggers the
1999 // MigrateItemPool now only for itself, not for the sub-objects.
2000 // nDstCnt is right, because previous inserts move group
2001 // object deeper and increase nDstCnt.
2002 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp
));
2004 pDstLst
->RemoveObject(nDstCnt
);
2006 GetMarkedObjectListWriteAccess().DeleteMark(nm
);
2012 aName
=SvxResId(STR_ObjNamePluralGRUP
); // Use the term "Group Objects," if different objects are grouped.
2013 SetUndoComment(SvxResId(STR_EditUngroup
),aName
);
2021 GetMarkedObjectListWriteAccess().Merge(aNewMark
,true); // Because of the sorting above, aNewMark is reversed
2022 MarkListHasChanged();
2030 rtl::Reference
<SdrObject
> SdrEditView::ImpConvertOneObj(SdrObject
* pObj
, bool bPath
, bool bLineToArea
)
2032 rtl::Reference
<SdrObject
> pNewObj
= pObj
->ConvertToPolyObj(bPath
, bLineToArea
);
2035 SdrObjList
* pOL
= pObj
->getParentSdrObjListFromSdrObject();
2036 const bool bUndo
= IsUndoEnabled();
2038 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoReplaceObject(*pObj
,*pNewObj
));
2040 pOL
->ReplaceObject(pNewObj
.get(), pObj
->GetOrdNum());
2045 void SdrEditView::ImpConvertTo(bool bPath
, bool bLineToArea
)
2047 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
2048 if (rMarkList
.GetMarkCount() == 0)
2051 bool bMrkChg
= false;
2052 const size_t nMarkCount
=rMarkList
.GetMarkCount();
2053 TranslateId pDscrID
;
2057 pDscrID
= STR_EditConvToContour
;
2059 pDscrID
= STR_EditConvToContours
;
2061 BegUndo(SvxResId(pDscrID
), rMarkList
.GetMarkDescription());
2066 if (nMarkCount
==1) pDscrID
=STR_EditConvToCurve
;
2067 else pDscrID
=STR_EditConvToCurves
;
2068 BegUndo(SvxResId(pDscrID
),rMarkList
.GetMarkDescription(),SdrRepeatFunc::ConvertToPath
);
2070 if (nMarkCount
==1) pDscrID
=STR_EditConvToPoly
;
2071 else pDscrID
=STR_EditConvToPolys
;
2072 BegUndo(SvxResId(pDscrID
),rMarkList
.GetMarkDescription(),SdrRepeatFunc::ConvertToPoly
);
2075 for (size_t nm
=nMarkCount
; nm
>0;) {
2077 SdrMark
* pM
=rMarkList
.GetMark(nm
);
2078 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
2079 SdrPageView
* pPV
=pM
->GetPageView();
2080 if (pObj
->IsGroupObject() && !pObj
->Is3DObj()) {
2081 SdrObject
* pGrp
=pObj
;
2082 SdrObjListIter
aIter(*pGrp
, SdrIterMode::DeepNoGroups
);
2083 while (aIter
.IsMore()) {
2085 ImpConvertOneObj(pObj
,bPath
,bLineToArea
);
2088 rtl::Reference
<SdrObject
> pNewObj
=ImpConvertOneObj(pObj
,bPath
,bLineToArea
);
2091 GetMarkedObjectListWriteAccess().ReplaceMark(SdrMark(pNewObj
.get(),pPV
),nm
);
2099 MarkListHasChanged();
2103 void SdrEditView::ConvertMarkedToPathObj(bool bLineToArea
)
2105 ImpConvertTo(true, bLineToArea
);
2108 void SdrEditView::ConvertMarkedToPolyObj()
2110 ImpConvertTo(false, false/*bLineToArea*/);
2115 GDIMetaFile
GetMetaFile(SdrGrafObj
const * pGraf
)
2117 if (pGraf
->HasGDIMetaFile())
2118 return pGraf
->GetTransformedGraphic(SdrGrafObjTransformsAttrs::MIRROR
).GetGDIMetaFile();
2119 assert(pGraf
->isEmbeddedVectorGraphicData());
2120 return pGraf
->getMetafileFromEmbeddedVectorGraphicData();
2125 void SdrEditView::DoImportMarkedMtf(SvdProgressInfo
*pProgrInfo
)
2127 const bool bUndo
= IsUndoEnabled();
2130 BegUndo(u
""_ustr
, u
""_ustr
, SdrRepeatFunc::ImportMtf
);
2132 const SdrMarkList
& rMarkList
= GetMarkedObjectList();
2133 rMarkList
.ForceSort();
2134 SdrMarkList aForTheDescription
;
2135 SdrMarkList aNewMarked
;
2136 for (size_t nm
=rMarkList
.GetMarkCount(); nm
> 0; )
2138 // create Undo objects for all new objects
2139 // check for cancellation between the metafiles
2140 if (pProgrInfo
!= nullptr)
2142 pProgrInfo
->SetNextObject();
2143 if (!pProgrInfo
->ReportActions(0))
2148 SdrMark
* pM
=rMarkList
.GetMark(nm
);
2149 SdrObject
* pObj
=pM
->GetMarkedSdrObj();
2150 SdrPageView
* pPV
=pM
->GetPageView();
2151 SdrObjList
* pOL
=pObj
->getParentSdrObjListFromSdrObject();
2152 const size_t nInsPos
=pObj
->GetOrdNum()+1;
2154 tools::Rectangle aLogicRect
;
2156 SdrGrafObj
* pGraf
= dynamic_cast<SdrGrafObj
*>( pObj
);
2157 if (pGraf
!= nullptr)
2159 Graphic aGraphic
= pGraf
->GetGraphic();
2160 auto const & pVectorGraphicData
= aGraphic
.getVectorGraphicData();
2162 if (pVectorGraphicData
&& pVectorGraphicData
->getType() == VectorGraphicDataType::Pdf
)
2164 auto pPdfium
= vcl::pdf::PDFiumLibrary::get();
2167 aLogicRect
= pGraf
->GetLogicRect();
2168 ImpSdrPdfImport
aFilter(GetModel(), pObj
->GetLayer(), aLogicRect
, aGraphic
);
2169 if (aGraphic
.getPageNumber() < aFilter
.GetPageCount())
2171 nInsCnt
= aFilter
.DoImport(*pOL
, nInsPos
, aGraphic
.getPageNumber(), pProgrInfo
);
2175 else if (pGraf
->HasGDIMetaFile() || pGraf
->isEmbeddedVectorGraphicData() )
2177 GDIMetaFile
aMetaFile(GetMetaFile(pGraf
));
2178 if (aMetaFile
.GetActionSize())
2180 aLogicRect
= pGraf
->GetLogicRect();
2181 ImpSdrGDIMetaFileImport
aFilter(GetModel(), pObj
->GetLayer(), aLogicRect
);
2182 nInsCnt
= aFilter
.DoImport(aMetaFile
, *pOL
, nInsPos
, pProgrInfo
);
2187 SdrOle2Obj
* pOle2
= dynamic_cast<SdrOle2Obj
*>(pObj
);
2190 if (const Graphic
* pGraphic
= pOle2
->GetGraphic())
2192 aLogicRect
= pOle2
->GetLogicRect();
2193 ImpSdrGDIMetaFileImport
aFilter(GetModel(), pObj
->GetLayer(), aLogicRect
);
2194 nInsCnt
= aFilter
.DoImport(pGraphic
->GetGDIMetaFile(), *pOL
, nInsPos
, pProgrInfo
);
2201 GeoStat
aGeoStat(pGraf
? pGraf
->GetGeoStat() : pOle2
->GetGeoStat());
2202 size_t nObj
= nInsPos
;
2204 if (aGeoStat
.m_nShearAngle
)
2205 aGeoStat
.RecalcTan();
2207 if (aGeoStat
.m_nRotationAngle
)
2208 aGeoStat
.RecalcSinCos();
2210 for (size_t i
= 0; i
< nInsCnt
; i
++)
2213 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoNewObject(*pOL
->GetObj(nObj
)));
2215 // update new MarkList
2216 SdrObject
* pCandidate
= pOL
->GetObj(nObj
);
2218 // apply original transformation
2219 if (aGeoStat
.m_nShearAngle
)
2220 pCandidate
->NbcShear(aLogicRect
.TopLeft(), aGeoStat
.m_nShearAngle
, aGeoStat
.mfTanShearAngle
, false);
2222 if (aGeoStat
.m_nRotationAngle
)
2223 pCandidate
->NbcRotate(aLogicRect
.TopLeft(), aGeoStat
.m_nRotationAngle
, aGeoStat
.mfSinRotationAngle
, aGeoStat
.mfCosRotationAngle
);
2225 SdrMark
aNewMark(pCandidate
, pPV
);
2226 aNewMarked
.InsertEntry(aNewMark
);
2231 aForTheDescription
.InsertEntry(*pM
);
2234 AddUndo(GetModel().GetSdrUndoFactory().CreateUndoDeleteObject(*pObj
));
2236 // remove object from selection and delete
2237 GetMarkedObjectListWriteAccess().DeleteMark(rMarkList
.FindObject(pObj
));
2238 pOL
->RemoveObject(nInsPos
-1);
2242 if (aNewMarked
.GetMarkCount())
2244 // create new selection
2245 for (size_t a
= 0; a
< aNewMarked
.GetMarkCount(); ++a
)
2247 GetMarkedObjectListWriteAccess().InsertEntry(*aNewMarked
.GetMark(a
));
2250 rMarkList
.ForceSort();
2255 SetUndoComment(SvxResId(STR_EditImportMtf
),aForTheDescription
.GetMarkDescription());
2260 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */