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