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/app/transobj.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 <scitems.hxx>
21
#include <editeng/justifyitem.hxx>
22
23
#include <com/sun/star/uno/Sequence.hxx>
24
#include <com/sun/star/embed/XTransactedObject.hpp>
25
26
#include <o3tl/unit_conversion.hxx>
27
#include <osl/diagnose.h>
28
#include <unotools/tempfile.hxx>
29
#include <unotools/ucbstreamhelper.hxx>
30
#include <unotools/streamwrap.hxx>
31
#include <comphelper/fileformat.h>
32
#include <comphelper/lok.hxx>
33
#include <comphelper/storagehelper.hxx>
34
#include <comphelper/servicehelper.hxx>
35
#include <sot/storage.hxx>
36
#include <utility>
37
#include <vcl/gdimtf.hxx>
38
#include <vcl/jobset.hxx>
39
#include <vcl/svapp.hxx>
40
#include <vcl/virdev.hxx>
41
#include <sfx2/docfile.hxx>
42
43
#include <transobj.hxx>
44
#include <patattr.hxx>
45
#include <cellvalue.hxx>
46
#include <cellform.hxx>
47
#include <document.hxx>
48
#include <viewopti.hxx>
49
#include <editutil.hxx>
50
#include <impex.hxx>
51
#include <formulacell.hxx>
52
#include <printfun.hxx>
53
#include <docfunc.hxx>
54
#include <scmod.hxx>
55
#include <dragdata.hxx>
56
#include <sortparam.hxx>
57
#include <tabvwsh.hxx>
58
59
#include <editeng/paperinf.hxx>
60
#include <editeng/sizeitem.hxx>
61
#include <formula/errorcodes.hxx>
62
#include <docsh.hxx>
63
#include <markdata.hxx>
64
#include <stlpool.hxx>
65
#include <viewdata.hxx>
66
#include <dociter.hxx>
67
#include <cellsuno.hxx>
68
#include <stringutil.hxx>
69
#include <formulaiter.hxx>
70
71
using namespace com::sun::star;
72
73
constexpr sal_uInt32 SCTRANS_TYPE_IMPEX              = 1;
74
constexpr sal_uInt32 SCTRANS_TYPE_EDIT_RTF           = 2;
75
constexpr sal_uInt32 SCTRANS_TYPE_EDIT_BIN           = 3;
76
constexpr sal_uInt32 SCTRANS_TYPE_EMBOBJ             = 4;
77
constexpr sal_uInt32 SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT = 5;
78
79
void ScTransferObj::GetAreaSize( const ScDocument& rDoc, SCTAB nTab1, SCTAB nTab2, SCROW& nRow, SCCOL& nCol )
80
0
{
81
0
    SCCOL nMaxCol = 0;
82
0
    SCROW nMaxRow = 0;
83
0
    for( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
84
0
    {
85
0
        SCCOL nLastCol = 0;
86
0
        SCROW nLastRow = 0;
87
        // GetPrintArea instead of GetCellArea - include drawing objects
88
0
        if( rDoc.GetPrintArea( nTab, nLastCol, nLastRow ) )
89
0
        {
90
0
            if( nLastCol > nMaxCol )
91
0
                nMaxCol = nLastCol;
92
0
            if( nLastRow > nMaxRow  )
93
0
                nMaxRow = nLastRow;
94
0
        }
95
0
    }
96
0
    nRow = nMaxRow;
97
0
    nCol = nMaxCol;
98
0
}
99
100
void ScTransferObj::PaintToDev( OutputDevice* pDev, ScDocument& rDoc, double nPrintFactor,
101
                                const ScRange& rBlock )
102
0
{
103
0
    tools::Rectangle aBound( Point(), pDev->GetOutputSize() );      //! use size from clip area?
104
105
0
    ScViewData aViewData(rDoc);
106
107
0
    aViewData.SetTabNo( rBlock.aEnd.Tab() );
108
0
    aViewData.SetScreen( rBlock.aStart.Col(), rBlock.aStart.Row(),
109
0
                            rBlock.aEnd.Col(), rBlock.aEnd.Row() );
110
111
0
    ScPrintFunc::DrawToDev( rDoc, pDev, nPrintFactor, aBound, aViewData, false/*bMetaFile*/ );
112
0
}
113
114
ScTransferObj::ScTransferObj( const std::shared_ptr<ScDocument>& pClipDoc, TransferableObjectDescriptor aDesc ) :
115
0
    m_pDoc( pClipDoc ),
116
0
    m_nNonFiltered(0),
117
0
    m_aObjDesc(std::move( aDesc )),
118
0
    m_nDragHandleX( 0 ),
119
0
    m_nDragHandleY( 0 ),
120
0
    m_nSourceCursorX( m_pDoc->MaxCol() + 1 ),
121
0
    m_nSourceCursorY( m_pDoc->MaxRow() + 1 ),
122
0
    m_nDragSourceFlags( ScDragSrc::Undefined ),
123
0
    m_bDragWasInternal( false ),
124
0
    m_bUsedForLink( false ),
125
0
    m_bUseInApi( false )
126
0
{
127
0
    OSL_ENSURE(m_pDoc->IsClipboard(), "wrong document");
128
129
    // get aBlock from clipboard doc
130
131
0
    SCCOL nCol1;
132
0
    SCROW nRow1;
133
0
    SCCOL nCol2;
134
0
    SCROW nRow2;
135
0
    m_pDoc->GetClipStart( nCol1, nRow1 );
136
0
    m_pDoc->GetClipArea( nCol2, nRow2, true );    // real source area - include filtered rows
137
0
    nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nCol1 );
138
0
    nRow2 = sal::static_int_cast<SCROW>( nRow2 + nRow1 );
139
140
0
    SCCOL nDummy;
141
0
    m_pDoc->GetClipArea( nDummy, m_nNonFiltered, false );
142
0
    m_bHasFiltered = (m_nNonFiltered < (nRow2 - nRow1));
143
0
    ++m_nNonFiltered;     // to get count instead of diff
144
145
0
    SCTAB nTab1=0;
146
0
    SCTAB nTab2=0;
147
0
    bool bFirst = true;
148
0
    for (SCTAB i=0; i< m_pDoc->GetTableCount(); i++)
149
0
        if (m_pDoc->HasTable(i))
150
0
        {
151
0
            if (bFirst)
152
0
                nTab1 = i;
153
0
            nTab2 = i;
154
0
            bFirst = false;
155
0
        }
156
0
    OSL_ENSURE(!bFirst, "no sheet selected");
157
158
    //  only limit to used cells if whole sheet was marked
159
    //  (so empty cell areas can be copied)
160
0
    if ( nCol2>=m_pDoc->MaxCol() && nRow2>=m_pDoc->MaxRow() )
161
0
    {
162
0
        SCROW nMaxRow;
163
0
        SCCOL nMaxCol;
164
0
        GetAreaSize( *m_pDoc, nTab1, nTab2, nMaxRow, nMaxCol );
165
0
        if( nMaxRow < nRow2 )
166
0
            nRow2 = nMaxRow;
167
0
        if( nMaxCol < nCol2 )
168
0
            nCol2 = nMaxCol;
169
0
    }
170
171
0
    m_aBlock = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
172
0
    m_nVisibleTab = nTab1;    // valid table as default
173
174
0
    tools::Rectangle aMMRect = m_pDoc->GetMMRect( nCol1,nRow1, nCol2,nRow2, nTab1 );
175
0
    m_aObjDesc.maSize = aMMRect.GetSize();
176
0
    PrepareOLE( m_aObjDesc );
177
0
}
178
179
ScTransferObj::~ScTransferObj()
180
0
{
181
0
    SolarMutexGuard aSolarGuard;
182
183
0
    ScModule* pScMod = ScModule::get();
184
0
    const ScDragData* pDragData = pScMod ? pScMod->GetDragData() : nullptr;
185
0
    if (pDragData && pDragData->pCellTransfer == this)
186
0
    {
187
0
        OSL_FAIL("ScTransferObj wasn't released");
188
0
        pScMod->ResetDragObject();
189
0
    }
190
191
0
    m_pDoc.reset();        // ScTransferObj is owner of clipboard document
192
193
0
    m_aDocShellRef.clear();   // before releasing the mutex
194
195
0
    m_aDrawPersistRef.clear();                    // after the model
196
197
0
}
198
199
ScTransferObj* ScTransferObj::GetOwnClipboard(const uno::Reference<datatransfer::XTransferable2>& xTransferable)
200
6.98M
{
201
6.98M
    return dynamic_cast<ScTransferObj*>(xTransferable.get());
202
6.98M
}
203
204
void ScTransferObj::AddSupportedFormats()
205
0
{
206
    //  same formats as in ScSelectionTransferObj::AddSupportedFormats
207
0
    AddFormat( SotClipboardFormatId::EMBED_SOURCE );
208
0
    AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
209
0
    AddFormat( SotClipboardFormatId::GDIMETAFILE );
210
0
    AddFormat( SotClipboardFormatId::PNG );
211
0
    AddFormat( SotClipboardFormatId::BITMAP );
212
213
    // ScImportExport formats
214
0
    AddFormat( SotClipboardFormatId::HTML );
215
0
    AddFormat( SotClipboardFormatId::SYLK );
216
0
    AddFormat( SotClipboardFormatId::LINK );
217
0
    AddFormat( SotClipboardFormatId::DIF );
218
0
    AddFormat( SotClipboardFormatId::STRING );
219
0
    AddFormat( SotClipboardFormatId::STRING_TSVC );
220
221
0
    AddFormat( SotClipboardFormatId::RTF );
222
0
    AddFormat( SotClipboardFormatId::RICHTEXT );
223
0
    if ( m_aBlock.aStart == m_aBlock.aEnd )
224
0
    {
225
0
        AddFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT );
226
0
    }
