Bump version to 24.04.3.4
[LibreOffice.git] / svx / source / svdraw / svdxcgv.cxx
blob5d16cbae259890f22deb7e9e8a325530f5f45b05
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
56 using namespace com::sun::star;
58 SdrExchangeView::SdrExchangeView(
59 SdrModel& rSdrModel,
60 OutputDevice* pOut)
61 : SdrObjEditView(rSdrModel, pOut)
65 bool SdrExchangeView::ImpLimitToWorkArea(Point& rPt) const
67 bool bRet(false);
69 if(!maMaxWorkArea.IsEmpty())
71 if(rPt.X()<maMaxWorkArea.Left())
73 rPt.setX( maMaxWorkArea.Left() );
74 bRet = true;
77 if(rPt.X()>maMaxWorkArea.Right())
79 rPt.setX( maMaxWorkArea.Right() );
80 bRet = true;
83 if(rPt.Y()<maMaxWorkArea.Top())
85 rPt.setY( maMaxWorkArea.Top() );
86 bRet = true;
89 if(rPt.Y()>maMaxWorkArea.Bottom())
91 rPt.setY( maMaxWorkArea.Bottom() );
92 bRet = true;
95 return bRet;
98 void SdrExchangeView::ImpGetPasteObjList(Point& /*rPos*/, SdrObjList*& rpLst)
100 if (rpLst==nullptr)
102 SdrPageView* pPV = GetSdrPageView();
104 if (pPV!=nullptr) {
105 rpLst=pPV->GetObjList();
110 bool SdrExchangeView::ImpGetPasteLayer(const SdrObjList* pObjList, SdrLayerID& rLayer) const
112 bool bRet=false;
113 rLayer=SdrLayerID(0);
114 if (pObjList!=nullptr) {
115 const SdrPage* pPg=pObjList->getSdrPageFromSdrObjList();
116 if (pPg!=nullptr) {
117 rLayer=pPg->GetLayerAdmin().GetLayerID(maActualLayer);
118 if (rLayer==SDRLAYER_NOTFOUND) rLayer=SdrLayerID(0);
119 SdrPageView* pPV = GetSdrPageView();
120 if (pPV!=nullptr) {
121 bRet=!pPV->GetLockedLayers().IsSet(rLayer) && pPV->GetVisibleLayers().IsSet(rLayer);
125 return bRet;
128 bool SdrExchangeView::Paste(const OUString& rStr, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
130 if (rStr.isEmpty())
131 return false;
133 Point aPos(rPos);
134 ImpGetPasteObjList(aPos,pLst);
135 ImpLimitToWorkArea( aPos );
136 if (pLst==nullptr) return false;
137 SdrLayerID nLayer;
138 if (!ImpGetPasteLayer(pLst,nLayer)) return false;
139 bool bUnmark = (nOptions & (SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
140 if (bUnmark) UnmarkAllObj();
141 tools::Rectangle aTextRect(0,0,500,500);
142 SdrPage* pPage=pLst->getSdrPageFromSdrObjList();
143 if (pPage!=nullptr) {
144 aTextRect.SetSize(pPage->GetSize());
146 rtl::Reference<SdrRectObj> pObj = new SdrRectObj(
147 getSdrModelFromSdrView(),
148 SdrObjKind::Text,
149 aTextRect);
151 pObj->SetLayer(nLayer);
152 pObj->NbcSetText(rStr); // SetText before SetAttr, else SetAttr doesn't work!
153 if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false);
155 pObj->SetMergedItemSet(maDefaultAttr);
157 SfxItemSet aTempAttr(GetModel().GetItemPool()); // no fill, no line
158 aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
159 aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
161 pObj->SetMergedItemSet(aTempAttr);
163 pObj->FitFrameToTextSize();
164 Size aSiz(pObj->GetLogicRect().GetSize());
165 MapUnit eMap = GetModel().GetScaleUnit();
166 ImpPasteObject(pObj.get(), *pLst, aPos, aSiz, MapMode(eMap), nOptions);
167 return true;
170 bool SdrExchangeView::Paste(SvStream& rInput, EETextFormat eFormat, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
172 Point aPos(rPos);
173 ImpGetPasteObjList(aPos,pLst);
174 ImpLimitToWorkArea( aPos );
175 if (pLst==nullptr) return false;
176 SdrLayerID nLayer;
177 if (!ImpGetPasteLayer(pLst,nLayer)) return false;
178 bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
179 if (bUnmark) UnmarkAllObj();
180 tools::Rectangle aTextRect(0,0,500,500);
181 SdrPage* pPage=pLst->getSdrPageFromSdrObjList();
182 if (pPage!=nullptr) {
183 aTextRect.SetSize(pPage->GetSize());
185 rtl::Reference<SdrRectObj> pObj = new SdrRectObj(
186 getSdrModelFromSdrView(),
187 SdrObjKind::Text,
188 aTextRect);
190 pObj->SetLayer(nLayer);
191 if (mpDefaultStyleSheet!=nullptr) pObj->NbcSetStyleSheet(mpDefaultStyleSheet, false);
193 pObj->SetMergedItemSet(maDefaultAttr);
195 SfxItemSet aTempAttr(GetModel().GetItemPool()); // no fill, no line
196 aTempAttr.Put(XLineStyleItem(drawing::LineStyle_NONE));
197 aTempAttr.Put(XFillStyleItem(drawing::FillStyle_NONE));
199 pObj->SetMergedItemSet(aTempAttr);
201 pObj->NbcSetText(rInput,OUString(),eFormat);
202 pObj->FitFrameToTextSize();
203 Size aSiz(pObj->GetLogicRect().GetSize());
204 MapUnit eMap = GetModel().GetScaleUnit();
205 ImpPasteObject(pObj.get(), *pLst, aPos, aSiz, MapMode(eMap), nOptions);
207 // b4967543
208 if(pObj->GetOutlinerParaObject())
210 SdrOutliner& rOutliner = pObj->getSdrModelFromSdrObject().GetHitTestOutliner();
211 rOutliner.SetText(*pObj->GetOutlinerParaObject());
213 if(1 == rOutliner.GetParagraphCount())
215 SfxStyleSheet* pCandidate = rOutliner.GetStyleSheet(0);
217 if(pCandidate)
219 if(pObj->getSdrModelFromSdrObject().GetStyleSheetPool() == pCandidate->GetPool())
221 pObj->NbcSetStyleSheet(pCandidate, true);
227 return true;
230 bool SdrExchangeView::Paste(
231 const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, SdrInsertFlags nOptions)
233 const SdrModel* pSrcMod=&rMod;
234 if (pSrcMod == &GetModel())
235 return false; // this can't work, right?
237 const bool bUndo = IsUndoEnabled();
239 if( bUndo )
240 BegUndo(SvxResId(STR_ExchangePaste));
242 if( mxSelectionController.is() && mxSelectionController->PasteObjModel( rMod ) )
244 if( bUndo )
245 EndUndo();
246 return true;
249 Point aPos(rPos);
250 ImpGetPasteObjList(aPos,pLst);
251 SdrPageView* pMarkPV=nullptr;
252 SdrPageView* pPV = GetSdrPageView();
254 if(pPV && pPV->GetObjList() == pLst )
255 pMarkPV=pPV;
257 ImpLimitToWorkArea( aPos );
258 if (pLst==nullptr)
259 return false;
261 bool bUnmark=(nOptions&(SdrInsertFlags::DONTMARK|SdrInsertFlags::ADDMARK))==SdrInsertFlags::NONE && !IsTextEdit();
262 if (bUnmark)
263 UnmarkAllObj();
265 // Rescale, if the Model uses a different MapUnit.
266 // Calculate the necessary factors first.
267 MapUnit eSrcUnit = pSrcMod->GetScaleUnit();
268 MapUnit eDstUnit = GetModel().GetScaleUnit();
269 bool bResize=eSrcUnit!=eDstUnit;
270 Fraction aXResize,aYResize;
271 Point aPt0;
272 if (bResize)
274 FrPair aResize(GetMapFactor(eSrcUnit,eDstUnit));
275 aXResize=aResize.X();
276 aYResize=aResize.Y();
278 SdrObjList* pDstLst=pLst;
279 sal_uInt16 nPg,nPgCount=pSrcMod->GetPageCount();
280 for (nPg=0; nPg<nPgCount; nPg++)
282 const SdrPage* pSrcPg=pSrcMod->GetPage(nPg);
284 // Use SnapRect, not BoundRect here
285 tools::Rectangle aR=pSrcPg->GetAllObjSnapRect();
287 if (bResize)
288 ResizeRect(aR,aPt0,aXResize,aYResize);
289 Point aDist(aPos-aR.Center());
290 Size aSiz(aDist.X(),aDist.Y());
291 size_t nCloneErrCnt = 0;
292 const size_t nObjCount = pSrcPg->GetObjCount();
293 bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE;
295 // #i13033#
296 // New mechanism to re-create the connections of cloned connectors
297 CloneList aCloneList;
298 std::unordered_set<rtl::OUString> aNameSet;
299 for (size_t nOb=0; nOb<nObjCount; ++nOb)
301 const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
303 rtl::Reference<SdrObject> pNewObj(pSrcOb->CloneSdrObject(GetModel()));
305 if (pNewObj!=nullptr)
307 if(bResize)
309 pNewObj->getSdrModelFromSdrObject().SetPasteResize(true);
310 pNewObj->NbcResize(aPt0,aXResize,aYResize);
311 pNewObj->getSdrModelFromSdrObject().SetPasteResize(false);
314 // #i39861#
315 pNewObj->NbcMove(aSiz);
317 const SdrPage* pPg = pDstLst->getSdrPageFromSdrObjList();
319 if(pPg)
321 // #i72535#
322 const SdrLayerAdmin& rAd = pPg->GetLayerAdmin();
323 SdrLayerID nLayer(0);
325 if(dynamic_cast<const FmFormObj*>( pNewObj.get()) != nullptr)
327 // for FormControls, force to form layer
328 nLayer = rAd.GetLayerID(rAd.GetControlLayerName());
330 else
332 nLayer = rAd.GetLayerID(maActualLayer);
335 if(SDRLAYER_NOTFOUND == nLayer)
337 nLayer = SdrLayerID(0);
340 pNewObj->SetLayer(nLayer);
343 pDstLst->InsertObjectThenMakeNameUnique(pNewObj.get(), aNameSet);
345 if( bUndo )
346 AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
348 if (bMark) {
349 // Don't already set Markhandles!
350 // That is instead being done by ModelHasChanged in MarkView.
351 MarkObj(pNewObj.get(),pMarkPV,false,true);
354 // #i13033#
355 aCloneList.AddPair(pSrcOb, pNewObj.get());
357 else
359 nCloneErrCnt++;
363 // #i13033#
364 // New mechanism to re-create the connections of cloned connectors
365 aCloneList.CopyConnections();
367 if(0 != nCloneErrCnt)
369 #ifdef DBG_UTIL
370 OStringBuffer aStr("SdrExchangeView::Paste(): Error when cloning ");
372 if(nCloneErrCnt == 1)
374 aStr.append("a drawing object.");
376 else
378 aStr.append(OString::number(static_cast<sal_Int32>(nCloneErrCnt))
379 + " drawing objects.");
382 aStr.append(" Not copying object connectors.");
384 OSL_FAIL(aStr.getStr());
385 #endif
389 if( bUndo )
390 EndUndo();
392 return true;
395 void SdrExchangeView::ImpPasteObject(SdrObject* pObj, SdrObjList& rLst, const Point& rCenter, const Size& rSiz, const MapMode& rMap, SdrInsertFlags nOptions)
397 BigInt nSizX(rSiz.Width());
398 BigInt nSizY(rSiz.Height());
399 MapUnit eSrcMU=rMap.GetMapUnit();
400 MapUnit eDstMU = GetModel().GetScaleUnit();
401 FrPair aMapFact(GetMapFactor(eSrcMU,eDstMU));
402 nSizX *= double(aMapFact.X() * rMap.GetScaleX());
403 nSizY *= double(aMapFact.Y() * rMap.GetScaleY());
404 tools::Long xs=nSizX;
405 tools::Long ys=nSizY;
406 // set the pos to 0, 0 for online case
407 bool isLOK = comphelper::LibreOfficeKit::isActive();
408 Point aPos(isLOK ? 0 : rCenter.X()-xs/2, isLOK ? 0 : rCenter.Y()-ys/2);
409 tools::Rectangle aR(aPos.X(),aPos.Y(),aPos.X()+xs,aPos.Y()+ys);
410 pObj->SetLogicRect(aR);
411 rLst.InsertObject(pObj, SAL_MAX_SIZE);
413 if( IsUndoEnabled() )
414 AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pObj));
416 SdrPageView* pMarkPV=nullptr;
417 SdrPageView* pPV = GetSdrPageView();
419 if(pPV && pPV->GetObjList()==&rLst)
420 pMarkPV=pPV;
422 bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE;
423 if (bMark)
424 { // select object the first PageView we found
425 MarkObj(pObj,pMarkPV);
429 BitmapEx SdrExchangeView::GetMarkedObjBitmapEx(bool bNoVDevIfOneBmpMarked, const sal_uInt32 nMaximumQuadraticPixels, const std::optional<Size>& rTargetDPI) const
431 BitmapEx aBmp;
433 if( AreObjectsMarked() )
435 if(1 == GetMarkedObjectCount())
437 if(bNoVDevIfOneBmpMarked)
439 SdrObject* pGrafObjTmp = GetMarkedObjectByIndex( 0 );
440 SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>( pGrafObjTmp );
442 if( pGrafObj && ( pGrafObj->GetGraphicType() == GraphicType::Bitmap ) )
444 aBmp = pGrafObj->GetTransformedGraphic().GetBitmapEx();
447 else
449 const SdrGrafObj* pSdrGrafObj = dynamic_cast< const SdrGrafObj* >(GetMarkedObjectByIndex(0));
451 if(pSdrGrafObj && pSdrGrafObj->isEmbeddedVectorGraphicData())
453 aBmp = pSdrGrafObj->GetGraphic().getVectorGraphicData()->getReplacement();
458 if( aBmp.IsEmpty() )
460 // choose conversion directly using primitives to bitmap to avoid
461 // rendering errors with tiled bitmap fills (these will be tiled in a
462 // in-between metafile, but tend to show 'gaps' since the target is *no*
463 // bitmap rendering)
464 ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
465 const sal_uInt32 nCount(aSdrObjects.size());
467 if(nCount)
469 // collect sub-primitives as group objects, thus no expensive append
470 // to existing sequence is needed
471 drawinglayer::primitive2d::Primitive2DContainer xPrimitives(nCount);
473 for(sal_uInt32 a(0); a < nCount; a++)
475 SdrObject* pCandidate = aSdrObjects[a];
476 SdrGrafObj* pSdrGrafObj = dynamic_cast< SdrGrafObj* >(pCandidate);
478 if(pSdrGrafObj)
480 // #122753# To ensure existence of graphic content, force swap in
481 pSdrGrafObj->ForceSwapIn();
484 drawinglayer::primitive2d::Primitive2DContainer xRetval;
485 pCandidate->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
486 xPrimitives[a] = new drawinglayer::primitive2d::GroupPrimitive2D(
487 std::move(xRetval));
490 // get logic range
491 const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
492 const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
494 if(!aRange.isEmpty())
496 o3tl::Length eRangeUnit = o3tl::Length::mm100;
498 if (GetModel().IsWriter())
500 eRangeUnit = o3tl::Length::twip;
503 // if we have geometry and it has a range, convert to BitmapEx using
504 // common tooling
505 aBmp = drawinglayer::convertPrimitive2DContainerToBitmapEx(
506 std::move(xPrimitives),
507 aRange,
508 nMaximumQuadraticPixels,
509 eRangeUnit,
510 rTargetDPI);
516 return aBmp;
520 GDIMetaFile SdrExchangeView::GetMarkedObjMetaFile(bool bNoVDevIfOneMtfMarked) const
522 GDIMetaFile aMtf;
524 if( AreObjectsMarked() )
526 tools::Rectangle aBound( GetMarkedObjBoundRect() );
527 Size aBoundSize( aBound.GetWidth(), aBound.GetHeight() );
528 MapMode aMap(GetModel().GetScaleUnit());
530 if( bNoVDevIfOneMtfMarked )
532 SdrObject* pGrafObjTmp = GetMarkedObjectByIndex( 0 );
533 SdrGrafObj* pGrafObj = ( GetMarkedObjectCount() ==1 ) ? dynamic_cast<SdrGrafObj*>( pGrafObjTmp ) : nullptr;
535 if( pGrafObj )
537 Graphic aGraphic( pGrafObj->GetTransformedGraphic() );
539 // #119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
540 aMtf = aGraphic.GetGDIMetaFile();
544 if( !aMtf.GetActionSize() )
546 ScopedVclPtrInstance< VirtualDevice > pOut;
547 const Size aDummySize(2, 2);
549 pOut->SetOutputSizePixel(aDummySize);
550 pOut->EnableOutput(false);
551 pOut->SetMapMode(aMap);
552 aMtf.Clear();
553 aMtf.Record(pOut);
555 DrawMarkedObj(*pOut);
557 aMtf.Stop();
558 aMtf.WindStart();
560 // moving the result is more reliable then setting a relative MapMode at the VDev (used
561 // before), also see #i99268# in GetObjGraphic() below. Some draw actions at
562 // the OutDev are simply not handled correctly when a MapMode is set at the
563 // target device, e.g. MetaFloatTransparentAction. Even the Move for this action
564 // was missing the manipulation of the embedded Metafile
565 aMtf.Move(-aBound.Left(), -aBound.Top());
567 aMtf.SetPrefMapMode( aMap );
569 // removed PrefSize extension. It is principally wrong to set a reduced size at
570 // the created MetaFile. The mentioned errors occur at output time since the integer
571 // MapModes from VCL lead to errors. It is now corrected in the VCLRenderer for
572 // primitives (and may later be done in breaking up a MetaFile to primitives)
573 aMtf.SetPrefSize(aBoundSize);
577 return aMtf;
581 Graphic SdrExchangeView::GetAllMarkedGraphic() const
583 Graphic aRet;
585 if( AreObjectsMarked() )
587 if( ( 1 == GetMarkedObjectCount() ) && GetSdrMarkByIndex( 0 ) )
588 aRet = SdrExchangeView::GetObjGraphic(*GetMarkedObjectByIndex(0));
589 else
590 aRet = GetMarkedObjMetaFile();
593 return aRet;
597 // tdf#155479 bSVG: need to know it's SVG export, default is false
598 Graphic SdrExchangeView::GetObjGraphic(const SdrObject& rSdrObject, bool bSVG)
600 Graphic aRet;
602 if (!rSdrObject.HasText())
604 // try to get a graphic from the object first
605 const SdrGrafObj* pSdrGrafObj(dynamic_cast<const SdrGrafObj*>(&rSdrObject));
606 const SdrOle2Obj* pSdrOle2Obj(dynamic_cast<const SdrOle2Obj*>(&rSdrObject));
608 if (pSdrGrafObj)
610 if (pSdrGrafObj->isEmbeddedVectorGraphicData())
612 // get Metafile for Svg content
613 aRet = pSdrGrafObj->getMetafileFromEmbeddedVectorGraphicData();
615 else
617 // Make behaviour coherent with metafile
618 // recording below (which of course also takes
619 // view-transformed objects)
620 aRet = pSdrGrafObj->GetTransformedGraphic();
623 else if (pSdrOle2Obj)
625 if (pSdrOle2Obj->GetGraphic())
627 aRet = *pSdrOle2Obj->GetGraphic();
630 else
632 // Support extracting a snapshot from video media, if possible.
633 const SdrMediaObj* pSdrMediaObj = dynamic_cast<const SdrMediaObj*>(&rSdrObject);
634 if (pSdrMediaObj)
636 const css::uno::Reference<css::graphic::XGraphic>& xGraphic
637 = pSdrMediaObj->getSnapshot();
638 if (xGraphic.is())
639 aRet = Graphic(xGraphic);
644 // if graphic could not be retrieved => go the hard way and create a MetaFile
645 if((GraphicType::NONE == aRet.GetType()) || (GraphicType::Default == aRet.GetType()))
647 ScopedVclPtrInstance< VirtualDevice > pOut;
648 GDIMetaFile aMtf;
649 const tools::Rectangle aBoundRect(rSdrObject.GetCurrentBoundRect());
650 const MapMode aMap(rSdrObject.getSdrModelFromSdrObject().GetScaleUnit());
652 pOut->EnableOutput(false);
653 pOut->SetMapMode(aMap);
654 aMtf.Record(pOut);
655 aMtf.setSVG(bSVG);
656 rSdrObject.SingleObjectPainter(*pOut);
657 aMtf.Stop();
658 aMtf.WindStart();
660 // #i99268# replace the original offset from using XOutDev's SetOffset
661 // NOT (as tried with #i92760#) with another MapMode which gets recorded
662 // by the Metafile itself (what always leads to problems), but by
663 // moving the result directly
664 aMtf.Move(-aBoundRect.Left(), -aBoundRect.Top());
665 aMtf.SetPrefMapMode(aMap);
666 aMtf.SetPrefSize(aBoundRect.GetSize());
668 if(aMtf.GetActionSize())
670 aRet = aMtf;
674 return aRet;
678 ::std::vector< SdrObject* > SdrExchangeView::GetMarkedObjects() const
680 SortMarkedObjects();
681 ::std::vector< SdrObject* > aRetval;
683 ::std::vector< ::std::vector< SdrMark* > > aObjVectors( 2 );
684 ::std::vector< SdrMark* >& rObjVector1 = aObjVectors[ 0 ];
685 ::std::vector< SdrMark* >& rObjVector2 = aObjVectors[ 1 ];
686 const SdrLayerAdmin& rLayerAdmin = GetModel().GetLayerAdmin();
687 const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID( rLayerAdmin.GetControlLayerName() );
689 for( size_t n = 0, nCount = GetMarkedObjectCount(); n < nCount; ++n )
691 SdrMark* pMark = GetSdrMarkByIndex( n );
693 // paint objects on control layer on top of all other objects
694 if( nControlLayerId == pMark->GetMarkedSdrObj()->GetLayer() )
695 rObjVector2.push_back( pMark );
696 else
697 rObjVector1.push_back( pMark );
700 for(const std::vector<SdrMark*> & rObjVector : aObjVectors)
702 for(SdrMark* pMark : rObjVector)
704 aRetval.push_back(pMark->GetMarkedSdrObj());
708 return aRetval;
712 void SdrExchangeView::DrawMarkedObj(OutputDevice& rOut) const
714 ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
716 if(!aSdrObjects.empty())
718 sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, std::move(aSdrObjects), aSdrObjects[0]->getSdrPageFromSdrObject());
719 sdr::contact::DisplayInfo aDisplayInfo;
721 // do processing
722 aPainter.ProcessDisplay(aDisplayInfo);
726 std::unique_ptr<SdrModel> SdrExchangeView::CreateMarkedObjModel() const
728 // Sorting the MarkList here might be problematic in the future, so
729 // use a copy.
730 SortMarkedObjects();
731 std::unique_ptr<SdrModel> pNewModel(GetModel().AllocModel());
732 rtl::Reference<SdrPage> pNewPage = pNewModel->AllocPage(false);
733 pNewModel->InsertPage(pNewPage.get());
734 ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
736 // #i13033#
737 // New mechanism to re-create the connections of cloned connectors
738 CloneList aCloneList;
740 for(SdrObject* pObj : aSdrObjects)
742 rtl::Reference<SdrObject> pNewObj;
744 if(nullptr != dynamic_cast< const SdrPageObj* >(pObj))
746 // convert SdrPageObj's to a graphic representation, because
747 // virtual connection to referenced page gets lost in new model
748 pNewObj = new SdrGrafObj(
749 *pNewModel,
750 GetObjGraphic(*pObj),
751 pObj->GetLogicRect());
753 else if(nullptr != dynamic_cast< const sdr::table::SdrTableObj* >(pObj))
755 // check if we have a valid selection *different* from whole table
756 // being selected
757 if(mxSelectionController.is())
759 pNewObj = mxSelectionController->GetMarkedSdrObjClone(*pNewModel);
763 if(!pNewObj)
765 // not cloned yet
766 if(pObj->GetObjIdentifier() == SdrObjKind::OLE2 && nullptr == GetModel().GetPersist())
768 // tdf#125520 - former fix was wrong, the SdrModel
769 // has to have a GetPersist() already, see task.
770 // We can still warn here when this is not the case
771 SAL_WARN( "svx", "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" );
774 // use default way
775 pNewObj = pObj->CloneSdrObject(*pNewModel);
778 if(pNewObj)
780 pNewPage->InsertObject(pNewObj.get(), SAL_MAX_SIZE);
782 // #i13033#
783 aCloneList.AddPair(pObj, pNewObj.get());
787 // #i13033#
788 // New mechanism to re-create the connections of cloned connectors
789 aCloneList.CopyConnections();
791 return pNewModel;
794 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */