Adjust includes
[LibreOffice.git] / svx / source / svdraw / svdedtv2.cxx
blob5d5e7dfaa6311ab921317cdbf8076bba1d425db4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svx/svdedtv.hxx>
21 #include <editeng/outliner.hxx>
22 #include <svx/svdundo.hxx>
23 #include <svx/svdogrp.hxx>
24 #include <svx/svdovirt.hxx>
25 #include <svx/svdopath.hxx>
26 #include <svx/svdpage.hxx>
27 #include <svx/svdpagv.hxx>
28 #include <svx/svditer.hxx>
29 #include <svx/svdograf.hxx>
30 #include <svx/svdoole2.hxx>
31 #include <svdglob.hxx>
32 #include "svdfmtf.hxx"
33 #include <svx/svdetc.hxx>
34 #include <sfx2/basedlgs.hxx>
35 #include <vcl/msgbox.hxx>
36 #include <editeng/outlobj.hxx>
37 #include <editeng/eeitem.hxx>
38 #include <basegfx/polygon/b2dpolypolygon.hxx>
39 #include <basegfx/polygon/b2dpolypolygontools.hxx>
40 #include <svx/svxdlg.hxx>
41 #include <svx/strings.hrc>
42 #include <svx/svdoashp.hxx>
43 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
44 #include <memory>
45 #include <vector>
46 using ::std::vector;
47 using namespace com::sun::star;
49 SdrObject* SdrEditView::GetMaxToTopObj(SdrObject* /*pObj*/) const
51 return nullptr;
54 SdrObject* SdrEditView::GetMaxToBtmObj(SdrObject* /*pObj*/) const
56 return nullptr;
59 void SdrEditView::ObjOrderChanged(SdrObject* /*pObj*/, size_t /*nOldPos*/, size_t /*nNewPos*/)
63 void SdrEditView::MovMarkedToTop()
65 const size_t nCount=GetMarkedObjectCount();
66 if (nCount!=0)
68 const bool bUndo = IsUndoEnabled();
70 if( bUndo )
71 BegUndo(ImpGetResStr(STR_EditMovToTop),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::MoveToTop);
73 SortMarkedObjects();
74 for (size_t nm=0; nm<nCount; ++nm)
75 { // All Ordnums have to be correct!
76 GetMarkedObjectByIndex(nm)->GetOrdNum();
78 bool bChg=false;
79 SdrObjList* pOL0=nullptr;
80 size_t nNewPos=0;
81 for (size_t nm=nCount; nm>0;)
83 --nm;
84 SdrMark* pM=GetSdrMarkByIndex(nm);
85 SdrObject* pObj=pM->GetMarkedSdrObj();
86 SdrObjList* pOL=pObj->GetObjList();
87 if (pOL!=pOL0)
89 nNewPos = pOL->GetObjCount()-1;
90 pOL0=pOL;
92 const size_t nNowPos = pObj->GetOrdNumDirect();
93 const tools::Rectangle& rBR=pObj->GetCurrentBoundRect();
94 size_t nCmpPos = nNowPos+1;
95 SdrObject* pMaxObj=GetMaxToTopObj(pObj);
96 if (pMaxObj!=nullptr)
98 size_t nMaxPos=pMaxObj->GetOrdNum();
99 if (nMaxPos!=0)
100 nMaxPos--;
101 if (nNewPos>nMaxPos)
102 nNewPos=nMaxPos; // neither go faster...
103 if (nNewPos<nNowPos)
104 nNewPos=nNowPos; // nor go in the other direction
106 bool bEnd=false;
107 while (nCmpPos<nNewPos && !bEnd)
109 SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
110 if (pCmpObj==nullptr)
112 OSL_FAIL("MovMarkedToTop(): Reference object not found.");
113 bEnd=true;
115 else if (pCmpObj==pMaxObj)
117 nNewPos=nCmpPos;
118 nNewPos--;
119 bEnd=true;
121 else if (rBR.IsOver(pCmpObj->GetCurrentBoundRect()))
123 nNewPos=nCmpPos;
124 bEnd=true;
126 else
128 nCmpPos++;
131 if (nNowPos!=nNewPos)
133 bChg=true;
134 pOL->SetObjectOrdNum(nNowPos,nNewPos);
135 if( bUndo )
136 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
137 ObjOrderChanged(pObj,nNowPos,nNewPos);
139 nNewPos--;
142 if( bUndo )
143 EndUndo();
145 if (bChg)
146 MarkListHasChanged();
150 void SdrEditView::MovMarkedToBtm()
152 const size_t nCount=GetMarkedObjectCount();
153 if (nCount!=0)
155 const bool bUndo = IsUndoEnabled();
157 if( bUndo )
158 BegUndo(ImpGetResStr(STR_EditMovToBtm),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::MoveToBottom);
160 SortMarkedObjects();
161 for (size_t nm=0; nm<nCount; ++nm)
162 { // All Ordnums have to be correct!
163 GetMarkedObjectByIndex(nm)->GetOrdNum();
166 bool bChg=false;
167 SdrObjList* pOL0=nullptr;
168 size_t nNewPos=0;
169 for (size_t nm=0; nm<nCount; ++nm)
171 SdrMark* pM=GetSdrMarkByIndex(nm);
172 SdrObject* pObj=pM->GetMarkedSdrObj();
173 SdrObjList* pOL=pObj->GetObjList();
174 if (pOL!=pOL0)
176 nNewPos=0;
177 pOL0=pOL;
179 const size_t nNowPos = pObj->GetOrdNumDirect();
180 const tools::Rectangle& rBR=pObj->GetCurrentBoundRect();
181 size_t nCmpPos = nNowPos;
182 if (nCmpPos>0)
183 --nCmpPos;
184 SdrObject* pMaxObj=GetMaxToBtmObj(pObj);
185 if (pMaxObj!=nullptr)
187 const size_t nMinPos=pMaxObj->GetOrdNum()+1;
188 if (nNewPos<nMinPos)
189 nNewPos=nMinPos; // neither go faster...
190 if (nNewPos>nNowPos)
191 nNewPos=nNowPos; // nor go in the other direction
193 bool bEnd=false;
194 // nNewPos in this case is the "maximum" position
195 // the object may reach without going faster than the object before
196 // it (multiple selection).
197 while (nCmpPos>nNewPos && !bEnd)
199 SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
200 if (pCmpObj==nullptr)
202 OSL_FAIL("MovMarkedToBtm(): Reference object not found.");
203 bEnd=true;
205 else if (pCmpObj==pMaxObj)
207 nNewPos=nCmpPos;
208 nNewPos++;
209 bEnd=true;
211 else if (rBR.IsOver(pCmpObj->GetCurrentBoundRect()))
213 nNewPos=nCmpPos;
214 bEnd=true;
216 else
218 nCmpPos--;
221 if (nNowPos!=nNewPos)
223 bChg=true;
224 pOL->SetObjectOrdNum(nNowPos,nNewPos);
225 if( bUndo )
226 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
227 ObjOrderChanged(pObj,nNowPos,nNewPos);
229 nNewPos++;
232 if(bUndo)
233 EndUndo();
235 if(bChg)
236 MarkListHasChanged();
240 void SdrEditView::PutMarkedToTop()
242 PutMarkedInFrontOfObj(nullptr);
245 void SdrEditView::PutMarkedInFrontOfObj(const SdrObject* pRefObj)
247 const size_t nCount=GetMarkedObjectCount();
248 if (nCount==0)
249 return;
251 const bool bUndo = IsUndoEnabled();
252 if( bUndo )
253 BegUndo(ImpGetResStr(STR_EditPutToTop),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::PutToTop);
255 SortMarkedObjects();
257 if (pRefObj!=nullptr)
259 // Make "in front of the object" work, even if the
260 // selected objects are already in front of the other object
261 const size_t nRefMark=TryToFindMarkedObject(pRefObj);
262 SdrMark aRefMark;
263 if (nRefMark!=SAL_MAX_SIZE)
265 aRefMark=*GetSdrMarkByIndex(nRefMark);
266 GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
268 PutMarkedToBtm();
269 if (nRefMark!=SAL_MAX_SIZE)
271 GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
272 SortMarkedObjects();
275 for (size_t nm=0; nm<nCount; ++nm)
276 { // All Ordnums have to be correct!
277 GetMarkedObjectByIndex(nm)->GetOrdNum();
279 bool bChg=false;
280 SdrObjList* pOL0=nullptr;
281 size_t nNewPos=0;
282 for (size_t nm=nCount; nm>0;)
284 --nm;
285 SdrMark* pM=GetSdrMarkByIndex(nm);
286 SdrObject* pObj=pM->GetMarkedSdrObj();
287 if (pObj!=pRefObj)
289 SdrObjList* pOL=pObj->GetObjList();
290 if (pOL!=pOL0)
292 nNewPos=pOL->GetObjCount()-1;
293 pOL0=pOL;
295 const size_t nNowPos=pObj->GetOrdNumDirect();
296 SdrObject* pMaxObj=GetMaxToTopObj(pObj);
297 if (pMaxObj!=nullptr)
299 size_t nMaxOrd=pMaxObj->GetOrdNum(); // sadly doesn't work any other way
300 if (nMaxOrd>0)
301 nMaxOrd--;
302 if (nNewPos>nMaxOrd)
303 nNewPos=nMaxOrd; // neither go faster...
304 if (nNewPos<nNowPos)
305 nNewPos=nNowPos; // nor go into the other direction
307 if (pRefObj!=nullptr)
309 if (pRefObj->GetObjList()==pObj->GetObjList())
311 const size_t nMaxOrd=pRefObj->GetOrdNum(); // sadly doesn't work any other way
312 if (nNewPos>nMaxOrd)
313 nNewPos=nMaxOrd; // neither go faster...
314 if (nNewPos<nNowPos)
315 nNewPos=nNowPos; // nor go into the other direction
317 else
319 nNewPos=nNowPos; // different PageView, so don't change
322 if (nNowPos!=nNewPos)
324 bChg=true;
325 pOL->SetObjectOrdNum(nNowPos,nNewPos);
326 if( bUndo )
327 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
328 ObjOrderChanged(pObj,nNowPos,nNewPos);
330 nNewPos--;
331 } // if (pObj!=pRefObj)
332 } // for loop over all selected objects
334 if( bUndo )
335 EndUndo();
337 if(bChg)
338 MarkListHasChanged();
341 void SdrEditView::PutMarkedToBtm()
343 PutMarkedBehindObj(nullptr);
346 void SdrEditView::PutMarkedBehindObj(const SdrObject* pRefObj)
348 const size_t nCount=GetMarkedObjectCount();
349 if (nCount==0)
350 return;
352 const bool bUndo = IsUndoEnabled();
354 if( bUndo )
355 BegUndo(ImpGetResStr(STR_EditPutToBtm),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::PutToBottom);
357 SortMarkedObjects();
358 if (pRefObj!=nullptr)
360 // Make "behind the object" work, even if the
361 // selected objects are already behind the other object
362 const size_t nRefMark=TryToFindMarkedObject(pRefObj);
363 SdrMark aRefMark;
364 if (nRefMark!=SAL_MAX_SIZE)
366 aRefMark=*GetSdrMarkByIndex(nRefMark);
367 GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
369 PutMarkedToTop();
370 if (nRefMark!=SAL_MAX_SIZE)
372 GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
373 SortMarkedObjects();
376 for (size_t nm=0; nm<nCount; ++nm) { // All Ordnums have to be correct!
377 GetMarkedObjectByIndex(nm)->GetOrdNum();
379 bool bChg=false;
380 SdrObjList* pOL0=nullptr;
381 size_t nNewPos=0;
382 for (size_t nm=0; nm<nCount; ++nm) {
383 SdrMark* pM=GetSdrMarkByIndex(nm);
384 SdrObject* pObj=pM->GetMarkedSdrObj();
385 if (pObj!=pRefObj) {
386 SdrObjList* pOL=pObj->GetObjList();
387 if (pOL!=pOL0) {
388 nNewPos=0;
389 pOL0=pOL;
391 const size_t nNowPos=pObj->GetOrdNumDirect();
392 SdrObject* pMinObj=GetMaxToBtmObj(pObj);
393 if (pMinObj!=nullptr) {
394 const size_t nMinOrd=pMinObj->GetOrdNum()+1; // sadly doesn't work any differently
395 if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster...
396 if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
398 if (pRefObj!=nullptr) {
399 if (pRefObj->GetObjList()==pObj->GetObjList()) {
400 const size_t nMinOrd=pRefObj->GetOrdNum(); // sadly doesn't work any differently
401 if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster...
402 if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
403 } else {
404 nNewPos=nNowPos; // different PageView, so don't change
407 if (nNowPos!=nNewPos) {
408 bChg=true;
409 pOL->SetObjectOrdNum(nNowPos,nNewPos);
410 if( bUndo )
411 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
412 ObjOrderChanged(pObj,nNowPos,nNewPos);
414 nNewPos++;
415 } // if (pObj!=pRefObj)
416 } // for loop over all selected objects
418 if(bUndo)
419 EndUndo();
421 if(bChg)
422 MarkListHasChanged();
426 void SdrEditView::ReverseOrderOfMarked()
428 SortMarkedObjects();
429 const size_t nMarkCount=GetMarkedObjectCount();
430 if (nMarkCount>0)
432 bool bChg=false;
434 bool bUndo = IsUndoEnabled();
435 if( bUndo )
436 BegUndo(ImpGetResStr(STR_EditRevOrder),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ReverseOrder);
438 size_t a=0;
439 do {
440 // take into account selection across multiple PageViews
441 size_t b=a+1;
442 while (b<nMarkCount && GetSdrPageViewOfMarkedByIndex(b) == GetSdrPageViewOfMarkedByIndex(a)) ++b;
443 --b;
444 SdrObjList* pOL=GetSdrPageViewOfMarkedByIndex(a)->GetObjList();
445 size_t c=b;
446 if (a<c) { // make sure OrdNums aren't dirty
447 GetMarkedObjectByIndex(a)->GetOrdNum();
449 while (a<c) {
450 SdrObject* pObj1=GetMarkedObjectByIndex(a);
451 SdrObject* pObj2=GetMarkedObjectByIndex(c);
452 const size_t nOrd1=pObj1->GetOrdNumDirect();
453 const size_t nOrd2=pObj2->GetOrdNumDirect();
454 if( bUndo )
456 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1,nOrd1,nOrd2));
457 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2,nOrd2-1,nOrd1));
459 pOL->SetObjectOrdNum(nOrd1,nOrd2);
460 // Obj 2 has moved forward by one position, so now nOrd2-1
461 pOL->SetObjectOrdNum(nOrd2-1,nOrd1);
462 // use Replace instead of SetOrdNum for performance reasons (recalculation of Ordnums)
463 ++a;
464 --c;
465 bChg=true;
467 a=b+1;
468 } while (a<nMarkCount);
470 if(bUndo)
471 EndUndo();
473 if(bChg)
474 MarkListHasChanged();
478 void SdrEditView::ImpCheckToTopBtmPossible()
480 const size_t nCount=GetMarkedObjectCount();
481 if (nCount==0)
482 return;
483 if (nCount==1)
484 { // special-casing for single selection
485 SdrObject* pObj=GetMarkedObjectByIndex(0);
486 SdrObjList* pOL=pObj->GetObjList();
487 SAL_WARN_IF(!pOL, "svx", "Object somehow has no ObjList");
488 size_t nMax = pOL ? pOL->GetObjCount() : 0;
489 size_t nMin = 0;
490 const size_t nObjNum=pObj->GetOrdNum();
491 SdrObject* pRestrict=GetMaxToTopObj(pObj);
492 if (pRestrict!=nullptr) {
493 const size_t nRestrict=pRestrict->GetOrdNum();
494 if (nRestrict<nMax) nMax=nRestrict;
496 pRestrict=GetMaxToBtmObj(pObj);
497 if (pRestrict!=nullptr) {
498 const size_t nRestrict=pRestrict->GetOrdNum();
499 if (nRestrict>nMin) nMin=nRestrict;
501 bToTopPossible=nObjNum<nMax-1;
502 bToBtmPossible=nObjNum>nMin;
503 } else { // multiple selection
504 SdrObjList* pOL0=nullptr;
505 size_t nPos0 = 0;
506 for (size_t nm = 0; !bToBtmPossible && nm<nCount; ++nm) { // check 'send to background'
507 SdrObject* pObj=GetMarkedObjectByIndex(nm);
508 SdrObjList* pOL=pObj->GetObjList();
509 if (pOL!=pOL0) {
510 nPos0 = 0;
511 pOL0=pOL;
513 const size_t nPos = pObj->GetOrdNum();
514 bToBtmPossible = nPos && (nPos-1 > nPos0);
515 nPos0 = nPos;
518 pOL0=nullptr;
519 nPos0 = SAL_MAX_SIZE;
520 for (size_t nm=nCount; !bToTopPossible && nm>0; ) { // check 'bring to front'
521 --nm;
522 SdrObject* pObj=GetMarkedObjectByIndex(nm);
523 SdrObjList* pOL=pObj->GetObjList();
524 if (pOL!=pOL0) {
525 nPos0=pOL->GetObjCount();
526 pOL0=pOL;
528 const size_t nPos = pObj->GetOrdNum();
529 bToTopPossible = nPos+1 < nPos0;
530 nPos0=nPos;
536 // Combine
539 void SdrEditView::ImpCopyAttributes(const SdrObject* pSource, SdrObject* pDest) const
541 if (pSource!=nullptr) {
542 SdrObjList* pOL=pSource->GetSubList();
543 if (pOL!=nullptr && !pSource->Is3DObj()) { // get first non-group object from group
544 SdrObjListIter aIter(*pOL,SdrIterMode::DeepNoGroups);
545 pSource=aIter.Next();
549 if(pSource && pDest)
551 SfxItemSet aSet(mpModel->GetItemPool(),
552 svl::Items<SDRATTR_START, SDRATTR_NOTPERSIST_FIRST-1,
553 SDRATTR_NOTPERSIST_LAST+1, SDRATTR_END,
554 EE_ITEMS_START, EE_ITEMS_END>{});
556 aSet.Put(pSource->GetMergedItemSet());
558 pDest->ClearMergedItem();
559 pDest->SetMergedItemSet(aSet);
561 pDest->NbcSetLayer(pSource->GetLayer());
562 pDest->NbcSetStyleSheet(pSource->GetStyleSheet(), true);
566 bool SdrEditView::ImpCanConvertForCombine1(const SdrObject* pObj)
568 // new condition IsLine() to be able to combine simple Lines
569 bool bIsLine(false);
571 const SdrPathObj* pPath = dynamic_cast< const SdrPathObj*>( pObj );
573 if(pPath)
575 bIsLine = pPath->IsLine();
578 SdrObjTransformInfoRec aInfo;
579 pObj->TakeObjInfo(aInfo);
581 return (aInfo.bCanConvToPath || aInfo.bCanConvToPoly || bIsLine);
584 bool SdrEditView::ImpCanConvertForCombine(const SdrObject* pObj)
586 SdrObjList* pOL = pObj->GetSubList();
588 if(pOL && !pObj->Is3DObj())
590 SdrObjListIter aIter(*pOL, SdrIterMode::DeepNoGroups);
592 while(aIter.IsMore())
594 SdrObject* pObj1 = aIter.Next();
596 // all members of a group have to be convertible
597 if(!ImpCanConvertForCombine1(pObj1))
599 return false;
603 else
605 if(!ImpCanConvertForCombine1(pObj))
607 return false;
611 return true;
614 basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon1(const SdrObject* pObj)
616 basegfx::B2DPolyPolygon aRetval;
617 const SdrPathObj* pPath = dynamic_cast<const SdrPathObj*>( pObj );
619 if(pPath && !pObj->GetOutlinerParaObject())
621 aRetval = pPath->GetPathPoly();
623 else
625 SdrObject* pConvObj = pObj->ConvertToPolyObj(true/*bCombine*/, false);
627 if(pConvObj)
629 SdrObjList* pOL = pConvObj->GetSubList();
631 if(pOL)
633 SdrObjListIter aIter(*pOL, SdrIterMode::DeepNoGroups);
635 while(aIter.IsMore())
637 SdrObject* pObj1 = aIter.Next();
638 pPath = dynamic_cast<SdrPathObj*>( pObj1 );
640 if(pPath)
642 aRetval.append(pPath->GetPathPoly());
646 else
648 pPath = dynamic_cast<SdrPathObj*>( pConvObj );
650 if(pPath)
652 aRetval = pPath->GetPathPoly();
656 SdrObject::Free( pConvObj );
660 return aRetval;
663 basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon(const SdrObject* pObj)
665 SdrObjList* pOL = pObj->GetSubList();
667 if(pOL && !pObj->Is3DObj())
669 basegfx::B2DPolyPolygon aRetval;
670 SdrObjListIter aIter(*pOL, SdrIterMode::DeepNoGroups);
672 while(aIter.IsMore())
674 SdrObject* pObj1 = aIter.Next();
675 aRetval.append(ImpGetPolyPolygon1(pObj1));
678 return aRetval;
680 else
682 return ImpGetPolyPolygon1(pObj);
686 basegfx::B2DPolygon SdrEditView::ImpCombineToSinglePolygon(const basegfx::B2DPolyPolygon& rPolyPolygon)
688 const sal_uInt32 nPolyCount(rPolyPolygon.count());
690 if(0 == nPolyCount)
692 return basegfx::B2DPolygon();
694 else if(1 == nPolyCount)
696 return rPolyPolygon.getB2DPolygon(0);
698 else
700 basegfx::B2DPolygon aRetval(rPolyPolygon.getB2DPolygon(0));
702 for(sal_uInt32 a(1); a < nPolyCount; a++)
704 basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
706 if(aRetval.count())
708 if(aCandidate.count())
710 const basegfx::B2DPoint aCA(aCandidate.getB2DPoint(0));
711 const basegfx::B2DPoint aCB(aCandidate.getB2DPoint(aCandidate.count() - 1));
712 const basegfx::B2DPoint aRA(aRetval.getB2DPoint(0));
713 const basegfx::B2DPoint aRB(aRetval.getB2DPoint(aRetval.count() - 1));
715 const double fRACA(basegfx::B2DVector(aCA - aRA).getLength());
716 const double fRACB(basegfx::B2DVector(aCB - aRA).getLength());
717 const double fRBCA(basegfx::B2DVector(aCA - aRB).getLength());
718 const double fRBCB(basegfx::B2DVector(aCB - aRB).getLength());
720 const double fSmallestRA(fRACA < fRACB ? fRACA : fRACB);
721 const double fSmallestRB(fRBCA < fRBCB ? fRBCA : fRBCB);
723 if(fSmallestRA < fSmallestRB)
725 // flip result
726 aRetval.flip();
729 const double fSmallestCA(fRACA < fRBCA ? fRACA : fRBCA);
730 const double fSmallestCB(fRACB < fRBCB ? fRACB : fRBCB);
732 if(fSmallestCB < fSmallestCA)
734 // flip candidate
735 aCandidate.flip();
738 // append candidate to retval
739 aRetval.append(aCandidate);
742 else
744 aRetval = aCandidate;
748 return aRetval;
752 // for distribution dialog function
753 struct ImpDistributeEntry
755 SdrObject* mpObj;
756 sal_Int32 mnPos;
757 sal_Int32 mnLength;
760 typedef vector< ImpDistributeEntry*> ImpDistributeEntryList;
762 void SdrEditView::DistributeMarkedObjects()
764 const size_t nMark(GetMarkedObjectCount());
766 if(nMark > 2)
768 SfxItemSet aNewAttr(mpModel->GetItemPool());
770 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
771 if(pFact)
773 ScopedVclPtr<AbstractSvxDistributeDialog> pDlg(pFact->CreateSvxDistributeDialog(aNewAttr));
774 DBG_ASSERT(pDlg, "Dialog creation failed!");
776 sal_uInt16 nResult = pDlg->Execute();
778 if(nResult == RET_OK)
780 SvxDistributeHorizontal eHor = pDlg->GetDistributeHor();
781 SvxDistributeVertical eVer = pDlg->GetDistributeVer();
782 ImpDistributeEntryList aEntryList;
783 ImpDistributeEntryList::iterator itEntryList;
784 sal_uInt32 nFullLength;
786 const bool bUndo = IsUndoEnabled();
787 if( bUndo )
788 BegUndo();
790 if(eHor != SvxDistributeHorizontal::NONE)
792 // build sorted entry list
793 nFullLength = 0;
795 for( size_t a = 0; a < nMark; ++a )
797 SdrMark* pMark = GetSdrMarkByIndex(a);
798 ImpDistributeEntry* pNew = new ImpDistributeEntry;
800 pNew->mpObj = pMark->GetMarkedSdrObj();
802 switch(eHor)
804 case SvxDistributeHorizontal::Left:
806 pNew->mnPos = pNew->mpObj->GetSnapRect().Left();
807 break;
809 case SvxDistributeHorizontal::Center:
811 pNew->mnPos = (pNew->mpObj->GetSnapRect().Right() + pNew->mpObj->GetSnapRect().Left()) / 2;
812 break;
814 case SvxDistributeHorizontal::Distance:
816 pNew->mnLength = pNew->mpObj->GetSnapRect().GetWidth() + 1;
817 nFullLength += pNew->mnLength;
818 pNew->mnPos = (pNew->mpObj->GetSnapRect().Right() + pNew->mpObj->GetSnapRect().Left()) / 2;
819 break;
821 case SvxDistributeHorizontal::Right:
823 pNew->mnPos = pNew->mpObj->GetSnapRect().Right();
824 break;
826 default: break;
829 for ( itEntryList = aEntryList.begin();
830 itEntryList < aEntryList.end() && (*itEntryList)->mnPos < pNew->mnPos;
831 ++itEntryList )
833 if ( itEntryList < aEntryList.end() )
834 aEntryList.insert( itEntryList, pNew );
835 else
836 aEntryList.push_back( pNew );
839 if(eHor == SvxDistributeHorizontal::Distance)
841 // calculate room in-between
842 sal_Int32 nWidth = GetAllMarkedBoundRect().GetWidth() + 1;
843 double fStepWidth = ((double)nWidth - (double)nFullLength) / (double)(aEntryList.size() - 1);
844 double fStepStart = (double)aEntryList[ 0 ]->mnPos;
845 fStepStart += fStepWidth + (double)((aEntryList[ 0 ]->mnLength + aEntryList[ 1 ]->mnLength) / 2);
847 // move entries 1..n-1
848 for( size_t i = 1, n = aEntryList.size()-1; i < n; ++i )
850 ImpDistributeEntry* pCurr = aEntryList[ i ];
851 ImpDistributeEntry* pNext = aEntryList[ i + 1];
852 sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
853 if( bUndo )
854 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
855 pCurr->mpObj->Move(Size(nDelta, 0));
856 fStepStart += fStepWidth + (double)((pCurr->mnLength + pNext->mnLength) / 2);
859 else
861 // calculate distances
862 sal_Int32 nWidth = aEntryList[ aEntryList.size() - 1 ]->mnPos - aEntryList[ 0 ]->mnPos;
863 double fStepWidth = (double)nWidth / (double)(aEntryList.size() - 1);
864 double fStepStart = (double)aEntryList[ 0 ]->mnPos;
865 fStepStart += fStepWidth;
867 // move entries 1..n-1
868 for( size_t i = 1 ; i < aEntryList.size()-1 ; ++i )
870 ImpDistributeEntry* pCurr = aEntryList[ i ];
871 sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
872 if( bUndo )
873 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
874 pCurr->mpObj->Move(Size(nDelta, 0));
875 fStepStart += fStepWidth;
879 // clear list
880 for (ImpDistributeEntry* p : aEntryList)
881 delete p;
882 aEntryList.clear();
885 if(eVer != SvxDistributeVertical::NONE)
887 // build sorted entry list
888 nFullLength = 0;
890 for( size_t a = 0; a < nMark; ++a )
892 SdrMark* pMark = GetSdrMarkByIndex(a);
893 ImpDistributeEntry* pNew = new ImpDistributeEntry;
895 pNew->mpObj = pMark->GetMarkedSdrObj();
897 switch(eVer)
899 case SvxDistributeVertical::Top:
901 pNew->mnPos = pNew->mpObj->GetSnapRect().Top();
902 break;
904 case SvxDistributeVertical::Center:
906 pNew->mnPos = (pNew->mpObj->GetSnapRect().Bottom() + pNew->mpObj->GetSnapRect().Top()) / 2;
907 break;
909 case SvxDistributeVertical::Distance:
911 pNew->mnLength = pNew->mpObj->GetSnapRect().GetHeight() + 1;
912 nFullLength += pNew->mnLength;
913 pNew->mnPos = (pNew->mpObj->GetSnapRect().Bottom() + pNew->mpObj->GetSnapRect().Top()) / 2;
914 break;
916 case SvxDistributeVertical::Bottom:
918 pNew->mnPos = pNew->mpObj->GetSnapRect().Bottom();
919 break;
921 default: break;
924 for ( itEntryList = aEntryList.begin();
925 itEntryList < aEntryList.end() && (*itEntryList)->mnPos < pNew->mnPos;
926 ++itEntryList )
928 if ( itEntryList < aEntryList.end() )
929 aEntryList.insert( itEntryList, pNew );
930 else
931 aEntryList.push_back( pNew );
934 if(eVer == SvxDistributeVertical::Distance)
936 // calculate room in-between
937 sal_Int32 nHeight = GetAllMarkedBoundRect().GetHeight() + 1;
938 double fStepWidth = ((double)nHeight - (double)nFullLength) / (double)(aEntryList.size() - 1);
939 double fStepStart = (double)aEntryList[ 0 ]->mnPos;
940 fStepStart += fStepWidth + (double)((aEntryList[ 0 ]->mnLength + aEntryList[ 1 ]->mnLength) / 2);
942 // move entries 1..n-1
943 for( size_t i = 1, n = aEntryList.size()-1; i < n; ++i)
945 ImpDistributeEntry* pCurr = aEntryList[ i ];
946 ImpDistributeEntry* pNext = aEntryList[ i + 1 ];
947 sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
948 if( bUndo )
949 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
950 pCurr->mpObj->Move(Size(0, nDelta));
951 fStepStart += fStepWidth + (double)((pCurr->mnLength + pNext->mnLength) / 2);
954 else
956 // calculate distances
957 sal_Int32 nHeight = aEntryList[ aEntryList.size() - 1 ]->mnPos - aEntryList[ 0 ]->mnPos;
958 double fStepWidth = (double)nHeight / (double)(aEntryList.size() - 1);
959 double fStepStart = (double)aEntryList[ 0 ]->mnPos;
960 fStepStart += fStepWidth;
962 // move entries 1..n-1
963 for(size_t i = 1, n = aEntryList.size()-1; i < n; ++i)
965 ImpDistributeEntry* pCurr = aEntryList[ i ];
966 sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
967 if( bUndo )
968 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
969 pCurr->mpObj->Move(Size(0, nDelta));
970 fStepStart += fStepWidth;
974 // clear list
975 for (ImpDistributeEntry* p : aEntryList)
976 delete p;
977 aEntryList.clear();
980 // UNDO-Comment and end of UNDO
981 mpModel->SetUndoComment(ImpGetResStr(STR_DistributeMarkedObjects));
983 if( bUndo )
984 EndUndo();
990 void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode)
992 // #i73441# check content
993 if(!AreObjectsMarked())
994 return;
996 SdrMarkList aRemove;
997 SortMarkedObjects();
999 const bool bUndo = IsUndoEnabled();
1001 if( bUndo )
1002 BegUndo();
1004 size_t nInsPos = SAL_MAX_SIZE;
1005 const SdrObject* pAttrObj = nullptr;
1006 basegfx::B2DPolyPolygon aMergePolyPolygonA;
1007 basegfx::B2DPolyPolygon aMergePolyPolygonB;
1009 SdrObjList* pInsOL = nullptr;
1010 SdrPageView* pInsPV = nullptr;
1011 bool bFirstObjectComplete(false);
1013 // make sure selected objects are contour objects
1014 // since now basegfx::utils::adaptiveSubdivide() is used, it is no longer
1015 // necessary to use ConvertMarkedToPolyObj which will subdivide curves using the old
1016 // mechanisms. In a next step the polygon clipper will even be able to clip curves...
1017 // ConvertMarkedToPolyObj(true);
1018 ConvertMarkedToPathObj(true);
1019 OSL_ENSURE(AreObjectsMarked(), "no more objects selected after preparations (!)");
1021 for(size_t a=0; a<GetMarkedObjectCount(); ++a)
1023 SdrMark* pM = GetSdrMarkByIndex(a);
1024 SdrObject* pObj = pM->GetMarkedSdrObj();
1026 if(ImpCanConvertForCombine(pObj))
1028 if(!pAttrObj)
1029 pAttrObj = pObj;
1031 nInsPos = pObj->GetOrdNum() + 1;
1032 pInsPV = pM->GetPageView();
1033 pInsOL = pObj->GetObjList();
1035 // #i76891# use single iteration from SJ here which works on SdrObjects and takes
1036 // groups into account by itself
1037 SdrObjListIter aIter(*pObj, SdrIterMode::DeepWithGroups);
1039 while(aIter.IsMore())
1041 SdrObject* pCandidate = aIter.Next();
1042 SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>( pCandidate );
1043 if(pPathObj)
1045 basegfx::B2DPolyPolygon aTmpPoly(pPathObj->GetPathPoly());
1047 // #i76891# unfortunately ConvertMarkedToPathObj has converted all
1048 // involved polygon data to curve segments, even if not necessary.
1049 // It is better to try to reduce to more simple polygons.
1050 aTmpPoly = basegfx::utils::simplifyCurveSegments(aTmpPoly);
1052 // for each part polygon as preparation, remove self-intersections
1053 // correct orientations and get rid of possible neutral polygons.
1054 aTmpPoly = basegfx::utils::prepareForPolygonOperation(aTmpPoly);
1056 if(!bFirstObjectComplete)
1058 // #i111987# Also need to collect ORed source shape when more than
1059 // a single polygon is involved
1060 if(aMergePolyPolygonA.count())
1062 aMergePolyPolygonA = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA, aTmpPoly);
1064 else
1066 aMergePolyPolygonA = aTmpPoly;
1069 else
1071 if(aMergePolyPolygonB.count())
1073 // to topologically correctly collect the 2nd polygon
1074 // group it is necessary to OR the parts (each is seen as
1075 // XOR-FillRule polygon and they are drawn over each-other)
1076 aMergePolyPolygonB = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonB, aTmpPoly);
1078 else
1080 aMergePolyPolygonB = aTmpPoly;
1086 // was there something added to the first polygon?
1087 if(!bFirstObjectComplete && aMergePolyPolygonA.count())
1089 bFirstObjectComplete = true;
1092 // move object to temporary delete list
1093 aRemove.InsertEntry(SdrMark(pObj, pM->GetPageView()));
1097 switch(eMode)
1099 case SdrMergeMode::Merge:
1101 // merge all contained parts (OR)
1102 static bool bTestXOR(false);
1103 if(bTestXOR)
1105 aMergePolyPolygonA = basegfx::utils::solvePolygonOperationXor(aMergePolyPolygonA, aMergePolyPolygonB);
1107 else
1109 aMergePolyPolygonA = basegfx::utils::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB);
1111 break;
1113 case SdrMergeMode::Subtract:
1115 // Subtract B from A
1116 aMergePolyPolygonA = basegfx::utils::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB);
1117 break;
1119 case SdrMergeMode::Intersect:
1121 // AND B and A
1122 aMergePolyPolygonA = basegfx::utils::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB);
1123 break;
1127 // #i73441# check insert list before taking actions
1128 if(pInsOL)
1130 SdrPathObj* pPath = new SdrPathObj(OBJ_PATHFILL, aMergePolyPolygonA);
1131 ImpCopyAttributes(pAttrObj, pPath);
1132 pInsOL->InsertObject(pPath, nInsPos);
1133 if( bUndo )
1134 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
1136 // #i124760# To have a correct selection with only the new object it is necessary to
1137 // unmark all objects first. If not doing so, there may remain invalid pointers to objects
1138 //TTTT:Not needed for aw080 (!)
1139 UnmarkAllObj(pInsPV);
1141 MarkObj(pPath, pInsPV, false, true);
1144 aRemove.ForceSort();
1145 switch(eMode)
1147 case SdrMergeMode::Merge:
1149 SetUndoComment(
1150 ImpGetResStr(STR_EditMergeMergePoly),
1151 aRemove.GetMarkDescription());
1152 break;
1154 case SdrMergeMode::Subtract:
1156 SetUndoComment(
1157 ImpGetResStr(STR_EditMergeSubstractPoly),
1158 aRemove.GetMarkDescription());
1159 break;
1161 case SdrMergeMode::Intersect:
1163 SetUndoComment(
1164 ImpGetResStr(STR_EditMergeIntersectPoly),
1165 aRemove.GetMarkDescription());
1166 break;
1169 DeleteMarkedList(aRemove);
1171 if( bUndo )
1172 EndUndo();
1175 void SdrEditView::EqualizeMarkedObjects(bool bWidth)
1177 const SdrMarkList& rMarkList = GetMarkedObjectList();
1178 size_t nMarked = rMarkList.GetMarkCount();
1180 if (nMarked < 2)
1181 return;
1183 size_t nLastSelected = 0;
1184 sal_Int64 nLastSelectedTime = rMarkList.GetMark(0)->getTimeStamp();
1185 for (size_t a = 1; a < nMarked; ++a)
1187 sal_Int64 nCandidateTime = rMarkList.GetMark(a)->getTimeStamp();
1188 if (nCandidateTime > nLastSelectedTime)
1190 nLastSelectedTime = nCandidateTime;
1191 nLastSelected = a;
1195 SdrObject* pLastSelectedObj = rMarkList.GetMark(nLastSelected)->GetMarkedSdrObj();
1196 Size aLastRectSize(pLastSelectedObj->GetLogicRect().GetSize());
1198 const bool bUndo = IsUndoEnabled();
1200 if (bUndo)
1201 BegUndo();
1203 for (size_t a = 0; a < nMarked; ++a)
1205 if (a == nLastSelected)
1206 continue;
1207 SdrMark* pM = rMarkList.GetMark(a);
1208 SdrObject* pObj = pM->GetMarkedSdrObj();
1209 tools::Rectangle aLogicRect(pObj->GetLogicRect());
1210 Size aLogicRectSize(aLogicRect.GetSize());
1211 if (bWidth)
1212 aLogicRectSize.Width() = aLastRectSize.Width();
1213 else
1214 aLogicRectSize.Height() = aLastRectSize.Height();
1215 aLogicRect.SetSize(aLogicRectSize);
1216 if (bUndo)
1217 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
1218 pObj->SetLogicRect(aLogicRect);
1221 SetUndoComment(
1222 ImpGetResStr(bWidth ? STR_EqualizeWidthMarkedObjects : STR_EqualizeHeightMarkedObjects),
1223 rMarkList.GetMarkDescription());
1225 if (bUndo)
1226 EndUndo();
1229 void SdrEditView::CombineMarkedObjects(bool bNoPolyPoly)
1231 // #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
1232 // create a 2nd Undo-action and Undo-Comment.
1234 bool bUndo = IsUndoEnabled();
1236 // Undo-String will be set later
1237 if( bUndo )
1238 BegUndo("", "", bNoPolyPoly ? SdrRepeatFunc::CombineOnePoly : SdrRepeatFunc::CombinePolyPoly);
1240 // #105899# First, guarantee that all objects are converted to polyobjects,
1241 // especially for SdrGrafObj with bitmap filling this is necessary to not
1242 // lose the bitmap filling.
1244 // #i12392#
1245 // ConvertMarkedToPolyObj was too strong here, it will lose quality and
1246 // information when curve objects are combined. This can be replaced by
1247 // using ConvertMarkedToPathObj without changing the previous fix.
1249 // #i21250#
1250 // Instead of simply passing true as LineToArea, use bNoPolyPoly as info
1251 // if this command is a 'Combine' or a 'Connect' command. On Connect it's true.
1252 // To not concert line segments with a set line width to polygons in that case,
1253 // use this info. Do not convert LineToArea on Connect commands.
1254 // ConvertMarkedToPathObj(!bNoPolyPoly);
1256 // This is used for Combine and Connect. In no case it is necessary to force
1257 // the content to curve, but it is also not good to force to polygons. Thus,
1258 // curve is the less information losing one. Remember: This place is not
1259 // used for merge.
1260 // LineToArea is never necessary, both commands are able to take over the
1261 // set line style and to display it correctly. Thus, i will use a
1262 // ConvertMarkedToPathObj with a false in any case. Only drawback is that
1263 // simple polygons will be changed to curves, but with no information loss.
1264 ConvertMarkedToPathObj(false /* bLineToArea */);
1266 // continue as before
1267 basegfx::B2DPolyPolygon aPolyPolygon;
1268 SdrObjList* pAktOL = nullptr;
1269 SdrMarkList aRemoveMerker;
1271 SortMarkedObjects();
1272 size_t nInsPos = SAL_MAX_SIZE;
1273 SdrObjList* pInsOL = nullptr;
1274 SdrPageView* pInsPV = nullptr;
1275 const SdrObject* pAttrObj = nullptr;
1277 for(size_t a = GetMarkedObjectCount(); a; )
1279 --a;
1280 SdrMark* pM = GetSdrMarkByIndex(a);
1281 SdrObject* pObj = pM->GetMarkedSdrObj();
1282 SdrObjList* pThisOL = pObj->GetObjList();
1284 if(pAktOL != pThisOL)
1286 pAktOL = pThisOL;
1289 if(ImpCanConvertForCombine(pObj))
1291 // remember objects to be able to copy attributes
1292 pAttrObj = pObj;
1294 // unfortunately ConvertMarkedToPathObj has converted all
1295 // involved polygon data to curve segments, even if not necessary.
1296 // It is better to try to reduce to more simple polygons.
1297 basegfx::B2DPolyPolygon aTmpPoly(basegfx::utils::simplifyCurveSegments(ImpGetPolyPolygon(pObj)));
1298 aPolyPolygon.insert(0L, aTmpPoly);
1300 if(!pInsOL)
1302 nInsPos = pObj->GetOrdNum() + 1;
1303 pInsPV = pM->GetPageView();
1304 pInsOL = pObj->GetObjList();
1307 aRemoveMerker.InsertEntry(SdrMark(pObj, pM->GetPageView()));
1311 if(bNoPolyPoly)
1313 basegfx::B2DPolygon aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon));
1314 aPolyPolygon.clear();
1315 aPolyPolygon.append(aCombinedPolygon);
1318 const sal_uInt32 nPolyCount(aPolyPolygon.count());
1320 if (nPolyCount && pAttrObj)
1322 SdrObjKind eKind = OBJ_PATHFILL;
1324 if(nPolyCount > 1)
1326 aPolyPolygon.setClosed(true);
1328 else
1330 // check for Polyline
1331 const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0));
1332 const sal_uInt32 nPointCount(aPolygon.count());
1334 if(nPointCount <= 2)
1336 eKind = OBJ_PATHLINE;
1338 else
1340 if(!aPolygon.isClosed())
1342 const basegfx::B2DPoint aPointA(aPolygon.getB2DPoint(0));
1343 const basegfx::B2DPoint aPointB(aPolygon.getB2DPoint(nPointCount - 1));
1344 const double fDistance(basegfx::B2DVector(aPointB - aPointA).getLength());
1345 const double fJoinTolerance(10.0);
1347 if(fDistance < fJoinTolerance)
1349 aPolyPolygon.setClosed(true);
1351 else
1353 eKind = OBJ_PATHLINE;
1359 SdrPathObj* pPath = new SdrPathObj(eKind,aPolyPolygon);
1361 // attributes of the lowest object
1362 ImpCopyAttributes(pAttrObj, pPath);
1364 // If LineStyle of pAttrObj is drawing::LineStyle_NONE force to drawing::LineStyle_SOLID to make visible.
1365 const drawing::LineStyle eLineStyle = pAttrObj->GetMergedItem(XATTR_LINESTYLE).GetValue();
1366 const drawing::FillStyle eFillStyle = pAttrObj->GetMergedItem(XATTR_FILLSTYLE).GetValue();
1368 // Take fill style/closed state of pAttrObj in account when deciding to change the line style
1369 bool bIsClosedPathObj(dynamic_cast<const SdrPathObj*>( pAttrObj) != nullptr && static_cast<const SdrPathObj*>(pAttrObj)->IsClosed());
1371 if(drawing::LineStyle_NONE == eLineStyle && (drawing::FillStyle_NONE == eFillStyle || !bIsClosedPathObj))
1373 pPath->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
1376 pInsOL->InsertObject(pPath,nInsPos);
1377 if( bUndo )
1378 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
1380 // Here was a severe error: Without UnmarkAllObj, the new object was marked
1381 // additionally to the two ones which are deleted below. As long as those are
1382 // in the UNDO there is no problem, but as soon as they get deleted, the
1383 // MarkList will contain deleted objects -> GPF.
1384 UnmarkAllObj(pInsPV);
1385 MarkObj(pPath, pInsPV, false, true);
1388 // build an UndoComment from the objects actually used
1389 aRemoveMerker.ForceSort(); // important for remove (see below)
1390 if( bUndo )
1391 SetUndoComment(ImpGetResStr(bNoPolyPoly?STR_EditCombine_OnePoly:STR_EditCombine_PolyPoly),aRemoveMerker.GetMarkDescription());
1393 // remove objects actually used from the list
1394 DeleteMarkedList(aRemoveMerker);
1395 if( bUndo )
1396 EndUndo();
1400 // Dismantle
1403 bool SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon& rPpolyPolygon, bool bMakeLines)
1405 bool bCan(false);
1406 const sal_uInt32 nPolygonCount(rPpolyPolygon.count());
1408 if(nPolygonCount >= 2)
1410 // #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
1411 bCan = true;
1413 else if(bMakeLines && 1 == nPolygonCount)
1415 // #i69172# ..or with at least 2 edges (curves or lines)
1416 const basegfx::B2DPolygon aPolygon(rPpolyPolygon.getB2DPolygon(0));
1417 const sal_uInt32 nPointCount(aPolygon.count());
1419 if(nPointCount > 2)
1421 bCan = true;
1425 return bCan;
1428 bool SdrEditView::ImpCanDismantle(const SdrObject* pObj, bool bMakeLines)
1430 bool bOtherObjs(false); // true=objects other than PathObj's existent
1431 bool bMin1PolyPoly(false); // true=at least 1 tools::PolyPolygon with more than one Polygon existent
1432 SdrObjList* pOL = pObj->GetSubList();
1434 if(pOL)
1436 // group object -- check all members if they're PathObjs
1437 SdrObjListIter aIter(*pOL, SdrIterMode::DeepNoGroups);
1439 while(aIter.IsMore() && !bOtherObjs)
1441 const SdrObject* pObj1 = aIter.Next();
1442 const SdrPathObj* pPath = dynamic_cast<const SdrPathObj*>( pObj1 );
1444 if(pPath)
1446 if(ImpCanDismantle(pPath->GetPathPoly(), bMakeLines))
1448 bMin1PolyPoly = true;
1451 SdrObjTransformInfoRec aInfo;
1452 pObj1->TakeObjInfo(aInfo);
1454 if(!aInfo.bCanConvToPath)
1456 // happens e. g. in the case of FontWork
1457 bOtherObjs = true;
1460 else
1462 bOtherObjs = true;
1466 else
1468 const SdrPathObj* pPath = dynamic_cast<const SdrPathObj*>(pObj);
1469 const SdrObjCustomShape* pCustomShape = dynamic_cast<const SdrObjCustomShape*>(pObj);
1471 // #i37011#
1472 if(pPath)
1474 if(ImpCanDismantle(pPath->GetPathPoly(),bMakeLines))
1476 bMin1PolyPoly = true;
1479 SdrObjTransformInfoRec aInfo;
1480 pObj->TakeObjInfo(aInfo);
1482 // new condition IsLine() to be able to break simple Lines
1483 if(!(aInfo.bCanConvToPath || aInfo.bCanConvToPoly) && !pPath->IsLine())
1485 // happens e. g. in the case of FontWork
1486 bOtherObjs = true;
1489 else if(pCustomShape)
1491 if(bMakeLines)
1493 // allow break command
1494 bMin1PolyPoly = true;
1497 else
1499 bOtherObjs = true;
1502 return bMin1PolyPoly && !bOtherObjs;
1505 void SdrEditView::ImpDismantleOneObject(const SdrObject* pObj, SdrObjList& rOL, size_t& rPos, SdrPageView* pPV, bool bMakeLines)
1507 const SdrPathObj* pSrcPath = dynamic_cast<const SdrPathObj*>( pObj );
1508 const SdrObjCustomShape* pCustomShape = dynamic_cast<const SdrObjCustomShape*>( pObj );
1510 const bool bUndo = IsUndoEnabled();
1512 if(pSrcPath)
1514 // #i74631# redesigned due to XpolyPolygon removal and explicit constructors
1515 SdrObject* pLast = nullptr; // to be able to apply OutlinerParaObject
1516 const basegfx::B2DPolyPolygon& rPolyPolygon(pSrcPath->GetPathPoly());
1517 const sal_uInt32 nPolyCount(rPolyPolygon.count());
1519 for(sal_uInt32 a(0); a < nPolyCount; a++)
1521 const basegfx::B2DPolygon& rCandidate(rPolyPolygon.getB2DPolygon(a));
1522 const sal_uInt32 nPointCount(rCandidate.count());
1524 if(!bMakeLines || nPointCount < 2)
1526 SdrPathObj* pPath = new SdrPathObj((SdrObjKind)pSrcPath->GetObjIdentifier(), basegfx::B2DPolyPolygon(rCandidate));
1527 ImpCopyAttributes(pSrcPath, pPath);
1528 pLast = pPath;
1529 rOL.InsertObject(pPath, rPos);
1530 if( bUndo )
1531 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, true));
1532 MarkObj(pPath, pPV, false, true);
1533 rPos++;
1535 else
1537 const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
1539 for(sal_uInt32 b(0); b < nLoopCount; b++)
1541 SdrObjKind eKind(OBJ_PLIN);
1542 basegfx::B2DPolygon aNewPolygon;
1543 const sal_uInt32 nNextIndex((b + 1) % nPointCount);
1545 aNewPolygon.append(rCandidate.getB2DPoint(b));
1547 if(rCandidate.areControlPointsUsed())
1549 aNewPolygon.appendBezierSegment(
1550 rCandidate.getNextControlPoint(b),
1551 rCandidate.getPrevControlPoint(nNextIndex),
1552 rCandidate.getB2DPoint(nNextIndex));
1553 eKind = OBJ_PATHLINE;
1555 else
1557 aNewPolygon.append(rCandidate.getB2DPoint(nNextIndex));
1560 SdrPathObj* pPath = new SdrPathObj(eKind, basegfx::B2DPolyPolygon(aNewPolygon));
1561 ImpCopyAttributes(pSrcPath, pPath);
1562 pLast = pPath;
1563 rOL.InsertObject(pPath, rPos);
1564 if( bUndo )
1565 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, true));
1566 MarkObj(pPath, pPV, false, true);
1567 rPos++;
1572 if(pLast && pSrcPath->GetOutlinerParaObject())
1574 pLast->SetOutlinerParaObject(new OutlinerParaObject(*pSrcPath->GetOutlinerParaObject()));
1577 else if(pCustomShape)
1579 if(bMakeLines)
1581 // break up custom shape
1582 const SdrObject* pReplacement = pCustomShape->GetSdrObjectFromCustomShape();
1584 if(pReplacement)
1586 SdrObject* pCandidate = pReplacement->Clone();
1587 DBG_ASSERT(pCandidate, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
1588 pCandidate->SetModel(pCustomShape->GetModel());
1590 if(pCustomShape->GetMergedItem(SDRATTR_SHADOW).GetValue())
1592 if(dynamic_cast<const SdrObjGroup*>( pReplacement) != nullptr)
1594 pCandidate->SetMergedItem(makeSdrShadowItem(true));
1598 rOL.InsertObject(pCandidate, rPos);
1599 if( bUndo )
1600 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pCandidate, true));
1601 MarkObj(pCandidate, pPV, false, true);
1603 if(pCustomShape->HasText() && !pCustomShape->IsTextPath())
1605 // #i37011# also create a text object and add at rPos + 1
1606 SdrObject* pTextObj = SdrObjFactory::MakeNewObject(
1607 pCustomShape->GetObjInventor(), OBJ_TEXT, nullptr, pCustomShape->GetModel());
1609 // Copy text content
1610 OutlinerParaObject* pParaObj = pCustomShape->GetOutlinerParaObject();
1611 if(pParaObj)
1613 pTextObj->NbcSetOutlinerParaObject(new OutlinerParaObject(*pParaObj));
1616 // copy all attributes
1617 SfxItemSet aTargetItemSet(pCustomShape->GetMergedItemSet());
1619 // clear fill and line style
1620 aTargetItemSet.Put(XLineStyleItem(drawing::LineStyle_NONE));
1621 aTargetItemSet.Put(XFillStyleItem(drawing::FillStyle_NONE));
1623 // get the text bounds and set at text object
1624 tools::Rectangle aTextBounds = pCustomShape->GetSnapRect();
1625 if(pCustomShape->GetTextBounds(aTextBounds))
1627 pTextObj->SetSnapRect(aTextBounds);
1630 // if rotated, copy GeoStat, too.
1631 const GeoStat& rSourceGeo = pCustomShape->GetGeoStat();
1632 if(rSourceGeo.nRotationAngle)
1634 pTextObj->NbcRotate(
1635 pCustomShape->GetSnapRect().Center(), rSourceGeo.nRotationAngle,
1636 rSourceGeo.nSin, rSourceGeo.nCos);
1639 // set modified ItemSet at text object
1640 pTextObj->SetMergedItemSet(aTargetItemSet);
1642 // insert object
1643 rOL.InsertObject(pTextObj, rPos + 1);
1644 if( bUndo )
1645 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pTextObj, true));
1646 MarkObj(pTextObj, pPV, false, true);
1653 void SdrEditView::DismantleMarkedObjects(bool bMakeLines)
1655 // temporary MarkList
1656 SdrMarkList aRemoveMerker;
1658 SortMarkedObjects();
1660 const bool bUndo = IsUndoEnabled();
1662 if( bUndo )
1664 // comment is constructed later
1665 BegUndo("", "", bMakeLines ? SdrRepeatFunc::DismantleLines : SdrRepeatFunc::DismantlePolys);
1668 SdrObjList* pOL0=nullptr;
1669 for (size_t nm=GetMarkedObjectCount(); nm>0;) {
1670 --nm;
1671 SdrMark* pM=GetSdrMarkByIndex(nm);
1672 SdrObject* pObj=pM->GetMarkedSdrObj();
1673 SdrPageView* pPV=pM->GetPageView();
1674 SdrObjList* pOL=pObj->GetObjList();
1675 if (pOL!=pOL0) { pOL0=pOL; pObj->GetOrdNum(); } // make sure OrdNums are correct!
1676 if (ImpCanDismantle(pObj,bMakeLines)) {
1677 aRemoveMerker.InsertEntry(SdrMark(pObj,pM->GetPageView()));
1678 const size_t nPos0=pObj->GetOrdNumDirect();
1679 size_t nPos=nPos0+1;
1680 SdrObjList* pSubList=pObj->GetSubList();
1681 if (pSubList!=nullptr && !pObj->Is3DObj()) {
1682 SdrObjListIter aIter(*pSubList,SdrIterMode::DeepNoGroups);
1683 while (aIter.IsMore()) {
1684 const SdrObject* pObj1=aIter.Next();
1685 ImpDismantleOneObject(pObj1,*pOL,nPos,pPV,bMakeLines);
1687 } else {
1688 ImpDismantleOneObject(pObj,*pOL,nPos,pPV,bMakeLines);
1690 if( bUndo )
1691 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj,true));
1692 pOL->RemoveObject(nPos0);
1694 if( !bUndo )
1695 SdrObject::Free(pObj);
1699 if( bUndo )
1701 // construct UndoComment from objects actually used
1702 SetUndoComment(ImpGetResStr(bMakeLines?STR_EditDismantle_Lines:STR_EditDismantle_Polys),aRemoveMerker.GetMarkDescription());
1703 // remove objects actually used from the list
1704 EndUndo();
1709 // Group
1712 void SdrEditView::GroupMarked()
1714 if (AreObjectsMarked())
1716 SortMarkedObjects();
1718 const bool bUndo = IsUndoEnabled();
1719 if( bUndo )
1721 BegUndo(ImpGetResStr(STR_EditGroup),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::Group);
1723 for(size_t nm = GetMarkedObjectCount(); nm>0; )
1725 // add UndoActions for all affected objects
1726 --nm;
1727 SdrMark* pM=GetSdrMarkByIndex(nm);
1728 SdrObject* pObj = pM->GetMarkedSdrObj();
1729 std::vector< SdrUndoAction* > vConnectorUndoActions( CreateConnectorUndo( *pObj ) );
1730 AddUndoActions( vConnectorUndoActions );
1731 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject( *pObj ));
1735 SdrMarkList aNewMark;
1736 SdrPageView* pPV = GetSdrPageView();
1738 if(pPV)
1740 SdrObjList* pAktLst=pPV->GetObjList();
1741 SdrObjList* pSrcLst=pAktLst;
1742 SdrObjList* pSrcLst0=pSrcLst;
1743 // make sure OrdNums are correct
1744 if (pSrcLst->IsObjOrdNumsDirty())
1745 pSrcLst->RecalcObjOrdNums();
1746 SdrObject* pGrp=nullptr;
1747 SdrObjList* pDstLst=nullptr;
1748 // if all selected objects come from foreign object lists.
1749 // the group object is the last one in the list.
1750 size_t nInsPos=pSrcLst->GetObjCount();
1751 bool bNeedInsPos=true;
1752 for (size_t nm=GetMarkedObjectCount(); nm>0;)
1754 --nm;
1755 SdrMark* pM=GetSdrMarkByIndex(nm);
1756 if (pM->GetPageView()==pPV)
1758 if (pGrp==nullptr)
1760 if (pGrp==nullptr)
1761 pGrp=new SdrObjGroup;
1762 pDstLst=pGrp->GetSubList();
1763 DBG_ASSERT(pDstLst!=nullptr,"Alleged group object doesn't return object list.");
1765 SdrObject* pObj=pM->GetMarkedSdrObj();
1766 pSrcLst=pObj->GetObjList();
1767 if (pSrcLst!=pSrcLst0)
1769 if (pSrcLst->IsObjOrdNumsDirty())
1770 pSrcLst->RecalcObjOrdNums();
1772 bool bForeignList=pSrcLst!=pAktLst;
1773 if (!bForeignList && bNeedInsPos)
1775 nInsPos=pObj->GetOrdNum(); // this way, all ObjOrdNum of the page are set
1776 nInsPos++;
1777 bNeedInsPos=false;
1779 pSrcLst->RemoveObject(pObj->GetOrdNumDirect());
1780 if (!bForeignList)
1781 nInsPos--; // correct InsertPos
1782 pDstLst->InsertObject(pObj,0);
1783 GetMarkedObjectListWriteAccess().DeleteMark(nm);
1784 pSrcLst0=pSrcLst;
1787 if (pGrp!=nullptr)
1789 aNewMark.InsertEntry(SdrMark(pGrp,pPV));
1790 const size_t nCount=pDstLst->GetObjCount();
1791 pAktLst->InsertObject(pGrp,nInsPos);
1792 if( bUndo )
1794 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pGrp,true)); // no recalculation!
1795 for (size_t no=0; no<nCount; ++no)
1797 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst->GetObj(no)));
1802 GetMarkedObjectListWriteAccess().Merge(aNewMark);
1803 MarkListHasChanged();
1805 if( bUndo )
1806 EndUndo();
1811 // Ungroup
1814 void SdrEditView::UnGroupMarked()
1816 SdrMarkList aNewMark;
1818 const bool bUndo = IsUndoEnabled();
1819 if( bUndo )
1820 BegUndo("", "", SdrRepeatFunc::Ungroup);
1822 size_t nCount=0;
1823 OUString aName1;
1824 OUString aName;
1825 bool bNameOk=false;
1826 for (size_t nm=GetMarkedObjectCount(); nm>0;) {
1827 --nm;
1828 SdrMark* pM=GetSdrMarkByIndex(nm);
1829 SdrObject* pGrp=pM->GetMarkedSdrObj();
1830 SdrObjList* pSrcLst=pGrp->GetSubList();
1831 if (pSrcLst!=nullptr) {
1832 nCount++;
1833 if (nCount==1) {
1834 aName = pGrp->TakeObjNameSingul(); // retrieve name of group
1835 aName1 = pGrp->TakeObjNamePlural(); // retrieve name of group
1836 bNameOk=true;
1837 } else {
1838 if (nCount==2) aName=aName1; // set plural name
1839 if (bNameOk) {
1840 OUString aStr(pGrp->TakeObjNamePlural()); // retrieve name of group
1842 if (aStr != aName)
1843 bNameOk = false;
1846 size_t nDstCnt=pGrp->GetOrdNum();
1847 SdrObjList* pDstLst=pM->GetPageView()->GetObjList();
1849 // FIRST move contained objects to parent of group, so that
1850 // the contained objects are NOT migrated to the UNDO-ItemPool
1851 // when AddUndo(new SdrUndoDelObj(*pGrp)) is called.
1852 const size_t nObjCount=pSrcLst->GetObjCount();
1854 if( bUndo )
1856 for (size_t no=nObjCount; no>0;)
1858 no--;
1859 SdrObject* pObj=pSrcLst->GetObj(no);
1860 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject(*pObj));
1863 for (size_t no=0; no<nObjCount; ++no)
1865 SdrObject* pObj=pSrcLst->RemoveObject(0);
1866 pDstLst->InsertObject(pObj,nDstCnt);
1867 if( bUndo )
1868 AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pObj,true));
1869 nDstCnt++;
1870 // No SortCheck when inserting into MarkList, because that would
1871 // provoke a RecalcOrdNums() each time because of pObj->GetOrdNum():
1872 aNewMark.InsertEntry(SdrMark(pObj,pM->GetPageView()),false);
1875 if( bUndo )
1877 // Now it is safe to add the delete-UNDO which triggers the
1878 // MigrateItemPool now only for itself, not for the sub-objects.
1879 // nDstCnt is right, because previous inserts move group
1880 // object deeper and increase nDstCnt.
1881 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp));
1883 pDstLst->RemoveObject(nDstCnt);
1885 if( !bUndo )
1886 SdrObject::Free(pGrp);
1888 GetMarkedObjectListWriteAccess().DeleteMark(nm);
1891 if (nCount!=0)
1893 if (!bNameOk)
1894 aName=ImpGetResStr(STR_ObjNamePluralGRUP); // Use the term "Group Objects," if different objects are grouped.
1895 SetUndoComment(ImpGetResStr(STR_EditUngroup),aName);
1898 if( bUndo )
1899 EndUndo();
1901 if (nCount!=0)
1903 GetMarkedObjectListWriteAccess().Merge(aNewMark,true); // Because of the sorting above, aNewMark is reversed
1904 MarkListHasChanged();
1909 // ConvertToPoly
1912 SdrObject* SdrEditView::ImpConvertOneObj(SdrObject* pObj, bool bPath, bool bLineToArea)
1914 SdrObject* pNewObj = pObj->ConvertToPolyObj(bPath, bLineToArea);
1915 if (pNewObj!=nullptr)
1917 SdrObjList* pOL=pObj->GetObjList();
1918 DBG_ASSERT(pOL!=nullptr,"ConvertTo: Object doesn't return object list");
1919 if (pOL!=nullptr)
1921 const bool bUndo = IsUndoEnabled();
1922 if( bUndo )
1923 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoReplaceObject(*pObj,*pNewObj));
1925 pOL->ReplaceObject(pNewObj,pObj->GetOrdNum());
1927 if( !bUndo )
1928 SdrObject::Free(pObj);
1931 return pNewObj;
1934 void SdrEditView::ImpConvertTo(bool bPath, bool bLineToArea)
1936 if (AreObjectsMarked()) {
1937 bool bMrkChg = false;
1938 const size_t nMarkCount=GetMarkedObjectCount();
1939 const char* pDscrID = nullptr;
1940 if(bLineToArea)
1942 if(nMarkCount == 1)
1943 pDscrID = STR_EditConvToContour;
1944 else
1945 pDscrID = STR_EditConvToContours;
1947 BegUndo(ImpGetResStr(pDscrID), GetDescriptionOfMarkedObjects());
1949 else
1951 if (bPath) {
1952 if (nMarkCount==1) pDscrID=STR_EditConvToCurve;
1953 else pDscrID=STR_EditConvToCurves;
1954 BegUndo(ImpGetResStr(pDscrID),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ConvertToPath);
1955 } else {
1956 if (nMarkCount==1) pDscrID=STR_EditConvToPoly;
1957 else pDscrID=STR_EditConvToPolys;
1958 BegUndo(ImpGetResStr(pDscrID),GetDescriptionOfMarkedObjects(),SdrRepeatFunc::ConvertToPoly);
1961 for (size_t nm=nMarkCount; nm>0;) {
1962 --nm;
1963 SdrMark* pM=GetSdrMarkByIndex(nm);
1964 SdrObject* pObj=pM->GetMarkedSdrObj();
1965 SdrPageView* pPV=pM->GetPageView();
1966 if (pObj->IsGroupObject() && !pObj->Is3DObj()) {
1967 SdrObject* pGrp=pObj;
1968 SdrObjListIter aIter(*pGrp,SdrIterMode::DeepNoGroups);
1969 while (aIter.IsMore()) {
1970 pObj=aIter.Next();
1971 ImpConvertOneObj(pObj,bPath,bLineToArea);
1973 } else {
1974 SdrObject* pNewObj=ImpConvertOneObj(pObj,bPath,bLineToArea);
1975 if (pNewObj!=nullptr) {
1976 bMrkChg=true;
1977 GetMarkedObjectListWriteAccess().ReplaceMark(SdrMark(pNewObj,pPV),nm);
1981 EndUndo();
1982 if (bMrkChg) AdjustMarkHdl();
1983 if (bMrkChg) MarkListHasChanged();
1987 void SdrEditView::ConvertMarkedToPathObj(bool bLineToArea)
1989 ImpConvertTo(true, bLineToArea);
1992 void SdrEditView::ConvertMarkedToPolyObj()
1994 ImpConvertTo(false, false/*bLineToArea*/);
1997 namespace
1999 GDIMetaFile GetMetaFile(SdrGrafObj const * pGraf)
2001 if (pGraf->HasGDIMetaFile())
2002 return pGraf->GetTransformedGraphic(SdrGrafObjTransformsAttrs::COLOR|SdrGrafObjTransformsAttrs::MIRROR).GetGDIMetaFile();
2003 assert(pGraf->isEmbeddedVectorGraphicData());
2004 return pGraf->getMetafileFromEmbeddedVectorGraphicData();
2008 // Metafile Import
2009 void SdrEditView::DoImportMarkedMtf(SvdProgressInfo *pProgrInfo)
2011 const bool bUndo = IsUndoEnabled();
2013 if( bUndo )
2014 BegUndo("", "", SdrRepeatFunc::ImportMtf);
2016 SortMarkedObjects();
2017 SdrMarkList aForTheDescription;
2018 SdrMarkList aNewMarked;
2019 const size_t nCount=GetMarkedObjectCount();
2021 for (size_t nm=nCount; nm>0;)
2022 { // create Undo objects for all new objects
2023 // check for cancellation between the metafiles
2024 if( pProgrInfo != nullptr )
2026 pProgrInfo->SetNextObject();
2027 if(!pProgrInfo->ReportActions(0))
2028 break;
2031 --nm;
2032 SdrMark* pM=GetSdrMarkByIndex(nm);
2033 SdrObject* pObj=pM->GetMarkedSdrObj();
2034 SdrPageView* pPV=pM->GetPageView();
2035 SdrObjList* pOL=pObj->GetObjList();
2036 const size_t nInsPos=pObj->GetOrdNum()+1;
2037 SdrGrafObj* pGraf= dynamic_cast<SdrGrafObj*>( pObj );
2038 SdrOle2Obj* pOle2= dynamic_cast<SdrOle2Obj*>( pObj );
2039 sal_uIntPtr nInsAnz=0;
2040 tools::Rectangle aLogicRect;
2042 if (pGraf && (pGraf->HasGDIMetaFile() || pGraf->isEmbeddedVectorGraphicData()))
2044 GDIMetaFile aMetaFile(GetMetaFile(pGraf));
2045 if(aMetaFile.GetActionSize())
2047 aLogicRect = pGraf->GetLogicRect();
2048 ImpSdrGDIMetaFileImport aFilter(*mpModel, pObj->GetLayer(), aLogicRect);
2049 nInsAnz = aFilter.DoImport(aMetaFile, *pOL, nInsPos, pProgrInfo);
2052 if ( pOle2!=nullptr && pOle2->GetGraphic() )
2054 aLogicRect = pOle2->GetLogicRect();
2055 ImpSdrGDIMetaFileImport aFilter(*mpModel, pObj->GetLayer(), aLogicRect);
2056 nInsAnz = aFilter.DoImport(pOle2->GetGraphic()->GetGDIMetaFile(), *pOL, nInsPos, pProgrInfo);
2058 if (nInsAnz!=0)
2060 // transformation
2061 GeoStat aGeoStat(pGraf ? pGraf->GetGeoStat() : pOle2->GetGeoStat());
2062 size_t nObj=nInsPos;
2064 if(aGeoStat.nShearAngle)
2066 aGeoStat.RecalcTan();
2069 if(aGeoStat.nRotationAngle)
2071 aGeoStat.RecalcSinCos();
2074 for (sal_uIntPtr i=0; i<nInsAnz; i++)
2076 if( bUndo )
2077 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pOL->GetObj(nObj)));
2079 // update new MarkList
2080 SdrObject* pCandidate = pOL->GetObj(nObj);
2082 // apply original transformation
2083 if(aGeoStat.nShearAngle)
2085 pCandidate->NbcShear(aLogicRect.TopLeft(), aGeoStat.nShearAngle, aGeoStat.nTan, false);
2088 if(aGeoStat.nRotationAngle)
2090 pCandidate->NbcRotate(aLogicRect.TopLeft(), aGeoStat.nRotationAngle, aGeoStat.nSin, aGeoStat.nCos);
2093 SdrMark aNewMark(pCandidate, pPV);
2094 aNewMarked.InsertEntry(aNewMark);
2096 nObj++;
2098 aForTheDescription.InsertEntry(*pM);
2100 if( bUndo )
2101 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
2103 // remove object from selection and delete
2104 GetMarkedObjectListWriteAccess().DeleteMark(TryToFindMarkedObject(pObj));
2105 pOL->RemoveObject(nInsPos-1);
2107 if( !bUndo )
2108 SdrObject::Free(pObj);
2112 if(aNewMarked.GetMarkCount())
2114 // create new selection
2115 for(size_t a = 0; a < aNewMarked.GetMarkCount(); ++a)
2117 GetMarkedObjectListWriteAccess().InsertEntry(*aNewMarked.GetMark(a));
2120 SortMarkedObjects();
2123 if( bUndo )
2125 SetUndoComment(ImpGetResStr(STR_EditImportMtf),aForTheDescription.GetMarkDescription());
2126 EndUndo();
2130 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */