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