227
0
}
228
229
static ScRange lcl_reduceBlock(const ScDocument& rDoc, ScRange aReducedBlock, bool bIncludeVisual = false)
230
0
{
231
0
    if ((aReducedBlock.aEnd.Col() == rDoc.MaxCol() || aReducedBlock.aEnd.Row() == rDoc.MaxRow()) &&
232
0
        aReducedBlock.aStart.Tab() == aReducedBlock.aEnd.Tab())
233
0
    {
234
        // Shrink the block here so we don't waste time creating huge
235
        // output when whole columns or rows are selected.
236
237
0
        SCCOL nPrintAreaEndCol = 0;
238
0
        SCROW nPrintAreaEndRow = 0;
239
0
        if (bIncludeVisual)
240
0
            rDoc.GetPrintArea( aReducedBlock.aStart.Tab(), nPrintAreaEndCol, nPrintAreaEndRow, true );
241
242
        // Shrink the area to allow pasting to external applications.
243
        // Shrink to real data area for HTML, RTF and RICHTEXT, but include
244
        // all objects and top-left area for BITMAP and PNG.
245
0
        SCCOL nStartCol = aReducedBlock.aStart.Col();
246
0
        SCROW nStartRow = aReducedBlock.aStart.Row();
247
0
        SCCOL nEndCol = aReducedBlock.aEnd.Col();
248
0
        SCROW nEndRow = aReducedBlock.aEnd.Row();
249
250
0
        if (bIncludeVisual)
251
0
        {
252
0
            ScDataAreaExtras aDataAreaExtras;
253
0
            aDataAreaExtras.mbCellNotes = true;
254
0
            aDataAreaExtras.mbCellDrawObjects = true;
255
0
            bool bShrunk = false;
256
0
            rDoc.ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
257
0
                    false, true /*bStickyTopRow*/, true /*bStickyLeftCol*/, &aDataAreaExtras);
258
0
            aDataAreaExtras.GetOverallRange( nStartCol, nStartRow, nEndCol, nEndRow, ScDataAreaExtras::Clip::None);
259
0
        }
260
0
        else
261
0
        {
262
0
            bool bShrunk = false;
263
0
            rDoc.ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
264
0
                    false, false /*bStickyTopRow*/, false /*bStickyLeftCol*/);
265
0
        }
266
267
0
        if ( nPrintAreaEndRow > nEndRow )
268
0
            nEndRow = nPrintAreaEndRow;
269
270
0
        if ( nPrintAreaEndCol > nEndCol )
271
0
            nEndCol = nPrintAreaEndCol;
272
273
0
        aReducedBlock = ScRange(nStartCol, nStartRow, aReducedBlock.aStart.Tab(), nEndCol, nEndRow, aReducedBlock.aEnd.Tab());
274
0
    }
275
0
    return aReducedBlock;
276
0
}
277
278
bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
279
0
{
280
0
    SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
281
0
    bool        bOK = false;
282
283
0
    if( HasFormat( nFormat ) )
284
0
    {
285
0
        ScRange aReducedBlock = m_aBlock;
286
287
0
        bool bReduceBlockFormat =
288
0
            nFormat == SotClipboardFormatId::HTML
289
0
            || nFormat == SotClipboardFormatId::RTF
290
0
            || nFormat == SotClipboardFormatId::RICHTEXT
291
0
            || nFormat == SotClipboardFormatId::BITMAP
292
0
            || nFormat == SotClipboardFormatId::PNG;
293
294
0
        const bool bIncludeVisual = (nFormat == SotClipboardFormatId::BITMAP ||
295
0
                                     nFormat == SotClipboardFormatId::PNG);
296
297
0
        if (bReduceBlockFormat)
298
0
            aReducedBlock = lcl_reduceBlock(*m_pDoc, m_aBlock, bIncludeVisual);
299
300
0
        if ( nFormat == SotClipboardFormatId::LINKSRCDESCRIPTOR || nFormat == SotClipboardFormatId::OBJECTDESCRIPTOR )
301
0
        {
302
0
            bOK = SetTransferableObjectDescriptor( m_aObjDesc );
303
0
        }
304
0
        else if ( ( nFormat == SotClipboardFormatId::RTF || nFormat == SotClipboardFormatId::RICHTEXT ||
305
0
            nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT ) && m_aBlock.aStart == m_aBlock.aEnd )
306
0
        {
307
            //  RTF from a single cell is handled by EditEngine
308
309
0
            SCCOL nCol = m_aBlock.aStart.Col();
310
0
            SCROW nRow = m_aBlock.aStart.Row();
311
0
            SCTAB nTab = m_aBlock.aStart.Tab();
312
0
            ScAddress aPos(nCol, nRow, nTab);
313
314
0
            const ScPatternAttr* pPattern = m_pDoc->GetPattern( nCol, nRow, nTab );
315
0
            if (pPattern)
316
0
            {
317
0
                ScTabEditEngine aEngine(*pPattern, m_pDoc->GetEditEnginePool(), *m_pDoc);
318
0
                ScRefCellValue aCell(*m_pDoc, aPos);
319
0
                if (aCell.getType() == CELLTYPE_EDIT)
320
0
                {
321
0
                    const EditTextObject* pObj = aCell.getEditText();
322
0
                    aEngine.SetTextCurrentDefaults(*pObj);
323
0
                }
324
0
                else
325
0
                {
326
0
                    ScInterpreterContext& rContext = m_pDoc->GetNonThreadedContext();
327
0
                    sal_uInt32 nNumFmt = pPattern->GetNumberFormat(rContext);
328
0
                    const Color* pColor;
329
0
                    OUString aText
330
0
                        = ScCellFormat::GetString(aCell, nNumFmt, &pColor, &rContext, *m_pDoc);
331
0
                    if (!aText.isEmpty())
332
0
                        aEngine.SetTextCurrentDefaults(aText);
333
0
                }
334
335
0
                bOK = SetObject(&aEngine,
336
0
                                ((nFormat == SotClipboardFormatId::RTF)
337
0
                                     ? SCTRANS_TYPE_EDIT_RTF
338
0
                                     : ((nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT)
339
0
                                            ? SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT
340
0
                                            : SCTRANS_TYPE_EDIT_BIN)),
341
0
                                rFlavor);
342
0
            }
343
0
        }
344
0
        else if ( ScImportExport::IsFormatSupported( nFormat ) || nFormat == SotClipboardFormatId::RTF
345
0
            || nFormat == SotClipboardFormatId::RICHTEXT )
346
0
        {
347
            //  if this transfer object was used to create a DDE link, filtered rows
348
            //  have to be included for subsequent calls (to be consistent with link data)
349
0
            if ( nFormat == SotClipboardFormatId::LINK )
350
0
                m_bUsedForLink = true;
351
352
0
            bool bIncludeFiltered = m_pDoc->IsCutMode() || m_bUsedForLink;
353
354
0
            ScImportExport aObj( *m_pDoc, aReducedBlock );
355
            // Plain text ("Unformatted text") may contain embedded tabs and
356
            // line breaks but is not enclosed in quotes. Which makes it
357
            // unsuitable for multiple cells, especially if one of them is
358
            // multi-line, but otherwise is expected behavior for plain text.
359
            // For multiple cells replace embedded line breaks (and tabs) with
360
            // space character, otherwise pasting would yield odd results.
361
            /* XXX: it's debatable whether this is actually expected, but
362
             * there's no way to satisfy all possible requirements when
363
             * copy/pasting unformatted text. */
364
0
            const bool bPlainMulti = (nFormat == SotClipboardFormatId::STRING &&
365
0
                    aReducedBlock.aStart != aReducedBlock.aEnd);
366
            // Add quotes only for STRING_TSVC.
367
            /* TODO: a possible future STRING_TSV should not contain embedded
368
             * line breaks nor tab (separator) characters and not be quoted.
369
             * A possible STRING_CSV should. */
370
0
            ScExportTextOptions aTextOptions( ScExportTextOptions::None, 0,
371
0
                    (nFormat == SotClipboardFormatId::STRING_TSVC));
372
0
            if ( bPlainMulti || m_bUsedForLink )
373
0
            {
374
                // For a DDE link or plain text multiple cells, convert line
375
                // breaks and separators to space.
376
0
                aTextOptions.meNewlineConversion = ScExportTextOptions::ToSpace;
377
0
                aTextOptions.mcSeparatorConvertTo = ' ';
378
0
                aTextOptions.mbAddQuotes = false;
379
0
            }
380
0
            aObj.SetExportTextOptions(aTextOptions);
381
0
            aObj.SetFormulas(m_pDoc->GetViewOptions().GetOption(sc::ViewOption::FORMULAS));
382
0
            aObj.SetIncludeFiltered( bIncludeFiltered );
383
384
            //  DataType depends on format type:
385
386
0
            if ( rFlavor.DataType.equals( ::cppu::UnoType<OUString>::get() ) )
387
0
            {
388
0
                OUString aString;
389
0
                if ( aObj.ExportString( aString, nFormat ) )
390
0
                    bOK = SetString( aString );
391
0
            }
392
0
            else if ( rFlavor.DataType.equals( cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) )
393
0
            {
394
                //  SetObject converts a stream into an Int8-Sequence
395
0
                bOK = SetObject( &aObj, SCTRANS_TYPE_IMPEX, rFlavor );
396
0
            }
397
0
            else
398
0
            {
399
0
                OSL_FAIL("unknown DataType");
400
0
            }
401
0
        }
402
0
        else if ( nFormat == SotClipboardFormatId::BITMAP || nFormat == SotClipboardFormatId::PNG )
403
0
        {
404
0
            tools::Rectangle aMMRect = m_pDoc->GetMMRect( aReducedBlock.aStart.Col(), aReducedBlock.aStart.Row(),
405
0
                                                 aReducedBlock.aEnd.Col(), aReducedBlock.aEnd.Row(),
406
0
                                                 aReducedBlock.aStart.Tab() );
407
0
            ScopedVclPtrInstance< VirtualDevice > pVirtDev;
408
409
            // tdf#160855 fix crash due to Skia's internal maximum pixel limit
410
            // Somewhere in the tens of thousands of selected fill cells,
411
            // the size of the VirtualDevice exceeds 1 GB of pixels. But
412
            // Skia, at least on macOS, will fail to create a surface.
413
            // Even if there is ample free memory, Skia/Raster will fail.
414
            // The second problem is that even if you disable Skia, the
415
            // crash is just delayed when a Bitmap is created from the
416
            // VirtualDevice and malloc() fails.
417
            // Since this data flavor really triggers one or more system
418
            // memory limits, lower the resolution of the bitmap by keeping
419
            // the VirtualDevice pixel size within an arbitrary number of
420
            // pixels.
421
            // Note: the arbitrary "maximum number of pixels" limit that
422
            // that Skia can handle may need to be raised or lowered for
423
            // platforms other than macOS.
424
0
            static constexpr tools::Long nCopyToImageMaxPixels = 8192 * 8192;
425
0
            Fraction aScale(1.0);
426
0
            Size aPixelSize = pVirtDev->LogicToPixel(aMMRect.GetSize(), MapMode(MapUnit::Map100thMM));
427
0
            tools::Long nPixels(aPixelSize.Width() * aPixelSize.Height());
428
0
            if (nPixels < 0 || nPixels > nCopyToImageMaxPixels)
429
0
            {
430
0
                aScale = Fraction(nCopyToImageMaxPixels, nPixels);
431
0
                aPixelSize = pVirtDev->LogicToPixel(aMMRect.GetSize(), MapMode(MapUnit::Map100thMM, Point(), aScale, aScale));
432
0
                nPixels = aPixelSize.Width() * aPixelSize.Height();
433
0
            }
434
435
0
            pVirtDev->SetOutputSizePixel(aPixelSize);
436
437
0
            PaintToDev( pVirtDev, *m_pDoc, 1.0, aReducedBlock );
438
439
0
            pVirtDev->SetMapMode( MapMode( MapUnit::MapPixel, Point(), aScale, aScale ) );
440
0
            Bitmap aBmp( pVirtDev->GetBitmap( Point(), pVirtDev->GetOutputSize() ) );
441
0
            bOK = SetBitmap(aBmp, rFlavor);
442
0
        }
443
0
        else if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
444
0
        {
445
            // #i123405# Do not limit visual size calculation for metafile creation.
446
            // It seems unlikely that removing the limitation causes problems since
447
            // metafile creation means that no real pixel device in the needed size is
448
            // created.
449
0
            InitDocShell(false);
450
451
0
            SfxObjectShell* pEmbObj = m_aDocShellRef.get();
452
453
            // like SvEmbeddedTransfer::GetData:
454
0
            GDIMetaFile     aMtf;
455
0
            ScopedVclPtrInstance< VirtualDevice > pVDev;
456
0
            MapMode         aMapMode( pEmbObj->GetMapUnit() );
457
0
            tools::Rectangle       aVisArea( pEmbObj->GetVisArea( ASPECT_CONTENT ) );
458
459
0
            pVDev->EnableOutput( false );
460
0
            pVDev->SetMapMode( aMapMode );
461
0
            aMtf.SetPrefSize( aVisArea.GetSize() );
462
0
            aMtf.SetPrefMapMode( aMapMode );
463
0
            aMtf.Record( pVDev );
464
465
0
            pEmbObj->DoDraw( pVDev, Point(), aVisArea.GetSize(), JobSetup() );
466
467
0
            aMtf.Stop();
468
0
            aMtf.WindStart();
469
470
0
            bOK = SetGDIMetaFile( aMtf );
471
0
        }
472
0
        else if ( nFormat == SotClipboardFormatId::EMBED_SOURCE )
473
0
        {
474
            //TODO/LATER: differentiate between formats?!
475
            // #i123405# Do limit visual size calculation to PageSize
476
0
            InitDocShell(true);         // set aDocShellRef
477
478
0
            SfxObjectShell* pEmbObj = m_aDocShellRef.get();
479
0
            bOK = SetObject( pEmbObj, SCTRANS_TYPE_EMBOBJ, rFlavor );
480
0
        }
481
0
    }
482
0
    return bOK;
483
0
}
484
485
bool ScTransferObj::WriteObject( SvStream& rOStm, void* pUserObject, sal_uInt32 nUserObjectId,
486
                                        const datatransfer::DataFlavor& rFlavor )
487
0
{
488
    // called from SetObject, put data into stream
489
490
0
    bool bRet = false;
491
0
    switch (nUserObjectId)
492
0
    {
493
0
        case SCTRANS_TYPE_IMPEX:
494
0
            {
495
0
                ScImportExport* pImpEx = static_cast<ScImportExport*>(pUserObject);
496
497
0
                SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
498
                // mba: no BaseURL for data exchange
499
0
                if ( pImpEx->ExportStream( rOStm, OUString(), nFormat ) )
500
0
                    bRet = ( rOStm.GetError() == ERRCODE_NONE );
501
0
            }
502
0
            break;
503
504
0
        case SCTRANS_TYPE_EDIT_RTF:
505
0
        case SCTRANS_TYPE_EDIT_BIN:
506
0
            {
507
0
                ScTabEditEngine* pEngine = static_cast<ScTabEditEngine*>(pUserObject);
508
0
                if ( nUserObjectId == SCTRANS_TYPE_EDIT_RTF )
509
0
                {
510
0
                    pEngine->Write( rOStm, EETextFormat::Rtf );
511
0
                    bRet = ( rOStm.GetError() == ERRCODE_NONE );
512
0
                }
513
0
                else
514
0
                {
515
                    //  can't use Write for EditEngine format because that would
516
                    //  write old format without support for unicode characters.
517
                    //  Get the data from the EditEngine's transferable instead.
518
519
0
                    sal_Int32 nParCnt = pEngine->GetParagraphCount();
520
0
                    if ( nParCnt == 0 )
521
0
                        nParCnt = 1;
522
0
                    ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
523
524
0
                    uno::Reference<datatransfer::XTransferable> xEditTrans = pEngine->CreateTransferable( aSel );
525
0
                    TransferableDataHelper aEditHelper( xEditTrans );
526
527
0
                    std::unique_ptr<SvStream> xStrm = aEditHelper.GetSotStorageStream( rFlavor );
528
0
                    bRet = bool(xStrm);
529
0
                    if (bRet)
530
0
                        rOStm.WriteStream(*xStrm);
531
0
                }
532
0
            }
533
0
            break;
534
535
0
        case SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT:
536
0
            {
537
0
                ScTabEditEngine* pEngine = static_cast<ScTabEditEngine*>(pUserObject);
538
0
                pEngine->Write(rOStm, EETextFormat::Xml);
539
0
                bRet = (rOStm.GetError() == ERRCODE_NONE);
540
0
            }
541
0
            break;
542
543
0
        case SCTRANS_TYPE_EMBOBJ:
544
0
            {
545
                // TODO/MBA: testing
546
0
                SfxObjectShell*   pEmbObj = static_cast<SfxObjectShell*>(pUserObject);
547
0
                ::utl::TempFileFast aTempFile;
548
0
                SvStream* pTempStream = aTempFile.GetStream(StreamMode::READWRITE);
549
0
                uno::Reference< embed::XStorage > xWorkStore =
550
0
                    ::comphelper::OStorageHelper::GetStorageFromStream( new utl::OStreamWrapper(*pTempStream) );
551
552
                // write document storage
553
0
                pEmbObj->SetupStorage( xWorkStore, SOFFICE_FILEFORMAT_CURRENT, false );
554
555
                // mba: no relative URLs for clipboard!
556
0
                SfxMedium aMedium( xWorkStore, OUString() );
557
0
                pEmbObj->DoSaveObjectAs( aMedium, false );
558
0
                pEmbObj->DoSaveCompleted();
559
560
0
                uno::Reference< embed::XTransactedObject > xTransact( xWorkStore, uno::UNO_QUERY );
561
0
                if ( xTransact.is() )
562
0
                    xTransact->commit();
563
564
0
                rOStm.SetBufferSize( 0xff00 );
565
0
                rOStm.WriteStream( *pTempStream );
566
567
0
                bRet = true;
568
569
0
                xWorkStore->dispose();
570
0
                xWorkStore.clear();
571
0
            }
572
0
            break;
573
574
0
        default:
575
0
            OSL_FAIL("unknown object id");
576
0
    }
577
0
    return bRet;
578
0
}
579
580
sal_Bool SAL_CALL ScTransferObj::isComplex()
581
0
{
582
0
    ScRange aReduced = lcl_reduceBlock(*m_pDoc, m_aBlock);
583
0
    size_t nCells = (aReduced.aEnd.Col() - aReduced.aStart.Col() + 1) *
584
0
                    (aReduced.aEnd.Row() - aReduced.aStart.Row() + 1) *
585
0
                    (aReduced.aEnd.Tab() - aReduced.aStart.Tab() + 1);
586
0
    return nCells > 1000;
587
0
}
588
589
void ScTransferObj::DragFinished( sal_Int8 nDropAction )
590
0
{
591
0
    if ( nDropAction == DND_ACTION_MOVE && !m_bDragWasInternal && !(m_nDragSourceFlags & ScDragSrc::Navigator) )
592
0
    {
593
        //  move: delete source data
594
0
        ScDocShell* pSourceSh = GetSourceDocShell();
595
0
        if (pSourceSh)
596
0
        {
597
0
            ScMarkData aMarkData = GetSourceMarkData();
598
            //  external drag&drop doesn't copy objects, so they also aren't deleted:
599
            //  bApi=TRUE, don't show error messages from drag&drop
600
0
            pSourceSh->GetDocFunc().DeleteContents( aMarkData, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, true, true );
601
0
        }
602
0
    }
603
604
0
    ScModule* pScMod = ScModule::get();
605
0
    const ScDragData* pDragData = pScMod ? pScMod->GetDragData() : nullptr;
606
0
    if (pDragData && pDragData->pCellTransfer == this)
607
0
        pScMod->ResetDragObject();
608
609
0
    m_xDragSourceRanges = nullptr;       // don't keep source after dropping
610
611
0
    TransferDataContainer::DragFinished( nDropAction );
612
0
}
613
614
void ScTransferObj::SetDragHandlePos( SCCOL nX, SCROW nY )
615
0
{
616
0
    m_nDragHandleX = nX;
617
0
    m_nDragHandleY = nY;
618
0
}
619
620
void ScTransferObj::SetSourceCursorPos( SCCOL nX, SCROW nY )
621
0
{
622
0
    m_nSourceCursorX = nX;
623
0
    m_nSourceCursorY = nY;
624
0
}
625
626
bool ScTransferObj::WasSourceCursorInSelection() const
627
0
{
628
0
    return
629
0
        m_nSourceCursorX >= m_aBlock.aStart.Col() && m_nSourceCursorX <= m_aBlock.aEnd.Col() &&
630
0
        m_nSourceCursorY >= m_aBlock.aStart.Row() && m_nSourceCursorY <= m_aBlock.aEnd.Row();
631
0
}
632
633
void ScTransferObj::SetVisibleTab( SCTAB nNew )
634
0
{
635
0
    m_nVisibleTab = nNew;
636
0
}
637
638
void ScTransferObj::SetDrawPersist( const SfxObjectShellRef& rRef )
639
0
{
640
0
    m_aDrawPersistRef = rRef;
641
0
}
642
643
void ScTransferObj::SetDragSource( ScDocShell* pSourceShell, const ScMarkData& rMark )
644
0
{
645
0
    ScRangeList aRanges;
646
0
    rMark.FillRangeListWithMarks( &aRanges, false );
647
0
    m_xDragSourceRanges = new ScCellRangesObj( pSourceShell, aRanges );
648
0
}
649
650
void ScTransferObj::SetDragSourceFlags(ScDragSrc nFlags)
651
0
{
652
0
    m_nDragSourceFlags = nFlags;
653
0
}
654
655
void ScTransferObj::SetDragWasInternal()
656
0
{
657
0
    m_bDragWasInternal = true;
658
0
}
659
660
void ScTransferObj::SetUseInApi( bool bSet )
661
0
{
662
0
    m_bUseInApi = bSet;
663
0
}
664
665
ScDocument* ScTransferObj::GetSourceDocument()
666
0
{
667
0
    ScDocShell* pSourceDocSh = GetSourceDocShell();
668
0
    if (pSourceDocSh)
669
0
        return &pSourceDocSh->GetDocument();
670
0
    return nullptr;
671
0
}
672
673
ScDocShell* ScTransferObj::GetSourceDocShell()
674
0
{
675
0
    if (m_xDragSourceRanges)
676
0
        return m_xDragSourceRanges->GetDocShell();
677
678
0
    return nullptr;    // none set
679
0
}
680
681
ScMarkData ScTransferObj::GetSourceMarkData() const
682
0
{
683
0
    ScMarkData aMarkData(m_pDoc->GetSheetLimits());
684
0
    if (m_xDragSourceRanges)
685
0
    {
686
0
        const ScRangeList& rRanges = m_xDragSourceRanges->GetRangeList();
687
0
        aMarkData.MarkFromRangeList( rRanges, false );
688
0
    }
689
0
    return aMarkData;
690
0
}
691
692
//  initialize aDocShellRef with a live document from the ClipDoc
693
694
// #i123405# added parameter to allow size calculation without limitation
695
// to PageSize, e.g. used for Metafile creation for clipboard.
696
697
void ScTransferObj::InitDocShell(bool bLimitToPageSize)
698
0
{
699
0
    if ( m_aDocShellRef.is() )
700
0
        return;
701
702
0
    m_aDocShellRef = new ScDocShell; // ref must be there before InitNew
703
704
0
    m_aDocShellRef->DoInitNew();
705
706
0
    ScDocument& rDestDoc = m_aDocShellRef->GetDocument();
707
0
    ScMarkData aDestMark(rDestDoc.GetSheetLimits());
708
0
    aDestMark.SelectTable( 0, true );
709
710
0
    rDestDoc.SetDocOptions( m_pDoc->GetDocOptions() );   // #i42666#
711
712
0
    OUString aTabName;
713
0
    m_pDoc->GetName( m_aBlock.aStart.Tab(), aTabName );
714
0
    rDestDoc.RenameTab( 0, aTabName );
715
716
0
    m_aDocShellRef->MakeDrawLayer();
717
718
0
    rDestDoc.CopyStdStylesFrom(*m_pDoc);
719
720
0
    SCCOL nStartX = m_aBlock.aStart.Col();
721
0
    SCROW nStartY = m_aBlock.aStart.Row();
722
0
    SCCOL nEndX = m_aBlock.aEnd.Col();
723
0
    SCROW nEndY = m_aBlock.aEnd.Row();
724
725
    //  widths / heights
726
    //  (must be copied before CopyFromClip, for drawing objects)
727
728
0
    SCCOL nCol;
729
0
    SCTAB nSrcTab = m_aBlock.aStart.Tab();
730
0
    rDestDoc.SetLayoutRTL(0, m_pDoc->IsLayoutRTL(nSrcTab));
731
0
    for (nCol=nStartX; nCol<=nEndX; nCol++)
732
0
        if ( m_pDoc->ColHidden(nCol, nSrcTab) )
733
0
            rDestDoc.ShowCol( nCol, 0, false );
734
0
        else
735
0
            rDestDoc.SetColWidth( nCol, 0, m_pDoc->GetColWidth( nCol, nSrcTab ) );
736
737
0
    if (nStartY > 0)
738
0
    {
739
        // Set manual height for all previous rows so we can ensure
740
        // that visible area will not change due to autoheight
741
0
        rDestDoc.SetManualHeight(0, nStartY - 1, 0, true);
742
0
    }
743
0
    for (SCROW nRow = nStartY; nRow <= nEndY; ++nRow)
744
0
    {
745
0
        if ( m_pDoc->RowHidden(nRow, nSrcTab) )
746
0
            rDestDoc.ShowRow( nRow, 0, false );
747
0
        else
748
0
        {
749
0
            rDestDoc.SetRowHeight( nRow, 0, m_pDoc->GetOriginalHeight( nRow, nSrcTab ) );
750
751
            //  if height was set manually, that flag has to be copied, too
752
0
            bool bManual = m_pDoc->IsManualRowHeight(nRow, nSrcTab);
753
0
            rDestDoc.SetManualHeight(nRow, nRow, 0, bManual);
754
0
        }
755
0
    }
756
757
    //  cell range is copied to the original position, but on the first sheet
758
    //  -> bCutMode must be set
759
    //  pDoc is always a Clipboard-document
760
761
0
    ScRange aDestRange( nStartX,nStartY,0, nEndX,nEndY,0 );
762
0
    bool bWasCut = m_pDoc->IsCutMode();
763
0
    if (!bWasCut)
764
0
        m_pDoc->SetClipArea( aDestRange, true );          // Cut
765
0
    rDestDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL, nullptr, m_pDoc.get(), false );
766
0
    m_pDoc->SetClipArea( aDestRange, bWasCut );
767
768
0
    StripRefs(*m_pDoc, nStartX,nStartY, nEndX,nEndY, rDestDoc);
769
770
0
    ScRange aMergeRange = aDestRange;
771
0
    rDestDoc.ExtendMerge( aMergeRange, true );
772
773
0
    m_pDoc->CopyDdeLinks( rDestDoc );         // copy values of DDE Links
774
775
    //  page format (grid etc) and page size (maximum size for ole object)
776
777
0
    Size aPaperSize = SvxPaperInfo::GetPaperSize( PAPER_A4 );       // Twips
778
0
    ScStyleSheetPool* pStylePool = m_pDoc->GetStyleSheetPool();
779
0
    OUString aStyleName = m_pDoc->GetPageStyle( m_aBlock.aStart.Tab() );
780
0
    SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
781
0
    if (pStyleSheet)
782
0
    {
783
0
        const SfxItemSet& rSourceSet = pStyleSheet->GetItemSet();
784
0
        aPaperSize = rSourceSet.Get(ATTR_PAGE_SIZE).GetSize();
785
786
        // CopyStyleFrom copies SetItems with correct pool
787
0
        ScStyleSheetPool* pDestPool = rDestDoc.GetStyleSheetPool();
788
0
        pDestPool->CopyStyleFrom( pStylePool, aStyleName, SfxStyleFamily::Page );
789
0
    }
790
791
0
    ScViewData aViewData(*m_aDocShellRef, nullptr);
792
0
    aViewData.SetScreen( nStartX,nStartY, nEndX,nEndY );
793
0
    aViewData.SetCurX( nStartX );
794
0
    aViewData.SetCurY( nStartY );
795
796
0
    rDestDoc.SetViewOptions( m_pDoc->GetViewOptions() );
797
798
    //      Size
799
    //! get while copying sizes
800
801
0
    tools::Long nPosX = 0;
802
0
    tools::Long nPosY = 0;
803
804
0
    for (nCol=0; nCol<nStartX; nCol++)
805
0
        nPosX += rDestDoc.GetColWidth( nCol, 0 );
806
0
    nPosY += rDestDoc.GetRowHeight( 0, nStartY-1, 0 );
807
0
    nPosX = o3tl::convert(nPosX, o3tl::Length::twip, o3tl::Length::mm100);
808
0
    nPosY = o3tl::convert(nPosY, o3tl::Length::twip, o3tl::Length::mm100);
809
810
0
    aPaperSize.setWidth( aPaperSize.Width() * 2 );       // limit OLE object to double of page size
811
0
    aPaperSize.setHeight( aPaperSize.Height() * 2 );
812
813
0
    tools::Long nSizeX = 0;
