Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/view/drawvie4.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 <svx/svditer.hxx>
21
#include <svx/svdograf.hxx>
22
#include <svx/svdogrp.hxx>
23
#include <svx/svdoole2.hxx>
24
#include <svx/svdundo.hxx>
25
#include <sfx2/docfile.hxx>
26
#include <tools/urlobj.hxx>
27
#include <toolkit/helper/vclunohelper.hxx>
28
#include <sal/log.hxx>
29
30
#include <drawview.hxx>
31
#include <global.hxx>
32
#include <drwlayer.hxx>
33
#include <viewdata.hxx>
34
#include <document.hxx>
35
#include <docsh.hxx>
36
#include <drwtrans.hxx>
37
#include <transobj.hxx>
38
#include <drawutil.hxx>
39
#include <scmod.hxx>
40
#include <globstr.hrc>
41
#include <scresid.hxx>
42
#include <gridwin.hxx>
43
#include <userdat.hxx>
44
45
#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
46
#include <com/sun/star/embed/Aspects.hpp>
47
#include <com/sun/star/embed/XEmbeddedObject.hpp>
48
#include <com/sun/star/chart2/XChartTypeContainer.hpp>
49
#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
50
#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
51
#include <com/sun/star/chart2/XChartDocument.hpp>
52
#include <comphelper/diagnose_ex.hxx>
53
54
using namespace com::sun::star;
55
56
Point aDragStartDiff;
57
58
void ScDrawView::BeginDrag( vcl::Window* pWindow, const Point& rStartPos )
59
0
{
60
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
61
0
    if ( rMarkList.GetMarkCount() == 0 )
62
0
        return;
63
64
0
    BrkAction();
65
66
0
    tools::Rectangle aMarkedRect = GetAllMarkedRect();
67
68
0
    aDragStartDiff = rStartPos - aMarkedRect.TopLeft();
69
70
0
    bool bAnyOle, bOneOle;
71
0
    CheckOle( rMarkList, bAnyOle, bOneOle );
72
73
0
    ScDocShellRef aDragShellRef;
74
0
    if (bAnyOle)
75
0
    {
76
0
        aDragShellRef = new ScDocShell;     // DocShell needs a Ref immediately
77
0
        aDragShellRef->DoInitNew();
78
0
    }
79
0
    ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() );
80
0
    std::unique_ptr<SdrModel> pModel(CreateMarkedObjModel());
81
0
    ScDrawLayer::SetGlobalDrawPersist(nullptr);
82
83
    //  Charts now always copy their data in addition to the source reference, so
84
    //  there's no need to call SchDLL::Update for the charts in the clipboard doc.
85
    //  Update with the data (including NumberFormatter) from the live document would
86
    //  also store the NumberFormatter in the clipboard chart (#88749#)
87
88
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
89
90
0
    TransferableObjectDescriptor aObjDesc;
91
0
    pDocSh->FillTransferableObjectDescriptor( aObjDesc );
92
0
    aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
93
    // maSize is set in ScDrawTransferObj ctor
94
95
0
    rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pModel), *pDocSh, std::move(aObjDesc) );
96
97
0
    pTransferObj->SetDrawPersist(aDragShellRef); // keep persist for ole objects alive
98
0
    pTransferObj->SetDragSource( this );               // copies selection
99
100
0
    ScModule::get()->SetDragObject(nullptr, pTransferObj.get()); // for internal D&D
101
0
    pTransferObj->StartDrag( pWindow, DND_ACTION_COPYMOVE | DND_ACTION_LINK );
102
0
}
103
104
namespace {
105
106
void getRangeFromDataSource( uno::Reference< chart2::data::XDataSource > const & xDataSource, std::vector<OUString>& rRangeRep)
107
0
{
108
0
    const uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence> > xSeqs = xDataSource->getDataSequences();
109
0
    for (const uno::Reference<chart2::data::XLabeledDataSequence>& xLS : xSeqs)
110
0
    {
111
0
        uno::Reference<chart2::data::XDataSequence> xSeq = xLS->getValues();
112
0
        if (xSeq.is())
113
0
        {
114
0
            OUString aRep = xSeq->getSourceRangeRepresentation();
115
0
            rRangeRep.push_back(aRep);
116
0
        }
117
0
        xSeq = xLS->getLabel();
118
0
        if (xSeq.is())
119
0
        {
120
0
            OUString aRep = xSeq->getSourceRangeRepresentation();
121
0
            rRangeRep.push_back(aRep);
122
0
        }
123
0
    }
124
0
}
125
126
void getRangeFromErrorBar(const uno::Reference< chart2::XChartDocument >& rChartDoc, std::vector<OUString>& rRangeRep)
127
0
{
128
0
    uno::Reference <chart2::XDiagram > xDiagram = rChartDoc->getFirstDiagram();
129
0
    if(!xDiagram.is())
130
0
        return;
131
132
0
    uno::Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY);
133
0
    if(!xCooSysContainer.is())
134
0
        return;
135
136
0
    const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems());
