Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdxcgv.cxx
Line
Count
Source
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
346k
:   SdrObjEditView(rSdrModel, pOut)
62
346k
{
63
346k
}
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
    double aXResize = 0.0;
267
0
    double aYResize = 0.0;
268
0
    Point aPt0;
269
0
    if (bResize)
270
0
    {
271
0
        FrPair aResize(GetMapFactor(eSrcUnit,eDstUnit));
272
0
        aXResize=aResize.X();
273
0
        aYResize=aResize.Y();
274
0
    }
275
0
    SdrObjList*  pDstLst=pLst;
276
0
    sal_uInt16 nPg,nPgCount=pSrcMod->GetPageCount();
277
0
    for (nPg=0; nPg<nPgCount; nPg++)
278
0
    {
279
0
        const SdrPage* pSrcPg=pSrcMod->GetPage(nPg);
280
281
        // Use SnapRect, not BoundRect here
282
0
        tools::Rectangle aR=pSrcPg->GetAllObjSnapRect();
283
284
0
        if (bResize)
285
0
            ResizeRect(aR,aPt0,aXResize,aYResize);
286
0
        Point aDist(aPos-aR.Center());
287
0
        Size  aSiz(aDist.X(),aDist.Y());
288
0
        size_t nCloneErrCnt = 0;
289
0
        const size_t nObjCount = pSrcPg->GetObjCount();
290
0
        bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE;
291
292
        // #i13033#
293
        // New mechanism to re-create the connections of cloned connectors
294
0
        CloneList aCloneList;
295
0
        std::unordered_set<rtl::OUString> aNameSet;
296
0
        for (size_t nOb=0; nOb<nObjCount; ++nOb)
297
0
        {
298
0
            const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
299
300
0
            rtl::Reference<SdrObject> pNewObj(pSrcOb->CloneSdrObject(GetModel()));
301
302
0
            if (pNewObj!=nullptr)
303
0
            {
304
0
                if(bResize)
305
0
                {
306
0
                    pNewObj->getSdrModelFromSdrObject().SetPasteResize(true);
307
0
                    pNewObj->NbcResize(aPt0,aXResize,aYResize);
308
0
                    pNewObj->getSdrModelFromSdrObject().SetPasteResize(false);
309
0
                }
310
311
                // #i39861#
312
0
                pNewObj->NbcMove(aSiz);
313
314
0
                const SdrPage* pPg = pDstLst->getSdrPageFromSdrObjList();
315
316
0
                if(pPg)
317
0
                {
318
                    // #i72535#
319
0
                    const SdrLayerAdmin& rAd = pPg->GetLayerAdmin();
320
0
                    SdrLayerID nLayer(0);
321
322
0
                    if(dynamic_cast<const FmFormObj*>( pNewObj.get()) !=  nullptr)
323
0
                    {
324
                        // for FormControls, force to form layer
325
0
                        nLayer = rAd.GetLayerID(rAd.GetControlLayerName());
326
0
                    }
327
0
                    else
328
0
                    {
329
0
                        nLayer = rAd.GetLayerID(maActualLayer);
330
0
                    }
331
332
0
                    if(SDRLAYER_NOTFOUND == nLayer)
333
0
                    {
334
0
                        nLayer = SdrLayerID(0);
335
0
                    }
336
337
0
                    pNewObj->SetLayer(nLayer);
338
0
                }
339
340
0
                pDstLst->InsertObjectThenMakeNameUnique(pNewObj.get(), aNameSet);
341
342
0
                if( bUndo )
343
0
                    AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
344
345
0
                if (bMark) {
346
                    // Don't already set Markhandles!
347
                    // That is instead being done by ModelHasChanged in MarkView.
348
0
                    MarkObj(pNewObj.get(),pMarkPV,false,true);
349
0
                }
350
351
                // #i13033#
352
0
                aCloneList.AddPair(pSrcOb, pNewObj.get());
353
0
            }
354
0
            else
355
0
            {
356
0
                nCloneErrCnt++;
357
0
            }
358
0
        }
359
360
        // #i13033#
361
        // New mechanism to re-create the connections of cloned connectors
362
0
        aCloneList.CopyConnections();
363
364
0
        if(0 != nCloneErrCnt)
365
0
        {
366
#ifdef DBG_UTIL
367
            OStringBuffer aStr("SdrExchangeView::Paste(): Error when cloning ");
368
369
            if(nCloneErrCnt == 1)
370
            {
371
                aStr.append("a drawing object.");
372
            }
373
            else
374
            {
375
                aStr.append(OString::number(static_cast<sal_Int32>(nCloneErrCnt))
376
                    + " drawing objects.");
377
            }
378
379
            aStr.append(" Not copying object connectors.");
380
381
            OSL_FAIL(aStr.getStr());
382
#endif
383
0
        }
384
0
    }
385
386
0
    if( bUndo )
387
0
        EndUndo();
388
389
0
    return true;
390
0
}
391
392
void SdrExchangeView::ImpPasteObject(SdrObject* pObj, SdrObjList& rLst, const Point& rCenter, const Size& rSiz, const MapMode& rMap, SdrInsertFlags nOptions)
393
0
{
394
0
    BigInt nSizX(rSiz.Width());
395
0
    BigInt nSizY(rSiz.Height());
396
0
    MapUnit eSrcMU=rMap.GetMapUnit();
397
0
    MapUnit eDstMU = GetModel().GetScaleUnit();
398
0
    FrPair aMapFact(GetMapFactor(eSrcMU,eDstMU));
399
0
    nSizX *= aMapFact.X() * rMap.GetScaleX();
400
0
    nSizY *= aMapFact.Y() * rMap.GetScaleY();
401
0
    tools::Long xs=nSizX;
402
0
    tools::Long ys=nSizY;
403
    // set the pos to 0, 0 for online case
404
0
    bool isLOK = comphelper::LibreOfficeKit::isActive();
405
0
    Point aPos(isLOK ? 0 : rCenter.X()-xs/2, isLOK ? 0 : rCenter.Y()-ys/2);
406
0
    tools::Rectangle aR(aPos.X(),aPos.Y(),aPos.X()+xs,aPos.Y()+ys);
407
0
    pObj->SetLogicRect(aR);
408
0
    rLst.InsertObject(pObj, SAL_MAX_SIZE);
409
410
0
    if( IsUndoEnabled() )
411
0
        AddUndo(getSdrModelFromSdrView().GetSdrUndoFactory().CreateUndoNewObject(*pObj));
412
413
0
    SdrPageView* pMarkPV=nullptr;
414
0
    SdrPageView* pPV = GetSdrPageView();
415
416
0
    if(pPV && pPV->GetObjList()==&rLst)
417
0
        pMarkPV=pPV;
418
419
0
    bool bMark = pMarkPV!=nullptr && !IsTextEdit() && (nOptions&SdrInsertFlags::DONTMARK)==SdrInsertFlags::NONE;
420
0
    if (bMark)
421
0
    { // select object the first PageView we found
422
0
        MarkObj(pObj,pMarkPV);
423
0
    }
424
0
}
425
426
Bitmap SdrExchangeView::GetMarkedObjBitmap(bool bNoVDevIfOneBmpMarked, const sal_uInt32 nMaximumQuadraticPixels, const std::optional<Size>& rTargetDPI) const
427
0
{
428
0
    Bitmap aBmp;
429
430
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
431
0
    if(1 == rMarkList.GetMarkCount())
432
0
    {
433
0
        if (auto pGrafObj
434
0
            = dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj()))
435
0
        {
436
0
            if(bNoVDevIfOneBmpMarked)
437
0
            {
438
0
                if (pGrafObj->GetGraphicType() == GraphicType::Bitmap)
439
0
                    aBmp = pGrafObj->GetTransformedGraphic().GetBitmap();
440
0
            }
441
0
            else
442
0
            {
443
0
                if (pGrafObj->isEmbeddedVectorGraphicData())
444
0
                    aBmp = pGrafObj->GetGraphic().getVectorGraphicData()->getReplacement();
445
0
            }
446
0
        }
447
0
    }
448
449
0
    if (aBmp.IsEmpty() && rMarkList.GetMarkCount() != 0)
450
0
    {
451
        // choose conversion directly using primitives to bitmap to avoid
452
        // rendering errors with tiled bitmap fills (these will be tiled in a
453
        // in-between metafile, but tend to show 'gaps' since the target is *no*
454
        // bitmap rendering)
455
0
        ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
456
0
        const size_t nCount(aSdrObjects.size());
457
458
        // collect sub-primitives as group objects, thus no expensive append
459
        // to existing sequence is needed
460
0
        drawinglayer::primitive2d::Primitive2DContainer xPrimitives(nCount);
461
462
0
        for (size_t a(0); a < nCount; a++)
463
0
        {
464
0
            const SdrObject* pCandidate = aSdrObjects[a];
465
466
0
            if (auto pSdrGrafObj = dynamic_cast<const SdrGrafObj*>(pCandidate))
467
0
            {
468
                // #122753# To ensure existence of graphic content, force swap in
469
0
                pSdrGrafObj->ForceSwapIn();
470
0
            }
471
472
0
            drawinglayer::primitive2d::Primitive2DContainer xRetval;
473
0
            pCandidate->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
474
0
            xPrimitives[a] = new drawinglayer::primitive2d::GroupPrimitive2D(
475
0
                std::move(xRetval));
476
0
        }
477
478
        // get logic range
479
0
        const drawinglayer::geometry::ViewInformation2D aViewInformation2D;
480
0
        const basegfx::B2DRange aRange(xPrimitives.getB2DRange(aViewInformation2D));
481
482
0
        if(!aRange.isEmpty())
483
0
        {
484
0
            o3tl::Length eRangeUnit = o3tl::Length::mm100;
485
486
0
            if (GetModel().IsWriter())
487
0
            {
488
0
                eRangeUnit = o3tl::Length::twip;
489
0
            }
490
491
            // if we have geometry and it has a range, convert to Bitmap using
492
            // common tooling
493
0
            aBmp = drawinglayer::convertPrimitive2DContainerToBitmap(
494
0
                std::move(xPrimitives),
495
0
                aRange,
496
0
                nMaximumQuadraticPixels,
497
0
                eRangeUnit,
498
0
                rTargetDPI);
499
0
        }
500
0
    }
501
502
0
    return aBmp;
503
0
}
504
505
506
GDIMetaFile SdrExchangeView::GetMarkedObjMetaFile(bool bNoVDevIfOneMtfMarked) const
507
0
{
508
0
    GDIMetaFile aMtf;
509
510
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
511
0
    if( rMarkList.GetMarkCount() != 0 )
512
0
    {
513
0
        tools::Rectangle   aBound( GetMarkedObjBoundRect() );
514
0
        Size        aBoundSize( aBound.GetWidth(), aBound.GetHeight() );
515
0
        MapMode aMap(GetModel().GetScaleUnit());
516
517
0
        if (bNoVDevIfOneMtfMarked && rMarkList.GetMarkCount() == 1)
518
0
        {
519
0
            if (auto pGrafObj
520
0
                = dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj()))
521
0
            {
522
0
                Graphic aGraphic( pGrafObj->GetTransformedGraphic() );
523
524
                // #119735# just use GetGDIMetaFile, it will create a buffered version of contained bitmap now automatically
525
0
                aMtf = aGraphic.GetGDIMetaFile();
526
0
            }
527
0
        }
528
529
0
        if( !aMtf.GetActionSize() )
530
0
        {
531
0
            ScopedVclPtrInstance< VirtualDevice > pOut;
532
0
            const Size aDummySize(2, 2);
533
534
0
            pOut->SetOutputSizePixel(aDummySize);
535
0
            pOut->EnableOutput(false);
536
0
            pOut->SetMapMode(aMap);
537
0
            aMtf.Clear();
538
0
            aMtf.Record(pOut);
539
540
0
            DrawMarkedObj(*pOut);
541
542
0
            aMtf.Stop();
543
0
            aMtf.WindStart();
544
545
            // moving the result is more reliable then setting a relative MapMode at the VDev (used
546
            // before), also see #i99268# in GetObjGraphic() below. Some draw actions at
547
            // the OutDev are simply not handled correctly when a MapMode is set at the
548
            // target device, e.g. MetaFloatTransparentAction. Even the Move for this action
549
            // was missing the manipulation of the embedded Metafile
550
0
            aMtf.Move(-aBound.Left(), -aBound.Top());
551
552
0
            aMtf.SetPrefMapMode( aMap );
553
554
            // removed PrefSize extension. It is principally wrong to set a reduced size at
555
            // the created MetaFile. The mentioned errors occur at output time since the integer
556
            // MapModes from VCL lead to errors. It is now corrected in the VCLRenderer for
557
            // primitives (and may later be done in breaking up a MetaFile to primitives)
558
0
            aMtf.SetPrefSize(aBoundSize);
559
0
        }
560
0
    }
561
562
0
    return aMtf;
563
0
}
564
565
566
Graphic SdrExchangeView::GetAllMarkedGraphic() const
567
0
{
568
0
    Graphic aRet;
569
570
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
571
0
    if( rMarkList.GetMarkCount() != 0 )
572
0
    {
573
0
        if( ( 1 == rMarkList.GetMarkCount() ) && rMarkList.GetMark( 0 ) )
574
0
            aRet = SdrExchangeView::GetObjGraphic(*rMarkList.GetMark(0)->GetMarkedSdrObj());
575
0
        else
576
0
            aRet = GetMarkedObjMetaFile();
577
0
    }
578
579
0
    return aRet;
580
0
}
581
582
583
// tdf#155479 bSVG: need to know it's SVG export, default is false
584
Graphic SdrExchangeView::GetObjGraphic(const SdrObject& rSdrObject, bool bSVG)
585
0
{
586
0
    Graphic aRet;
587
588
0
    if (!rSdrObject.HasText())
589
0
    {
590
        // try to get a graphic from the object first
591
0
        const SdrGrafObj* pSdrGrafObj(dynamic_cast<const SdrGrafObj*>(&rSdrObject));
592
0
        const SdrOle2Obj* pSdrOle2Obj(dynamic_cast<const SdrOle2Obj*>(&rSdrObject));
593
594
0
        if (pSdrGrafObj)
595
0
        {
596
0
            if (pSdrGrafObj->isEmbeddedVectorGraphicData())
597
0
            {
598
                // get Metafile for Svg content
599
0
                aRet = pSdrGrafObj->getMetafileFromEmbeddedVectorGraphicData();
600
0
            }
601
0
            else
602
0
            {
603
                // Make behaviour coherent with metafile
604
                // recording below (which of course also takes
605
                // view-transformed objects)
606
0
                aRet = pSdrGrafObj->GetTransformedGraphic();
607
0
            }
608
0
        }
609
0
        else if (pSdrOle2Obj)
610
0
        {
611
0
            if (const Graphic* pGraphic = pSdrOle2Obj->GetGraphic())
612
0
            {
613
0
                aRet = *pGraphic;
614
0
            }
615
0
        }
616
0
        else
617
0
        {
618
            // Support extracting a snapshot from video media, if possible.
619
0
            const SdrMediaObj* pSdrMediaObj = dynamic_cast<const SdrMediaObj*>(&rSdrObject);
620
0
            if (pSdrMediaObj)
621
0
            {
622
0
                const css::uno::Reference<css::graphic::XGraphic>& xGraphic
623
0
                    = pSdrMediaObj->getSnapshot();
624
0
                if (xGraphic.is())
625
0
                    aRet = Graphic(xGraphic);
626
0
            }
627
0
        }
628
0
    }
629
630
    // if graphic could not be retrieved => go the hard way and create a MetaFile
631
0
    if((GraphicType::NONE == aRet.GetType()) || (GraphicType::Default == aRet.GetType()))
632
0
    {
633
0
        ScopedVclPtrInstance< VirtualDevice > pOut;
634
0
        GDIMetaFile aMtf;
635
0
        const tools::Rectangle aBoundRect(rSdrObject.GetCurrentBoundRect());
636
0
        const MapMode aMap(rSdrObject.getSdrModelFromSdrObject().GetScaleUnit());
637
638
0
        pOut->EnableOutput(false);
639
0
        pOut->SetMapMode(aMap);
640
0
        aMtf.Record(pOut);
641
0
        aMtf.setSVG(bSVG);
642
0
        rSdrObject.SingleObjectPainter(*pOut);
643
0
        aMtf.Stop();
644
0
        aMtf.WindStart();
645
646
        // #i99268# replace the original offset from using XOutDev's SetOffset
647
        // NOT (as tried with #i92760#) with another MapMode which gets recorded
648
        // by the Metafile itself (what always leads to problems), but by
649
        // moving the result directly
650
0
        aMtf.Move(-aBoundRect.Left(), -aBoundRect.Top());
651
0
        aMtf.SetPrefMapMode(aMap);
652
0
        aMtf.SetPrefSize(aBoundRect.GetSize());
653
654
0
        if(aMtf.GetActionSize())
655
0
        {
656
0
            aRet = aMtf;
657
0
        }
658
0
    }
659
660
0
    return aRet;
661
0
}
662
663
664
::std::vector< SdrObject* > SdrExchangeView::GetMarkedObjects() const
665
0
{
666
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
667
0
    rMarkList.ForceSort();
668
0
    ::std::vector< SdrObject* > aRetval;
669
670
0
    ::std::vector< ::std::vector< SdrMark* > >  aObjVectors( 2 );
671
0
    ::std::vector< SdrMark* >&                  rObjVector1 = aObjVectors[ 0 ];
672
0
    ::std::vector< SdrMark* >&                  rObjVector2 = aObjVectors[ 1 ];
673
0
    const SdrLayerAdmin& rLayerAdmin = GetModel().GetLayerAdmin();
674
0
    const SdrLayerID                            nControlLayerId = rLayerAdmin.GetLayerID( rLayerAdmin.GetControlLayerName() );
675
676
0
    for( size_t n = 0, nCount = rMarkList.GetMarkCount(); n < nCount; ++n )
677
0
    {
678
0
        SdrMark* pMark = rMarkList.GetMark( n );
679
680
        // paint objects on control layer on top of all other objects
681
0
        if( nControlLayerId == pMark->GetMarkedSdrObj()->GetLayer() )
682
0
            rObjVector2.push_back( pMark );
683
0
        else
684
0
            rObjVector1.push_back( pMark );
685
0
    }
686
687
0
    for(const std::vector<SdrMark*> & rObjVector : aObjVectors)
688
0
    {
689
0
        for(SdrMark* pMark : rObjVector)
690
0
        {
691
0
            aRetval.push_back(pMark->GetMarkedSdrObj());
692
0
        }
693
0
    }
694
695
0
    return aRetval;
696
0
}
697
698
699
void SdrExchangeView::DrawMarkedObj(OutputDevice& rOut) const
700
0
{
701
0
    ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
702
703
0
    if(!aSdrObjects.empty())
704
0
    {
705
0
        SdrPage* pPage = aSdrObjects[0]->getSdrPageFromSdrObject();
706
0
        sdr::contact::ObjectContactOfObjListPainter aPainter(rOut, std::move(aSdrObjects), pPage);
707
0
        sdr::contact::DisplayInfo aDisplayInfo;
708
709
        // do processing
710
0
        aPainter.ProcessDisplay(aDisplayInfo);
711
0
    }
712
0
}
713
714
std::unique_ptr<SdrModel> SdrExchangeView::CreateMarkedObjModel() const
715
0
{
716
    // Sorting the MarkList here might be problematic in the future, so
717
    // use a copy.
718
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
719
0
    rMarkList.ForceSort();
720
0
    std::unique_ptr<SdrModel> pNewModel(GetModel().AllocModel());
721
0
    rtl::Reference<SdrPage> pNewPage = pNewModel->AllocPage(false);
722
0
    pNewModel->InsertPage(pNewPage.get());
723
0
    ::std::vector< SdrObject* > aSdrObjects(GetMarkedObjects());
724
725
    // #i13033#
726
    // New mechanism to re-create the connections of cloned connectors
727
0
    CloneList aCloneList;
728
729
0
    for(SdrObject* pObj : aSdrObjects)
730
0
    {
731
0
        assert(pObj);
732
733
0
        rtl::Reference<SdrObject> pNewObj;
734
735
0
        if(nullptr != dynamic_cast< const SdrPageObj* >(pObj))
736
0
        {
737
            // convert SdrPageObj's to a graphic representation, because
738
            // virtual connection to referenced page gets lost in new model
739
0
            pNewObj = new SdrGrafObj(
740
0
                *pNewModel,
741
0
                GetObjGraphic(*pObj),
742
0
                pObj->GetLogicRect());
743
0
        }
744
0
        else if(nullptr != dynamic_cast< const sdr::table::SdrTableObj* >(pObj))
745
0
        {
746
            // check if we have a valid selection *different* from whole table
747
            // being selected
748
0
            if(mxSelectionController.is())
749
0
            {
750
0
                pNewObj = mxSelectionController->GetMarkedSdrObjClone(*pNewModel);
751
0
            }
752
0
        }
753
754
0
        if(!pNewObj)
755
0
        {
756
            // not cloned yet
757
0
            if(pObj->GetObjIdentifier() == SdrObjKind::OLE2 && nullptr == GetModel().GetPersist())
758
0
            {
759
                // tdf#125520 - former fix was wrong, the SdrModel
760
                // has to have a GetPersist() already, see task.
761
                // We can still warn here when this is not the case
762
0
                SAL_WARN( "svx", "OLE gets cloned Persist, EmbeddedObjectContainer will not be copied" );
763
0
            }
764
765
            // use default way
766
0
            pNewObj = pObj->CloneSdrObject(*pNewModel);
767
0
        }
768
769
0
        if(pNewObj)
770
0
        {
771
0
            pNewPage->InsertObject(pNewObj.get(), SAL_MAX_SIZE);
772
773
            // #i13033#
774
0
            aCloneList.AddPair(pObj, pNewObj.get());
775
0
        }
776
0
    }
777
778
    // #i13033#
779
    // New mechanism to re-create the connections of cloned connectors
780
0
    aCloneList.CopyConnections();
781
782
0
    return pNewModel;
783
0
}
784
785
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */