/src/libreoffice/svx/source/svdraw/svdxcgv.cxx
Line | Count | Source (jump to first uncovered line) |
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 <vector> |
21 | | #include <unordered_set> |
22 | | #include <editeng/editdata.hxx> |
23 | | #include <rtl/strbuf.hxx> |
24 | | #include <svx/xfillit0.hxx> |
25 | | #include <svx/xlineit0.hxx> |
26 | | #include <svx/svdxcgv.hxx> |
27 | | #include <svx/svdoutl.hxx> |
28 | | #include <svx/svdundo.hxx> |
29 | | #include <svx/svdograf.hxx> |
30 | | #include <svx/svdomedia.hxx> |
31 | | #include <svx/svdoole2.hxx> |
32 | | #include <svx/svdorect.hxx> |
33 | | #include <svx/svdopage.hxx> |
34 | | #include <svx/svdpage.hxx> |
35 | | #include <svx/svdpagv.hxx> |
36 | | #include <svx/svdtrans.hxx> |
37 | | #include <svx/strings.hrc> |
38 | | #include <svx/dialmgr.hxx> |
39 | | #include <tools/bigint.hxx> |
40 | | #include <clonelist.hxx> |
41 | | #include <vcl/virdev.hxx> |
42 | | #include <svl/style.hxx> |
43 | | #include <fmobj.hxx> |
44 | | #include <vcl/vectorgraphicdata.hxx> |
45 | | #include <drawinglayer/primitive2d/groupprimitive2d.hxx> |
46 | | #include <drawinglayer/geometry/viewinformation2d.hxx> |
47 | | #include <drawinglayer/converters.hxx> |
48 | | #include <svx/sdr/contact/viewcontact.hxx> |
49 | | #include <sdr/contact/objectcontactofobjlistpainter.hxx> |
50 | | #include <svx/sdr/contact/displayinfo.hxx> |
51 | | #include <svx/svdotable.hxx> |
52 | | #include <sal/log.hxx> |
53 | | #include <osl/diagnose.h> |
54 | | #include <comphelper/lok.hxx> |
55 | | |
56 | | using namespace com::sun::star; |
57 | | |
58 | | SdrExchangeView::SdrExchangeView( |
59 | | SdrModel& rSdrModel, |
60 | | OutputDevice* pOut) |
61 | 391k | : SdrObjEditView(rSdrModel, pOut) |
62 | 391k | { |
63 | 391k | } |
64 | | |
65 | | bool SdrExchangeView::ImpLimitToWorkArea(Point& rPt) const |
66 | 0 | { |
67 | 0 | bool bRet(false); |
68 | |
|
69 | 0 | if(!maMaxWorkArea.IsEmpty()) |
70 | 0 | { |
71 | 0 | if(rPt.X()<maMaxWorkArea.Left()) |
72 | 0 | { |
73 | 0 | rPt.setX( maMaxWorkArea.Left() ); |
74 | 0 | bRet = true; |
75 | 0 | } |
76 | |
|
77 | 0 | if(rPt.X()>maMaxWorkArea.Right()) |
78 | 0 | { |
79 | 0 | rPt.setX( maMaxWorkArea.Right() ); |
80 | 0 | bRet = true; |
81 | 0 | } |
82 | |
|
83 | 0 | if(rPt.Y()<maMaxWorkArea.Top()) |
84 | 0 | { |
85 | 0 | rPt.setY( maMaxWorkArea.Top() ); |
86 | 0 | bRet = true; |
87 | 0 | } |
88 | |
|
89 | 0 | if(rPt.Y()>maMaxWorkArea.Bottom()) |
90 | 0 | { |
91 | 0 | rPt.setY( maMaxWorkArea.Bottom() ); |
92 | 0 | bRet = true; |
93 | 0 | } |
94 | 0 | } |
95 | 0 | return bRet; |
96 | 0 | } |
97 | | |
98 | | void SdrExchangeView::ImpGetPasteObjList(Point& /*rPos*/, SdrObjList*& rpLst) |
99 | 0 | { |
100 | 0 | if (rpLst==nullptr) |
101 | 0 | { |
102 | 0 | SdrPageView* pPV = GetSdrPageView(); |
103 | |
|
104 | 0 | if (pPV!=nullptr) { |
105 | 0 | rpLst=pPV->GetObjList(); |
106 | 0 | } |
107 | 0 | } |
108 | 0 | } |
109 | | |
110 | | bool SdrExchangeView::ImpGetPasteLayer(const SdrObjList* pObjList, SdrLayerID& rLayer) const |
111 | 0 | { |
112 | 0 | bool bRet=false; |
113 | 0 | rLayer=SdrLayerID(0); |
114 | 0 | if (pObjList!=nullptr) { |
115 | 0 | const SdrPage* pPg=pObjList->getSdrPageFromSdrObjList(); |
116 | 0 | if (pPg!=nullptr) { |
117 | 0 | rLayer=pPg->GetLayerAdmin().GetLayerID(maActualLayer); |
118 | 0 | if (rLayer==SDRLAYER_NOTFOUND) rLayer=SdrLayerID(0); |
119 | 0 | SdrPageView* pPV = GetSdrPageView(); |
120 | 0 | if (pPV!=nullptr) { |
121 | 0 | bRet=!pPV->GetLockedLayers().IsSet(rLayer) && pPV->GetVisibleLayers().IsSet(rLayer); |
122 | 0 | } |
123 | 0 | } |
124 | 0 | } |
125 | 0 | return bRet; |
126 | 0 | } |
127 | | |
128 | | bool SdrExchangeView::Paste(const OUString& rStr, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions) |
129 | 0 | { |
130 | 0 | if (rStr.isEmpty()) |
131 | 0 | return false; |
132 | | |
133 | 0 | Point aPos(rPos); |
134 | 0 | ImpGetPasteObjList(aPos,pLst); |
135 | 0 | ImpLimitToWorkArea( aPos ); |
136 | 0 | if (pLst==nullptr) return false; |
137 | 0 | SdrLayerID nLayer; |
138 | 0 | if (!ImpGetPasteLayer(pLst,nLayer)) return false; |
139 | 0 | bool bUnmark = (nOptions & (SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit(); |
140 | 0 | if (bUnmark) UnmarkAllObj(); |
141 | 0 | tools::Rectangle aTextRect(0,0,500,500); |
142 | 0 | SdrPage* pPage=pLst->getSdrPageFromSdrObjList(); |
143 | 0 | if (pPage!=nullptr) { |
144 | 0 | aTextRect.SetSize(pPage->GetSize()); |
145 | 0 | } |
146 | 0 | rtl::Reference<SdrRectObj> pObj = new SdrRectObj( |
147 | 0 | getSdrModelFromSdrView(), aTextRect, SdrObjKind::Text); |
148 | |
|
149 | 0 | pObj->SetLayer(nLayer); |
150 | 0 | pObj->NbcSetText(rStr); // SetText before SetAttr, else SetAttr doesn't work! |
151 | 0 | if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false); |
152 | |
|
153 | 0 | pObj->SetMergedItemSet(maDefaultAttr); |
154 | |
|
155 | 0 | SfxItemSet aTempAttr(GetModel().GetItemPool()); // no fill, no line |
156 | 0 | aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE)); |
157 | 0 | aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE)); |
158 | |
|
159 | 0 | pObj->SetMergedItemSet(aTempAttr); |
160 | |
|
161 | 0 | pObj->FitFrameToTextSize(); |
162 | 0 | Size aSiz(pObj->GetLogicRect().GetSize()); |
163 | 0 | MapUnit eMap = GetModel().GetScaleUnit(); |
164 | 0 | ImpPasteObject(pObj.get(), *pLst, aPos, aSiz, MapMode(eMap), nOptions); |
165 | 0 | return true; |
166 | 0 | } |
167 | | |
168 | | bool SdrExchangeView::Paste(SvStream& rInput, EETextFormat eFormat, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions) |
169 | 0 | { |
170 | 0 | Point aPos(rPos); |
171 | 0 | ImpGetPasteObjList(aPos,pLst); |
172 | 0 | ImpLimitToWorkArea( aPos ); |
173 | 0 | if (pLst==nullptr) return false; |
174 | 0 | SdrLayerID nLayer; |
175 | 0 | if (!ImpGetPasteLayer(pLst,nLayer)) return false; |
176 | 0 | bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit(); |
177 | 0 | if (bUnmark) UnmarkAllObj(); |
178 | 0 | tools::Rectangle aTextRect(0,0,500,500); |
179 | 0 | SdrPage* pPage=pLst->getSdrPageFromSdrObjList(); |
180 | 0 | if (pPage!=nullptr) { |
181 | 0 | aTextRect.SetSize(pPage->GetSize()); |
182 | 0 | } |
183 | 0 | rtl::Reference<SdrRectObj> pObj = new SdrRectObj( |
184 | 0 | getSdrModelFromSdrView(), aTextRect, SdrObjKind::Text); |
185 | |
|
186 | 0 | pObj->SetLayer(nLayer); |
187 | 0 | if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false); |
188 | |
|
189 | 0 | pObj->SetMergedItemSet(maDefaultAttr); |
190 | |
|
191 | 0 | SfxItemSet aTempAttr(GetModel().GetItemPool()); // no fill, no line |
192 | 0 | aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE)); |
193 | 0 | aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE)); |
194 | |
|
195 | 0 | pObj->SetMergedItemSet(aTempAttr); |
196 | |
|
197 | 0 | pObj->NbcSetText(rInput,OUString(),eFormat); |
198 | 0 | pObj->FitFrameToTextSize(); |
199 | 0 | Size aSiz(pObj->GetLogicRect().GetSize()); |
200 | 0 | MapUnit eMap = GetModel().GetScaleUnit(); |
201 | 0 | ImpPasteObject(pObj.get(), *pLst, aPos, aSiz, MapMode(eMap), nOptions); |
202 | | |
203 | | // b4967543 |
204 | 0 | if(pObj->GetOutlinerParaObject()) |
205 | 0 | { |
206 | 0 | SdrOutliner& rOutliner = pObj->getSdrModelFromSdrObject().GetHitTestOutliner(); |
207 | 0 | rOutliner.SetText(*pObj->GetOutlinerParaObject()); |
208 | |
|
209 | 0 | if(1 == rOutliner.GetParagraphCount()) |
210 | 0 | { |
211 | 0 | SfxStyleSheet* pCandidate = rOutliner.GetStyleSheet(0); |
212 | |
|
213 | 0 | if(pCandidate) |
214 | 0 | { |
215 | 0 | if(pObj->getSdrModelFromSdrObject().GetStyleSheetPool() == pCandidate->GetPool()) |
216 | 0 | { |
217 | 0 | pObj->NbcSetStyleSheet(pCandidate, true); |
218 | 0 | } |
219 | 0 | } |
220 | 0 | } |
221 | 0 | } |
222 | |
|
223 | 0 | return true; |
224 | 0 | } |
225 | | |
226 | | bool SdrExchangeView::Paste( |
227 | | const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions) |
228 | 0 | { |
229 | 0 | const SdrModel* pSrcMod=&rMod; |
230 | 0 | if (pSrcMod == &GetModel()) |
231 | 0 | return false; // this can't work, right? |
232 | | |
233 | 0 | const bool bUndo = IsUndoEnabled(); |
234 | |
|
235 | 0 | if( bUndo ) |
236 | 0 | BegUndo(SvxResId(STR_ExchangePaste)); |
237 | |
|
238 | 0 | if( mxSelectionController.is() && mxSelectionController->PasteObjModel( rMod ) ) |
239 | 0 | { |
240 | 0 | if( bUndo ) |
241 | 0 | EndUndo(); |
242 | 0 | return true; |
243 | 0 | } |
244 | | |
245 | 0 | Point aPos(rPos); |
246 | 0 | ImpGetPasteObjList(aPos,pLst); |
247 | 0 | SdrPageView* pMarkPV=nullptr; |
248 | 0 | SdrPageView* pPV = GetSdrPageView(); |
249 | |
|
250 | 0 | if(pPV && pPV->GetObjList() == pLst ) |
251 | 0 | pMarkPV=pPV; |
252 | |
|
253 | 0 | ImpLimitToWorkArea( aPos ); |
254 | 0 | if (pLst==nullptr) |
255 | 0 | return false; |
256 | | |
257 | 0 | bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit(); |
258 | 0 | if (bUnmark) |
259 | 0 | UnmarkAllObj(); |
260 | | |
261 | | // Rescale, if the Model uses a different MapUnit. |
262 | | // Calculate the necessary factors first. |
263 | 0 | MapUnit eSrcUnit = pSrcMod->GetScaleUnit(); |
264 | 0 | MapUnit eDstUnit = GetModel().GetScaleUnit(); |
265 | 0 | bool bResize=eSrcUnit!=eDstUnit; |
266 | 0 | Fraction aXResize,aYResize; |
267 | 0 | Point aPt0; |
268 | 0 | if (bResize) |
269 | 0 | { |
270 | 0 | FrPair aResize(GetMapFactor(eSrcUnit,eDstUnit)); |
271 | 0 | aXResize=aResize.X(); |
272 | 0 | aYResize=aResize.Y(); |
273 | 0 | } |
274 | 0 | SdrObjList* pDstLst=pLst; |
275 | 0 | sal_uInt16 nPg,nPgCount=pSrcMod->GetPageCount(); |
276 | 0 | for (nPg=0; nPg<nPgCount; nPg++) |
277 | 0 | { |
278 | 0 | const SdrPage* pSrcPg=pSrcMod->GetPage(nPg); |
279 | | |
280 | | // Use SnapRect, not BoundRect here |
281 | 0 | tools::Rectangle aR=pSrcPg->GetAllObjSnapRect(); |
282 | |
|
283 | 0 | if (bResize) |
284 | 0 | ResizeRect(aR,aPt0,aXResize,aYResize); |
285 | 0 | Point aDist(aPos-aR.Center()); |
286 | 0 | Size aSiz(aDist.X(),aDist.Y()); |
287 | 0 | size_t nCloneErrCnt = 0; |
288 | 0 | const size_t nObjCount = pSrcPg->GetObjCount(); |
289 | 0 | bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE; |
290 | | |
291 | | // #i13033# |
292 | | // New mechanism to re-create the connections of cloned connectors |
293 | 0 | CloneList aCloneList; |
294 | 0 | std::unordered_set<rtl::OUString> aNameSet; |
295 | 0 | for (size_t nOb=0; nOb<nObjCount; ++nOb) |
296 | 0 | { |
297 | 0 | const SdrObject* pSrcOb=pSrcPg->GetObj(nOb); |
298 | |
|
299 | 0 | rtl::Reference<SdrObject> pNewObj(pSrcOb->CloneSdrObject(GetModel())); |
300 | |
|
301 | 0 | if (pNewObj!=nullptr) |
302 | 0 | { |
303 | 0 | if(bResize) |
304 | 0 | { |
305 | 0 | pNewObj->getSdrModelFromSdrObject().SetPasteResize(true); |
306 | 0 | pNewObj->NbcResize(aPt0,aXResize,aYResize); |
307 | 0 | pNewObj->getSdrModelFromSdrObject().SetPasteResize(false); |
308 | 0 | } |
309 | | |
310 | | // #i39861# |
311 | 0 | pNewObj->NbcMove(aSiz); |
312 | |
|
313 | 0 | const SdrPage* pPg = pDstLst->getSdrPageFromSdrObjList(); |
314 | |
|
315 | 0 | if(pPg) |
316 | 0 | { |
317 | | // #i72535# |
318 | 0 | const SdrLayerAdmin& rAd = pPg->GetLayerAdmin(); |
319 | 0 | SdrLayerID nLayer(0); |
320 | |
|
321 | 0 | if(dynamic_cast<const FmFormObj*>( pNewObj.get()) != nullptr) |
322 | 0 | { |
323 | | // for FormControls, force to form layer |
324 | 0 | nLayer = rAd.GetLayerID(rAd.GetControlLayerName()); |
325 | 0 | } |
326 | 0 | else |
327 | 0 | { |
328 | 0 | nLayer = rAd.GetLayerID(maActualLayer); |
329 | 0 | } |
330 | |
|
331 | 0 | if(SDRLAYER_NOTFOUND == nLayer) |
332 | 0 | { |
333 | 0 | nLayer = SdrLayerID(0); |
334 | 0 | } |
335 | |
|
336 | 0 | pNewObj->SetLayer(nLayer); |
337 | 0 | } |
338 | |
|
339 | 0 | pDstLst->InsertObjectThenMakeNameUnique(pNewObj.get(), aNameSet); |
340 | |
|
341 | 0 | if( bUndo ) |
342 | 0 | AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pNewObj)); |
343 | |
|
344 | 0 | if (bMark) { |
345 | | // Don't already set Markhandles! |
346 | | // That is instead being done by ModelHasChanged in MarkView. |
347 | 0 | MarkObj(pNewObj.get(),pMarkPV,false,true); |
348 | 0 | } |
349 | | |
350 | | // #i13033# |
351 | 0 | aCloneList.AddPair(pSrcOb, pNewObj.get()); |
352 | 0 | } |
353 | 0 | else |
354 | 0 | { |
355 | 0 | nCloneErrCnt++; |
356 | 0 | } |
357 | 0 | } |
358 | | |
359 | | // #i13033# |
360 | | // New mechanism to re-create the connections of cloned connectors |
361 | 0 | aCloneList.CopyConnections(); |
362 | |
|
363 | 0 | if(0 != nCloneErrCnt) |
364 | 0 | { |
365 | | #ifdef DBG_UTIL |
366 | | OStringBuffer aStr("SdrExchangeView::Paste(): Error when cloning "); |
367 | | |
368 | | if(nCloneErrCnt == 1) |
369 | | { |
370 | | aStr.append("a drawing object."); |
371 | | } |
372 | | else |
373 | | { |
374 | | aStr.append(OString::number(static_cast<sal_Int32>(nCloneErrCnt)) |
375 | | + " drawing objects."); |
376 | | } |
377 | | |
378 | | aStr.append(" Not copying object connectors."); |
379 | | |
380 | | OSL_FAIL(aStr.getStr()); |
381 | | #endif |
382 | 0 | } |
383 | 0 | } |
384 | |
|
385 | 0 | if( bUndo ) |
386 | 0 | EndUndo(); |
387 | |
|
388 | 0 | return true; |
389 | 0 | } |
390 | | |
391 | | void SdrExchangeView::ImpPasteObject(SdrObject* pObj, SdrObjList& rLst, const Point& rCenter, const Size& rSiz, const MapMode& rMap, SdrInsertFlags nOptions) |
392 | 0 | { |
393 | 0 | BigInt nSizX(rSiz.Width()); |
394 | 0 | BigInt nSizY(rSiz.Height()); |
395 | 0 | MapUnit eSrcMU=rMap.GetMapUnit(); |
396 | 0 | MapUnit eDstMU = GetModel().GetScaleUnit(); |
397 | 0 | FrPair aMapFact(GetMapFactor(eSrcMU,eDstMU)); |
398 | 0 | nSizX *= double(aMapFact.X() * rMap.GetScaleX()); |
399 | 0 | nSizY *= double(aMapFact.Y() * rMap.GetScaleY()); |
400 | 0 | tools::Long xs=nSizX; |
401 | 0 | tools::Long ys=nSizY; |
402 | | // set the pos to 0, 0 for online case |
403 | 0 | bool isLOK = comphelper::LibreOfficeKit::isActive(); |
404 | 0 | Point aPos(isLOK ? 0 : rCenter.X()-xs/2, isLOK ? 0 : rCenter.Y()-ys/2); |
405 | 0 | tools::Rectangle aR(aPos.X(),aPos.Y(),aPos.X()+xs,aPos.Y()+ys); |
406 | 0 | pObj->SetLogicRect(aR); |
407 | 0 | rLst.InsertObject(pObj, SAL_MAX_SIZE); |
408 | |
|
409 | 0 | if( IsUndoEnabled() ) |
410 | 0 | AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pObj)); |
411 | |
|
412 | 0 | SdrPageView* pMarkPV=nullptr; |
413 | 0 | SdrPageView* pPV = GetSdrPageView(); |
414 | |
|
415 | 0 | if(pPV && pPV->GetObjList()==&rLst) |
416 | 0 | pMarkPV=pPV; |
417 | |
|
418 | 0 | bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE; |
419 | 0 | if (bMark) |
420 | 0 | { // select object the first PageView we found |
421 | 0 | MarkObj(pObj,pMarkPV); |
422 | 0 | } |
423 | 0 | } |
424 | | |
425 | | BitmapEx SdrExchangeView::GetMarkedObjBitmapEx(bool bNoVDevIfOneBmpMarked, const sal_uInt32 nMaximumQuadraticPixels, const std::optional<Size>& rTargetDPI) const |
426 | 0 | { |
427 | 0 | BitmapEx aBmp; |
428 | |
|
429 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
430 | 0 | if(1 == rMarkList.GetMarkCount()) |
431 | 0 | { |
432 | 0 | if (auto pGrafObj |
433 | 0 | = dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj())) |
434 | 0 | { |
435 | 0 | if(bNoVDevIfOneBmpMarked) |
436 | 0 | { |
437 | 0 | if (pGrafObj->GetGraphicType() == GraphicType::Bitmap) |
438 | 0 | aBmp = pGrafObj->GetTransformedGraphic().GetBitmapEx(); |
439 | 0 | } |
440 | 0 | else |
441 | 0 | { |
442 | 0 | if (pGrafObj->isEmbeddedVectorGraphicData()) |
443 | 0 | aBmp = pGrafObj->GetGraphic().getVectorGraphicData()->getReplacement(); |
444 | 0 | } |
445 | 0 | } |
446 | 0 | } |
447 | |
|
448 | 0 | if (aBmp.IsEmpty() && rMarkList.GetMarkCount() != 0) |
449 | 0 | { |
450 | | // choose conversion directly using primitives to bitmap to avoid |
451 | | // rendering errors with tiled bitmap fills (these will be tiled in a |
452 | | // in-between metafile, but tend to show 'gaps' since the target is *no* |
453 | | // bitmap rendering) |
454 | 0 | ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects()); |
455 | 0 | const size_t nCount(aSdrObjects.size()); |
456 | | |
457 | | // collect sub-primitives as group objects, thus no expensive append |
458 | | // to existing sequence is needed |
459 | 0 | drawinglayer::primitive2d::Primitive2DContainer xPrimitives(nCount); |
460 | |
|
461 | 0 | for (size_t a(0); a < nCount; a++) |
462 | 0 | { |
463 | 0 | const SdrObject* pCandidate = aSdrObjects[a]; |
464 | |
|
465 | 0 | if (auto pSdrGrafObj = dynamic_cast<const SdrGrafObj*>(pCandidate)) |
466 | 0 | { |
467 | | // #122753# To ensure existence of graphic content, force swap in |
468 | 0 | pSdrGrafObj->ForceSwapIn(); |
469 | 0 | } |
470 | |
|
471 | 0 | drawinglayer::primitive2d::Primitive2DContainer xRetval; |
472 | 0 | pCandidate->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval); |
473 | 0 | xPrimitives[a] = new drawinglayer::primitive2d::GroupPrimitive2D( |
474 | 0 | std::move(xRetval)); |
475 | 0 | } |
476 | | |
477 | | // get logic range |
478 | 0 | const drawinglayer::geometry::ViewInformation2D aViewInformation2D; |
479 | 0 | const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D)); |
480 | |
|
481 | 0 | if(!aRange.isEmpty()) |
482 | 0 | { |
483 | 0 | o3tl::Length eRangeUnit = o3tl::Length::mm100; |
484 | |
|
485 | 0 | if (GetModel().IsWriter()) |
486 | 0 | { |
487 | 0 | eRangeUnit = o3tl::Length::twip; |
488 | 0 | } |
489 | | |
490 | | // if we have geometry and it has a range, convert to BitmapEx using |
491 | | // common tooling |
492 | 0 | aBmp = drawinglayer::convertPrimitive2DContainerToBitmapEx( |
493 | 0 | std::move(xPrimitives), |
494 | 0 | aRange, |
495 | 0 | nMaximumQuadraticPixels, |
496 | 0 | eRangeUnit, |
497 | 0 | rTargetDPI); |
498 | 0 | } |
499 | 0 | } |
500 | |
|
501 | 0 | return aBmp; |
502 | 0 | } |
503 | | |
504 | | |
505 | | GDIMetaFile SdrExchangeView::GetMarkedObjMetaFile(bool bNoVDevIfOneMtfMarked) const |
506 | 0 | { |
507 | 0 | GDIMetaFile aMtf; |
508 | |
|
509 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
510 | 0 | if( rMarkList.GetMarkCount() != 0 ) |
511 | 0 | { |
512 | 0 | tools::Rectangle aBound( GetMarkedObjBoundRect() ); |
513 | 0 | Size aBoundSize( aBound.GetWidth(), aBound.GetHeight() ); |
514 | 0 | MapMode aMap(GetModel().GetScaleUnit()); |
515 | |
|
516 | 0 | if (bNoVDevIfOneMtfMarked && rMarkList.GetMarkCount() == 1) |
517 | 0 | { |
518 | 0 | if (auto pGrafObj |
519 | 0 | = dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj())) |
520 | 0 | { |
521 | 0 | Graphic aGraphic( pGrafObj->GetTransformedGraphic() ); |
522 | | |
523 | | // #119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically |
524 | 0 | aMtf = aGraphic.GetGDIMetaFile(); |
525 | 0 | } |
526 | 0 | } |
527 | |
|
528 | 0 | if( !aMtf.GetActionSize() ) |
529 | 0 | { |
530 | 0 | ScopedVclPtrInstance< VirtualDevice > pOut; |
531 | 0 | const Size aDummySize(2, 2); |
532 | |
|
533 | 0 | pOut->SetOutputSizePixel(aDummySize); |
534 | 0 | pOut->EnableOutput(false); |
535 | 0 | pOut->SetMapMode(aMap); |
536 | 0 | aMtf.Clear(); |
537 | 0 | aMtf.Record(pOut); |
538 | |
|
539 | 0 | DrawMarkedObj(*pOut); |
540 | |
|
541 | 0 | aMtf.Stop(); |
542 | 0 | aMtf.WindStart(); |
543 | | |
544 | | // moving the result is more reliable then setting a relative MapMode at the VDev (used |
545 | | // before), also see #i99268# in GetObjGraphic() below. Some draw actions at |
546 | | // the OutDev are simply not handled correctly when a MapMode is set at the |
547 | | // target device, e.g. MetaFloatTransparentAction. Even the Move for this action |
548 | | // was missing the manipulation of the embedded Metafile |
549 | 0 | aMtf.Move(-aBound.Left(), -aBound.Top()); |
550 | |
|
551 | 0 | aMtf.SetPrefMapMode( aMap ); |
552 | | |
553 | | // removed PrefSize extension. It is principally wrong to set a reduced size at |
554 | | // the created MetaFile. The mentioned errors occur at output time since the integer |
555 | | // MapModes from VCL lead to errors. It is now corrected in the VCLRenderer for |
556 | | // primitives (and may later be done in breaking up a MetaFile to primitives) |
557 | 0 | aMtf.SetPrefSize(aBoundSize); |
558 | 0 | } |
559 | 0 | } |
560 | |
|
561 | 0 | return aMtf; |
562 | 0 | } |
563 | | |
564 | | |
565 | | Graphic SdrExchangeView::GetAllMarkedGraphic() const |
566 | 0 | { |
567 | 0 | Graphic aRet; |
568 | |
|
569 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
570 | 0 | if( rMarkList.GetMarkCount() != 0 ) |
571 | 0 | { |
572 | 0 | if( ( 1 == rMarkList.GetMarkCount() ) && rMarkList.GetMark( 0 ) ) |
573 | 0 | aRet = SdrExchangeView::GetObjGraphic(*rMarkList.GetMark(0)->GetMarkedSdrObj()); |
574 | 0 | else |
575 | 0 | aRet = GetMarkedObjMetaFile(); |
576 | 0 | } |
577 | |
|
578 | 0 | return aRet; |
579 | 0 | } |
580 | | |
581 | | |
582 | | // tdf#155479 bSVG: need to know it's SVG export, default is false |
583 | | Graphic SdrExchangeView::GetObjGraphic(const SdrObject& rSdrObject, bool bSVG) |
584 | 0 | { |
585 | 0 | Graphic aRet; |
586 | |
|
587 | 0 | if (!rSdrObject.HasText()) |
588 | 0 | { |
589 | | // try to get a graphic from the object first |
590 | 0 | const SdrGrafObj* pSdrGrafObj(dynamic_cast<const SdrGrafObj*>(&rSdrObject)); |
591 | 0 | const SdrOle2Obj* pSdrOle2Obj(dynamic_cast<const SdrOle2Obj*>(&rSdrObject)); |
592 | |
|
593 | 0 | if (pSdrGrafObj) |
594 | 0 | { |
595 | 0 | if (pSdrGrafObj->isEmbeddedVectorGraphicData()) |
596 | 0 | { |
597 | | // get Metafile for Svg content |
598 | 0 | aRet = pSdrGrafObj->getMetafileFromEmbeddedVectorGraphicData(); |
599 | 0 | } |
600 | 0 | else |
601 | 0 | { |
602 | | // Make behaviour coherent with metafile |
603 | | // recording below (which of course also takes |
604 | | // view-transformed objects) |
605 | 0 | aRet = pSdrGrafObj->GetTransformedGraphic(); |
606 | 0 | } |
607 | 0 | } |
608 | 0 | else if (pSdrOle2Obj) |
609 | 0 | { |
610 | 0 | if (const Graphic* pGraphic = pSdrOle2Obj->GetGraphic()) |
611 | 0 | { |
612 | 0 | aRet = *pGraphic; |
613 | 0 | } |
614 | 0 | } |
615 | 0 | else |
616 | 0 | { |
617 | | // Support extracting a snapshot from video media, if possible. |
618 | 0 | const SdrMediaObj* pSdrMediaObj = dynamic_cast<const SdrMediaObj*>(&rSdrObject); |
619 | 0 | if (pSdrMediaObj) |
620 | 0 | { |
621 | 0 | const css::uno::Reference<css::graphic::XGraphic>& xGraphic |
622 | 0 | = pSdrMediaObj->getSnapshot(); |
623 | 0 | if (xGraphic.is()) |
624 | 0 | aRet = Graphic(xGraphic); |
625 | 0 | } |
626 | 0 | } |
627 | 0 | } |
628 | | |
629 | | // if graphic could not be retrieved => go the hard way and create a MetaFile |
630 | 0 | if((GraphicType::NONE == aRet.GetType()) || (GraphicType::Default == aRet.GetType())) |
631 | 0 | { |
632 | 0 | ScopedVclPtrInstance< VirtualDevice > pOut; |
633 | 0 | GDIMetaFile aMtf; |
634 | 0 | const tools::Rectangle aBoundRect(rSdrObject.GetCurrentBoundRect()); |
635 | 0 | const MapMode aMap(rSdrObject.getSdrModelFromSdrObject().GetScaleUnit()); |
636 | |
|
637 | 0 | pOut->EnableOutput(false); |
638 | 0 | pOut->SetMapMode(aMap); |
639 | 0 | aMtf.Record(pOut); |
640 | 0 | aMtf.setSVG(bSVG); |
641 | 0 | rSdrObject.SingleObjectPainter(*pOut); |
642 | 0 | aMtf.Stop(); |
643 | 0 | aMtf.WindStart(); |
644 | | |
645 | | // #i99268# replace the original offset from using XOutDev's SetOffset |
646 | | // NOT (as tried with #i92760#) with another MapMode which gets recorded |
647 | | // by the Metafile itself (what always leads to problems), but by |
648 | | // moving the result directly |
649 | 0 | aMtf.Move(-aBoundRect.Left(), -aBoundRect.Top()); |
650 | 0 | aMtf.SetPrefMapMode(aMap); |
651 | 0 | aMtf.SetPrefSize(aBoundRect.GetSize()); |
652 | |
|
653 | 0 | if(aMtf.GetActionSize()) |
654 | 0 | { |
655 | 0 | aRet = aMtf; |
656 | 0 | } |
657 | 0 | } |
658 | |
|
659 | 0 | return aRet; |
660 | 0 | } |
661 | | |
662 | | |
663 | | ::std::vector< SdrObject* > SdrExchangeView::GetMarkedObjects() const |
664 | 0 | { |
665 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
666 | 0 | rMarkList.ForceSort(); |
667 | 0 | ::std::vector< SdrObject* > aRetval; |
668 | |
|
669 | 0 | ::std::vector< ::std::vector< SdrMark* > > aObjVectors( 2 ); |
670 | 0 | ::std::vector< SdrMark* >& rObjVector1 = aObjVectors[ 0 ]; |
671 | 0 | ::std::vector< SdrMark* >& rObjVector2 = aObjVectors[ 1 ]; |
672 | 0 | const SdrLayerAdmin& rLayerAdmin = GetModel().GetLayerAdmin(); |
673 | 0 | const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID( rLayerAdmin.GetControlLayerName() ); |
674 | |
|
675 | 0 | for( size_t n = 0, nCount = rMarkList.GetMarkCount(); n < nCount; ++n ) |
676 | 0 | { |
677 | 0 | SdrMark* pMark = rMarkList.GetMark( n ); |
678 | | |
679 | | // paint objects on control layer on top of all other objects |
680 | 0 | if( nControlLayerId == pMark->GetMarkedSdrObj()->GetLayer() ) |
681 | 0 | rObjVector2.push_back( pMark ); |
682 | 0 | else |
683 | 0 | rObjVector1.push_back( pMark ); |
684 | 0 | } |
685 | |
|
686 | 0 | for(const std::vector<SdrMark*> & rObjVector : aObjVectors) |
687 | 0 | { |
688 | 0 | for(SdrMark* pMark : rObjVector) |
689 | 0 | { |
690 | 0 | aRetval.push_back(pMark->GetMarkedSdrObj()); |
691 | 0 | } |
692 | 0 | } |
693 | |
|
694 | 0 | return aRetval; |
695 | 0 | } |
696 | | |
697 | | |
698 | | void SdrExchangeView::DrawMarkedObj(OutputDevice& rOut) const |
699 | 0 | { |
700 | 0 | ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects()); |
701 | |
|
702 | 0 | if(!aSdrObjects.empty()) |
703 | 0 | { |
704 | 0 | SdrPage* pPage = aSdrObjects[0]->getSdrPageFromSdrObject(); |
705 | 0 | sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, std::move(aSdrObjects), pPage); |
706 | 0 | sdr::contact::DisplayInfo aDisplayInfo; |
707 | | |
708 | | // do processing |
709 | 0 | aPainter.ProcessDisplay(aDisplayInfo); |
710 | 0 | } |
711 | 0 | } |
712 | | |
713 | | std::unique_ptr<SdrModel> SdrExchangeView::CreateMarkedObjModel() const |
714 | 0 | { |
715 | | // Sorting the MarkList here might be problematic in the future, so |
716 | | // use a copy. |
717 | 0 | const SdrMarkList& rMarkList = GetMarkedObjectList(); |
718 | 0 | rMarkList.ForceSort(); |
719 | 0 | std::unique_ptr<SdrModel> pNewModel(GetModel().AllocModel()); |
720 | 0 | rtl::Reference<SdrPage> pNewPage = pNewModel->AllocPage(false); |
721 | 0 | pNewModel->InsertPage(pNewPage.get()); |
722 | 0 | ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects()); |
723 | | |
724 | | // #i13033# |
725 | | // New mechanism to re-create the connections of cloned connectors |
726 | 0 | CloneList aCloneList; |
727 | |
|
728 | 0 | for(SdrObject* pObj : aSdrObjects) |
729 | 0 | { |
730 | 0 | assert(pObj); |
731 | |
|
732 | 0 | rtl::Reference<SdrObject> pNewObj; |
733 | |
|
734 | 0 | if(nullptr != dynamic_cast< const SdrPageObj* >(pObj)) |
735 | 0 | { |
736 | | // convert SdrPageObj's to a graphic representation, because |
737 | | // virtual connection to referenced page gets lost in new model |
738 | 0 | pNewObj = new SdrGrafObj( |
739 | 0 | *pNewModel, |
740 | 0 | GetObjGraphic(*pObj), |
741 | 0 | pObj->GetLogicRect()); |
742 | 0 | } |
743 | 0 | else if(nullptr != dynamic_cast< const sdr::table::SdrTableObj* >(pObj)) |
744 | 0 | { |
745 | | // check if we have a valid selection *different* from whole table |
746 | | // being selected |
747 | 0 | if(mxSelectionController.is()) |
748 | 0 | { |
749 | 0 | pNewObj = mxSelectionController->GetMarkedSdrObjClone(*pNewModel); |
750 | 0 | } |
751 | 0 | } |
752 | |
|
753 | 0 | if(!pNewObj) |
754 | 0 | { |
755 | | // not cloned yet |
756 | 0 | if(pObj->GetObjIdentifier() == SdrObjKind::OLE2 && nullptr == GetModel().GetPersist()) |
757 | 0 | { |
758 | | // tdf#125520 - former fix was wrong, the SdrModel |
759 | | // has to have a GetPersist() already, see task. |
760 | | // We can still warn here when this is not the case |
761 | 0 | SAL_WARN( "svx", "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" ); |
762 | 0 | } |
763 | | |
764 | | // use default way |
765 | 0 | pNewObj = pObj->CloneSdrObject(*pNewModel); |
766 | 0 | } |
767 | | |
768 | 0 | if(pNewObj) |
769 | 0 | { |
770 | 0 | pNewPage->InsertObject(pNewObj.get(), SAL_MAX_SIZE); |
771 | | |
772 | | // #i13033# |
773 | 0 | aCloneList.AddPair(pObj, pNewObj.get()); |
774 | 0 | } |
775 | 0 | } |
776 | | |
777 | | // #i13033# |
778 | | // New mechanism to re-create the connections of cloned connectors |
779 | 0 | aCloneList.CopyConnections(); |
780 | |
|
781 | 0 | return pNewModel; |
782 | 0 | } |
783 | | |
784 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |