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