Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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 "svx/svdstr.hrc"
32 : #include "svx/svdglob.hxx"
33 : #include "svdfmtf.hxx"
34 : #include <svx/svdetc.hxx>
35 : #include <sfx2/basedlgs.hxx>
36 : #include <vcl/msgbox.hxx>
37 : #include <editeng/outlobj.hxx>
38 : #include <editeng/eeitem.hxx>
39 : #include <basegfx/polygon/b2dpolypolygon.hxx>
40 : #include <basegfx/polygon/b2dpolypolygontools.hxx>
41 :
42 : #include <svx/svxdlg.hxx>
43 : #include <svx/dialogs.hrc>
44 :
45 : // #i37011#
46 : #include <svx/svdoashp.hxx>
47 : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
48 :
49 : #include <vector>
50 : using ::std::vector;
51 :
52 0 : SdrObject* SdrEditView::GetMaxToTopObj(SdrObject* /*pObj*/) const
53 : {
54 0 : return NULL;
55 : }
56 :
57 0 : SdrObject* SdrEditView::GetMaxToBtmObj(SdrObject* /*pObj*/) const
58 : {
59 0 : return NULL;
60 : }
61 :
62 0 : void SdrEditView::ObjOrderChanged(SdrObject* /*pObj*/, sal_uIntPtr /*nOldPos*/, sal_uIntPtr /*nNewPos*/)
63 : {
64 0 : }
65 :
66 0 : void SdrEditView::MovMarkedToTop()
67 : {
68 0 : sal_uIntPtr nAnz=GetMarkedObjectCount();
69 0 : if (nAnz!=0)
70 : {
71 0 : const bool bUndo = IsUndoEnabled();
72 :
73 0 : if( bUndo )
74 0 : BegUndo(ImpGetResStr(STR_EditMovToTop),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_MOVTOTOP);
75 :
76 0 : SortMarkedObjects();
77 : sal_uIntPtr nm;
78 0 : for (nm=0; nm<nAnz; nm++)
79 : { // All Ordnums have to be correct!
80 0 : GetMarkedObjectByIndex(nm)->GetOrdNum();
81 : }
82 0 : bool bChg=false;
83 0 : SdrObjList* pOL0=NULL;
84 0 : sal_uIntPtr nNewPos=0;
85 0 : for (nm=nAnz; nm>0;)
86 : {
87 0 : nm--;
88 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
89 0 : SdrObject* pObj=pM->GetMarkedSdrObj();
90 0 : SdrObjList* pOL=pObj->GetObjList();
91 0 : if (pOL!=pOL0)
92 : {
93 0 : nNewPos=sal_uIntPtr(pOL->GetObjCount()-1);
94 0 : pOL0=pOL;
95 : }
96 0 : sal_uIntPtr nNowPos=pObj->GetOrdNumDirect();
97 0 : const Rectangle& rBR=pObj->GetCurrentBoundRect();
98 0 : sal_uIntPtr nCmpPos=nNowPos+1;
99 0 : SdrObject* pMaxObj=GetMaxToTopObj(pObj);
100 0 : if (pMaxObj!=NULL)
101 : {
102 0 : sal_uIntPtr nMaxPos=pMaxObj->GetOrdNum();
103 0 : if (nMaxPos!=0)
104 0 : nMaxPos--;
105 0 : if (nNewPos>nMaxPos)
106 0 : nNewPos=nMaxPos; // neither go faster...
107 0 : if (nNewPos<nNowPos)
108 0 : nNewPos=nNowPos; // nor go in the other direction
109 : }
110 0 : bool bEnd=false;
111 0 : while (nCmpPos<nNewPos && !bEnd)
112 : {
113 0 : SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
114 0 : if (pCmpObj==NULL)
115 : {
116 : OSL_FAIL("MovMarkedToTop(): Reference object not found.");
117 0 : bEnd=true;
118 : }
119 0 : else if (pCmpObj==pMaxObj)
120 : {
121 0 : nNewPos=nCmpPos;
122 0 : nNewPos--;
123 0 : bEnd=true;
124 : }
125 0 : else if (rBR.IsOver(pCmpObj->GetCurrentBoundRect()))
126 : {
127 0 : nNewPos=nCmpPos;
128 0 : bEnd=true;
129 : }
130 : else
131 : {
132 0 : nCmpPos++;
133 : }
134 : }
135 0 : if (nNowPos!=nNewPos)
136 : {
137 0 : bChg=true;
138 0 : pOL->SetObjectOrdNum(nNowPos,nNewPos);
139 0 : if( bUndo )
140 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
141 0 : ObjOrderChanged(pObj,nNowPos,nNewPos);
142 : }
143 0 : nNewPos--;
144 : }
145 :
146 0 : if( bUndo )
147 0 : EndUndo();
148 :
149 0 : if (bChg)
150 0 : MarkListHasChanged();
151 : }
152 0 : }
153 :
154 0 : void SdrEditView::MovMarkedToBtm()
155 : {
156 0 : sal_uIntPtr nAnz=GetMarkedObjectCount();
157 0 : if (nAnz!=0)
158 : {
159 0 : const bool bUndo = IsUndoEnabled();
160 :
161 0 : if( bUndo )
162 0 : BegUndo(ImpGetResStr(STR_EditMovToBtm),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_MOVTOBTM);
163 :
164 0 : SortMarkedObjects();
165 : sal_uIntPtr nm;
166 0 : for (nm=0; nm<nAnz; nm++)
167 : { // All Ordnums have to be correct!
168 0 : GetMarkedObjectByIndex(nm)->GetOrdNum();
169 : }
170 :
171 0 : bool bChg=false;
172 0 : SdrObjList* pOL0=NULL;
173 0 : sal_uIntPtr nNewPos=0;
174 0 : for (nm=0; nm<nAnz; nm++)
175 : {
176 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
177 0 : SdrObject* pObj=pM->GetMarkedSdrObj();
178 0 : SdrObjList* pOL=pObj->GetObjList();
179 0 : if (pOL!=pOL0)
180 : {
181 0 : nNewPos=0;
182 0 : pOL0=pOL;
183 : }
184 0 : sal_uIntPtr nNowPos=pObj->GetOrdNumDirect();
185 0 : const Rectangle& rBR=pObj->GetCurrentBoundRect();
186 0 : sal_uIntPtr nCmpPos=nNowPos; if (nCmpPos>0) nCmpPos--;
187 0 : SdrObject* pMaxObj=GetMaxToBtmObj(pObj);
188 0 : if (pMaxObj!=NULL)
189 : {
190 0 : sal_uIntPtr nMinPos=pMaxObj->GetOrdNum()+1;
191 0 : if (nNewPos<nMinPos)
192 0 : nNewPos=nMinPos; // neither go faster...
193 0 : if (nNewPos>nNowPos)
194 0 : nNewPos=nNowPos; // nor go in the other direction
195 : }
196 0 : bool bEnd=false;
197 : // nNewPos in this case is the "maximum" position
198 : // the object may reach without going faster than the object before
199 : // it (multiple selection).
200 0 : while (nCmpPos>nNewPos && !bEnd)
201 : {
202 0 : SdrObject* pCmpObj=pOL->GetObj(nCmpPos);
203 0 : if (pCmpObj==NULL)
204 : {
205 : OSL_FAIL("MovMarkedToBtm(): Reference object not found.");
206 0 : bEnd=true;
207 : }
208 0 : else if (pCmpObj==pMaxObj)
209 : {
210 0 : nNewPos=nCmpPos;
211 0 : nNewPos++;
212 0 : bEnd=true;
213 : }
214 0 : else if (rBR.IsOver(pCmpObj->GetCurrentBoundRect()))
215 : {
216 0 : nNewPos=nCmpPos;
217 0 : bEnd=true;
218 : }
219 : else
220 : {
221 0 : nCmpPos--;
222 : }
223 : }
224 0 : if (nNowPos!=nNewPos)
225 : {
226 0 : bChg=true;
227 0 : pOL->SetObjectOrdNum(nNowPos,nNewPos);
228 0 : if( bUndo )
229 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
230 0 : ObjOrderChanged(pObj,nNowPos,nNewPos);
231 : }
232 0 : nNewPos++;
233 : }
234 :
235 0 : if(bUndo)
236 0 : EndUndo();
237 :
238 0 : if(bChg)
239 0 : MarkListHasChanged();
240 : }
241 0 : }
242 :
243 0 : void SdrEditView::PutMarkedToTop()
244 : {
245 0 : PutMarkedInFrontOfObj(NULL);
246 0 : }
247 :
248 0 : void SdrEditView::PutMarkedInFrontOfObj(const SdrObject* pRefObj)
249 : {
250 0 : sal_uIntPtr nAnz=GetMarkedObjectCount();
251 0 : if (nAnz!=0)
252 : {
253 0 : const bool bUndo = IsUndoEnabled();
254 0 : if( bUndo )
255 0 : BegUndo(ImpGetResStr(STR_EditPutToTop),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_PUTTOTOP);
256 :
257 0 : SortMarkedObjects();
258 :
259 0 : if (pRefObj!=NULL)
260 : {
261 : // Make "in front of the object" work, even if the
262 : // selected objects are already in front of the other object
263 0 : sal_uIntPtr nRefMark=TryToFindMarkedObject(pRefObj);
264 0 : SdrMark aRefMark;
265 0 : if (nRefMark!=CONTAINER_ENTRY_NOTFOUND)
266 : {
267 0 : aRefMark=*GetSdrMarkByIndex(nRefMark);
268 0 : GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
269 : }
270 0 : PutMarkedToBtm();
271 0 : if (nRefMark!=CONTAINER_ENTRY_NOTFOUND)
272 : {
273 0 : GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
274 0 : SortMarkedObjects();
275 0 : }
276 : }
277 : sal_uIntPtr nm;
278 0 : for (nm=0; nm<nAnz; nm++)
279 : { // All Ordnums have to be correct!
280 0 : GetMarkedObjectByIndex(nm)->GetOrdNum();
281 : }
282 0 : bool bChg=false;
283 0 : SdrObjList* pOL0=NULL;
284 0 : sal_uIntPtr nNewPos=0;
285 0 : for (nm=nAnz; nm>0;)
286 : {
287 0 : nm--;
288 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
289 0 : SdrObject* pObj=pM->GetMarkedSdrObj();
290 0 : if (pObj!=pRefObj)
291 : {
292 0 : SdrObjList* pOL=pObj->GetObjList();
293 0 : if (pOL!=pOL0)
294 : {
295 0 : nNewPos=sal_uIntPtr(pOL->GetObjCount()-1);
296 0 : pOL0=pOL;
297 : }
298 0 : sal_uIntPtr nNowPos=pObj->GetOrdNumDirect();
299 0 : SdrObject* pMaxObj=GetMaxToTopObj(pObj);
300 0 : if (pMaxObj!=NULL)
301 : {
302 0 : sal_uIntPtr nMaxOrd=pMaxObj->GetOrdNum(); // sadly doesn't work any other way
303 0 : if (nMaxOrd>0)
304 0 : nMaxOrd--;
305 0 : if (nNewPos>nMaxOrd)
306 0 : nNewPos=nMaxOrd; // neither go faster...
307 0 : if (nNewPos<nNowPos)
308 0 : nNewPos=nNowPos; // nor go into the other direction
309 : }
310 0 : if (pRefObj!=NULL)
311 : {
312 0 : if (pRefObj->GetObjList()==pObj->GetObjList())
313 : {
314 0 : sal_uIntPtr nMaxOrd=pRefObj->GetOrdNum(); // sadly doesn't work any other way
315 0 : if (nNewPos>nMaxOrd)
316 0 : nNewPos=nMaxOrd; // neither go faster...
317 0 : if (nNewPos<nNowPos)
318 0 : nNewPos=nNowPos; // nor go into the other direction
319 : }
320 : else
321 : {
322 0 : nNewPos=nNowPos; // different PageView, so don't change
323 : }
324 : }
325 0 : if (nNowPos!=nNewPos)
326 : {
327 0 : bChg=true;
328 0 : pOL->SetObjectOrdNum(nNowPos,nNewPos);
329 0 : if( bUndo )
330 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
331 0 : ObjOrderChanged(pObj,nNowPos,nNewPos);
332 : }
333 0 : nNewPos--;
334 : } // if (pObj!=pRefObj)
335 : } // for loop over all selected objects
336 :
337 0 : if( bUndo )
338 0 : EndUndo();
339 :
340 0 : if(bChg)
341 0 : MarkListHasChanged();
342 : }
343 0 : }
344 :
345 0 : void SdrEditView::PutMarkedToBtm()
346 : {
347 0 : PutMarkedBehindObj(NULL);
348 0 : }
349 :
350 0 : void SdrEditView::PutMarkedBehindObj(const SdrObject* pRefObj)
351 : {
352 0 : sal_uIntPtr nAnz=GetMarkedObjectCount();
353 0 : if (nAnz!=0)
354 : {
355 0 : const bool bUndo = IsUndoEnabled();
356 :
357 0 : if( bUndo )
358 0 : BegUndo(ImpGetResStr(STR_EditPutToBtm),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_PUTTOBTM);
359 :
360 0 : SortMarkedObjects();
361 0 : if (pRefObj!=NULL)
362 : {
363 : // Make "behind the object" work, even if the
364 : // selected objects are already behind the other object
365 0 : sal_uIntPtr nRefMark=TryToFindMarkedObject(pRefObj);
366 0 : SdrMark aRefMark;
367 0 : if (nRefMark!=CONTAINER_ENTRY_NOTFOUND)
368 : {
369 0 : aRefMark=*GetSdrMarkByIndex(nRefMark);
370 0 : GetMarkedObjectListWriteAccess().DeleteMark(nRefMark);
371 : }
372 0 : PutMarkedToTop();
373 0 : if (nRefMark!=CONTAINER_ENTRY_NOTFOUND)
374 : {
375 0 : GetMarkedObjectListWriteAccess().InsertEntry(aRefMark);
376 0 : SortMarkedObjects();
377 0 : }
378 : }
379 : sal_uIntPtr nm;
380 0 : for (nm=0; nm<nAnz; nm++) { // All Ordnums have to be correct!
381 0 : GetMarkedObjectByIndex(nm)->GetOrdNum();
382 : }
383 0 : bool bChg=false;
384 0 : SdrObjList* pOL0=NULL;
385 0 : sal_uIntPtr nNewPos=0;
386 0 : for (nm=0; nm<nAnz; nm++) {
387 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
388 0 : SdrObject* pObj=pM->GetMarkedSdrObj();
389 0 : if (pObj!=pRefObj) {
390 0 : SdrObjList* pOL=pObj->GetObjList();
391 0 : if (pOL!=pOL0) {
392 0 : nNewPos=0;
393 0 : pOL0=pOL;
394 : }
395 0 : sal_uIntPtr nNowPos=pObj->GetOrdNumDirect();
396 0 : SdrObject* pMinObj=GetMaxToBtmObj(pObj);
397 0 : if (pMinObj!=NULL) {
398 0 : sal_uIntPtr nMinOrd=pMinObj->GetOrdNum()+1; // sadly doesn't work any differently
399 0 : if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster...
400 0 : if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
401 : }
402 0 : if (pRefObj!=NULL) {
403 0 : if (pRefObj->GetObjList()==pObj->GetObjList()) {
404 0 : sal_uIntPtr nMinOrd=pRefObj->GetOrdNum(); // sadly doesn't work any differently
405 0 : if (nNewPos<nMinOrd) nNewPos=nMinOrd; // neither go faster...
406 0 : if (nNewPos>nNowPos) nNewPos=nNowPos; // nor go into the other direction
407 : } else {
408 0 : nNewPos=nNowPos; // different PageView, so don't change
409 : }
410 : }
411 0 : if (nNowPos!=nNewPos) {
412 0 : bChg=true;
413 0 : pOL->SetObjectOrdNum(nNowPos,nNewPos);
414 0 : if( bUndo )
415 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj,nNowPos,nNewPos));
416 0 : ObjOrderChanged(pObj,nNowPos,nNewPos);
417 : }
418 0 : nNewPos++;
419 : } // if (pObj!=pRefObj)
420 : } // for loop over all selected objects
421 :
422 0 : if(bUndo)
423 0 : EndUndo();
424 :
425 0 : if(bChg)
426 0 : MarkListHasChanged();
427 : }
428 0 : }
429 :
430 0 : void SdrEditView::ReverseOrderOfMarked()
431 : {
432 0 : SortMarkedObjects();
433 0 : sal_uIntPtr nMarkAnz=GetMarkedObjectCount();
434 0 : if (nMarkAnz>0)
435 : {
436 0 : bool bChg=false;
437 :
438 0 : bool bUndo = IsUndoEnabled();
439 0 : if( bUndo )
440 0 : BegUndo(ImpGetResStr(STR_EditRevOrder),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_REVORDER);
441 :
442 0 : sal_uIntPtr a=0;
443 0 : do {
444 : // take into account selection across multiple PageViews
445 0 : sal_uIntPtr b=a+1;
446 0 : while (b<nMarkAnz && GetSdrPageViewOfMarkedByIndex(b) == GetSdrPageViewOfMarkedByIndex(a)) b++;
447 0 : b--;
448 0 : SdrObjList* pOL=GetSdrPageViewOfMarkedByIndex(a)->GetObjList();
449 0 : sal_uIntPtr c=b;
450 0 : if (a<c) { // make sure OrdNums aren't dirty
451 0 : GetMarkedObjectByIndex(a)->GetOrdNum();
452 : }
453 0 : while (a<c) {
454 0 : SdrObject* pObj1=GetMarkedObjectByIndex(a);
455 0 : SdrObject* pObj2=GetMarkedObjectByIndex(c);
456 0 : sal_uIntPtr nOrd1=pObj1->GetOrdNumDirect();
457 0 : sal_uIntPtr nOrd2=pObj2->GetOrdNumDirect();
458 0 : if( bUndo )
459 : {
460 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj1,nOrd1,nOrd2));
461 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoObjectOrdNum(*pObj2,nOrd2-1,nOrd1));
462 : }
463 0 : pOL->SetObjectOrdNum(nOrd1,nOrd2);
464 : // Obj 2 has moved forward by one position, so now nOrd2-1
465 0 : pOL->SetObjectOrdNum(nOrd2-1,nOrd1);
466 : // use Replace instead of SetOrdNum for performance reasons (recalculation of Ordnums)
467 0 : a++; c--;
468 0 : bChg=true;
469 : }
470 0 : a=b+1;
471 : } while (a<nMarkAnz);
472 :
473 0 : if(bUndo)
474 0 : EndUndo();
475 :
476 0 : if(bChg)
477 0 : MarkListHasChanged();
478 : }
479 0 : }
480 :
481 0 : void SdrEditView::ImpCheckToTopBtmPossible()
482 : {
483 0 : sal_uIntPtr nAnz=GetMarkedObjectCount();
484 0 : if (nAnz==0)
485 0 : return;
486 0 : if (nAnz==1)
487 : { // special-casing for single selection
488 0 : SdrObject* pObj=GetMarkedObjectByIndex(0);
489 0 : SdrObjList* pOL=pObj->GetObjList();
490 0 : sal_uIntPtr nMax=pOL->GetObjCount();
491 0 : sal_uIntPtr nMin=0;
492 0 : sal_uIntPtr nObjNum=pObj->GetOrdNum();
493 0 : SdrObject* pRestrict=GetMaxToTopObj(pObj);
494 0 : if (pRestrict!=NULL) {
495 0 : sal_uIntPtr nRestrict=pRestrict->GetOrdNum();
496 0 : if (nRestrict<nMax) nMax=nRestrict;
497 : }
498 0 : pRestrict=GetMaxToBtmObj(pObj);
499 0 : if (pRestrict!=NULL) {
500 0 : sal_uIntPtr nRestrict=pRestrict->GetOrdNum();
501 0 : if (nRestrict>nMin) nMin=nRestrict;
502 : }
503 0 : bToTopPossible=nObjNum<sal_uIntPtr(nMax-1);
504 0 : bToBtmPossible=nObjNum>nMin;
505 : } else { // multiple selection
506 0 : sal_uIntPtr nm=0;
507 0 : SdrObjList* pOL0=NULL;
508 0 : long nPos0=-1;
509 0 : while (!bToBtmPossible && nm<nAnz) { // check 'send to background'
510 0 : SdrObject* pObj=GetMarkedObjectByIndex(nm);
511 0 : SdrObjList* pOL=pObj->GetObjList();
512 0 : if (pOL!=pOL0) {
513 0 : nPos0=-1;
514 0 : pOL0=pOL;
515 : }
516 0 : sal_uIntPtr nPos=pObj->GetOrdNum();
517 0 : bToBtmPossible=nPos>sal_uIntPtr(nPos0+1);
518 0 : nPos0=long(nPos);
519 0 : nm++;
520 : }
521 0 : nm=nAnz;
522 0 : pOL0=NULL;
523 0 : nPos0=0x7FFFFFFF;
524 0 : while (!bToTopPossible && nm>0) { // check 'bring to front'
525 0 : nm--;
526 0 : SdrObject* pObj=GetMarkedObjectByIndex(nm);
527 0 : SdrObjList* pOL=pObj->GetObjList();
528 0 : if (pOL!=pOL0) {
529 0 : nPos0=pOL->GetObjCount();
530 0 : pOL0=pOL;
531 : }
532 0 : sal_uIntPtr nPos=pObj->GetOrdNum();
533 0 : bToTopPossible=nPos+1<sal_uIntPtr(nPos0);
534 0 : nPos0=nPos;
535 : }
536 : }
537 : }
538 :
539 :
540 : // Combine
541 :
542 :
543 0 : void SdrEditView::ImpCopyAttributes(const SdrObject* pSource, SdrObject* pDest) const
544 : {
545 0 : if (pSource!=NULL) {
546 0 : SdrObjList* pOL=pSource->GetSubList();
547 0 : if (pOL!=NULL && !pSource->Is3DObj()) { // get first non-group object from group
548 0 : SdrObjListIter aIter(*pOL,IM_DEEPNOGROUPS);
549 0 : pSource=aIter.Next();
550 : }
551 : }
552 :
553 0 : if(pSource && pDest)
554 : {
555 0 : SfxItemSet aSet(pMod->GetItemPool(),
556 : SDRATTR_START, SDRATTR_NOTPERSIST_FIRST-1,
557 : SDRATTR_NOTPERSIST_LAST+1, SDRATTR_END,
558 : EE_ITEMS_START, EE_ITEMS_END,
559 0 : 0, 0);
560 :
561 0 : aSet.Put(pSource->GetMergedItemSet());
562 :
563 0 : pDest->ClearMergedItem();
564 0 : pDest->SetMergedItemSet(aSet);
565 :
566 0 : pDest->NbcSetLayer(pSource->GetLayer());
567 0 : pDest->NbcSetStyleSheet(pSource->GetStyleSheet(), true);
568 : }
569 0 : }
570 :
571 0 : bool SdrEditView::ImpCanConvertForCombine1(const SdrObject* pObj) const
572 : {
573 : // new condition IsLine() to be able to combine simple Lines
574 0 : bool bIsLine(false);
575 :
576 0 : const SdrPathObj* pPath = PTR_CAST(SdrPathObj,pObj);
577 :
578 0 : if(pPath)
579 : {
580 0 : bIsLine = pPath->IsLine();
581 : }
582 :
583 0 : SdrObjTransformInfoRec aInfo;
584 0 : pObj->TakeObjInfo(aInfo);
585 :
586 0 : return (aInfo.bCanConvToPath || aInfo.bCanConvToPoly || bIsLine);
587 : }
588 :
589 0 : bool SdrEditView::ImpCanConvertForCombine(const SdrObject* pObj) const
590 : {
591 0 : SdrObjList* pOL = pObj->GetSubList();
592 :
593 0 : if(pOL && !pObj->Is3DObj())
594 : {
595 0 : SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
596 :
597 0 : while(aIter.IsMore())
598 : {
599 0 : SdrObject* pObj1 = aIter.Next();
600 :
601 : // all members of a group have to be convertible
602 0 : if(!ImpCanConvertForCombine1(pObj1))
603 : {
604 0 : return false;
605 : }
606 0 : }
607 : }
608 : else
609 : {
610 0 : if(!ImpCanConvertForCombine1(pObj))
611 : {
612 0 : return false;
613 : }
614 : }
615 :
616 0 : return true;
617 : }
618 :
619 0 : basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon1(const SdrObject* pObj, bool bCombine) const
620 : {
621 0 : basegfx::B2DPolyPolygon aRetval;
622 0 : SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
623 :
624 0 : if(bCombine && pPath && !pObj->GetOutlinerParaObject())
625 : {
626 0 : aRetval = pPath->GetPathPoly();
627 : }
628 : else
629 : {
630 0 : SdrObject* pConvObj = pObj->ConvertToPolyObj(bCombine, false);
631 :
632 0 : if(pConvObj)
633 : {
634 0 : SdrObjList* pOL = pConvObj->GetSubList();
635 :
636 0 : if(pOL)
637 : {
638 0 : SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
639 :
640 0 : while(aIter.IsMore())
641 : {
642 0 : SdrObject* pObj1 = aIter.Next();
643 0 : pPath = PTR_CAST(SdrPathObj, pObj1);
644 :
645 0 : if(pPath)
646 : {
647 0 : aRetval.append(pPath->GetPathPoly());
648 : }
649 0 : }
650 : }
651 : else
652 : {
653 0 : pPath = PTR_CAST(SdrPathObj, pConvObj);
654 :
655 0 : if(pPath)
656 : {
657 0 : aRetval = pPath->GetPathPoly();
658 : }
659 : }
660 :
661 0 : SdrObject::Free( pConvObj );
662 : }
663 : }
664 :
665 0 : return aRetval;
666 : }
667 :
668 0 : basegfx::B2DPolyPolygon SdrEditView::ImpGetPolyPolygon(const SdrObject* pObj, bool bCombine) const
669 : {
670 0 : SdrObjList* pOL = pObj->GetSubList();
671 :
672 0 : if(pOL && !pObj->Is3DObj())
673 : {
674 0 : basegfx::B2DPolyPolygon aRetval;
675 0 : SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
676 :
677 0 : while(aIter.IsMore())
678 : {
679 0 : SdrObject* pObj1 = aIter.Next();
680 0 : aRetval.append(ImpGetPolyPolygon1(pObj1, bCombine));
681 : }
682 :
683 0 : return aRetval;
684 : }
685 : else
686 : {
687 0 : return ImpGetPolyPolygon1(pObj, bCombine);
688 : }
689 : }
690 :
691 0 : basegfx::B2DPolygon SdrEditView::ImpCombineToSinglePolygon(const basegfx::B2DPolyPolygon& rPolyPolygon) const
692 : {
693 0 : const sal_uInt32 nPolyCount(rPolyPolygon.count());
694 :
695 0 : if(0L == nPolyCount)
696 : {
697 0 : return basegfx::B2DPolygon();
698 : }
699 0 : else if(1L == nPolyCount)
700 : {
701 0 : return rPolyPolygon.getB2DPolygon(0L);
702 : }
703 : else
704 : {
705 0 : basegfx::B2DPolygon aRetval(rPolyPolygon.getB2DPolygon(0L));
706 :
707 0 : for(sal_uInt32 a(1L); a < nPolyCount; a++)
708 : {
709 0 : basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
710 :
711 0 : if(aRetval.count())
712 : {
713 0 : if(aCandidate.count())
714 : {
715 0 : const basegfx::B2DPoint aCA(aCandidate.getB2DPoint(0L));
716 0 : const basegfx::B2DPoint aCB(aCandidate.getB2DPoint(aCandidate.count() - 1L));
717 0 : const basegfx::B2DPoint aRA(aRetval.getB2DPoint(0L));
718 0 : const basegfx::B2DPoint aRB(aRetval.getB2DPoint(aRetval.count() - 1L));
719 :
720 0 : const double fRACA(basegfx::B2DVector(aCA - aRA).getLength());
721 0 : const double fRACB(basegfx::B2DVector(aCB - aRA).getLength());
722 0 : const double fRBCA(basegfx::B2DVector(aCA - aRB).getLength());
723 0 : const double fRBCB(basegfx::B2DVector(aCB - aRB).getLength());
724 :
725 0 : const double fSmallestRA(fRACA < fRACB ? fRACA : fRACB);
726 0 : const double fSmallestRB(fRBCA < fRBCB ? fRBCA : fRBCB);
727 :
728 0 : if(fSmallestRA < fSmallestRB)
729 : {
730 : // flip result
731 0 : aRetval.flip();
732 : }
733 :
734 0 : const double fSmallestCA(fRACA < fRBCA ? fRACA : fRBCA);
735 0 : const double fSmallestCB(fRACB < fRBCB ? fRACB : fRBCB);
736 :
737 0 : if(fSmallestCB < fSmallestCA)
738 : {
739 : // flip candidate
740 0 : aCandidate.flip();
741 : }
742 :
743 : // append candidate to retval
744 0 : aRetval.append(aCandidate);
745 : }
746 : }
747 : else
748 : {
749 0 : aRetval = aCandidate;
750 : }
751 0 : }
752 :
753 0 : return aRetval;
754 : }
755 : }
756 :
757 : // for distribution dialog function
758 : struct ImpDistributeEntry
759 : {
760 : SdrObject* mpObj;
761 : sal_Int32 mnPos;
762 : sal_Int32 mnLength;
763 : };
764 :
765 : typedef vector< ImpDistributeEntry*> ImpDistributeEntryList;
766 :
767 0 : void SdrEditView::DistributeMarkedObjects()
768 : {
769 0 : sal_uInt32 nMark(GetMarkedObjectCount());
770 :
771 0 : if(nMark > 2)
772 : {
773 0 : SfxItemSet aNewAttr(pMod->GetItemPool());
774 :
775 0 : SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
776 0 : if(pFact)
777 : {
778 0 : AbstractSvxDistributeDialog *pDlg = pFact->CreateSvxDistributeDialog(NULL, aNewAttr);
779 : DBG_ASSERT(pDlg, "Dialogdiet fail!");
780 :
781 0 : sal_uInt16 nResult = pDlg->Execute();
782 :
783 0 : if(nResult == RET_OK)
784 : {
785 0 : SvxDistributeHorizontal eHor = pDlg->GetDistributeHor();
786 0 : SvxDistributeVertical eVer = pDlg->GetDistributeVer();
787 0 : ImpDistributeEntryList aEntryList;
788 0 : ImpDistributeEntryList::iterator itEntryList;
789 : sal_uInt32 nFullLength;
790 :
791 0 : const bool bUndo = IsUndoEnabled();
792 0 : if( bUndo )
793 0 : BegUndo();
794 :
795 0 : if(eHor != SvxDistributeHorizontalNone)
796 : {
797 : // build sorted entry list
798 0 : nFullLength = 0L;
799 :
800 0 : for( sal_uInt32 a = 0; a < nMark; a++ )
801 : {
802 0 : SdrMark* pMark = GetSdrMarkByIndex(a);
803 0 : ImpDistributeEntry* pNew = new ImpDistributeEntry;
804 :
805 0 : pNew->mpObj = pMark->GetMarkedSdrObj();
806 :
807 0 : switch(eHor)
808 : {
809 : case SvxDistributeHorizontalLeft:
810 : {
811 0 : pNew->mnPos = pNew->mpObj->GetSnapRect().Left();
812 0 : break;
813 : }
814 : case SvxDistributeHorizontalCenter:
815 : {
816 0 : pNew->mnPos = (pNew->mpObj->GetSnapRect().Right() + pNew->mpObj->GetSnapRect().Left()) / 2;
817 0 : break;
818 : }
819 : case SvxDistributeHorizontalDistance:
820 : {
821 0 : pNew->mnLength = pNew->mpObj->GetSnapRect().GetWidth() + 1;
822 0 : nFullLength += pNew->mnLength;
823 0 : pNew->mnPos = (pNew->mpObj->GetSnapRect().Right() + pNew->mpObj->GetSnapRect().Left()) / 2;
824 0 : break;
825 : }
826 : case SvxDistributeHorizontalRight:
827 : {
828 0 : pNew->mnPos = pNew->mpObj->GetSnapRect().Right();
829 0 : break;
830 : }
831 0 : default: break;
832 : }
833 :
834 0 : for ( itEntryList = aEntryList.begin();
835 0 : itEntryList < aEntryList.end() && (*itEntryList)->mnPos < pNew->mnPos;
836 : ++itEntryList )
837 : {};
838 0 : if ( itEntryList < aEntryList.end() )
839 0 : aEntryList.insert( itEntryList, pNew );
840 : else
841 0 : aEntryList.push_back( pNew );
842 : }
843 :
844 0 : if(eHor == SvxDistributeHorizontalDistance)
845 : {
846 : // calculate room in-between
847 0 : sal_Int32 nWidth = GetAllMarkedBoundRect().GetWidth() + 1;
848 0 : double fStepWidth = ((double)nWidth - (double)nFullLength) / (double)(aEntryList.size() - 1);
849 0 : double fStepStart = (double)aEntryList[ 0 ]->mnPos;
850 0 : fStepStart += fStepWidth + (double)((aEntryList[ 0 ]->mnLength + aEntryList[ 1 ]->mnLength) / 2);
851 :
852 : // move entries 1..n-1
853 0 : for( size_t i = 1, n = aEntryList.size()-1; i < n; ++i )
854 : {
855 0 : ImpDistributeEntry* pCurr = aEntryList[ i ];
856 0 : ImpDistributeEntry* pNext = aEntryList[ i + 1];
857 0 : sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
858 0 : if( bUndo )
859 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
860 0 : pCurr->mpObj->Move(Size(nDelta, 0));
861 0 : fStepStart += fStepWidth + (double)((pCurr->mnLength + pNext->mnLength) / 2);
862 : }
863 : }
864 : else
865 : {
866 : // calculate distances
867 0 : sal_Int32 nWidth = aEntryList[ aEntryList.size() - 1 ]->mnPos - aEntryList[ 0 ]->mnPos;
868 0 : double fStepWidth = (double)nWidth / (double)(aEntryList.size() - 1);
869 0 : double fStepStart = (double)aEntryList[ 0 ]->mnPos;
870 0 : fStepStart += fStepWidth;
871 :
872 : // move entries 1..n-1
873 0 : for( size_t i = 1 ; i < aEntryList.size()-1 ; ++i )
874 : {
875 0 : ImpDistributeEntry* pCurr = aEntryList[ i ];
876 0 : sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
877 0 : if( bUndo )
878 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
879 0 : pCurr->mpObj->Move(Size(nDelta, 0));
880 0 : fStepStart += fStepWidth;
881 : }
882 : }
883 :
884 : // clear list
885 0 : for ( size_t i = 0, n = aEntryList.size(); i < n; ++i )
886 0 : delete aEntryList[ i ];
887 0 : aEntryList.clear();
888 : }
889 :
890 0 : if(eVer != SvxDistributeVerticalNone)
891 : {
892 : // build sorted entry list
893 0 : nFullLength = 0L;
894 :
895 0 : for( sal_uInt32 a = 0; a < nMark; a++ )
896 : {
897 0 : SdrMark* pMark = GetSdrMarkByIndex(a);
898 0 : ImpDistributeEntry* pNew = new ImpDistributeEntry;
899 :
900 0 : pNew->mpObj = pMark->GetMarkedSdrObj();
901 :
902 0 : switch(eVer)
903 : {
904 : case SvxDistributeVerticalTop:
905 : {
906 0 : pNew->mnPos = pNew->mpObj->GetSnapRect().Top();
907 0 : break;
908 : }
909 : case SvxDistributeVerticalCenter:
910 : {
911 0 : pNew->mnPos = (pNew->mpObj->GetSnapRect().Bottom() + pNew->mpObj->GetSnapRect().Top()) / 2;
912 0 : break;
913 : }
914 : case SvxDistributeVerticalDistance:
915 : {
916 0 : pNew->mnLength = pNew->mpObj->GetSnapRect().GetHeight() + 1;
917 0 : nFullLength += pNew->mnLength;
918 0 : pNew->mnPos = (pNew->mpObj->GetSnapRect().Bottom() + pNew->mpObj->GetSnapRect().Top()) / 2;
919 0 : break;
920 : }
921 : case SvxDistributeVerticalBottom:
922 : {
923 0 : pNew->mnPos = pNew->mpObj->GetSnapRect().Bottom();
924 0 : break;
925 : }
926 0 : default: break;
927 : }
928 :
929 0 : for ( itEntryList = aEntryList.begin();
930 0 : itEntryList < aEntryList.end() && (*itEntryList)->mnPos < pNew->mnPos;
931 : ++itEntryList )
932 : {};
933 0 : if ( itEntryList < aEntryList.end() )
934 0 : aEntryList.insert( itEntryList, pNew );
935 : else
936 0 : aEntryList.push_back( pNew );
937 : }
938 :
939 0 : if(eVer == SvxDistributeVerticalDistance)
940 : {
941 : // calculate room in-between
942 0 : sal_Int32 nHeight = GetAllMarkedBoundRect().GetHeight() + 1;
943 0 : double fStepWidth = ((double)nHeight - (double)nFullLength) / (double)(aEntryList.size() - 1);
944 0 : double fStepStart = (double)aEntryList[ 0 ]->mnPos;
945 0 : fStepStart += fStepWidth + (double)((aEntryList[ 0 ]->mnLength + aEntryList[ 1 ]->mnLength) / 2);
946 :
947 : // move entries 1..n-1
948 0 : for( size_t i = 1, n = aEntryList.size()-1; i < n; ++i)
949 : {
950 0 : ImpDistributeEntry* pCurr = aEntryList[ i ];
951 0 : ImpDistributeEntry* pNext = aEntryList[ i + 1 ];
952 0 : sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
953 0 : if( bUndo )
954 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
955 0 : pCurr->mpObj->Move(Size(0, nDelta));
956 0 : fStepStart += fStepWidth + (double)((pCurr->mnLength + pNext->mnLength) / 2);
957 : }
958 : }
959 : else
960 : {
961 : // calculate distances
962 0 : sal_Int32 nHeight = aEntryList[ aEntryList.size() - 1 ]->mnPos - aEntryList[ 0 ]->mnPos;
963 0 : double fStepWidth = (double)nHeight / (double)(aEntryList.size() - 1);
964 0 : double fStepStart = (double)aEntryList[ 0 ]->mnPos;
965 0 : fStepStart += fStepWidth;
966 :
967 : // move entries 1..n-1
968 0 : for(size_t i = 1, n = aEntryList.size()-1; i < n; ++i)
969 : {
970 0 : ImpDistributeEntry* pCurr = aEntryList[ i ];
971 0 : sal_Int32 nDelta = (sal_Int32)(fStepStart + 0.5) - pCurr->mnPos;
972 0 : if( bUndo )
973 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pCurr->mpObj));
974 0 : pCurr->mpObj->Move(Size(0, nDelta));
975 0 : fStepStart += fStepWidth;
976 : }
977 : }
978 :
979 : // clear list
980 0 : for ( size_t i = 0, n = aEntryList.size(); i < n; ++i )
981 0 : delete aEntryList[ i ];
982 0 : aEntryList.clear();
983 : }
984 :
985 : // UNDO-Comment and end of UNDO
986 0 : SetUndoComment(ImpGetResStr(STR_DistributeMarkedObjects));
987 :
988 0 : if( bUndo )
989 0 : EndUndo();
990 : }
991 :
992 0 : delete(pDlg);
993 0 : }
994 : }
995 0 : }
996 :
997 0 : void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode)
998 : {
999 : // #i73441# check content
1000 0 : if(AreObjectsMarked())
1001 : {
1002 0 : SdrMarkList aRemove;
1003 0 : SortMarkedObjects();
1004 :
1005 0 : const bool bUndo = IsUndoEnabled();
1006 :
1007 0 : if( bUndo )
1008 0 : BegUndo();
1009 :
1010 0 : sal_uInt32 nInsPos=0xFFFFFFFF;
1011 0 : const SdrObject* pAttrObj = NULL;
1012 0 : basegfx::B2DPolyPolygon aMergePolyPolygonA;
1013 0 : basegfx::B2DPolyPolygon aMergePolyPolygonB;
1014 :
1015 0 : SdrObjList* pInsOL = NULL;
1016 0 : SdrPageView* pInsPV = NULL;
1017 0 : bool bFirstObjectComplete(false);
1018 :
1019 : // make sure selected objects are contour objects
1020 : // since now basegfx::tools::adaptiveSubdivide() is used, it is no longer
1021 : // necessary to use ConvertMarkedToPolyObj which will subdivide curves using the old
1022 : // mechanisms. In a next step the polygon clipper will even be able to clip curves...
1023 : // ConvertMarkedToPolyObj(true);
1024 0 : ConvertMarkedToPathObj(true);
1025 : OSL_ENSURE(AreObjectsMarked(), "no more objects selected after preparations (!)");
1026 :
1027 0 : for(sal_uInt32 a=0;a<GetMarkedObjectCount();a++)
1028 : {
1029 0 : SdrMark* pM = GetSdrMarkByIndex(a);
1030 0 : SdrObject* pObj = pM->GetMarkedSdrObj();
1031 :
1032 0 : if(ImpCanConvertForCombine(pObj))
1033 : {
1034 0 : if(!pAttrObj)
1035 0 : pAttrObj = pObj;
1036 :
1037 0 : nInsPos = pObj->GetOrdNum() + 1;
1038 0 : pInsPV = pM->GetPageView();
1039 0 : pInsOL = pObj->GetObjList();
1040 :
1041 : // #i76891# use single iteration from SJ here which works on SdrObjects and takes
1042 : // groups into account by itself
1043 0 : SdrObjListIter aIter(*pObj, IM_DEEPWITHGROUPS);
1044 :
1045 0 : while(aIter.IsMore())
1046 : {
1047 0 : SdrObject* pCandidate = aIter.Next();
1048 0 : SdrPathObj* pPathObj = PTR_CAST(SdrPathObj, pCandidate);
1049 0 : if(pPathObj)
1050 : {
1051 0 : basegfx::B2DPolyPolygon aTmpPoly(pPathObj->GetPathPoly());
1052 :
1053 : // #i76891# unfortunately ConvertMarkedToPathObj has converted all
1054 : // involved polygon data to curve segments, even if not necessary.
1055 : // It is better to try to reduce to more simple polygons.
1056 0 : aTmpPoly = basegfx::tools::simplifyCurveSegments(aTmpPoly);
1057 :
1058 : // for each part polygon as preparation, remove self-intersections
1059 : // correct orientations and get rid of possible neutral polygons.
1060 0 : aTmpPoly = basegfx::tools::prepareForPolygonOperation(aTmpPoly);
1061 :
1062 0 : if(!bFirstObjectComplete)
1063 : {
1064 : // #i111987# Also need to collect ORed source shape when more than
1065 : // a single polygon is involved
1066 0 : if(aMergePolyPolygonA.count())
1067 : {
1068 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aTmpPoly);
1069 : }
1070 : else
1071 : {
1072 0 : aMergePolyPolygonA = aTmpPoly;
1073 : }
1074 : }
1075 : else
1076 : {
1077 0 : if(aMergePolyPolygonB.count())
1078 : {
1079 : // to topologically correctly collect the 2nd polygon
1080 : // group it is necessary to OR the parts (each is seen as
1081 : // XOR-FillRule polygon and they are drawn over each-other)
1082 0 : aMergePolyPolygonB = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonB, aTmpPoly);
1083 : }
1084 : else
1085 : {
1086 0 : aMergePolyPolygonB = aTmpPoly;
1087 : }
1088 0 : }
1089 : }
1090 : }
1091 :
1092 : // was there something added to the first polygon?
1093 0 : if(!bFirstObjectComplete && aMergePolyPolygonA.count())
1094 : {
1095 0 : bFirstObjectComplete = true;
1096 : }
1097 :
1098 : // move object to temporary delete list
1099 0 : aRemove.InsertEntry(SdrMark(pObj, pM->GetPageView()));
1100 : }
1101 : }
1102 :
1103 0 : switch(eMode)
1104 : {
1105 : case SDR_MERGE_MERGE:
1106 : {
1107 : // merge all contained parts (OR)
1108 : static bool bTestXOR(false);
1109 0 : if(bTestXOR)
1110 : {
1111 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationXor(aMergePolyPolygonA, aMergePolyPolygonB);
1112 : }
1113 : else
1114 : {
1115 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationOr(aMergePolyPolygonA, aMergePolyPolygonB);
1116 : }
1117 0 : break;
1118 : }
1119 : case SDR_MERGE_SUBSTRACT:
1120 : {
1121 : // Substract B from A
1122 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationDiff(aMergePolyPolygonA, aMergePolyPolygonB);
1123 0 : break;
1124 : }
1125 : case SDR_MERGE_INTERSECT:
1126 : {
1127 : // AND B and A
1128 0 : aMergePolyPolygonA = basegfx::tools::solvePolygonOperationAnd(aMergePolyPolygonA, aMergePolyPolygonB);
1129 0 : break;
1130 : }
1131 : }
1132 :
1133 : // #i73441# check insert list before taking actions
1134 0 : if(pInsOL)
1135 : {
1136 0 : SdrPathObj* pPath = new SdrPathObj(OBJ_PATHFILL, aMergePolyPolygonA);
1137 0 : ImpCopyAttributes(pAttrObj, pPath);
1138 0 : SdrInsertReason aReason(SDRREASON_VIEWCALL, pAttrObj);
1139 0 : pInsOL->InsertObject(pPath, nInsPos, &aReason);
1140 0 : if( bUndo )
1141 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
1142 0 : MarkObj(pPath, pInsPV, false, true);
1143 : }
1144 :
1145 0 : aRemove.ForceSort();
1146 0 : switch(eMode)
1147 : {
1148 : case SDR_MERGE_MERGE:
1149 : {
1150 : SetUndoComment(
1151 : ImpGetResStr(STR_EditMergeMergePoly),
1152 0 : aRemove.GetMarkDescription());
1153 0 : break;
1154 : }
1155 : case SDR_MERGE_SUBSTRACT:
1156 : {
1157 : SetUndoComment(
1158 : ImpGetResStr(STR_EditMergeSubstractPoly),
1159 0 : aRemove.GetMarkDescription());
1160 0 : break;
1161 : }
1162 : case SDR_MERGE_INTERSECT:
1163 : {
1164 : SetUndoComment(
1165 : ImpGetResStr(STR_EditMergeIntersectPoly),
1166 0 : aRemove.GetMarkDescription());
1167 0 : break;
1168 : }
1169 : }
1170 0 : DeleteMarkedList(aRemove);
1171 :
1172 0 : if( bUndo )
1173 0 : EndUndo();
1174 : }
1175 0 : }
1176 :
1177 0 : void SdrEditView::CombineMarkedObjects(bool bNoPolyPoly)
1178 : {
1179 : // #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
1180 : // create a 2nd Undo-action and Undo-Comment.
1181 :
1182 0 : bool bUndo = IsUndoEnabled();
1183 :
1184 : // Undo-String will be set later
1185 0 : if( bUndo )
1186 0 : BegUndo("", "", bNoPolyPoly ? SDRREPFUNC_OBJ_COMBINE_ONEPOLY : SDRREPFUNC_OBJ_COMBINE_POLYPOLY);
1187 :
1188 : // #105899# First, guarantee that all objects are converted to polyobjects,
1189 : // especially for SdrGrafObj with bitmap filling this is necessary to not
1190 : // loose the bitmap filling.
1191 :
1192 : // #i12392#
1193 : // ConvertMarkedToPolyObj was too strong here, it will loose quality and
1194 : // information when curve objects are combined. This can be replaced by
1195 : // using ConvertMarkedToPathObj without changing the previous fix.
1196 :
1197 : // #i21250#
1198 : // Instead of simply passing true as LineToArea, use bNoPolyPoly as info
1199 : // if this command is a 'Combine' or a 'Connect' command. On Connect it's true.
1200 : // To not concert line segments with a set line width to polygons in that case,
1201 : // use this info. Do not convert LineToArea on Connect commands.
1202 : // ConvertMarkedToPathObj(!bNoPolyPoly);
1203 :
1204 : // This is used for Combine and Connect. In no case it is necessary to force
1205 : // the content to curve, but it is also not good to force to polygons. Thus,
1206 : // curve is the less information loosing one. Remember: This place is not
1207 : // used for merge.
1208 : // LineToArea is never necessary, both commands are able to take over the
1209 : // set line style and to display it correctly. Thus, i will use a
1210 : // ConvertMarkedToPathObj with a false in any case. Only drawback is that
1211 : // simple polygons will be changed to curves, but with no information loss.
1212 0 : ConvertMarkedToPathObj(false /* bLineToArea */);
1213 :
1214 : // continue as before
1215 0 : basegfx::B2DPolyPolygon aPolyPolygon;
1216 0 : SdrObjList* pAktOL = 0L;
1217 0 : SdrMarkList aRemoveMerker;
1218 :
1219 0 : SortMarkedObjects();
1220 0 : sal_uInt32 nInsPos(0xFFFFFFFF);
1221 0 : SdrObjList* pInsOL = 0L;
1222 0 : SdrPageView* pInsPV = 0L;
1223 0 : const sal_uInt32 nAnz(GetMarkedObjectCount());
1224 0 : const SdrObject* pAttrObj = 0L;
1225 :
1226 0 : for(sal_uInt32 a(nAnz); a > 0L; )
1227 : {
1228 0 : a--;
1229 0 : SdrMark* pM = GetSdrMarkByIndex(a);
1230 0 : SdrObject* pObj = pM->GetMarkedSdrObj();
1231 0 : SdrObjList* pThisOL = pObj->GetObjList();
1232 :
1233 0 : if(pAktOL != pThisOL)
1234 : {
1235 0 : pAktOL = pThisOL;
1236 : }
1237 :
1238 0 : if(ImpCanConvertForCombine(pObj))
1239 : {
1240 : // remember objects to be able to copy attributes
1241 0 : pAttrObj = pObj;
1242 :
1243 : // unfortunately ConvertMarkedToPathObj has converted all
1244 : // involved polygon data to curve segments, even if not necessary.
1245 : // It is better to try to reduce to more simple polygons.
1246 0 : basegfx::B2DPolyPolygon aTmpPoly(basegfx::tools::simplifyCurveSegments(ImpGetPolyPolygon(pObj, true)));
1247 0 : aPolyPolygon.insert(0L, aTmpPoly);
1248 :
1249 0 : if(!pInsOL)
1250 : {
1251 0 : nInsPos = pObj->GetOrdNum() + 1L;
1252 0 : pInsPV = pM->GetPageView();
1253 0 : pInsOL = pObj->GetObjList();
1254 : }
1255 :
1256 0 : aRemoveMerker.InsertEntry(SdrMark(pObj, pM->GetPageView()));
1257 : }
1258 : }
1259 :
1260 0 : if(bNoPolyPoly)
1261 : {
1262 0 : basegfx::B2DPolygon aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon));
1263 0 : aPolyPolygon.clear();
1264 0 : aPolyPolygon.append(aCombinedPolygon);
1265 : }
1266 :
1267 0 : const sal_uInt32 nPolyCount(aPolyPolygon.count());
1268 :
1269 0 : if (nPolyCount && pAttrObj)
1270 : {
1271 0 : SdrObjKind eKind = OBJ_PATHFILL;
1272 :
1273 0 : if(nPolyCount > 1L)
1274 : {
1275 0 : aPolyPolygon.setClosed(true);
1276 : }
1277 : else
1278 : {
1279 : // check for Polyline
1280 0 : const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0L));
1281 0 : const sal_uInt32 nPointCount(aPolygon.count());
1282 :
1283 0 : if(nPointCount <= 2L)
1284 : {
1285 0 : eKind = OBJ_PATHLINE;
1286 : }
1287 : else
1288 : {
1289 0 : if(!aPolygon.isClosed())
1290 : {
1291 0 : const basegfx::B2DPoint aPointA(aPolygon.getB2DPoint(0L));
1292 0 : const basegfx::B2DPoint aPointB(aPolygon.getB2DPoint(nPointCount - 1L));
1293 0 : const double fDistance(basegfx::B2DVector(aPointB - aPointA).getLength());
1294 0 : const double fJoinTolerance(10.0);
1295 :
1296 0 : if(fDistance < fJoinTolerance)
1297 : {
1298 0 : aPolyPolygon.setClosed(true);
1299 : }
1300 : else
1301 : {
1302 0 : eKind = OBJ_PATHLINE;
1303 0 : }
1304 : }
1305 0 : }
1306 : }
1307 :
1308 0 : SdrPathObj* pPath = new SdrPathObj(eKind,aPolyPolygon);
1309 :
1310 : // attributes of the lowest object
1311 0 : ImpCopyAttributes(pAttrObj, pPath);
1312 :
1313 : // If LineStyle of pAttrObj is XLINE_NONE force to XLINE_SOLID to make visible.
1314 0 : const XLineStyle eLineStyle = ((const XLineStyleItem&)pAttrObj->GetMergedItem(XATTR_LINESTYLE)).GetValue();
1315 0 : const XFillStyle eFillStyle = ((const XFillStyleItem&)pAttrObj->GetMergedItem(XATTR_FILLSTYLE)).GetValue();
1316 :
1317 : // Take fill style/closed state of pAttrObj in account when deciding to change the line style
1318 0 : bool bIsClosedPathObj(pAttrObj->ISA(SdrPathObj) && ((SdrPathObj*)pAttrObj)->IsClosed());
1319 :
1320 0 : if(XLINE_NONE == eLineStyle && (XFILL_NONE == eFillStyle || !bIsClosedPathObj))
1321 : {
1322 0 : pPath->SetMergedItem(XLineStyleItem(XLINE_SOLID));
1323 : }
1324 :
1325 0 : SdrInsertReason aReason(SDRREASON_VIEWCALL,pAttrObj);
1326 0 : pInsOL->InsertObject(pPath,nInsPos,&aReason);
1327 0 : if( bUndo )
1328 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
1329 :
1330 : // Here was a severe error: Without UnmarkAllObj, the new object was marked
1331 : // additionally to the two ones which are deleted below. As long as those are
1332 : // in the UNDO there is no problem, but as soon as they get deleted, the
1333 : // MarkList will contain deleted objects -> GPF.
1334 0 : UnmarkAllObj(pInsPV);
1335 0 : MarkObj(pPath, pInsPV, false, true);
1336 : }
1337 :
1338 : // build an UndoComment from the objects actually used
1339 0 : aRemoveMerker.ForceSort(); // important for remove (see below)
1340 0 : if( bUndo )
1341 0 : SetUndoComment(ImpGetResStr(bNoPolyPoly?STR_EditCombine_OnePoly:STR_EditCombine_PolyPoly),aRemoveMerker.GetMarkDescription());
1342 :
1343 : // remove objects actually used from the list
1344 0 : DeleteMarkedList(aRemoveMerker);
1345 0 : if( bUndo )
1346 0 : EndUndo();
1347 0 : }
1348 :
1349 :
1350 : // Dismantle
1351 :
1352 :
1353 0 : bool SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon& rPpolyPolygon, bool bMakeLines) const
1354 : {
1355 0 : bool bCan(false);
1356 0 : const sal_uInt32 nPolygonCount(rPpolyPolygon.count());
1357 :
1358 0 : if(nPolygonCount >= 2L)
1359 : {
1360 : // #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
1361 0 : bCan = true;
1362 : }
1363 0 : else if(bMakeLines && 1L == nPolygonCount)
1364 : {
1365 : // #i69172# ..or with at least 2 edges (curves or lines)
1366 0 : const basegfx::B2DPolygon aPolygon(rPpolyPolygon.getB2DPolygon(0L));
1367 0 : const sal_uInt32 nPointCount(aPolygon.count());
1368 :
1369 0 : if(nPointCount > 2L)
1370 : {
1371 0 : bCan = true;
1372 0 : }
1373 : }
1374 :
1375 0 : return bCan;
1376 : }
1377 :
1378 0 : bool SdrEditView::ImpCanDismantle(const SdrObject* pObj, bool bMakeLines) const
1379 : {
1380 0 : bool bOtherObjs(false); // true=objects other than PathObj's existent
1381 0 : bool bMin1PolyPoly(false); // true=at least 1 PolyPolygon with more than one Polygon existent
1382 0 : SdrObjList* pOL = pObj->GetSubList();
1383 :
1384 0 : if(pOL)
1385 : {
1386 : // group object -- check all members if they're PathObjs
1387 0 : SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
1388 :
1389 0 : while(aIter.IsMore() && !bOtherObjs)
1390 : {
1391 0 : const SdrObject* pObj1 = aIter.Next();
1392 0 : const SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj1);
1393 :
1394 0 : if(pPath)
1395 : {
1396 0 : if(ImpCanDismantle(pPath->GetPathPoly(), bMakeLines))
1397 : {
1398 0 : bMin1PolyPoly = true;
1399 : }
1400 :
1401 0 : SdrObjTransformInfoRec aInfo;
1402 0 : pObj1->TakeObjInfo(aInfo);
1403 :
1404 0 : if(!aInfo.bCanConvToPath)
1405 : {
1406 : // happens e. g. in the case of FontWork
1407 0 : bOtherObjs = true;
1408 : }
1409 : }
1410 : else
1411 : {
1412 0 : bOtherObjs = true;
1413 : }
1414 0 : }
1415 : }
1416 : else
1417 : {
1418 0 : const SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
1419 0 : const SdrObjCustomShape* pCustomShape = PTR_CAST(SdrObjCustomShape, pObj);
1420 :
1421 : // #i37011#
1422 0 : if(pPath)
1423 : {
1424 0 : if(ImpCanDismantle(pPath->GetPathPoly(),bMakeLines))
1425 : {
1426 0 : bMin1PolyPoly = true;
1427 : }
1428 :
1429 0 : SdrObjTransformInfoRec aInfo;
1430 0 : pObj->TakeObjInfo(aInfo);
1431 :
1432 : // new condition IsLine() to be able to break simple Lines
1433 0 : if(!(aInfo.bCanConvToPath || aInfo.bCanConvToPoly) && !pPath->IsLine())
1434 : {
1435 : // happens e. g. in the case of FontWork
1436 0 : bOtherObjs = true;
1437 : }
1438 : }
1439 0 : else if(pCustomShape)
1440 : {
1441 0 : if(bMakeLines)
1442 : {
1443 : // allow break command
1444 0 : bMin1PolyPoly = true;
1445 : }
1446 : }
1447 : else
1448 : {
1449 0 : bOtherObjs = true;
1450 : }
1451 : }
1452 0 : return bMin1PolyPoly && !bOtherObjs;
1453 : }
1454 :
1455 0 : void SdrEditView::ImpDismantleOneObject(const SdrObject* pObj, SdrObjList& rOL, sal_uIntPtr& rPos, SdrPageView* pPV, bool bMakeLines)
1456 : {
1457 0 : const SdrPathObj* pSrcPath = PTR_CAST(SdrPathObj, pObj);
1458 0 : const SdrObjCustomShape* pCustomShape = PTR_CAST(SdrObjCustomShape, pObj);
1459 :
1460 0 : const bool bUndo = IsUndoEnabled();
1461 :
1462 0 : if(pSrcPath)
1463 : {
1464 : // #i74631# redesigned due to XpolyPolygon removal and explicit constructors
1465 0 : SdrObject* pLast = 0; // to be able to apply OutlinerParaObject
1466 0 : const basegfx::B2DPolyPolygon& rPolyPolygon(pSrcPath->GetPathPoly());
1467 0 : const sal_uInt32 nPolyCount(rPolyPolygon.count());
1468 :
1469 0 : for(sal_uInt32 a(0); a < nPolyCount; a++)
1470 : {
1471 0 : const basegfx::B2DPolygon& rCandidate(rPolyPolygon.getB2DPolygon(a));
1472 0 : const sal_uInt32 nPointCount(rCandidate.count());
1473 :
1474 0 : if(!bMakeLines || nPointCount < 2)
1475 : {
1476 0 : SdrPathObj* pPath = new SdrPathObj((SdrObjKind)pSrcPath->GetObjIdentifier(), basegfx::B2DPolyPolygon(rCandidate));
1477 0 : ImpCopyAttributes(pSrcPath, pPath);
1478 0 : pLast = pPath;
1479 0 : SdrInsertReason aReason(SDRREASON_VIEWCALL, pSrcPath);
1480 0 : rOL.InsertObject(pPath, rPos, &aReason);
1481 0 : if( bUndo )
1482 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, true));
1483 0 : MarkObj(pPath, pPV, false, true);
1484 0 : rPos++;
1485 : }
1486 : else
1487 : {
1488 0 : const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
1489 :
1490 0 : for(sal_uInt32 b(0); b < nLoopCount; b++)
1491 : {
1492 0 : SdrObjKind eKind(OBJ_PLIN);
1493 0 : basegfx::B2DPolygon aNewPolygon;
1494 0 : const sal_uInt32 nNextIndex((b + 1) % nPointCount);
1495 :
1496 0 : aNewPolygon.append(rCandidate.getB2DPoint(b));
1497 :
1498 0 : if(rCandidate.areControlPointsUsed())
1499 : {
1500 : aNewPolygon.appendBezierSegment(
1501 : rCandidate.getNextControlPoint(b),
1502 : rCandidate.getPrevControlPoint(nNextIndex),
1503 0 : rCandidate.getB2DPoint(nNextIndex));
1504 0 : eKind = OBJ_PATHLINE;
1505 : }
1506 : else
1507 : {
1508 0 : aNewPolygon.append(rCandidate.getB2DPoint(nNextIndex));
1509 : }
1510 :
1511 0 : SdrPathObj* pPath = new SdrPathObj(eKind, basegfx::B2DPolyPolygon(aNewPolygon));
1512 0 : ImpCopyAttributes(pSrcPath, pPath);
1513 0 : pLast = pPath;
1514 0 : SdrInsertReason aReason(SDRREASON_VIEWCALL, pSrcPath);
1515 0 : rOL.InsertObject(pPath, rPos, &aReason);
1516 0 : if( bUndo )
1517 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, true));
1518 0 : MarkObj(pPath, pPV, false, true);
1519 0 : rPos++;
1520 0 : }
1521 : }
1522 0 : }
1523 :
1524 0 : if(pLast && pSrcPath->GetOutlinerParaObject())
1525 : {
1526 0 : pLast->SetOutlinerParaObject(new OutlinerParaObject(*pSrcPath->GetOutlinerParaObject()));
1527 : }
1528 : }
1529 0 : else if(pCustomShape)
1530 : {
1531 0 : if(bMakeLines)
1532 : {
1533 : // break up custom shape
1534 0 : const SdrObject* pReplacement = pCustomShape->GetSdrObjectFromCustomShape();
1535 :
1536 0 : if(pReplacement)
1537 : {
1538 0 : SdrObject* pCandidate = pReplacement->Clone();
1539 : DBG_ASSERT(pCandidate, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
1540 0 : pCandidate->SetModel(pCustomShape->GetModel());
1541 :
1542 0 : if(((SdrShadowItem&)pCustomShape->GetMergedItem(SDRATTR_SHADOW)).GetValue())
1543 : {
1544 0 : if(pReplacement->ISA(SdrObjGroup))
1545 : {
1546 0 : pCandidate->SetMergedItem(SdrShadowItem(true));
1547 : }
1548 : }
1549 :
1550 0 : SdrInsertReason aReason(SDRREASON_VIEWCALL, pCustomShape);
1551 0 : rOL.InsertObject(pCandidate, rPos, &aReason);
1552 0 : if( bUndo )
1553 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pCandidate, true));
1554 0 : MarkObj(pCandidate, pPV, false, true);
1555 :
1556 0 : if(pCustomShape->HasText() && !pCustomShape->IsTextPath())
1557 : {
1558 : // #i37011# also create a text object and add at rPos + 1
1559 : SdrObject* pTextObj = SdrObjFactory::MakeNewObject(
1560 0 : pCustomShape->GetObjInventor(), OBJ_TEXT, 0L, pCustomShape->GetModel());
1561 :
1562 : // Copy text content
1563 0 : OutlinerParaObject* pParaObj = pCustomShape->GetOutlinerParaObject();
1564 0 : if(pParaObj)
1565 : {
1566 0 : pTextObj->NbcSetOutlinerParaObject(new OutlinerParaObject(*pParaObj));
1567 : }
1568 :
1569 : // copy all attributes
1570 0 : SfxItemSet aTargetItemSet(pCustomShape->GetMergedItemSet());
1571 :
1572 : // clear fill and line style
1573 0 : aTargetItemSet.Put(XLineStyleItem(XLINE_NONE));
1574 0 : aTargetItemSet.Put(XFillStyleItem(XFILL_NONE));
1575 :
1576 : // get the text bounds and set at text object
1577 0 : Rectangle aTextBounds = pCustomShape->GetSnapRect();
1578 0 : if(pCustomShape->GetTextBounds(aTextBounds))
1579 : {
1580 0 : pTextObj->SetSnapRect(aTextBounds);
1581 : }
1582 :
1583 : // if rotated, copy GeoStat, too.
1584 0 : const GeoStat& rSourceGeo = pCustomShape->GetGeoStat();
1585 0 : if(rSourceGeo.nDrehWink)
1586 : {
1587 : pTextObj->NbcRotate(
1588 0 : pCustomShape->GetSnapRect().Center(), rSourceGeo.nDrehWink,
1589 0 : rSourceGeo.nSin, rSourceGeo.nCos);
1590 : }
1591 :
1592 : // set modified ItemSet at text object
1593 0 : pTextObj->SetMergedItemSet(aTargetItemSet);
1594 :
1595 : // insert object
1596 0 : rOL.InsertObject(pTextObj, rPos + 1, &aReason);
1597 0 : if( bUndo )
1598 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pTextObj, true));
1599 0 : MarkObj(pTextObj, pPV, false, true);
1600 : }
1601 : }
1602 : }
1603 : }
1604 0 : }
1605 :
1606 0 : void SdrEditView::DismantleMarkedObjects(bool bMakeLines)
1607 : {
1608 : // temporary MarkList
1609 0 : SdrMarkList aRemoveMerker;
1610 :
1611 0 : SortMarkedObjects();
1612 :
1613 0 : const bool bUndo = IsUndoEnabled();
1614 :
1615 0 : if( bUndo )
1616 : {
1617 : // comment is constructed later
1618 0 : BegUndo("", "", bMakeLines ? SDRREPFUNC_OBJ_DISMANTLE_LINES : SDRREPFUNC_OBJ_DISMANTLE_POLYS);
1619 : }
1620 :
1621 : sal_uIntPtr nm;
1622 0 : sal_uIntPtr nAnz=GetMarkedObjectCount();
1623 0 : SdrObjList* pOL0=NULL;
1624 0 : for (nm=nAnz; nm>0;) {
1625 0 : nm--;
1626 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
1627 0 : SdrObject* pObj=pM->GetMarkedSdrObj();
1628 0 : SdrPageView* pPV=pM->GetPageView();
1629 0 : SdrObjList* pOL=pObj->GetObjList();
1630 0 : if (pOL!=pOL0) { pOL0=pOL; pObj->GetOrdNum(); } // make sure OrdNums are correct!
1631 0 : if (ImpCanDismantle(pObj,bMakeLines)) {
1632 0 : aRemoveMerker.InsertEntry(SdrMark(pObj,pM->GetPageView()));
1633 0 : sal_uIntPtr nPos0=pObj->GetOrdNumDirect();
1634 0 : sal_uIntPtr nPos=nPos0+1;
1635 0 : SdrObjList* pSubList=pObj->GetSubList();
1636 0 : if (pSubList!=NULL && !pObj->Is3DObj()) {
1637 0 : SdrObjListIter aIter(*pSubList,IM_DEEPNOGROUPS);
1638 0 : while (aIter.IsMore()) {
1639 0 : const SdrObject* pObj1=aIter.Next();
1640 0 : ImpDismantleOneObject(pObj1,*pOL,nPos,pPV,bMakeLines);
1641 0 : }
1642 : } else {
1643 0 : ImpDismantleOneObject(pObj,*pOL,nPos,pPV,bMakeLines);
1644 : }
1645 0 : if( bUndo )
1646 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj,true));
1647 0 : pOL->RemoveObject(nPos0);
1648 :
1649 0 : if( !bUndo )
1650 0 : SdrObject::Free(pObj);
1651 : }
1652 : }
1653 :
1654 0 : if( bUndo )
1655 : {
1656 : // construct UndoComment from objects actually used
1657 0 : SetUndoComment(ImpGetResStr(bMakeLines?STR_EditDismantle_Lines:STR_EditDismantle_Polys),aRemoveMerker.GetMarkDescription());
1658 : // remove objects actually used from the list
1659 0 : EndUndo();
1660 0 : }
1661 0 : }
1662 :
1663 :
1664 : // Group
1665 :
1666 :
1667 0 : void SdrEditView::GroupMarked(const SdrObject* pUserGrp)
1668 : {
1669 0 : if (AreObjectsMarked())
1670 : {
1671 0 : SortMarkedObjects();
1672 :
1673 0 : const bool bUndo = IsUndoEnabled();
1674 0 : if( bUndo )
1675 : {
1676 0 : BegUndo(ImpGetResStr(STR_EditGroup),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_GROUP);
1677 :
1678 0 : const sal_uIntPtr nAnz = GetMarkedObjectCount();
1679 0 : for(sal_uIntPtr nm = nAnz; nm>0; )
1680 : {
1681 : // add UndoActions for all affected objects
1682 0 : nm--;
1683 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
1684 0 : SdrObject* pObj = pM->GetMarkedSdrObj();
1685 0 : std::vector< SdrUndoAction* > vConnectorUndoActions( CreateConnectorUndo( *pObj ) );
1686 0 : AddUndoActions( vConnectorUndoActions );
1687 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject( *pObj ));
1688 0 : }
1689 : }
1690 :
1691 0 : SdrMarkList aNewMark;
1692 0 : SdrPageView* pPV = GetSdrPageView();
1693 :
1694 0 : if(pPV)
1695 : {
1696 0 : SdrObjList* pAktLst=pPV->GetObjList();
1697 0 : SdrObjList* pSrcLst=pAktLst;
1698 0 : SdrObjList* pSrcLst0=pSrcLst;
1699 0 : SdrPage* pPage=pPV->GetPage();
1700 : // make sure OrdNums are correct
1701 0 : if (pSrcLst->IsObjOrdNumsDirty())
1702 0 : pSrcLst->RecalcObjOrdNums();
1703 0 : SdrObject* pGrp=NULL;
1704 0 : SdrObject* pRefObj=NULL; // reference for InsertReason (-> anchors in Writer)
1705 0 : SdrObject* pRefObj1=NULL; // reference for InsertReason (-> anchors in Writer)
1706 0 : SdrObjList* pDstLst=NULL;
1707 : // if all selected objects come from foreign object lists.
1708 : // the group object is the last one in the list.
1709 0 : sal_uIntPtr nInsPos=pSrcLst->GetObjCount();
1710 0 : bool bNeedInsPos=true;
1711 0 : for (sal_uIntPtr nm=GetMarkedObjectCount(); nm>0;)
1712 : {
1713 0 : nm--;
1714 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
1715 0 : if (pM->GetPageView()==pPV)
1716 : {
1717 0 : if (pGrp==NULL)
1718 : {
1719 0 : if (pUserGrp!=NULL)
1720 0 : pGrp=pUserGrp->Clone();
1721 0 : if (pGrp==NULL)
1722 0 : pGrp=new SdrObjGroup;
1723 0 : pDstLst=pGrp->GetSubList();
1724 : DBG_ASSERT(pDstLst!=NULL,"Alleged group object doesn't return object list.");
1725 : }
1726 0 : SdrObject* pObj=pM->GetMarkedSdrObj();
1727 0 : pSrcLst=pObj->GetObjList();
1728 0 : if (pSrcLst!=pSrcLst0)
1729 : {
1730 0 : if (pSrcLst->IsObjOrdNumsDirty())
1731 0 : pSrcLst->RecalcObjOrdNums();
1732 : }
1733 0 : bool bForeignList=pSrcLst!=pAktLst;
1734 0 : bool bGrouped=pSrcLst!=pPage;
1735 0 : if (!bForeignList && bNeedInsPos)
1736 : {
1737 0 : nInsPos=pObj->GetOrdNum(); // this way, all ObjOrdNum of the page are set
1738 0 : nInsPos++;
1739 0 : bNeedInsPos=false;
1740 : }
1741 0 : pSrcLst->RemoveObject(pObj->GetOrdNumDirect());
1742 0 : if (!bForeignList)
1743 0 : nInsPos--; // correct InsertPos
1744 0 : SdrInsertReason aReason(SDRREASON_VIEWCALL);
1745 0 : pDstLst->InsertObject(pObj,0,&aReason);
1746 0 : GetMarkedObjectListWriteAccess().DeleteMark(nm);
1747 0 : if (pRefObj1==NULL)
1748 0 : pRefObj1=pObj; // the topmost visible object
1749 0 : if (!bGrouped)
1750 : {
1751 0 : if (pRefObj==NULL)
1752 0 : pRefObj=pObj; // the topmost visible non-group object
1753 : }
1754 0 : pSrcLst0=pSrcLst;
1755 : }
1756 : }
1757 0 : if (pRefObj==NULL)
1758 0 : pRefObj=pRefObj1;
1759 0 : if (pGrp!=NULL)
1760 : {
1761 0 : aNewMark.InsertEntry(SdrMark(pGrp,pPV));
1762 0 : sal_uIntPtr nAnz=pDstLst->GetObjCount();
1763 0 : SdrInsertReason aReason(SDRREASON_VIEWCALL,pRefObj);
1764 0 : pAktLst->InsertObject(pGrp,nInsPos,&aReason);
1765 0 : if( bUndo )
1766 : {
1767 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pGrp,true)); // no recalculation!
1768 0 : for (sal_uIntPtr no=0; no<nAnz; no++)
1769 : {
1770 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst->GetObj(no)));
1771 : }
1772 : }
1773 : }
1774 : }
1775 0 : GetMarkedObjectListWriteAccess().Merge(aNewMark);
1776 0 : MarkListHasChanged();
1777 :
1778 0 : if( bUndo )
1779 0 : EndUndo();
1780 : }
1781 0 : }
1782 :
1783 :
1784 : // Ungroup
1785 :
1786 :
1787 0 : void SdrEditView::UnGroupMarked()
1788 : {
1789 0 : SdrMarkList aNewMark;
1790 :
1791 0 : const bool bUndo = IsUndoEnabled();
1792 0 : if( bUndo )
1793 0 : BegUndo("", "", SDRREPFUNC_OBJ_UNGROUP);
1794 :
1795 0 : sal_uIntPtr nCount=0;
1796 0 : OUString aName1;
1797 0 : OUString aName;
1798 0 : bool bNameOk=false;
1799 0 : for (sal_uIntPtr nm=GetMarkedObjectCount(); nm>0;) {
1800 0 : nm--;
1801 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
1802 0 : SdrObject* pGrp=pM->GetMarkedSdrObj();
1803 0 : SdrObjList* pSrcLst=pGrp->GetSubList();
1804 0 : if (pSrcLst!=NULL) {
1805 0 : nCount++;
1806 0 : if (nCount==1) {
1807 0 : aName = pGrp->TakeObjNameSingul(); // retrieve name of group
1808 0 : aName1 = pGrp->TakeObjNamePlural(); // retrieve name of group
1809 0 : bNameOk=true;
1810 : } else {
1811 0 : if (nCount==2) aName=aName1; // set plural name
1812 0 : if (bNameOk) {
1813 0 : OUString aStr(pGrp->TakeObjNamePlural()); // retrieve name of group
1814 :
1815 0 : if (aStr != aName)
1816 0 : bNameOk = false;
1817 : }
1818 : }
1819 0 : sal_uIntPtr nDstCnt=pGrp->GetOrdNum();
1820 0 : SdrObjList* pDstLst=pM->GetPageView()->GetObjList();
1821 :
1822 : // FIRST move contained objects to parent of group, so that
1823 : // the contained objects are NOT migrated to the UNDO-ItemPool
1824 : // when AddUndo(new SdrUndoDelObj(*pGrp)) is called.
1825 0 : sal_uIntPtr nAnz=pSrcLst->GetObjCount();
1826 : sal_uIntPtr no;
1827 :
1828 0 : if( bUndo )
1829 : {
1830 0 : for (no=nAnz; no>0;)
1831 : {
1832 0 : no--;
1833 0 : SdrObject* pObj=pSrcLst->GetObj(no);
1834 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject(*pObj));
1835 : }
1836 : }
1837 0 : for (no=0; no<nAnz; no++)
1838 : {
1839 0 : SdrObject* pObj=pSrcLst->RemoveObject(0);
1840 0 : SdrInsertReason aReason(SDRREASON_VIEWCALL,pGrp);
1841 0 : pDstLst->InsertObject(pObj,nDstCnt,&aReason);
1842 0 : if( bUndo )
1843 0 : AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pObj,true));
1844 0 : nDstCnt++;
1845 : // No SortCheck when inserting into MarkList, because that would
1846 : // provoke a RecalcOrdNums() each time because of pObj->GetOrdNum():
1847 0 : aNewMark.InsertEntry(SdrMark(pObj,pM->GetPageView()),false);
1848 : }
1849 :
1850 0 : if( bUndo )
1851 : {
1852 : // Now it is safe to add the delete-UNDO which triggers the
1853 : // MigrateItemPool now only for itself, not for the sub-objects.
1854 : // nDstCnt is right, because previous inserts move group
1855 : // object deeper and increase nDstCnt.
1856 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp));
1857 : }
1858 0 : pDstLst->RemoveObject(nDstCnt);
1859 :
1860 0 : if( !bUndo )
1861 0 : SdrObject::Free(pGrp);
1862 :
1863 0 : GetMarkedObjectListWriteAccess().DeleteMark(nm);
1864 : }
1865 : }
1866 0 : if (nCount!=0)
1867 : {
1868 0 : if (!bNameOk)
1869 0 : aName=ImpGetResStr(STR_ObjNamePluralGRUP); // Use the term "Group Objects," if different objects are grouped.
1870 0 : SetUndoComment(ImpGetResStr(STR_EditUngroup),aName);
1871 : }
1872 :
1873 0 : if( bUndo )
1874 0 : EndUndo();
1875 :
1876 0 : if (nCount!=0)
1877 : {
1878 0 : GetMarkedObjectListWriteAccess().Merge(aNewMark,true); // Because of the sorting above, aNewMark is reversed
1879 0 : MarkListHasChanged();
1880 0 : }
1881 0 : }
1882 :
1883 :
1884 : // ConvertToPoly
1885 :
1886 :
1887 0 : SdrObject* SdrEditView::ImpConvertOneObj(SdrObject* pObj, bool bPath, bool bLineToArea)
1888 : {
1889 0 : SdrObject* pNewObj = pObj->ConvertToPolyObj(bPath, bLineToArea);
1890 0 : if (pNewObj!=NULL)
1891 : {
1892 0 : SdrObjList* pOL=pObj->GetObjList();
1893 : DBG_ASSERT(pOL!=NULL,"ConvertTo: Object doesn't return object list");
1894 0 : if (pOL!=NULL)
1895 : {
1896 0 : const bool bUndo = IsUndoEnabled();
1897 0 : if( bUndo )
1898 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoReplaceObject(*pObj,*pNewObj));
1899 :
1900 0 : pOL->ReplaceObject(pNewObj,pObj->GetOrdNum());
1901 :
1902 0 : if( !bUndo )
1903 0 : SdrObject::Free(pObj);
1904 : }
1905 : }
1906 0 : return pNewObj;
1907 : }
1908 :
1909 0 : void SdrEditView::ImpConvertTo(bool bPath, bool bLineToArea)
1910 : {
1911 0 : bool bMrkChg=false;
1912 0 : if (AreObjectsMarked()) {
1913 0 : sal_uIntPtr nMarkAnz=GetMarkedObjectCount();
1914 0 : sal_uInt16 nDscrID=0;
1915 0 : if(bLineToArea)
1916 : {
1917 0 : if(nMarkAnz == 1)
1918 0 : nDscrID = STR_EditConvToContour;
1919 : else
1920 0 : nDscrID = STR_EditConvToContours;
1921 :
1922 0 : BegUndo(ImpGetResStr(nDscrID), GetDescriptionOfMarkedObjects());
1923 : }
1924 : else
1925 : {
1926 0 : if (bPath) {
1927 0 : if (nMarkAnz==1) nDscrID=STR_EditConvToCurve;
1928 0 : else nDscrID=STR_EditConvToCurves;
1929 0 : BegUndo(ImpGetResStr(nDscrID),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_CONVERTTOPATH);
1930 : } else {
1931 0 : if (nMarkAnz==1) nDscrID=STR_EditConvToPoly;
1932 0 : else nDscrID=STR_EditConvToPolys;
1933 0 : BegUndo(ImpGetResStr(nDscrID),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_CONVERTTOPOLY);
1934 : }
1935 : }
1936 0 : for (sal_uIntPtr nm=nMarkAnz; nm>0;) {
1937 0 : nm--;
1938 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
1939 0 : SdrObject* pObj=pM->GetMarkedSdrObj();
1940 0 : SdrPageView* pPV=pM->GetPageView();
1941 0 : if (pObj->IsGroupObject() && !pObj->Is3DObj()) {
1942 0 : SdrObject* pGrp=pObj;
1943 0 : SdrObjListIter aIter(*pGrp,IM_DEEPNOGROUPS);
1944 0 : while (aIter.IsMore()) {
1945 0 : pObj=aIter.Next();
1946 0 : ImpConvertOneObj(pObj,bPath,bLineToArea);
1947 0 : }
1948 : } else {
1949 0 : SdrObject* pNewObj=ImpConvertOneObj(pObj,bPath,bLineToArea);
1950 0 : if (pNewObj!=NULL) {
1951 0 : bMrkChg=true;
1952 0 : GetMarkedObjectListWriteAccess().ReplaceMark(SdrMark(pNewObj,pPV),nm);
1953 : }
1954 : }
1955 : }
1956 0 : EndUndo();
1957 0 : if (bMrkChg) AdjustMarkHdl();
1958 0 : if (bMrkChg) MarkListHasChanged();
1959 : }
1960 0 : }
1961 :
1962 0 : void SdrEditView::ConvertMarkedToPathObj(bool bLineToArea)
1963 : {
1964 0 : ImpConvertTo(true, bLineToArea);
1965 0 : }
1966 :
1967 0 : void SdrEditView::ConvertMarkedToPolyObj(bool bLineToArea)
1968 : {
1969 0 : ImpConvertTo(false, bLineToArea);
1970 0 : }
1971 :
1972 :
1973 : // Metafile Import
1974 :
1975 :
1976 0 : void SdrEditView::DoImportMarkedMtf(SvdProgressInfo *pProgrInfo)
1977 : {
1978 0 : const bool bUndo = IsUndoEnabled();
1979 :
1980 0 : if( bUndo )
1981 0 : BegUndo("", "", SDRREPFUNC_OBJ_IMPORTMTF);
1982 :
1983 0 : SortMarkedObjects();
1984 0 : SdrMarkList aForTheDescription;
1985 0 : SdrMarkList aNewMarked;
1986 0 : sal_uIntPtr nAnz=GetMarkedObjectCount();
1987 :
1988 0 : for (sal_uIntPtr nm=nAnz; nm>0;)
1989 : { // create Undo objects for all new objects
1990 : // check for cancellation between the metafiles
1991 0 : if( pProgrInfo != NULL )
1992 : {
1993 0 : pProgrInfo->SetNextObject();
1994 0 : if(!pProgrInfo->ReportActions(0))
1995 0 : break;
1996 : }
1997 :
1998 0 : nm--;
1999 0 : SdrMark* pM=GetSdrMarkByIndex(nm);
2000 0 : SdrObject* pObj=pM->GetMarkedSdrObj();
2001 0 : SdrPageView* pPV=pM->GetPageView();
2002 0 : SdrObjList* pOL=pObj->GetObjList();
2003 0 : sal_uIntPtr nInsPos=pObj->GetOrdNum()+1;
2004 0 : SdrGrafObj* pGraf=PTR_CAST(SdrGrafObj,pObj);
2005 0 : SdrOle2Obj* pOle2=PTR_CAST(SdrOle2Obj,pObj);
2006 0 : sal_uIntPtr nInsAnz=0;
2007 0 : Rectangle aLogicRect;
2008 :
2009 0 : if(pGraf && (pGraf->HasGDIMetaFile() || pGraf->isEmbeddedSvg()))
2010 : {
2011 0 : GDIMetaFile aMetaFile;
2012 :
2013 0 : if(pGraf->HasGDIMetaFile())
2014 : {
2015 0 : aMetaFile = pGraf->GetTransformedGraphic(SDRGRAFOBJ_TRANSFORMATTR_COLOR|SDRGRAFOBJ_TRANSFORMATTR_MIRROR).GetGDIMetaFile();
2016 : }
2017 0 : else if(pGraf->isEmbeddedSvg())
2018 : {
2019 0 : aMetaFile = pGraf->getMetafileFromEmbeddedSvg();
2020 : }
2021 :
2022 0 : if(aMetaFile.GetActionSize())
2023 : {
2024 0 : aLogicRect = pGraf->GetLogicRect();
2025 0 : ImpSdrGDIMetaFileImport aFilter(*pMod, pObj->GetLayer(), aLogicRect);
2026 0 : nInsAnz = aFilter.DoImport(aMetaFile, *pOL, nInsPos, pProgrInfo);
2027 0 : }
2028 : }
2029 0 : if ( pOle2!=NULL && pOle2->GetGraphic() )
2030 : {
2031 0 : aLogicRect = pOle2->GetLogicRect();
2032 0 : ImpSdrGDIMetaFileImport aFilter(*pMod, pObj->GetLayer(), aLogicRect);
2033 0 : nInsAnz = aFilter.DoImport(pOle2->GetGraphic()->GetGDIMetaFile(), *pOL, nInsPos, pProgrInfo);
2034 : }
2035 0 : if (nInsAnz!=0)
2036 : {
2037 : // transformation
2038 0 : GeoStat aGeoStat(pGraf ? pGraf->GetGeoStat() : pOle2->GetGeoStat());
2039 0 : sal_uIntPtr nObj=nInsPos;
2040 :
2041 0 : if(aGeoStat.nShearWink)
2042 : {
2043 0 : aGeoStat.RecalcTan();
2044 : }
2045 :
2046 0 : if(aGeoStat.nDrehWink)
2047 : {
2048 0 : aGeoStat.RecalcSinCos();
2049 : }
2050 :
2051 0 : for (sal_uIntPtr i=0; i<nInsAnz; i++)
2052 : {
2053 0 : if( bUndo )
2054 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pOL->GetObj(nObj)));
2055 :
2056 : // update new MarkList
2057 0 : SdrObject* pCandidate = pOL->GetObj(nObj);
2058 :
2059 : // apply original transformation
2060 0 : if(aGeoStat.nShearWink)
2061 : {
2062 0 : pCandidate->NbcShear(aLogicRect.TopLeft(), aGeoStat.nShearWink, aGeoStat.nTan, false);
2063 : }
2064 :
2065 0 : if(aGeoStat.nDrehWink)
2066 : {
2067 0 : pCandidate->NbcRotate(aLogicRect.TopLeft(), aGeoStat.nDrehWink, aGeoStat.nSin, aGeoStat.nCos);
2068 : }
2069 :
2070 0 : SdrMark aNewMark(pCandidate, pPV);
2071 0 : aNewMarked.InsertEntry(aNewMark);
2072 :
2073 0 : nObj++;
2074 0 : }
2075 0 : aForTheDescription.InsertEntry(*pM);
2076 :
2077 0 : if( bUndo )
2078 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
2079 :
2080 : // remove object from selection and delete
2081 0 : GetMarkedObjectListWriteAccess().DeleteMark(TryToFindMarkedObject(pObj));
2082 0 : pOL->RemoveObject(nInsPos-1);
2083 :
2084 0 : if( !bUndo )
2085 0 : SdrObject::Free(pObj);
2086 : }
2087 : }
2088 :
2089 0 : if(aNewMarked.GetMarkCount())
2090 : {
2091 : // create new selection
2092 0 : for(sal_uIntPtr a(0); a < aNewMarked.GetMarkCount(); a++)
2093 : {
2094 0 : GetMarkedObjectListWriteAccess().InsertEntry(*aNewMarked.GetMark(a));
2095 : }
2096 :
2097 0 : SortMarkedObjects();
2098 : }
2099 :
2100 0 : if( bUndo )
2101 : {
2102 0 : SetUndoComment(ImpGetResStr(STR_EditImportMtf),aForTheDescription.GetMarkDescription());
2103 0 : EndUndo();
2104 0 : }
2105 0 : }
2106 :
2107 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|