137
0
    for(const auto& rCooSys : xCooSysSequence)
138
0
    {
139
0
        uno::Reference< chart2::XChartTypeContainer > xChartTypeContainer( rCooSys, uno::UNO_QUERY);
140
0
        if(!xChartTypeContainer.is())
141
0
            continue;
142
143
0
        const uno::Sequence< uno::Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() );
144
0
        for(const auto& rChartType : xChartTypeSequence)
145
0
        {
146
0
            uno::Reference< chart2::XDataSeriesContainer > xDataSequenceContainer( rChartType, uno::UNO_QUERY);
147
0
            if(!xDataSequenceContainer.is())
148
0
                continue;
149
150
0
            const uno::Sequence< uno::Reference< chart2::XDataSeries > > xSeriesSequence( xDataSequenceContainer->getDataSeries() );
151
0
            for(const uno::Reference<chart2::XDataSeries>& xSeries : xSeriesSequence)
152
0
            {
153
0
                uno::Reference< beans::XPropertySet > xPropSet( xSeries, uno::UNO_QUERY);
154
0
                uno::Reference< chart2::data::XDataSource > xErrorBarY;
155
0
                xPropSet->getPropertyValue(u"ErrorBarY"_ustr) >>= xErrorBarY;
156
0
                if(xErrorBarY.is())
157
0
                    getRangeFromDataSource(xErrorBarY, rRangeRep);
158
0
                uno::Reference< chart2::data::XDataSource > xErrorBarX;
159
0
                xPropSet->getPropertyValue(u"ErrorBarX"_ustr) >>= xErrorBarX;
160
0
                if(xErrorBarX.is())
161
0
                    getRangeFromDataSource(xErrorBarX, rRangeRep);
162
0
            }
163
0
        }
164
0
    }
165
0
}
166
167
void getRangeFromOle2Object(const SdrOle2Obj& rObj, std::vector<OUString>& rRangeRep)
168
0
{
169
0
    if (!rObj.IsChart())
170
        // not a chart object.
171
0
        return;
172
173
0
    const uno::Reference<embed::XEmbeddedObject>& xObj = rObj.GetObjRef();
174
0
    if (!xObj.is())
175
0
        return;
176
177
0
    uno::Reference<chart2::XChartDocument> xChartDoc(xObj->getComponent(), uno::UNO_QUERY);
178
0
    if (!xChartDoc.is())
179
0
        return;
180
181
0
    if(xChartDoc->hasInternalDataProvider())
182
0
        return;
183
184
0
    getRangeFromErrorBar(xChartDoc, rRangeRep);
185
186
0
    uno::Reference<chart2::data::XDataSource> xDataSource(xChartDoc, uno::UNO_QUERY);
187
0
    if (!xDataSource.is())
188
0
        return;
189
190
    // Get all data sources used in this chart.
191
0
    getRangeFromDataSource(xDataSource, rRangeRep);
192
193
0
    return;
194
0
}
195
196
// Get all cell ranges that are referenced by the selected chart objects.
197
void getOleSourceRanges(const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle, std::vector<ScRange>* pRanges = nullptr, const ScDocument* pDoc = nullptr )
198
0
{
199
0
    bool bCalcSourceRanges = pRanges && pDoc;
200
0
    std::vector<OUString> aRangeReps;
201
0
    rAnyOle = rOneOle = false;
202
0
    const size_t nCount = rMarkList.GetMarkCount();
203
0
    for (size_t i=0; i<nCount; ++i)
204
0
    {
205
0
        SdrMark* pMark = rMarkList.GetMark(i);
206
0
        if ( !pMark )
207
0
            continue;
208
209
0
        SdrObject* pObj = pMark->GetMarkedSdrObj();
210
0
        if ( !pObj )
211
0
            continue;
212
213
0
        SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
214
0
        if (nSdrObjKind == SdrObjKind::OLE2)
215
0
        {
216
0
            rAnyOle = true;
217
0
            rOneOle = (nCount == 1);
218
0
            if ( bCalcSourceRanges )
219
0
                getRangeFromOle2Object( static_cast<const SdrOle2Obj&>( *pObj ), aRangeReps );
220
0
            else
221
0
                break;
222
0
        }
223
0
        else if ( dynamic_cast<const SdrObjGroup*>( pObj) !=  nullptr )
224
0
        {
225
0
            SdrObjListIter aIter( *pObj, SdrIterMode::DeepNoGroups );
226
0
            SdrObject* pSubObj = aIter.Next();
227
0
            while (pSubObj)
228
0
            {
229
0
                if ( pSubObj->GetObjIdentifier() == SdrObjKind::OLE2 )
230
0
                {
231
0
                    rAnyOle = true;
232
                    // rOneOle remains false - a group isn't treated like a single OLE object
233
0
                    if ( !bCalcSourceRanges )
234
0
                        return;
235
236
0
                    getRangeFromOle2Object( static_cast<const SdrOle2Obj&>( *pSubObj ), aRangeReps );
237
0
                }
238
0
                pSubObj = aIter.Next();
239
0
            }
240
0
        }
241
0
    }
242
243
0
    if (!bCalcSourceRanges)
244
0
        return;
245
246
    // Compile all range representation strings into ranges.
247
0
    for (const auto& rRangeRep : aRangeReps)
248
0
    {
249
0
        ScRangeList aRange;
250
0
        ScAddress aAddr;
251
0
        if (aRange.Parse(rRangeRep, *pDoc, pDoc->GetAddressConvention()) & ScRefFlags::VALID)
252
0
        {
253
0
            pRanges->insert(pRanges->end(), aRange.begin(), aRange.end());
254
0
        }
255
0
        else if (aAddr.Parse(rRangeRep, *pDoc, pDoc->GetAddressConvention()) & ScRefFlags::VALID)
256
0
            pRanges->push_back(ScRange(aAddr));
257
0
    }
258
259
0
    return;
260
0
}
261
262
class InsertTabIndex
263
{
264
    std::vector<SCTAB>& mrTabs;
265
public:
266
0
    explicit InsertTabIndex(std::vector<SCTAB>& rTabs) : mrTabs(rTabs) {}
267
    void operator() (const ScRange& rRange)
268
0
    {
269
0
        mrTabs.push_back(rRange.aStart.Tab());
270
0
    }
271
};
272
273
class CopyRangeData
274
{
275
    ScDocument& mrSrc;
276
    ScDocument& mrDest;
277
public:
278
0
    CopyRangeData(ScDocument& rSrc, ScDocument& rDest) : mrSrc(rSrc), mrDest(rDest) {}
279
280
    void operator() (const ScRange& rRange)
281
0
    {
282
0
        OUString aTabName;
283
0
        mrSrc.GetName(rRange.aStart.Tab(), aTabName);
284
285
0
        SCTAB nTab;
286
0
        if (!mrDest.GetTable(aTabName, nTab))
287
            // Sheet by this name doesn't exist.
288
0
            return;
289
290
0
        mrSrc.CopyStaticToDocument(rRange, nTab, mrDest);
291
0
    }
292
};
293
294
void copyChartRefDataToClipDoc(ScDocument& rSrcDoc, ScDocument& rClipDoc, const std::vector<ScRange>& rRanges)
295
0
{
296
    // Get a list of referenced table indices.
297
0
    std::vector<SCTAB> aTabs;
298
0
    std::for_each(rRanges.begin(), rRanges.end(), InsertTabIndex(aTabs));
299
0
    std::sort(aTabs.begin(), aTabs.end());
300
0
    aTabs.erase(std::unique(aTabs.begin(), aTabs.end()), aTabs.end());
301
302
    // Get table names.
303
0
    if (aTabs.empty())
304
0
        return;
305
306
    // Create sheets only for referenced source sheets.
307
0
    OUString aName;
308
0
    std::vector<SCTAB>::const_iterator it = aTabs.begin(), itEnd = aTabs.end();
309
0
    if (!rSrcDoc.GetName(*it, aName))
310
0
        return;
311
312
0
    rClipDoc.SetTabNameOnLoad(0, aName); // document initially has one sheet.
313
314
0
    for (++it; it != itEnd; ++it)
315
0
    {
316
0
        if (!rSrcDoc.GetName(*it, aName))
317
0
            return;
318
319
0
        rClipDoc.AppendTabOnLoad(aName);
320
0
    }
321
322
0
    std::for_each(rRanges.begin(), rRanges.end(), CopyRangeData(rSrcDoc, rClipDoc));
323
0
}
324
325
}
326
327
void ScDrawView::CheckOle( const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle )
328
0
{
329
0
    getOleSourceRanges( rMarkList, rAnyOle, rOneOle );
330
0
}
331
332
void ScDrawView::DoCopy()
333
0
{
334
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
335
0
    std::vector<ScRange> aRanges;
336
0
    bool bAnyOle = false, bOneOle = false;
337
0
    getOleSourceRanges( rMarkList, bAnyOle, bOneOle, &aRanges, &rDoc );
338
339
    // update ScGlobal::xDrawClipDocShellRef
340
0
    ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
341
0
    if (ScGlobal::xDrawClipDocShellRef.is() && !aRanges.empty())
342
0
    {
343
        // Copy data referenced by the chart objects to the draw clip
344
        // document. We need to do this before CreateMarkedObjModel() below.
345
0
        ScDocShellRef xDocSh = ScGlobal::xDrawClipDocShellRef;
346
0
        ScDocument& rClipDoc = xDocSh->GetDocument();
347
0
        copyChartRefDataToClipDoc(rDoc, rClipDoc, aRanges);
348
0
    }
349
0
    std::unique_ptr<SdrModel> pModel(CreateMarkedObjModel());
350
0
    ScDrawLayer::SetGlobalDrawPersist(nullptr);
351
352
    //  Charts now always copy their data in addition to the source reference, so
353
    //  there's no need to call SchDLL::Update for the charts in the clipboard doc.
354
    //  Update with the data (including NumberFormatter) from the live document would
355
    //  also store the NumberFormatter in the clipboard chart (#88749#)
356
357
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
358
359
0
    TransferableObjectDescriptor aObjDesc;
360
0
    pDocSh->FillTransferableObjectDescriptor( aObjDesc );
361
0
    aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
362
    // maSize is set in ScDrawTransferObj ctor
363
364
0
    rtl::Reference<ScDrawTransferObj> pTransferObj(new ScDrawTransferObj( std::move(pModel), *pDocSh, std::move(aObjDesc) ));
365
366
0
    if ( ScGlobal::xDrawClipDocShellRef.is() )
367
0
    {
368
0
        pTransferObj->SetDrawPersist( ScGlobal::xDrawClipDocShellRef );    // keep persist for ole objects alive
369
0
    }
370
371
0
    pTransferObj->CopyToClipboard( rViewData.GetActiveWin() );     // system clipboard
372
0
}
373
374
uno::Reference<datatransfer::XTransferable> ScDrawView::CopyToTransferable()
375
0
{
376
0
    bool bAnyOle, bOneOle;
377
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
378
0
    CheckOle( rMarkList, bAnyOle, bOneOle );
379
380
    // update ScGlobal::xDrawClipDocShellRef
381
0
    ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
382
0
    std::unique_ptr<SdrModel> pModel( CreateMarkedObjModel() );
383
0
    ScDrawLayer::SetGlobalDrawPersist(nullptr);
384
385
    //  Charts now always copy their data in addition to the source reference, so
386
    //  there's no need to call SchDLL::Update for the charts in the clipboard doc.
387
    //  Update with the data (including NumberFormatter) from the live document would
388
    //  also store the NumberFormatter in the clipboard chart (#88749#)
389
    // lcl_RefreshChartData( pModel, rViewData.GetDocument() );
390
391
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
392
393
0
    TransferableObjectDescriptor aObjDesc;
394
0
    pDocSh->FillTransferableObjectDescriptor( aObjDesc );
395
0
    aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
396
    // maSize is set in ScDrawTransferObj ctor
397
398
0
    rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pModel), *pDocSh, std::move(aObjDesc) );
399
400
0
    if ( ScGlobal::xDrawClipDocShellRef.is() )
401
0
    {
402
0
        pTransferObj->SetDrawPersist( ScGlobal::xDrawClipDocShellRef );    // keep persist for ole objects alive
403
0
    }
404
405
0
    return pTransferObj;
406
0
}
407
408
// Calculate correction for 100%, regardless of current settings
409
410
void ScDrawView::CalcNormScale( double& rFractX, double& rFractY ) const
411
0
{
412
0
    double nPPTX = ScGlobal::nScreenPPTX;
413
0
    double nPPTY = ScGlobal::nScreenPPTY;
414
415
0
    nPPTX /= rViewData.GetDocShell()->GetOutputFactor();
416
417
0
    SCCOL nEndCol = 0;
418
0
    SCROW nEndRow = 0;
419
0
    rDoc.GetTableArea( nTab, nEndCol, nEndRow );
420
0
    if (nEndCol<20)
421
0
        nEndCol = 20;
422
0
    if (nEndRow<20)
423
0
        nEndRow = 1000;
424
425
0
    double fZoom(1.0);
426
0
    ScDrawUtil::CalcScale( rDoc, nTab, 0,0, nEndCol,nEndRow, pDev, fZoom, fZoom,
427
0
                           nPPTX, nPPTY, rFractX,rFractY );
428
0
}
429
430
void ScDrawView::SetMarkedOriginalSize()
431
0
{
432
0
    std::unique_ptr<SdrUndoGroup> pUndoGroup(new SdrUndoGroup(GetModel()));
433
434
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
435
0
    tools::Long nDone = 0;
436
0
    const size_t nCount = rMarkList.GetMarkCount();
437
0
    for (size_t i=0; i<nCount; ++i)
438
0
    {
439
0
        SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
440
0
        SdrObjKind nIdent = pObj->GetObjIdentifier();
441
0
        bool bDo = false;
442
0
        Size aOriginalSize;
443
0
        if (nIdent == SdrObjKind::OLE2)
444
0
        {
445
            // TODO/LEAN: working with visual area can switch object to running state
446
0
            uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObj)->GetObjRef();
447
0
            if ( xObj.is() )    // NULL for an invalid object that couldn't be loaded
448
0
            {
449
0
                sal_Int64 nAspect = static_cast<SdrOle2Obj*>(pObj)->GetAspect();
450
451
0
                if ( nAspect == embed::Aspects::MSOLE_ICON )
452
0
                {
453
0
                    MapMode aMapMode( MapUnit::Map100thMM );
454
0
                    aOriginalSize = static_cast<SdrOle2Obj*>(pObj)->GetOrigObjSize( &aMapMode );
455
0
                    bDo = true;
456
0
                }
457
0
                else
458
0
                {
459
0
                    MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( static_cast<SdrOle2Obj*>(pObj)->GetAspect() ) );
460
0
                    try
461
0
                    {
462
0
                        awt::Size aSz = xObj->getVisualAreaSize( static_cast<SdrOle2Obj*>(pObj)->GetAspect() );
463
0
                        aOriginalSize = OutputDevice::LogicToLogic(
464
0
                                            Size( aSz.Width, aSz.Height ),
465
0
                                            MapMode(aUnit),
466
0
                                            MapMode(MapUnit::Map100thMM));
467
0
                        bDo = true;
468
0
                    } catch( embed::NoVisualAreaSizeException& )
469
0
                    {
470
0
                        TOOLS_WARN_EXCEPTION("sc.ui", "Can't get the original size of the object!" );
471
0
                    }
472
0
                }
473
0
            }
474
0
        }
475
0
        else if (nIdent == SdrObjKind::Graphic)
476
0
        {
477
0
            const SdrGrafObj* pSdrGrafObj = static_cast<const SdrGrafObj*>(pObj);
478
479
0
            MapMode aSourceMap = pSdrGrafObj->GetGraphic().GetPrefMapMode();
480
0
            MapMode aDestMap( MapUnit::Map100thMM );
481
0
            if (aSourceMap.GetMapUnit() == MapUnit::MapPixel)
482
0
            {
483
                // consider pixel correction, so that the bitmap is correct on the screen
484
0
                double fNormScaleX, fNormScaleY;
485
0
                CalcNormScale( fNormScaleX, fNormScaleY );
486
0
                aDestMap.SetScaleX(fNormScaleX);
487
0
                aDestMap.SetScaleY(fNormScaleY);
488
0
            }
489
0
            aOriginalSize = pSdrGrafObj->getOriginalSize();
490
0
            bDo = true;
491
0
        }
492
493
0
        if ( bDo )
494
0
        {
495
0
            tools::Rectangle aDrawRect = pObj->GetLogicRect();
496
497
0
            if (aDrawRect.GetWidth() && aDrawRect.GetHeight())
498
0
            {
499
0
                pUndoGroup->AddAction( std::make_unique<SdrUndoGeoObj>( *pObj ) );
500
0
                pObj->Resize( aDrawRect.TopLeft(), double( aOriginalSize.Width() ) / aDrawRect.GetWidth(),
501
0
                                                     double( aOriginalSize.Height() ) / aDrawRect.GetHeight() );
502
0
                ++nDone;
503
0
            }
504
0
        }