814
0
    tools::Long nSizeY = 0;
815
0
    for (nCol=nStartX; nCol<=nEndX; nCol++)
816
0
    {
817
0
        tools::Long nAdd = rDestDoc.GetColWidth( nCol, 0 );
818
0
        if ( bLimitToPageSize && nSizeX+nAdd > aPaperSize.Width() && nSizeX )   // above limit?
819
0
            break;
820
0
        nSizeX += nAdd;
821
0
    }
822
0
    for (SCROW nRow=nStartY; nRow<=nEndY; nRow++)
823
0
    {
824
0
        tools::Long nAdd = rDestDoc.GetRowHeight( nRow, 0 );
825
0
        if ( bLimitToPageSize && nSizeY+nAdd > aPaperSize.Height() && nSizeY )  // above limit?
826
0
            break;
827
0
        nSizeY += nAdd;
828
0
    }
829
0
    nSizeX = o3tl::convert(nSizeX, o3tl::Length::twip, o3tl::Length::mm100);
830
0
    nSizeY = o3tl::convert(nSizeY, o3tl::Length::twip, o3tl::Length::mm100);
831
832
//      m_aDocShellRef->SetVisAreaSize( Size(nSizeX,nSizeY) );
833
834
0
    tools::Rectangle aNewArea( Point(nPosX,nPosY), Size(nSizeX,nSizeY) );
835
    //TODO/LATER: why twice?!
836
    //m_aDocShellRef->SvInPlaceObject::SetVisArea( aNewArea );
837
0
    m_aDocShellRef->SetVisArea(aNewArea);
838
839
0
    m_aDocShellRef->UpdateOle(aViewData, true);
840
841
    //! SetDocumentModified?
842
0
    if ( rDestDoc.IsChartListenerCollectionNeedsUpdate() )
843
0
        rDestDoc.UpdateChartListenerCollection();
844
0
}
845
846
SfxObjectShell* ScTransferObj::SetDrawClipDoc( bool bAnyOle, const std::shared_ptr<ScDocument>& pDoc )
847
0
{
848
    // update ScGlobal::xDrawClipDocShellRef
849
850
0
    ScGlobal::xDrawClipDocShellRef.clear();
851
0
    if (bAnyOle)
852
0
    {
853
0
        ScGlobal::xDrawClipDocShellRef = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS, pDoc); // there must be a ref
854
0
        ScGlobal::xDrawClipDocShellRef->DoInitNew();
855
0
    }
856
857
0
    return ScGlobal::xDrawClipDocShellRef.get();
858
0
}
859
860
void ScTransferObj::StripRefs( ScDocument& rDoc,
861
                    SCCOL nStartX, SCROW nStartY, SCCOL nEndX, SCROW nEndY,
862
                    ScDocument& rDestDoc )
863
0
{
864
    //  In a clipboard doc the data don't have to be on the first sheet
865
866
0
    SCTAB nSrcTab = 0;
867
0
    while (nSrcTab < rDoc.GetTableCount() && !rDoc.HasTable(nSrcTab))
868
0
        ++nSrcTab;
869
0
    SCTAB nDestTab = 0;
870
0
    while (nDestTab < rDestDoc.GetTableCount() && !rDestDoc.HasTable(nDestTab))
871
0
        ++nDestTab;
872
873
0
    if (!rDoc.HasTable(nSrcTab) || !rDestDoc.HasTable(nDestTab))
874
0
    {
875
0
        OSL_FAIL("Sheet not found in ScTransferObj::StripRefs");
876
0
        return;
877
0
    }
878
879
0
    ScRange aRef;
880
881
0
    ScCellIterator aIter( rDoc, ScRange(nStartX, nStartY, nSrcTab, nEndX, nEndY, nSrcTab) );
882
0
    for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
883
0
    {
884
0
        if (aIter.getType() != CELLTYPE_FORMULA)
885
0
            continue;
886
887
0
        ScFormulaCell* pFCell = aIter.getFormulaCell();
888
0
        bool bOut = false;
889
0
        ScDetectiveRefIter aRefIter( rDoc, pFCell );
890
0
        while ( !bOut && aRefIter.GetNextRef( aRef ) )
891
0
        {
892
0
            if ( aRef.aStart.Tab() != nSrcTab || aRef.aEnd.Tab() != nSrcTab ||
893
0
                    aRef.aStart.Col() < nStartX || aRef.aEnd.Col() > nEndX ||
894
0
                    aRef.aStart.Row() < nStartY || aRef.aEnd.Row() > nEndY )
895
0
                bOut = true;
896
0
        }
897
0
        if (bOut)
898
0
        {
899
0
            SCCOL nCol = aIter.GetPos().Col();
900
0
            SCROW nRow = aIter.GetPos().Row();
901
902
0
            FormulaError nErrCode = pFCell->GetErrCode();
903
0
            ScAddress aPos(nCol, nRow, nDestTab);
904
0
            if (nErrCode != FormulaError::NONE)
905
0
            {
906
0
                if ( rDestDoc.GetAttr( nCol,nRow,nDestTab, ATTR_HOR_JUSTIFY).GetValue() ==
907
0
                        SvxCellHorJustify::Standard )
908
0
                    rDestDoc.ApplyAttr( nCol,nRow,nDestTab,
909
0
                            SvxHorJustifyItem(SvxCellHorJustify::Right, ATTR_HOR_JUSTIFY) );
910
911
0
                ScSetStringParam aParam;
912
0
                aParam.setTextInput();
913
0
                rDestDoc.SetString(aPos, ScGlobal::GetErrorString(nErrCode), &aParam);
914
0
            }
915
0
            else if (pFCell->IsValue())
916
0
            {
917
0
                rDestDoc.SetValue(aPos, pFCell->GetValue());
918
0
            }
919
0
            else
920
0
            {
921
0
                OUString aStr = pFCell->GetString().getString();
922
0
                if ( pFCell->IsMultilineResult() )
923
0
                {
924
0
                    ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine();
925
0
                    rEngine.SetTextCurrentDefaults(aStr);
926
0
                    rDestDoc.SetEditText(ScAddress(nCol,nRow,nDestTab), rEngine.CreateTextObject());
927
0
                }
928
0
                else
929
0
                {
930
0
                    ScSetStringParam aParam;
931
0
                    aParam.setTextInput();
932
0
                    rDestDoc.SetString(aPos, aStr, &aParam);
933
0
                }
934
0
            }
935
0
        }
936
0
    }
937
0
}
938
939
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */