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