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