505
0
    }
506
507
0
    if (nDone)
508
0
    {
509
0
        pUndoGroup->SetComment(ScResId( STR_UNDO_ORIGINALSIZE ));
510
0
        ScDocShell* pDocSh = rViewData.GetDocShell();
511
0
        pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup));
512
0
        pDocSh->SetDrawModified();
513
0
    }
514
0
}
515
516
void ScDrawView::FitToCellSize()
517
0
{
518
0
    const SdrMarkList& rMarkList = GetMarkedObjectList();
519
520
0
    if (rMarkList.GetMarkCount() != 1)
521
0
    {
522
0
        SAL_WARN("sc.ui", "Fit to cell only works with one graphic!");
523
0
        return;
524
0
    }
525
526
0
    SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
527
528
0
    ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj);
529
0
    if (aAnchorType != SCA_CELL && aAnchorType != SCA_CELL_RESIZE)
530
0
    {
531
0
        SAL_WARN("sc.ui", "Fit to cell only works with cell anchored graphics!");
532
0
        return;
533
0
    }
534
535
0
    ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObj);
536
0
    if (!pObjData)
537
0
    {
538
0
        SAL_WARN("sc.ui", "Missing ScDrawObjData!");
539
0
        return;
540
0
    }
541
542
0
    std::unique_ptr<SdrUndoGroup> pUndoGroup(new SdrUndoGroup(GetModel()));
543
0
    tools::Rectangle aGraphicRect = pObj->GetSnapRect();
544
0
    tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( rDoc, pObjData->maStart, true);
545
546
    // For graphic objects, we want to keep the aspect ratio
547
0
    if (pObj->shouldKeepAspectRatio())
548
0
    {
549
0
        tools::Long nWidth = aGraphicRect.GetWidth();
550
0
        assert(nWidth && "div-by-zero");
551
0
        double fScaleX = static_cast<double>(aCellRect.GetWidth()) / static_cast<double>(nWidth);
552
0
        tools::Long nHeight = aGraphicRect.GetHeight();
553
0
        assert(nHeight && "div-by-zero");
554
0
        double fScaleY = static_cast<double>(aCellRect.GetHeight()) / static_cast<double>(nHeight);
555
0
        double fScaleMin = std::min(fScaleX, fScaleY);
556
557
0
        aCellRect.setWidth(static_cast<double>(aGraphicRect.GetWidth()) * fScaleMin);
558
0
        aCellRect.setHeight(static_cast<double>(aGraphicRect.GetHeight()) * fScaleMin);
559
0
    }
560
561
0
    pUndoGroup->AddAction( std::make_unique<SdrUndoGeoObj>( *pObj ) );
562
0
    if (pObj->GetObjIdentifier() == SdrObjKind::CustomShape)
563
0
        pObj->AdjustToMaxRect(aCellRect);
564
0
    else
565
0
        pObj->SetSnapRect(aCellRect);
566
567
0
    pUndoGroup->SetComment(ScResId( STR_UNDO_FITCELLSIZE ));
568
0
    ScDocShell* pDocSh = rViewData.GetDocShell();
569
0
    pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup));
570
571
0
}
572
573
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */