Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/view/viewfun7.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 <com/sun/star/embed/NoVisualAreaSizeException.hpp>
21
#include <com/sun/star/embed/XEmbeddedObject.hpp>
22
23
#include <svx/svditer.hxx>
24
#include <svx/svdograf.hxx>
25
#include <svx/svdoole2.hxx>
26
#include <svx/svdouno.hxx>
27
#include <svx/svdpage.hxx>
28
#include <svx/svdpagv.hxx>
29
#include <svx/svdundo.hxx>
30
#include <svtools/embedhlp.hxx>
31
#include <sfx2/objsh.hxx>
32
#include <sfx2/ipclient.hxx>
33
#include <toolkit/helper/vclunohelper.hxx>
34
#include <com/sun/star/embed/Aspects.hpp>
35
#include <osl/diagnose.h>
36
37
#include <document.hxx>
38
#include <viewfunc.hxx>
39
#include <tabvwsh.hxx>
40
#include <drawview.hxx>
41
#include <scmod.hxx>
42
#include <drwlayer.hxx>
43
#include <drwtrans.hxx>
44
#include <globstr.hrc>
45
#include <scresid.hxx>
46
#include <docuno.hxx>
47
#include <docsh.hxx>
48
#include <dragdata.hxx>
49
#include <gridwin.hxx>
50
#include <stlpool.hxx>
51
52
bool bPasteIsMove = false;
53
54
using namespace com::sun::star;
55
56
static void lcl_AdjustInsertPos( ScViewData& rData, Point& rPos, const Size& rSize )
57
0
{
58
0
    SdrPage* pPage = rData.GetScDrawView()->GetModel().GetPage( static_cast<sal_uInt16>(rData.CurrentTabForData()) );
59
0
    assert(pPage && "pPage ???");
60
0
    Size aPgSize( pPage->GetSize() );
61
0
    if (aPgSize.Width() < 0)
62
0
        aPgSize.setWidth( -aPgSize.Width() );
63
0
    tools::Long x = aPgSize.Width() - rPos.X() - rSize.Width();
64
0
    tools::Long y = aPgSize.Height() - rPos.Y() - rSize.Height();
65
    // if necessary: adjustments (80/200) for pixel approx. errors
66
0
    if( x < 0 )
67
0
        rPos.AdjustX(x + 80 );
68
0
    if( y < 0 )
69
0
        rPos.AdjustY(y + 200 );
70
0
    rPos.AdjustX(rSize.Width() / 2 );          // position at paste is center
71
0
    rPos.AdjustY(rSize.Height() / 2 );
72
0
}
73
74
void ScViewFunc::PasteDraw( const Point& rLogicPos, SdrModel* pModel,
75
        bool bGroup, std::u16string_view rSrcShellID, std::u16string_view rDestShellID )
76
0
{
77
0
    bool bSameDocClipboard = rSrcShellID == rDestShellID;
78
79
0
    MakeDrawLayer();
80
0
    Point aPos( rLogicPos );
81
82
    // MapMode at Outliner-RefDevice has to be right (as in FuText::MakeOutliner)
83
    //! merge with FuText::MakeOutliner?
84
0
    MapMode aOldMapMode;
85
0
    OutputDevice* pRef = GetViewData().GetDocument().GetDrawLayer()->GetRefDevice();
86
0
    if (pRef)
87
0
    {
88
0
        aOldMapMode = pRef->GetMapMode();
89
0
        pRef->SetMapMode( MapMode(MapUnit::Map100thMM) );
90
0
    }
91
92
0
    bool bNegativePage = GetViewData().GetDocument().IsNegativePage( GetViewData().CurrentTabForData() );
93
94
0
    SdrView* pDragEditView = nullptr;
95
0
    const ScDragData* pData = ScModule::get()->GetDragData();
96
0
    ScDrawTransferObj* pDrawTrans = pData ? pData->pDrawTransfer : nullptr;
97
0
    if (pDrawTrans)
98
0
    {
99
0
        pDragEditView = pDrawTrans->GetDragSourceView();
100
101
0
        aPos -= aDragStartDiff;
102
0
        if ( bNegativePage )
103
0
        {
104
0
            if (aPos.X() > 0) aPos.setX( 0 );
105
0
        }
106
0
        else
107
0
        {
108
0
            if (aPos.X() < 0) aPos.setX( 0 );
109
0
        }
110
0
        if (aPos.Y() < 0) aPos.setY( 0 );
111
0
    }
112
113
0
    ScDrawView* pScDrawView = GetScDrawView();
114
0
    if (bGroup)
115
0
        pScDrawView->BegUndo( ScResId( STR_UNDO_PASTE ) );
116
117
0
    bool bSameDoc = ( pDragEditView && &pDragEditView->GetModel() == &pScDrawView->GetModel() );
118
0
    if (bSameDoc)
119
0
    {
120
            // copy locally - incl. charts
121
122
0
        Point aSourceStart = pDragEditView->GetAllMarkedRect().TopLeft();
123
0
        tools::Long nDiffX = aPos.X() - aSourceStart.X();
124
0
        tools::Long nDiffY = aPos.Y() - aSourceStart.Y();
125
126
            // move within a page?
127
128
0
        if ( bPasteIsMove &&
129
0
                pScDrawView->GetSdrPageView()->GetPage() ==
130
0
                pDragEditView->GetSdrPageView()->GetPage() )
131
0
        {
132
0
            if ( nDiffX != 0 || nDiffY != 0 )
133
0
                pDragEditView->MoveAllMarked(Size(nDiffX,nDiffY));
134
0
        }
135
0
        else
136
0
        {
137
0
            SdrModel& rDrawModel = pDragEditView->GetModel();
138
0
            SCTAB nTab = GetViewData().CurrentTabForData();
139
0
            SdrPage* pDestPage = rDrawModel.GetPage( static_cast< sal_uInt16 >( nTab ) );
140
0
            OSL_ENSURE(pDestPage,"who is this, Page?");
141
142
0
            ::std::vector< OUString > aExcludedChartNames;
143
0
            if ( pDestPage )
144
0
            {
145
0
                ScChartHelper::GetChartNames( aExcludedChartNames, pDestPage );
146
0
            }
147
148
0
            const SdrMarkList& rMarkList = pDragEditView->GetMarkedObjectList();
149
0
            rMarkList.ForceSort();
150
0
            const size_t nMarkCnt=rMarkList.GetMarkCount();
151
0
            for (size_t nm=0; nm<nMarkCnt; ++nm) {
152
0
                const SdrMark* pM=rMarkList.GetMark(nm);
153
0
                const SdrObject* pObj=pM->GetMarkedSdrObj();
154
155
                // Directly Clone to target SdrModel
156
0
                rtl::Reference<SdrObject> pNewObj(pObj->CloneSdrObject(rDrawModel));
157
158
0
                if (pNewObj!=nullptr)
159
0
                {
160
                    //  copy graphics within the same model - always needs new name
161
0
                    if ( dynamic_cast<const SdrGrafObj*>( pNewObj.get()) !=  nullptr && !bPasteIsMove )
162
0
                        pNewObj->SetName(static_cast<ScDrawLayer*>(&rDrawModel)->GetNewGraphicName());
163
164
0
                    if (nDiffX!=0 || nDiffY!=0)
165
0
                        pNewObj->NbcMove(Size(nDiffX,nDiffY));
166
0
                    if (pDestPage)
167
0
                        pDestPage->InsertObject( pNewObj.get() );
168
0
                    pScDrawView->AddUndo(std::make_unique<SdrUndoInsertObj>( *pNewObj ));
169
170
0
                    if (ScDrawLayer::IsCellAnchored(*pNewObj))
171
0
                        ScDrawLayer::SetCellAnchoredFromPosition(*pNewObj, GetViewData().GetDocument(), nTab,
172
0
                                                                 ScDrawLayer::IsResizeWithCell(*pNewObj));
173
0
                }
174
0
            }
175
176
0
            if (bPasteIsMove)
177
0
                pDragEditView->DeleteMarked();
178
179
0
            ScDocument& rDocument = GetViewData().GetDocument();
180
0
            ScDocShell* pDocShell = GetViewData().GetDocShell();
181
0
            ScModelObj* pModelObj = ( pDocShell ? pDocShell->GetModel() : nullptr );
182
0
            if ( pDestPage && pModelObj && pDrawTrans )
183
0
            {
184
0
                const ScRangeListVector& rProtectedChartRangesVector( pDrawTrans->GetProtectedChartRangesVector() );
185
0
                ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument, pDestPage, pModelObj, nTab,
186
0
                    rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
187
0
            }
188
0
        }
189
0
    }
190
0
    else
191
0
    {
192
0
        bPasteIsMove = false;       // no internal move happened
193
0
        SdrView aView(*pModel);     // #i71529# never create a base class of SdrView directly!
194
0
        SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel().GetPage(0));
195
0
        aView.MarkAllObj(pPv);
196
0
        Size aSize = aView.GetAllMarkedRect().GetSize();
197
0
        lcl_AdjustInsertPos( GetViewData(), aPos, aSize );
198
199
        // don't change marking if OLE object is active
200
        // (at Drop from OLE object it would be deactivated in the middle of ExecuteDrag!)
201
202
0
        SdrInsertFlags nOptions = SdrInsertFlags::NONE;
203
0
        SfxInPlaceClient* pClient = GetViewData().GetViewShell()->GetIPClient();
204
0
        if ( pClient && pClient->IsObjectInPlaceActive() )
205
0
            nOptions |= SdrInsertFlags::DONTMARK;
206
207
0
        ::std::vector< OUString > aExcludedChartNames;
208
0
        SCTAB nTab = GetViewData().CurrentTabForData();
209
0
        SdrPage* pPage = pScDrawView->GetModel().GetPage( static_cast< sal_uInt16 >( nTab ) );
210
0
        OSL_ENSURE( pPage, "Page?" );
211
0
        if ( pPage )
212
0
        {
213
0
            ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
214
0
        }
215
216
0
        if ( !bSameDocClipboard )
217
0
        {
218
0
            auto pPool = static_cast<ScStyleSheetPool*>(pScDrawView->GetModel().GetStyleSheetPool());
219
0
            pPool->CopyUsedGraphicStylesFrom(pModel->GetStyleSheetPool());
220
221
            // #89247# Set flag for ScDocument::UpdateChartListeners() which is
222
            // called during paste.
223
0
            GetViewData().GetDocument().SetPastingDrawFromOtherDoc( true );
224
0
        }
225
226
0
        pScDrawView->Paste(*pModel, aPos, nullptr, nOptions);
227
228
0
        if ( !bSameDocClipboard )
229
0
            GetViewData().GetDocument().SetPastingDrawFromOtherDoc( false );
230
231
        // Paste puts all objects on the active (front) layer
232
        // controls must be on SC_LAYER_CONTROLS
233
0
        if (pPage)
234
0
        {
235
0
            SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
236
0
            SdrObject* pObject = aIter.Next();
237
0
            while (pObject)
238
0
            {
239
0
                if ( dynamic_cast<const SdrUnoObj*>( pObject) !=  nullptr && pObject->GetLayer() != SC_LAYER_CONTROLS )
240
0
                    pObject->NbcSetLayer(SC_LAYER_CONTROLS);
241
242
0
                if (ScDrawLayer::IsCellAnchored(*pObject))
243
0
                    ScDrawLayer::SetCellAnchoredFromPosition(*pObject, GetViewData().GetDocument(), nTab,
244
0
                                                             ScDrawLayer::IsResizeWithCell(*pObject));
245
246
0
                pObject = aIter.Next();
247
0
            }
248
0
        }
249
250
        // all graphics objects must have names
251
0
        GetViewData().GetDocument().EnsureGraphicNames();
252
253
0
        ScDocument& rDocument = GetViewData().GetDocument();
254
0
        ScDocShell* pDocShell = GetViewData().GetDocShell();
255
0
        ScModelObj* pModelObj = ( pDocShell ? pDocShell->GetModel() : nullptr );
256
0
        const ScDrawTransferObj* pTransferObj = ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(GetViewData().GetActiveWin()));
257
0
        if ( pPage && pModelObj && ( pTransferObj || pDrawTrans ) )
258
0
        {
259
0
            const ScRangeListVector& rProtectedChartRangesVector(
260
0
                pTransferObj ? pTransferObj->GetProtectedChartRangesVector() : pDrawTrans->GetProtectedChartRangesVector() );
261
0
            ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument, pPage, pModelObj, nTab,
262
0
                rProtectedChartRangesVector, aExcludedChartNames, bSameDocClipboard );
263
0
        }
264
0
    }
265
266
0
    if (bGroup)
267
0
    {
268
0
        pScDrawView->GroupMarked();
269
0
        pScDrawView->EndUndo();
270
0
    }
271
272
0
    if (pRef)
273
0
        pRef->SetMapMode( aOldMapMode );
274
275
    // GetViewData().GetViewShell()->SetDrawShell( true );
276
    // It is not sufficient to just set the DrawShell if we pasted, for
277
    // example, a chart.  SetDrawShellOrSub() would only work for D&D in the
278
    // same document but not if inserting from the clipboard, therefore
279
    // MarkListHasChanged() is what we need.
280
0
    pScDrawView->MarkListHasChanged();
281
282
0
}
283
284
bool ScViewFunc::PasteObject( const Point& rPos, const uno::Reference < embed::XEmbeddedObject >& xObj,
285
                                const Size* pDescSize, const Graphic* pReplGraph, const OUString& aMediaType, sal_Int64 nAspect )
286
0
{
287
0
    MakeDrawLayer();
288
0
    if ( xObj.is() )
289
0
    {
290
0
        OUString aName;
291
        //TODO/MBA: is that OK?
292
0
        comphelper::EmbeddedObjectContainer& aCnt = GetViewData().GetViewShell()->GetObjectShell()->GetEmbeddedObjectContainer();
293
0
        if ( !aCnt.HasEmbeddedObject( xObj ) )
294
0
            aCnt.InsertEmbeddedObject( xObj, aName );
295
0
        else
296
0
            aName = aCnt.GetEmbeddedObjectName( xObj );
297
298
0
        svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
299
0
        if ( pReplGraph )
300
0
            aObjRef.SetGraphic( *pReplGraph, aMediaType );
301
302
0
        Size aSize;
303
0
        if ( nAspect == embed::Aspects::MSOLE_ICON )
304
0
        {
305
0
            MapMode aMapMode( MapUnit::Map100thMM );
306
0
            aSize = aObjRef.GetSize( &aMapMode );
307
0
        }
308
0
        else
309
0
        {
310
            // working with visual area can switch object to running state
311
0
            MapUnit aMapObj = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
312
0
            MapUnit aMap100 = MapUnit::Map100thMM;
313
314
0
            if ( pDescSize && pDescSize->Width() && pDescSize->Height() )
315
0
            {
316
                // use size from object descriptor if given
317
0
                aSize = OutputDevice::LogicToLogic(*pDescSize, MapMode(aMap100), MapMode(aMapObj));
318
0
                awt::Size aSz;
319
0
                aSz.Width = aSize.Width();
320
0
                aSz.Height = aSize.Height();
321
0
                xObj->setVisualAreaSize( nAspect, aSz );
322
0
            }
323
324
0
            awt::Size aSz;
325
0
            try
326
0
            {
327
0
                aSz = xObj->getVisualAreaSize( nAspect );
328
0
            }
329
0
            catch ( embed::NoVisualAreaSizeException& )
330
0
            {
331
                // the default size will be set later
332
0
            }
333
334
0
            aSize = Size( aSz.Width, aSz.Height );
335
0
            aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapObj), MapMode(aMap100)); // for SdrOle2Obj
336
337
0
            if( aSize.IsEmpty() )
338
0
            {
339
0
                OSL_FAIL("SvObjectDescriptor::GetSize == 0");
340
0
                aSize.setWidth( 5000 );
341
0
                aSize.setHeight( 5000 );
342
0
                aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMap100), MapMode(aMapObj));
343
0
                aSz.Width = aSize.Width();
344
0
                aSz.Height = aSize.Height();
345
0
                xObj->setVisualAreaSize( nAspect, aSz );
346
0
            }
347
0
        }
348
349
        // don't call AdjustInsertPos
350
0
        Point aInsPos = rPos;
351
0
        if ( GetViewData().GetDocument().IsNegativePage( GetViewData().CurrentTabForData() ) )
352
0
            aInsPos.AdjustX( -(aSize.Width()) );
353
0
        tools::Rectangle aRect( aInsPos, aSize );
354
355
0
        ScDrawView* pDrView = GetScDrawView();
356
0
        rtl::Reference<SdrOle2Obj> pSdrObj = new SdrOle2Obj(
357
0
            pDrView->getSdrModelFromSdrView(),
358
0
            aObjRef,
359
0
            aName,
360
0
            aRect);
361
362
0
        SdrPageView* pPV = pDrView->GetSdrPageView();
363
0
        pDrView->InsertObjectSafe( pSdrObj.get(), *pPV );             // don't mark if OLE
364
0
        GetViewData().GetViewShell()->SetDrawShell( true );
365
0
        return true;
366
0
    }
367
0
    else
368
0
        return false;
369
0
}
370
371
bool ScViewFunc::PasteBitmap( const Point& rPos, const Bitmap& rBmp )
372
0
{
373
0
    Graphic aGraphic(rBmp);
374
0
    return PasteGraphic( rPos, aGraphic, u""_ustr );
375
0
}
376
377
bool ScViewFunc::PasteMetaFile( const Point& rPos, const GDIMetaFile& rMtf )
378
0
{
379
0
    Graphic aGraphic(rMtf);
380
0
    return PasteGraphic( rPos, aGraphic, u""_ustr );
381
0
}
382
383
bool ScViewFunc::PasteGraphic( const Point& rPos, const Graphic& rGraphic,
384
                                const OUString& rFile )
385
0
{
386
0
    MakeDrawLayer();
387
0
    ScDrawView* pScDrawView = GetScDrawView();
388
389
0
    if (!pScDrawView)
390
0
        return false;
391
392
    // #i123922# check if the drop was over an existing object; if yes, evtl. replace
393
    // the graphic for a SdrGraphObj (including link state updates) or adapt the fill
394
    // style for other objects
395
0
    SdrPageView* pPageView = pScDrawView->GetSdrPageView();
396
0
    if (pPageView)
397
0
    {
398
0
        SdrObject* pPickObj = pScDrawView->PickObj(rPos, pScDrawView->getHitTolLog(), pPageView);
399
0
        if (pPickObj)
400
0
        {
401
0
            const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
402
0
            SdrObject* pResult = pScDrawView->ApplyGraphicToObject(
403
0
                *pPickObj,
404
0
                rGraphic,
405
0
                aBeginUndo,
406
0
                rFile);
407
408
0
            if (pResult)
409
0
            {
410
                // we are done; mark the modified/new object
411
0
                pScDrawView->MarkObj(pResult, pScDrawView->GetSdrPageView());
412
0
                return true;
413
0
            }
414
0
        }
415
0
    }
416
417
0
    Point aPos( rPos );
418
0
    vcl::Window* pWin = GetActiveWin();
419
0
    MapMode aSourceMap = rGraphic.GetPrefMapMode();
420
0
    MapMode aDestMap( MapUnit::Map100thMM );
421
422
0
    if (aSourceMap.GetMapUnit() == MapUnit::MapPixel)
423
0
    {
424
        // consider pixel correction, so bitmap fits to screen
425
0
        Fraction aScaleX, aScaleY;
426
0
        pScDrawView->CalcNormScale( aScaleX, aScaleY );
427
0
        aDestMap.SetScaleX(aScaleX);
428
0
        aDestMap.SetScaleY(aScaleY);
429
0
    }
430
431
0
    Size aSize = pWin->LogicToLogic( rGraphic.GetPrefSize(), &aSourceMap, &aDestMap );
432
433
0
    if ( GetViewData().GetDocument().IsNegativePage( GetViewData().CurrentTabForData() ) )
434
0
        aPos.AdjustX( -(aSize.Width()) );
435
436
0
    GetViewData().GetViewShell()->SetDrawShell( true );
437
0
    tools::Rectangle aRect(aPos, aSize);
438
0
    rtl::Reference<SdrGrafObj> pGrafObj = new SdrGrafObj(
439
0
        pScDrawView->getSdrModelFromSdrView(),
440
0
        rGraphic,
441
0
        aRect);
442
443
    // path was the name of the graphic in history
444
445
0
    ScDrawLayer* pLayer = static_cast<ScDrawLayer*>(&pScDrawView->GetModel());
446
0
    OUString aName = pLayer->GetNewGraphicName();                 // "Graphics"
447
0
    pGrafObj->SetName(aName);
448
449
    // don't mark if OLE
450
0
    bool bSuccess = pScDrawView->InsertObjectSafe(pGrafObj.get(), *pScDrawView->GetSdrPageView());
451
452
    // SetGraphicLink has to be used after inserting the object,
453
    // otherwise an empty graphic is swapped in and the contact stuff crashes.
454
    // See #i37444#.
455
0
    if (bSuccess && !rFile.isEmpty())
456
0
        pGrafObj->SetGraphicLink( rFile );
457
458
0
    return bSuccess;
459
0
}
460
461
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */