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 which 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
1168 // #124760# To have a correct selection with only the new object it is necessary to
1169 // unmark all objects first. If not doing so, there may remain invalid pointers to objects
1170 //TTTT:Not needed for aw080 (!)
1171 UnmarkAllObj(pInsPV);
1172
1173 MarkObj(pPath, pInsPV, sal_False, sal_True);
1174 }
1175
1176 aRemove.ForceSort();
1177 switch(eMode)
1178 {
1179 case SDR_MERGE_MERGE:
1180 {
1181 SetUndoComment(
1182 ImpGetResStr(STR_EditMergeMergePoly),
1183 aRemove.GetMarkDescription());
1184 break;
1185 }
1186 case SDR_MERGE_SUBSTRACT:
1187 {
1188 SetUndoComment(
1189 ImpGetResStr(STR_EditMergeSubstractPoly),
1190 aRemove.GetMarkDescription());
1191 break;
1192 }
1193 case SDR_MERGE_INTERSECT:
1194 {
1195 SetUndoComment(
1196 ImpGetResStr(STR_EditMergeIntersectPoly),
1197 aRemove.GetMarkDescription());
1198 break;
1199 }
1200 }
1201 DeleteMarkedList(aRemove);
1202
1203 if( bUndo )
1204 EndUndo();
1205 }
1206 }
1207
CombineMarkedObjects(sal_Bool bNoPolyPoly)1208 void SdrEditView::CombineMarkedObjects(sal_Bool bNoPolyPoly)
1209 {
1210 // #105899# Start of Combine-Undo put to front, else ConvertMarkedToPolyObj would
1211 // create a 2nd Undo-action and Undo-Comment.
1212
1213 bool bUndo = IsUndoEnabled();
1214
1215 // Undo-String will be set later
1216 if( bUndo )
1217 BegUndo(String(), String(), bNoPolyPoly ? SDRREPFUNC_OBJ_COMBINE_ONEPOLY : SDRREPFUNC_OBJ_COMBINE_POLYPOLY);
1218
1219 // #105899# First, guarantee that all objects are converted to polyobjects,
1220 // especially for SdrGrafObj with bitmap filling this is necessary to not
1221 // loose the bitmap filling.
1222
1223 // #i12392#
1224 // ConvertMarkedToPolyObj was too strong here, it will loose quality and
1225 // information when curve objects are combined. This can be replaced by
1226 // using ConvertMarkedToPathObj without changing the previous fix.
1227
1228 // #i21250#
1229 // Instead of simply passing sal_True as LineToArea, use bNoPolyPoly as info
1230 // if this command is a 'Combine' or a 'Connect' command. On Connect it's sal_True.
1231 // To not concert line segments with a set line width to polygons in that case,
1232 // use this info. Do not convert LineToArea on Connect commands.
1233 // ConvertMarkedToPathObj(!bNoPolyPoly);
1234
1235 // #114310#
1236 // This is used for Combine and Connect. In no case it is necessary to force
1237 // the content to curve, but it is also not good to force to polygons. Thus,
1238 // curve is the less information losing one. Remember: This place is not
1239 // used for merge.
1240 // LineToArea is never necessary, both commands are able to take over the
1241 // set line style and to display it correctly. Thus, i will use a
1242 // ConvertMarkedToPathObj with a sal_False in any case. Only drawback is that
1243 // simple polygons will be changed to curves, but with no information loss.
1244 ConvertMarkedToPathObj(sal_False /* bLineToArea */);
1245
1246 // continue as before
1247 basegfx::B2DPolyPolygon aPolyPolygon;
1248 SdrObjList* pAktOL = 0L;
1249 SdrMarkList aRemoveMerker;
1250
1251 SortMarkedObjects();
1252 sal_uInt32 nInsPos(0xFFFFFFFF);
1253 SdrObjList* pInsOL = 0L;
1254 SdrPageView* pInsPV = 0L;
1255 const sal_uInt32 nAnz(GetMarkedObjectCount());
1256 const SdrObject* pAttrObj = 0L;
1257
1258 for(sal_uInt32 a(nAnz); a > 0L; )
1259 {
1260 a--;
1261 SdrMark* pM = GetSdrMarkByIndex(a);
1262 SdrObject* pObj = pM->GetMarkedSdrObj();
1263 SdrObjList* pThisOL = pObj->GetObjList();
1264
1265 if(pAktOL != pThisOL)
1266 {
1267 pAktOL = pThisOL;
1268 }
1269
1270 if(ImpCanConvertForCombine(pObj))
1271 {
1272 // Obj merken fuer Attribute kopieren
1273 pAttrObj = pObj;
1274
1275 // unfortunately ConvertMarkedToPathObj has converted all
1276 // involved polygon data to curve segments, even if not necessary.
1277 // It is better to try to reduce to more simple polygons.
1278 basegfx::B2DPolyPolygon aTmpPoly(basegfx::tools::simplifyCurveSegments(ImpGetPolyPolygon(pObj, sal_True)));
1279 aPolyPolygon.insert(0L, aTmpPoly);
1280
1281 if(!pInsOL)
1282 {
1283 nInsPos = pObj->GetOrdNum() + 1L;
1284 pInsPV = pM->GetPageView();
1285 pInsOL = pObj->GetObjList();
1286 }
1287
1288 aRemoveMerker.InsertEntry(SdrMark(pObj, pM->GetPageView()));
1289 }
1290 }
1291
1292 if(bNoPolyPoly)
1293 {
1294 basegfx::B2DPolygon aCombinedPolygon(ImpCombineToSinglePolygon(aPolyPolygon));
1295 aPolyPolygon.clear();
1296 aPolyPolygon.append(aCombinedPolygon);
1297 }
1298
1299 const sal_uInt32 nPolyCount(aPolyPolygon.count());
1300
1301 if(nPolyCount)
1302 {
1303 SdrObjKind eKind = OBJ_PATHFILL;
1304
1305 if(nPolyCount > 1L)
1306 {
1307 aPolyPolygon.setClosed(true);
1308 }
1309 else
1310 {
1311 // auf Polyline Checken
1312 const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(0L));
1313 const sal_uInt32 nPointCount(aPolygon.count());
1314
1315 if(nPointCount <= 2L)
1316 {
1317 eKind = OBJ_PATHLINE;
1318 }
1319 else
1320 {
1321 if(!aPolygon.isClosed())
1322 {
1323 const basegfx::B2DPoint aPointA(aPolygon.getB2DPoint(0L));
1324 const basegfx::B2DPoint aPointB(aPolygon.getB2DPoint(nPointCount - 1L));
1325 const double fDistance(basegfx::B2DVector(aPointB - aPointA).getLength());
1326 const double fJoinTolerance(10.0);
1327
1328 if(fDistance < fJoinTolerance)
1329 {
1330 aPolyPolygon.setClosed(true);
1331 }
1332 else
1333 {
1334 eKind = OBJ_PATHLINE;
1335 }
1336 }
1337 }
1338 }
1339
1340 SdrPathObj* pPath = new SdrPathObj(eKind,aPolyPolygon);
1341
1342 // Attribute des untersten Objekts
1343 ImpCopyAttributes(pAttrObj, pPath);
1344
1345 // #100408# If LineStyle of pAttrObj is XLINE_NONE force to XLINE_SOLID to make visible.
1346 const XLineStyle eLineStyle = ((const XLineStyleItem&)pAttrObj->GetMergedItem(XATTR_LINESTYLE)).GetValue();
1347 const XFillStyle eFillStyle = ((const XFillStyleItem&)pAttrObj->GetMergedItem(XATTR_FILLSTYLE)).GetValue();
1348
1349 // #110635#
1350 // Take fill style/closed state of pAttrObj in account when deciding to change the line style
1351 sal_Bool bIsClosedPathObj(pAttrObj->ISA(SdrPathObj) && ((SdrPathObj*)pAttrObj)->IsClosed());
1352
1353 if(XLINE_NONE == eLineStyle && (XFILL_NONE == eFillStyle || !bIsClosedPathObj))
1354 {
1355 pPath->SetMergedItem(XLineStyleItem(XLINE_SOLID));
1356 }
1357
1358 SdrInsertReason aReason(SDRREASON_VIEWCALL,pAttrObj);
1359 pInsOL->InsertObject(pPath,nInsPos,&aReason);
1360 if( bUndo )
1361 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath));
1362
1363 // #111111#
1364 // Here was a severe error: Without UnmarkAllObj, the new object was marked
1365 // additionally to the two ones which are deleted below. As long as those are
1366 // in the UNDO there is no problem, but as soon as they get deleted, the
1367 // MarkList will contain deleted objects -> GPF.
1368 UnmarkAllObj(pInsPV);
1369 MarkObj(pPath, pInsPV, sal_False, sal_True);
1370 }
1371
1372 // UndoComment aus den tatsaechlich verwendeten Objekten zusammenbauen
1373 aRemoveMerker.ForceSort(); // wichtig fuer Remove (s.u.)
1374 if( bUndo )
1375 SetUndoComment(ImpGetResStr(bNoPolyPoly?STR_EditCombine_OnePoly:STR_EditCombine_PolyPoly),aRemoveMerker.GetMarkDescription());
1376
1377 // die tatsaechlich verwendeten Objekten aus der Liste entfernen
1378 DeleteMarkedList(aRemoveMerker);
1379 if( bUndo )
1380 EndUndo();
1381 }
1382
1383 ////////////////////////////////////////////////////////////////////////////////////////////////////
1384 //
1385 // @@@@@ @@ @@@@ @@ @@ @@@@ @@ @@ @@@@@@ @@ @@@@@
1386 // @@ @@ @@ @@ @@ @@@ @@@ @@ @@ @@@ @@ @@ @@ @@
1387 // @@ @@ @@ @@ @@@@@@@ @@ @@ @@@@@@ @@ @@ @@
1388 // @@ @@ @@ @@@@ @@@@@@@ @@@@@@ @@@@@@ @@ @@ @@@@
1389 // @@ @@ @@ @@ @@ @ @@ @@ @@ @@ @@@ @@ @@ @@
1390 // @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@ @@
1391 // @@@@@ @@ @@@@ @@ @@ @@ @@ @@ @@ @@ @@@@@ @@@@@
1392 //
1393 ////////////////////////////////////////////////////////////////////////////////////////////////////
1394
ImpCanDismantle(const basegfx::B2DPolyPolygon & rPpolyPolygon,sal_Bool bMakeLines) const1395 sal_Bool SdrEditView::ImpCanDismantle(const basegfx::B2DPolyPolygon& rPpolyPolygon, sal_Bool bMakeLines) const
1396 {
1397 sal_Bool bCan(sal_False);
1398 const sal_uInt32 nPolygonCount(rPpolyPolygon.count());
1399
1400 if(nPolygonCount >= 2L)
1401 {
1402 // #i69172# dismantle makes sense with 2 or more polygons in a polyPolygon
1403 bCan = sal_True;
1404 }
1405 else if(bMakeLines && 1L == nPolygonCount)
1406 {
1407 // #i69172# ..or with at least 2 edges (curves or lines)
1408 const basegfx::B2DPolygon aPolygon(rPpolyPolygon.getB2DPolygon(0L));
1409 const sal_uInt32 nPointCount(aPolygon.count());
1410
1411 if(nPointCount > 2L)
1412 {
1413 bCan = sal_True;
1414 }
1415 }
1416
1417 return bCan;
1418 }
1419
ImpCanDismantle(const SdrObject * pObj,sal_Bool bMakeLines) const1420 sal_Bool SdrEditView::ImpCanDismantle(const SdrObject* pObj, sal_Bool bMakeLines) const
1421 {
1422 sal_Bool bOtherObjs(sal_False); // sal_True=andere Objekte ausser PathObj's vorhanden
1423 sal_Bool bMin1PolyPoly(sal_False); // sal_True=mind. 1 PolyPolygon mit mehr als ein Polygon vorhanden
1424 SdrObjList* pOL = pObj->GetSubList();
1425
1426 if(pOL)
1427 {
1428 // Aha, Gruppenobjekt. Also alle Member ansehen.
1429 // Alle muessen PathObjs sein !
1430 SdrObjListIter aIter(*pOL, IM_DEEPNOGROUPS);
1431
1432 while(aIter.IsMore() && !bOtherObjs)
1433 {
1434 const SdrObject* pObj1 = aIter.Next();
1435 const SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj1);
1436
1437 if(pPath)
1438 {
1439 if(ImpCanDismantle(pPath->GetPathPoly(), bMakeLines))
1440 {
1441 bMin1PolyPoly = sal_True;
1442 }
1443
1444 SdrObjTransformInfoRec aInfo;
1445 pObj1->TakeObjInfo(aInfo);
1446
1447 if(!aInfo.bCanConvToPath)
1448 {
1449 // Passiert z.B. im Falle Fontwork (Joe, 28-11-95)
1450 bOtherObjs = sal_True;
1451 }
1452 }
1453 else
1454 {
1455 bOtherObjs = sal_True;
1456 }
1457 }
1458 }
1459 else
1460 {
1461 const SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
1462 const SdrObjCustomShape* pCustomShape = PTR_CAST(SdrObjCustomShape, pObj);
1463
1464 // #i37011#
1465 if(pPath)
1466 {
1467 if(ImpCanDismantle(pPath->GetPathPoly(),bMakeLines))
1468 {
1469 bMin1PolyPoly = sal_True;
1470 }
1471
1472 SdrObjTransformInfoRec aInfo;
1473 pObj->TakeObjInfo(aInfo);
1474
1475 // #69711 : new condition IsLine() to be able to break simple Lines
1476 if(!(aInfo.bCanConvToPath || aInfo.bCanConvToPoly) && !pPath->IsLine())
1477 {
1478 // Passiert z.B. im Falle Fontwork (Joe, 28-11-95)
1479 bOtherObjs = sal_True;
1480 }
1481 }
1482 else if(pCustomShape)
1483 {
1484 if(bMakeLines)
1485 {
1486 // allow break command
1487 bMin1PolyPoly = sal_True;
1488 }
1489 }
1490 else
1491 {
1492 bOtherObjs = sal_True;
1493 }
1494 }
1495 return bMin1PolyPoly && !bOtherObjs;
1496 }
1497
ImpDismantleOneObject(const SdrObject * pObj,SdrObjList & rOL,sal_uIntPtr & rPos,SdrPageView * pPV,sal_Bool bMakeLines)1498 void SdrEditView::ImpDismantleOneObject(const SdrObject* pObj, SdrObjList& rOL, sal_uIntPtr& rPos, SdrPageView* pPV, sal_Bool bMakeLines)
1499 {
1500 const SdrPathObj* pSrcPath = PTR_CAST(SdrPathObj, pObj);
1501 const SdrObjCustomShape* pCustomShape = PTR_CAST(SdrObjCustomShape, pObj);
1502
1503 const bool bUndo = IsUndoEnabled();
1504
1505 if(pSrcPath)
1506 {
1507 // #i74631# redesigned due to XpolyPolygon removal and explicit constructors
1508 SdrObject* pLast = 0; // fuer die Zuweisung des OutlinerParaObject
1509 const basegfx::B2DPolyPolygon& rPolyPolygon(pSrcPath->GetPathPoly());
1510 const sal_uInt32 nPolyCount(rPolyPolygon.count());
1511
1512 for(sal_uInt32 a(0); a < nPolyCount; a++)
1513 {
1514 const basegfx::B2DPolygon& rCandidate(rPolyPolygon.getB2DPolygon(a));
1515 const sal_uInt32 nPointCount(rCandidate.count());
1516
1517 if(!bMakeLines || nPointCount < 2)
1518 {
1519 SdrPathObj* pPath = new SdrPathObj((SdrObjKind)pSrcPath->GetObjIdentifier(), basegfx::B2DPolyPolygon(rCandidate));
1520 ImpCopyAttributes(pSrcPath, pPath);
1521 pLast = pPath;
1522 SdrInsertReason aReason(SDRREASON_VIEWCALL, pSrcPath);
1523 rOL.InsertObject(pPath, rPos, &aReason);
1524 if( bUndo )
1525 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, sal_True));
1526 MarkObj(pPath, pPV, sal_False, sal_True);
1527 rPos++;
1528 }
1529 else
1530 {
1531 const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
1532
1533 for(sal_uInt32 b(0); b < nLoopCount; b++)
1534 {
1535 SdrObjKind eKind(OBJ_PLIN);
1536 basegfx::B2DPolygon aNewPolygon;
1537 const sal_uInt32 nNextIndex((b + 1) % nPointCount);
1538
1539 aNewPolygon.append(rCandidate.getB2DPoint(b));
1540
1541 if(rCandidate.areControlPointsUsed())
1542 {
1543 aNewPolygon.appendBezierSegment(
1544 rCandidate.getNextControlPoint(b),
1545 rCandidate.getPrevControlPoint(nNextIndex),
1546 rCandidate.getB2DPoint(nNextIndex));
1547 eKind = OBJ_PATHLINE;
1548 }
1549 else
1550 {
1551 aNewPolygon.append(rCandidate.getB2DPoint(nNextIndex));
1552 }
1553
1554 SdrPathObj* pPath = new SdrPathObj(eKind, basegfx::B2DPolyPolygon(aNewPolygon));
1555 ImpCopyAttributes(pSrcPath, pPath);
1556 pLast = pPath;
1557 SdrInsertReason aReason(SDRREASON_VIEWCALL, pSrcPath);
1558 rOL.InsertObject(pPath, rPos, &aReason);
1559 if( bUndo )
1560 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pPath, sal_True));
1561 MarkObj(pPath, pPV, sal_False, sal_True);
1562 rPos++;
1563 }
1564 }
1565 }
1566
1567 if(pLast && pSrcPath->GetOutlinerParaObject())
1568 {
1569 pLast->SetOutlinerParaObject(new OutlinerParaObject(*pSrcPath->GetOutlinerParaObject()));
1570 }
1571 }
1572 else if(pCustomShape)
1573 {
1574 if(bMakeLines)
1575 {
1576 // break up custom shape
1577 const SdrObject* pReplacement = pCustomShape->GetSdrObjectFromCustomShape();
1578
1579 if(pReplacement)
1580 {
1581 SdrObject* pCandidate = pReplacement->Clone();
1582 DBG_ASSERT(pCandidate, "SdrEditView::ImpDismantleOneObject: Could not clone SdrObject (!)");
1583 pCandidate->SetModel(pCustomShape->GetModel());
1584
1585 if(((SdrShadowItem&)pCustomShape->GetMergedItem(SDRATTR_SHADOW)).GetValue())
1586 {
1587 if(pReplacement->ISA(SdrObjGroup))
1588 {
1589 pCandidate->SetMergedItem(SdrShadowItem(sal_True));
1590 }
1591 }
1592
1593 SdrInsertReason aReason(SDRREASON_VIEWCALL, pCustomShape);
1594 rOL.InsertObject(pCandidate, rPos, &aReason);
1595 if( bUndo )
1596 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pCandidate, true));
1597 MarkObj(pCandidate, pPV, sal_False, sal_True);
1598
1599 if(pCustomShape->HasText() && !pCustomShape->IsTextPath())
1600 {
1601 // #i37011# also create a text object and add at rPos + 1
1602 SdrTextObj* pTextObj = (SdrTextObj*)SdrObjFactory::MakeNewObject(
1603 pCustomShape->GetObjInventor(), OBJ_TEXT, 0L, pCustomShape->GetModel());
1604
1605 // Copy text content
1606 OutlinerParaObject* pParaObj = pCustomShape->GetOutlinerParaObject();
1607 if(pParaObj)
1608 {
1609 pTextObj->NbcSetOutlinerParaObject(new OutlinerParaObject(*pParaObj));
1610 }
1611
1612 // copy all attributes
1613 SfxItemSet aTargetItemSet(pCustomShape->GetMergedItemSet());
1614
1615 // clear fill and line style
1616 aTargetItemSet.Put(XLineStyleItem(XLINE_NONE));
1617 aTargetItemSet.Put(XFillStyleItem(XFILL_NONE));
1618
1619 // get the text bounds and set at text object
1620 Rectangle aTextBounds = pCustomShape->GetSnapRect();
1621 if(pCustomShape->GetTextBounds(aTextBounds))
1622 {
1623 pTextObj->SetSnapRect(aTextBounds);
1624 }
1625
1626 // if rotated, copy GeoStat, too.
1627 const GeoStat& rSourceGeo = pCustomShape->GetGeoStat();
1628 if(rSourceGeo.nDrehWink)
1629 {
1630 pTextObj->NbcRotate(
1631 pCustomShape->GetSnapRect().Center(), rSourceGeo.nDrehWink,
1632 rSourceGeo.nSin, rSourceGeo.nCos);
1633 }
1634
1635 // set modified ItemSet at text object
1636 pTextObj->SetMergedItemSet(aTargetItemSet);
1637
1638 // insert object
1639 rOL.InsertObject(pTextObj, rPos + 1, &aReason);
1640 if( bUndo )
1641 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pTextObj, true));
1642 MarkObj(pTextObj, pPV, sal_False, sal_True);
1643 }
1644 }
1645 }
1646 }
1647 }
1648
DismantleMarkedObjects(sal_Bool bMakeLines)1649 void SdrEditView::DismantleMarkedObjects(sal_Bool bMakeLines)
1650 {
1651 //sal_uInt32 nCnt(0);
1652 // Temporaere Marklist
1653 SdrMarkList aRemoveMerker;
1654
1655 SortMarkedObjects();
1656
1657 const bool bUndo = IsUndoEnabled();
1658
1659 if( bUndo )
1660 {
1661 // Der Comment wird spaeter zusammengebaut
1662 BegUndo(String(), String(),
1663 bMakeLines ? SDRREPFUNC_OBJ_DISMANTLE_LINES : SDRREPFUNC_OBJ_DISMANTLE_POLYS);
1664 }
1665
1666 sal_uIntPtr nm;
1667 sal_uIntPtr nAnz=GetMarkedObjectCount();
1668 SdrObjList* pOL0=NULL;
1669 for (nm=nAnz; nm>0;) {
1670 nm--;
1671 SdrMark* pM=GetSdrMarkByIndex(nm);
1672 SdrObject* pObj=pM->GetMarkedSdrObj();
1673 SdrPageView* pPV=pM->GetPageView();
1674 SdrObjList* pOL=pObj->GetObjList();
1675 if (pOL!=pOL0) { pOL0=pOL; pObj->GetOrdNum(); } // sicherstellen, dass OrdNums stimmen!
1676 if (ImpCanDismantle(pObj,bMakeLines)) {
1677 aRemoveMerker.InsertEntry(SdrMark(pObj,pM->GetPageView()));
1678 sal_uIntPtr nPos0=pObj->GetOrdNumDirect();
1679 sal_uIntPtr nPos=nPos0+1;
1680 SdrObjList* pSubList=pObj->GetSubList();
1681 if (pSubList!=NULL && !pObj->Is3DObj()) {
1682 SdrObjListIter aIter(*pSubList,IM_DEEPNOGROUPS);
1683 while (aIter.IsMore()) {
1684 const SdrObject* pObj1=aIter.Next();
1685 ImpDismantleOneObject(pObj1,*pOL,nPos,pPV,bMakeLines);
1686 }
1687 } else {
1688 ImpDismantleOneObject(pObj,*pOL,nPos,pPV,bMakeLines);
1689 }
1690 if( bUndo )
1691 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj,sal_True));
1692 pOL->RemoveObject(nPos0);
1693
1694 if( !bUndo )
1695 SdrObject::Free(pObj);
1696 }
1697 }
1698
1699 if( bUndo )
1700 {
1701 // UndoComment aus den tatsaechlich verwendeten Objekten zusammenbauen
1702 SetUndoComment(ImpGetResStr(bMakeLines?STR_EditDismantle_Lines:STR_EditDismantle_Polys),aRemoveMerker.GetMarkDescription());
1703 // die tatsaechlich verwendeten Objekten aus der Liste entfernen
1704 EndUndo();
1705 }
1706 }
1707
1708 ////////////////////////////////////////////////////////////////////////////////////////////////////
1709 //
1710 // #### #### ### # # ####
1711 // # # # # # # # # #
1712 // # ## #### # # # # ####
1713 // # # # # # # # # #
1714 // #### # # ### ### #
1715 //
1716 ////////////////////////////////////////////////////////////////////////////////////////////////////
1717
GroupMarked(const SdrObject * pUserGrp)1718 void SdrEditView::GroupMarked(const SdrObject* pUserGrp)
1719 {
1720 if (AreObjectsMarked())
1721 {
1722 SortMarkedObjects();
1723
1724 const bool bUndo = IsUndoEnabled();
1725 if( bUndo )
1726 {
1727 BegUndo(ImpGetResStr(STR_EditGroup),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_GROUP);
1728
1729 const sal_uIntPtr nAnz = GetMarkedObjectCount();
1730 for(sal_uIntPtr nm = nAnz; nm>0; )
1731 {
1732 // UndoActions fuer alle betroffenen Objekte anlegen
1733 nm--;
1734 SdrMark* pM=GetSdrMarkByIndex(nm);
1735 SdrObject* pObj = pM->GetMarkedSdrObj();
1736 std::vector< SdrUndoAction* > vConnectorUndoActions( CreateConnectorUndo( *pObj ) );
1737 AddUndoActions( vConnectorUndoActions );
1738 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject( *pObj ));
1739 }
1740 }
1741
1742 SdrMarkList aNewMark;
1743 SdrPageView* pPV = GetSdrPageView();
1744
1745 if(pPV)
1746 {
1747 SdrObjList* pAktLst=pPV->GetObjList();
1748 SdrObjList* pSrcLst=pAktLst;
1749 SdrObjList* pSrcLst0=pSrcLst;
1750 SdrPage* pPage=pPV->GetPage();
1751 // sicherstellen, dass die OrdNums stimmen
1752 if (pSrcLst->IsObjOrdNumsDirty())
1753 pSrcLst->RecalcObjOrdNums();
1754 SdrObject* pGrp=NULL;
1755 SdrObject* pRefObj=NULL; // Referenz fuer InsertReason (-> rumankern im Writer)
1756 SdrObject* pRefObj1=NULL; // Referenz fuer InsertReason (-> rumankern im Writer)
1757 SdrObjList* pDstLst=NULL;
1758 // Falls alle markierten Objekte aus Fremden Obj-Listen
1759 // kommen, kommt das Gruppenobjekt an das Ende der Liste.
1760 sal_uIntPtr nInsPos=pSrcLst->GetObjCount();
1761 sal_Bool bNeedInsPos=sal_True;
1762 for (sal_uIntPtr nm=GetMarkedObjectCount(); nm>0;)
1763 {
1764 nm--;
1765 SdrMark* pM=GetSdrMarkByIndex(nm);
1766 if (pM->GetPageView()==pPV)
1767 {
1768 if (pGrp==NULL)
1769 {
1770 if (pUserGrp!=NULL)
1771 pGrp=pUserGrp->Clone();
1772 if (pGrp==NULL)
1773 pGrp=new SdrObjGroup;
1774 pDstLst=pGrp->GetSubList();
1775 DBG_ASSERT(pDstLst!=NULL,"Angebliches Gruppenobjekt liefert keine Objektliste");
1776 }
1777 SdrObject* pObj=pM->GetMarkedSdrObj();
1778 pSrcLst=pObj->GetObjList();
1779 if (pSrcLst!=pSrcLst0)
1780 {
1781 if (pSrcLst->IsObjOrdNumsDirty())
1782 pSrcLst->RecalcObjOrdNums();
1783 }
1784 sal_Bool bForeignList=pSrcLst!=pAktLst;
1785 sal_Bool bGrouped=pSrcLst!=pPage;
1786 if (!bForeignList && bNeedInsPos)
1787 {
1788 nInsPos=pObj->GetOrdNum(); // ua, damit sind alle ObjOrdNum der Page gesetzt
1789 nInsPos++;
1790 bNeedInsPos=sal_False;
1791 }
1792 pSrcLst->RemoveObject(pObj->GetOrdNumDirect());
1793 if (!bForeignList)
1794 nInsPos--; // InsertPos korregieren
1795 SdrInsertReason aReason(SDRREASON_VIEWCALL);
1796 pDstLst->InsertObject(pObj,0,&aReason);
1797 GetMarkedObjectListWriteAccess().DeleteMark(nm);
1798 if (pRefObj1==NULL)
1799 pRefObj1=pObj; // Das oberste sichtbare Objekt
1800 if (!bGrouped)
1801 {
1802 if (pRefObj==NULL)
1803 pRefObj=pObj; // Das oberste sichtbare nicht gruppierte Objekt
1804 }
1805 pSrcLst0=pSrcLst;
1806 }
1807 }
1808 if (pRefObj==NULL)
1809 pRefObj=pRefObj1;
1810 if (pGrp!=NULL)
1811 {
1812 aNewMark.InsertEntry(SdrMark(pGrp,pPV));
1813 sal_uIntPtr nAnz=pDstLst->GetObjCount();
1814 SdrInsertReason aReason(SDRREASON_VIEWCALL,pRefObj);
1815 pAktLst->InsertObject(pGrp,nInsPos,&aReason);
1816 if( bUndo )
1817 {
1818 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pGrp,true)); // Kein Recalc!
1819 for (sal_uIntPtr no=0; no<nAnz; no++)
1820 {
1821 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pDstLst->GetObj(no)));
1822 }
1823 }
1824 }
1825 }
1826 GetMarkedObjectListWriteAccess().Merge(aNewMark);
1827 MarkListHasChanged();
1828
1829 if( bUndo )
1830 EndUndo();
1831 }
1832 }
1833
1834 ////////////////////////////////////////////////////////////////////////////////////////////////////
1835 //
1836 // # # # # #### #### ### # # ####
1837 // # # ## # # # # # # # # # #
1838 // # # # # # # ## #### # # # # ####
1839 // # # # ## # # # # # # # # #
1840 // ### # # #### # # ### ### #
1841 //
1842 ////////////////////////////////////////////////////////////////////////////////////////////////////
1843
UnGroupMarked()1844 void SdrEditView::UnGroupMarked()
1845 {
1846 SdrMarkList aNewMark;
1847
1848 const bool bUndo = IsUndoEnabled();
1849 if( bUndo )
1850 BegUndo(String(), String(), SDRREPFUNC_OBJ_UNGROUP);
1851
1852 sal_uIntPtr nCount=0;
1853 XubString aName1;
1854 XubString aName;
1855 sal_Bool bNameOk=sal_False;
1856 for (sal_uIntPtr nm=GetMarkedObjectCount(); nm>0;) {
1857 nm--;
1858 SdrMark* pM=GetSdrMarkByIndex(nm);
1859 SdrObject* pGrp=pM->GetMarkedSdrObj();
1860 SdrObjList* pSrcLst=pGrp->GetSubList();
1861 if (pSrcLst!=NULL) {
1862 nCount++;
1863 if (nCount==1) {
1864 pGrp->TakeObjNameSingul(aName); // Bezeichnung der Gruppe holen
1865 pGrp->TakeObjNamePlural(aName1); // Bezeichnung der Gruppe holen
1866 bNameOk=sal_True;
1867 } else {
1868 if (nCount==2) aName=aName1; // Pluralname setzen
1869 if (bNameOk) {
1870 XubString aStr;
1871 pGrp->TakeObjNamePlural(aStr); // Bezeichnung der Gruppe holen
1872
1873 if(!aStr.Equals(aName))
1874 bNameOk = sal_False;
1875 }
1876 }
1877 sal_uIntPtr nDstCnt=pGrp->GetOrdNum();
1878 SdrObjList* pDstLst=pM->GetPageView()->GetObjList();
1879
1880 // FIRST move contained objects to parent of group, so that
1881 // the contained objects are NOT migrated to the UNDO-ItemPool
1882 // when AddUndo(new SdrUndoDelObj(*pGrp)) is called.
1883 sal_uIntPtr nAnz=pSrcLst->GetObjCount();
1884 sal_uIntPtr no;
1885
1886 if( bUndo )
1887 {
1888 for (no=nAnz; no>0;)
1889 {
1890 no--;
1891 SdrObject* pObj=pSrcLst->GetObj(no);
1892 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoRemoveObject(*pObj));
1893 }
1894 }
1895 for (no=0; no<nAnz; no++)
1896 {
1897 SdrObject* pObj=pSrcLst->RemoveObject(0);
1898 SdrInsertReason aReason(SDRREASON_VIEWCALL,pGrp);
1899 pDstLst->InsertObject(pObj,nDstCnt,&aReason);
1900 if( bUndo )
1901 AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoInsertObject(*pObj,true));
1902 nDstCnt++;
1903 // Kein SortCheck beim einfuegen in die MarkList, denn das
1904 // wuerde wg. pObj->GetOrdNum() jedesmal ein RecalcOrdNums()
1905 // provozieren:
1906 aNewMark.InsertEntry(SdrMark(pObj,pM->GetPageView()),sal_False);
1907 }
1908
1909 if( bUndo )
1910 {
1911 // Now it is safe to add the delete-UNDO which trigers the
1912 // MigrateItemPool now only for itself, not for the subobjects.
1913 // nDstCnt is right, because previous inserts move group
1914 // object deeper and increase nDstCnt.
1915 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pGrp));
1916 }
1917 pDstLst->RemoveObject(nDstCnt);
1918
1919 if( !bUndo )
1920 SdrObject::Free(pGrp);
1921
1922 GetMarkedObjectListWriteAccess().DeleteMark(nm);
1923 }
1924 }
1925 if (nCount!=0)
1926 {
1927 if (!bNameOk)
1928 aName=ImpGetResStr(STR_ObjNamePluralGRUP); // Oberbegriff Gruppenobjekte verwenden, wenn verschiedene Objekte.
1929 SetUndoComment(ImpGetResStr(STR_EditUngroup),aName);
1930 }
1931
1932 if( bUndo )
1933 EndUndo();
1934
1935 if (nCount!=0)
1936 {
1937 GetMarkedObjectListWriteAccess().Merge(aNewMark,sal_True); // Durch das obige Einsortieren ist aNewMark genau verkehrtherum
1938 MarkListHasChanged();
1939 }
1940 }
1941
1942 ////////////////////////////////////////////////////////////////////////////////////////////////////
1943 //
1944 // ### ### # # # # ##### #### ##### ##### ### #### ### # # #
1945 // # # # # ## # # # # # # # # # # # # # # # # #
1946 // # # # # # # # # #### #### # # # # #### # # # #
1947 // # # # # # ## # # # # # # # # # # # # # #
1948 // ### ### # # # ##### # # # # ### # ### #### #
1949 //
1950 ////////////////////////////////////////////////////////////////////////////////////////////////////
1951
ImpConvertOneObj(SdrObject * pObj,sal_Bool bPath,sal_Bool bLineToArea)1952 SdrObject* SdrEditView::ImpConvertOneObj(SdrObject* pObj, sal_Bool bPath, sal_Bool bLineToArea)
1953 {
1954 SdrObject* pNewObj = pObj->ConvertToPolyObj(bPath, bLineToArea);
1955 if (pNewObj!=NULL)
1956 {
1957 SdrObjList* pOL=pObj->GetObjList();
1958 DBG_ASSERT(pOL!=NULL,"ConvertTo: Obj liefert keine ObjList");
1959 if (pOL!=NULL)
1960 {
1961 const bool bUndo = IsUndoEnabled();
1962 if( bUndo )
1963 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoReplaceObject(*pObj,*pNewObj));
1964
1965 pOL->ReplaceObject(pNewObj,pObj->GetOrdNum());
1966
1967 if( !bUndo )
1968 SdrObject::Free(pObj);
1969 }
1970 }
1971 return pNewObj;
1972 }
1973
ImpConvertTo(sal_Bool bPath,sal_Bool bLineToArea)1974 void SdrEditView::ImpConvertTo(sal_Bool bPath, sal_Bool bLineToArea)
1975 {
1976 sal_Bool bMrkChg=sal_False;
1977 sal_Bool bModChg=sal_False;
1978 if (AreObjectsMarked()) {
1979 sal_uIntPtr nMarkAnz=GetMarkedObjectCount();
1980 sal_uInt16 nDscrID=0;
1981 if(bLineToArea)
1982 {
1983 if(nMarkAnz == 1)
1984 nDscrID = STR_EditConvToContour;
1985 else
1986 nDscrID = STR_EditConvToContours;
1987
1988 BegUndo(ImpGetResStr(nDscrID), GetDescriptionOfMarkedObjects());
1989 }
1990 else
1991 {
1992 if (bPath) {
1993 if (nMarkAnz==1) nDscrID=STR_EditConvToCurve;
1994 else nDscrID=STR_EditConvToCurves;
1995 BegUndo(ImpGetResStr(nDscrID),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_CONVERTTOPATH);
1996 } else {
1997 if (nMarkAnz==1) nDscrID=STR_EditConvToPoly;
1998 else nDscrID=STR_EditConvToPolys;
1999 BegUndo(ImpGetResStr(nDscrID),GetDescriptionOfMarkedObjects(),SDRREPFUNC_OBJ_CONVERTTOPOLY);
2000 }
2001 }
2002 for (sal_uIntPtr nm=nMarkAnz; nm>0;) {
2003 nm--;
2004 SdrMark* pM=GetSdrMarkByIndex(nm);
2005 SdrObject* pObj=pM->GetMarkedSdrObj();
2006 SdrPageView* pPV=pM->GetPageView();
2007 if (pObj->IsGroupObject() && !pObj->Is3DObj()) {
2008 SdrObject* pGrp=pObj;
2009 SdrObjListIter aIter(*pGrp,IM_DEEPNOGROUPS);
2010 while (aIter.IsMore()) {
2011 pObj=aIter.Next();
2012 if (ImpConvertOneObj(pObj,bPath,bLineToArea)) bModChg=sal_True;
2013 }
2014 } else {
2015 SdrObject* pNewObj=ImpConvertOneObj(pObj,bPath,bLineToArea);
2016 if (pNewObj!=NULL) {
2017 bModChg=sal_True;
2018 bMrkChg=sal_True;
2019 GetMarkedObjectListWriteAccess().ReplaceMark(SdrMark(pNewObj,pPV),nm);
2020 }
2021 }
2022 }
2023 EndUndo();
2024 if (bMrkChg) AdjustMarkHdl();
2025 if (bMrkChg) MarkListHasChanged();
2026 }
2027 }
2028
ConvertMarkedToPathObj(sal_Bool bLineToArea)2029 void SdrEditView::ConvertMarkedToPathObj(sal_Bool bLineToArea)
2030 {
2031 ImpConvertTo(sal_True, bLineToArea);
2032 }
2033
ConvertMarkedToPolyObj(sal_Bool bLineToArea)2034 void SdrEditView::ConvertMarkedToPolyObj(sal_Bool bLineToArea)
2035 {
2036 ImpConvertTo(sal_False, bLineToArea);
2037 }
2038
2039 ////////////////////////////////////////////////////////////////////////////////////////////////////
2040 //
2041 // # # ##### ##### ### ##### # # ##### # # # #### ### #### #####
2042 // ## ## # # # # # # # # # ## ## # # # # # # #
2043 // # # # #### # ##### ### # # #### ### # # # # #### # # #### #
2044 // # # # # # # # # # # # # # # # # # # #
2045 // # # ##### # # # # # #### ##### # # # # ### # # #
2046 //
2047 ////////////////////////////////////////////////////////////////////////////////////////////////////
2048
DoImportMarkedMtf(SvdProgressInfo * pProgrInfo)2049 void SdrEditView::DoImportMarkedMtf(SvdProgressInfo *pProgrInfo)
2050 {
2051 const bool bUndo = IsUndoEnabled();
2052
2053 if( bUndo )
2054 BegUndo(String(), String(), SDRREPFUNC_OBJ_IMPORTMTF);
2055
2056 SortMarkedObjects();
2057 SdrMarkList aForTheDescription;
2058 SdrMarkList aNewMarked;
2059 sal_uIntPtr nAnz=GetMarkedObjectCount();
2060
2061 for (sal_uIntPtr nm=nAnz; nm>0;)
2062 { // Undo Objekte fuer alle neuen Objekte erzeugen
2063 // zwischen den Metafiles auf Abbruch testen
2064 if( pProgrInfo != NULL )
2065 {
2066 pProgrInfo->SetNextObject();
2067 if(!pProgrInfo->ReportActions(0))
2068 break;
2069 }
2070
2071 nm--;
2072 SdrMark* pM=GetSdrMarkByIndex(nm);
2073 SdrObject* pObj=pM->GetMarkedSdrObj();
2074 SdrPageView* pPV=pM->GetPageView();
2075 SdrObjList* pOL=pObj->GetObjList();
2076 sal_uIntPtr nInsPos=pObj->GetOrdNum()+1;
2077 SdrGrafObj* pGraf=PTR_CAST(SdrGrafObj,pObj);
2078 SdrOle2Obj* pOle2=PTR_CAST(SdrOle2Obj,pObj);
2079 sal_uIntPtr nInsAnz=0;
2080 Rectangle aLogicRect;
2081
2082 if(pGraf && (pGraf->HasGDIMetaFile() || pGraf->isEmbeddedSvg()))
2083 {
2084 GDIMetaFile aMetaFile;
2085
2086 if(pGraf->HasGDIMetaFile())
2087 {
2088 aMetaFile = pGraf->GetTransformedGraphic(SDRGRAFOBJ_TRANSFORMATTR_COLOR|SDRGRAFOBJ_TRANSFORMATTR_MIRROR).GetGDIMetaFile();
2089 }
2090 else if(pGraf->isEmbeddedSvg())
2091 {
2092 aMetaFile = pGraf->getMetafileFromEmbeddedSvg();
2093 }
2094
2095 if(aMetaFile.GetActionCount())
2096 {
2097 aLogicRect = pGraf->GetLogicRect();
2098 ImpSdrGDIMetaFileImport aFilter(*pMod, pObj->GetLayer(), aLogicRect);
2099 nInsAnz = aFilter.DoImport(aMetaFile, *pOL, nInsPos, pProgrInfo);
2100 }
2101 }
2102 if ( pOle2!=NULL && pOle2->GetGraphic() )
2103 {
2104 aLogicRect = pOle2->GetLogicRect();
2105 ImpSdrGDIMetaFileImport aFilter(*pMod, pObj->GetLayer(), aLogicRect);
2106 nInsAnz = aFilter.DoImport(pOle2->GetGraphic()->GetGDIMetaFile(), *pOL, nInsPos, pProgrInfo);
2107 }
2108 if (nInsAnz!=0)
2109 {
2110 // transformation
2111 GeoStat aGeoStat(pGraf ? pGraf->GetGeoStat() : pOle2->GetGeoStat());
2112 sal_uIntPtr nObj=nInsPos;
2113
2114 if(aGeoStat.nShearWink)
2115 {
2116 aGeoStat.RecalcTan();
2117 }
2118
2119 if(aGeoStat.nDrehWink)
2120 {
2121 aGeoStat.RecalcSinCos();
2122 }
2123
2124 for (sal_uIntPtr i=0; i<nInsAnz; i++)
2125 {
2126 if( bUndo )
2127 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pOL->GetObj(nObj)));
2128
2129 // Neue MarkList pflegen
2130 SdrObject* pCandidate = pOL->GetObj(nObj);
2131
2132 // apply original transformation
2133 if(aGeoStat.nShearWink)
2134 {
2135 pCandidate->NbcShear(aLogicRect.TopLeft(), aGeoStat.nShearWink, aGeoStat.nTan, false);
2136 }
2137
2138 if(aGeoStat.nDrehWink)
2139 {
2140 pCandidate->NbcRotate(aLogicRect.TopLeft(), aGeoStat.nDrehWink, aGeoStat.nSin, aGeoStat.nCos);
2141 }
2142
2143 SdrMark aNewMark(pCandidate, pPV);
2144 aNewMarked.InsertEntry(aNewMark);
2145
2146 nObj++;
2147 }
2148 aForTheDescription.InsertEntry(*pM);
2149
2150 if( bUndo )
2151 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pObj));
2152
2153 // Objekt aus selektion loesen und loeschen
2154 GetMarkedObjectListWriteAccess().DeleteMark(TryToFindMarkedObject(pObj));
2155 pOL->RemoveObject(nInsPos-1);
2156
2157 if( !bUndo )
2158 SdrObject::Free(pObj);
2159 }
2160 }
2161
2162 // MarkObj... fehlt... jetzt nicht mehr (AW)
2163 if(aNewMarked.GetMarkCount())
2164 {
2165 // Neue Selektion bilden
2166 for(sal_uIntPtr a(0); a < aNewMarked.GetMarkCount(); a++)
2167 {
2168 GetMarkedObjectListWriteAccess().InsertEntry(*aNewMarked.GetMark(a));
2169 }
2170
2171 SortMarkedObjects();
2172 }
2173
2174 if( bUndo )
2175 {
2176 SetUndoComment(ImpGetResStr(STR_EditImportMtf),aForTheDescription.GetMarkDescription());
2177 EndUndo();
2178 }
2179 }
2180
2181