Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/docshell/docsh5.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 <memory>
21
#include <sal/config.h>
22
23
#include <cassert>
24
25
#include <osl/diagnose.h>
26
#include <vcl/svapp.hxx>
27
#include <vcl/vclenum.hxx>
28
#include <vcl/weld/MessageDialog.hxx>
29
#include <vcl/weld/weld.hxx>
30
#include <sfx2/app.hxx>
31
#include <sfx2/bindings.hxx>
32
#include <unotools/charclass.hxx>
33
34
#include <com/sun/star/script/vba/XVBACompatibility.hpp>
35
36
#include <dociter.hxx>
37
#include <docsh.hxx>
38
#include <global.hxx>
39
#include <globstr.hrc>
40
#include <scresid.hxx>
41
#include <globalnames.hxx>
42
#include <undodat.hxx>
43
#include <undotab.hxx>
44
#include <undoblk.hxx>
45
#include <dpobject.hxx>
46
#include <dpshttab.hxx>
47
#include <dbdocfun.hxx>
48
#include <consoli.hxx>
49
#include <dbdata.hxx>
50
#include <progress.hxx>
51
#include <olinetab.hxx>
52
#include <patattr.hxx>
53
#include <attrib.hxx>
54
#include <docpool.hxx>
55
#include <uiitems.hxx>
56
#include <sc.hrc>
57
#include <sizedev.hxx>
58
#include <clipparam.hxx>
59
#include <rowheightcontext.hxx>
60
#include <refupdatecontext.hxx>
61
62
using com::sun::star::script::XLibraryContainer;
63
using com::sun::star::script::vba::XVBACompatibility;
64
using com::sun::star::container::XNameContainer;
65
using com::sun::star::uno::Reference;
66
using com::sun::star::uno::UNO_QUERY;
67
68
//  former viewfunc/dbfunc methods
69
70
void ScDocShell::ErrorMessage(TranslateId pGlobStrId)
71
0
{
72
    //! StopMarking at the (active) view?
73
74
0
    weld::Window* pParent = GetActiveDialogParent();
75
0
    weld::WaitObject aWaitOff( pParent );
76
0
    bool bFocus = pParent && pParent->has_focus();
77
78
0
    if (pGlobStrId && pGlobStrId == STR_PROTECTIONERR)
79
0
    {
80
0
        if (IsReadOnly())
81
0
        {
82
0
            pGlobStrId = STR_READONLYERR;
83
0
        }
84
0
    }
85
86
0
    std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
87
0
                                                  VclMessageType::Info, VclButtonsType::Ok,
88
0
                                                  ScResId(pGlobStrId)));
89
0
    xInfoBox->run();
90
91
0
    if (bFocus)
92
0
        pParent->grab_focus();
93
0
}
94
95
bool ScDocShell::IsEditable() const
96
20.3k
{
97
    // import into read-only document is possible - must be extended if other filters use api
98
    // #i108547# MSOOXML filter uses "IsChangeReadOnlyEnabled" property
99
100
20.3k
    return !IsReadOnly() || m_pDocument->IsImportingXML() || m_pDocument->IsChangeReadOnlyEnabled();
101
20.3k
}
102
103
void ScDocShell::DBAreaDeleted( SCTAB nTab, SCCOL nX1, SCROW nY1, SCCOL nX2 )
104
0
{
105
0
    ScDocShellModificator aModificator( *this );
106
    // the auto-filter is in the first row of the area
107
0
    m_pDocument->RemoveFlagsTab( nX1, nY1, nX2, nY1, nTab, ScMF::Auto );
108
0
    PostPaint( nX1, nY1, nTab, nX2, nY1, nTab, PaintPartFlags::Grid );
109
    // No SetDocumentModified, as the unnamed database range might have to be restored later.
110
    // The UNO hint is broadcast directly instead, to keep UNO objects in valid state.
111
0
    m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
112
0
}
113
114
ScDBData* ScDocShell::GetDBData( const ScRange& rMarked, ScGetDBMode eMode, ScGetDBSelection eSel )
115
0
{
116
0
    SCCOL nCol = rMarked.aStart.Col();
117
0
    SCROW nRow = rMarked.aStart.Row();
118
0
    SCTAB nTab = rMarked.aStart.Tab();
119
120
0
    SCCOL nStartCol = nCol;
121
0
    SCROW nStartRow = nRow;
122
0
    SCTAB nStartTab = nTab;
123
0
    SCCOL nEndCol = rMarked.aEnd.Col();
124
0
    SCROW nEndRow = rMarked.aEnd.Row();
125
    //  Not simply GetDBAtCursor: The continuous data range for "unnamed" (GetDataArea) may be
126
    //  located next to the cursor; so a named DB range needs to be searched for there as well.
127
0
    ScDBCollection* pColl = m_pDocument->GetDBCollection();
128
0
    ScDBData* pData = m_pDocument->GetDBAtArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
129
0
    if (!pData)
130
0
        pData = pColl->GetDBNearCursor(nCol, nRow, nTab );
131
132
0
    bool bSelected = ( eSel == ScGetDBSelection::ForceMark ||
133
0
            (rMarked.aStart != rMarked.aEnd && eSel != ScGetDBSelection::RowDown) );
134
0
    bool bOnlyDown = (!bSelected && eSel == ScGetDBSelection::RowDown && rMarked.aStart.Row() == rMarked.aEnd.Row());
135
136
0
    bool bUseThis = false;
137
0
    if (pData)
138
0
    {
139
        //      take range, if nothing else is marked
140
141
0
        SCTAB nDummy;
142
0
        SCCOL nOldCol1;
143
0
        SCROW nOldRow1;
144
0
        SCCOL nOldCol2;
145
0
        SCROW nOldRow2;
146
0
        pData->GetArea( nDummy, nOldCol1,nOldRow1, nOldCol2,nOldRow2 );
147
0
        bool bIsNoName = ( pData->GetName() == STR_DB_LOCAL_NONAME );
148
149
0
        if (!bSelected)
150
0
        {
151
0
            bUseThis = true;
152
0
            if ( bIsNoName && (eMode == SC_DB_MAKE || eMode == SC_DB_AUTOFILTER) )
153
0
            {
154
                // If nothing marked or only one row marked, adapt
155
                // "unnamed" to contiguous area.
156
0
                nStartCol = nCol;
157
0
                nStartRow = nRow;
158
0
                if (bOnlyDown)
159
0
                {
160
0
                    nEndCol = rMarked.aEnd.Col();
161
0
                    nEndRow = rMarked.aEnd.Row();
162
0
                }
163
0
                else
164
0
                {
165
0
                    nEndCol = nStartCol;
166
0
                    nEndRow = nStartRow;
167
0
                }
168
0
                m_pDocument->GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, bOnlyDown );
169
0
                if ( nOldCol1 != nStartCol || nOldCol2 != nEndCol || nOldRow1 != nStartRow )
170
0
                    bUseThis = false;               // doesn't fit at all
171
0
                else if ( nOldRow2 != nEndRow )
172
0
                {
173
                    //  extend range to new end row
174
0
                    pData->SetArea( nTab, nOldCol1,nOldRow1, nOldCol2,nEndRow );
175
0
                }
176
0
            }
177
0
        }
178
0
        else
179
0
        {
180
0
            if ( nOldCol1 == nStartCol && nOldRow1 == nStartRow &&
181
0
                 nOldCol2 == nEndCol && nOldRow2 == nEndRow )               // marked precisely?
182
0
                bUseThis = true;
183
0
            else
184
0
                bUseThis = false;           // always take marking (Bug 11964)
185
0
        }
186
187
        //      never take "unnamed" for import
188
189
0
        if ( bUseThis && eMode == SC_DB_IMPORT && bIsNoName )
190
0
            bUseThis = false;
191
0
    }
192
193
0
    if ( bUseThis )
194
0
    {
195
0
        pData->GetArea( nStartTab, nStartCol,nStartRow, nEndCol,nEndRow );
196
0
    }
197
    // tdf#168478 - use the previously found range rather than returning an empty one
198
0
    else if ( eMode != SC_DB_OLD )
199
0
    {
200
0
        if ( !bSelected )
201
0
        {                                       // continuous range
202
0
            nStartCol = nCol;
203
0
            nStartRow = nRow;
204
0
            if (bOnlyDown)
205
0
            {
206
0
                nEndCol = rMarked.aEnd.Col();
207
0
                nEndRow = rMarked.aEnd.Row();
208
0
            }
209
0
            else
210
0
            {
211
0
                nEndCol = nStartCol;
212
0
                nEndRow = nStartRow;
213
0
            }
214
0
            m_pDocument->GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, bOnlyDown );
215
0
        }
216
217
0
        bool bHasHeader = m_pDocument->HasColHeader( nStartCol,nStartRow, nEndCol,nEndRow, nTab );
218
219
0
        ScDBData* pNoNameData = m_pDocument->GetAnonymousDBData(nTab);
220
0
        if ( eMode != SC_DB_IMPORT && pNoNameData)
221
0
        {
222
            // Do not reset AutoFilter range during temporary operations on
223
            // other ranges, use the document global temporary anonymous range
224
            // instead. But, if AutoFilter is to be toggled then do use the
225
            // sheet-local DB range.
226
0
            bool bSheetLocal = true;
227
0
            if (eMode != SC_DB_AUTOFILTER && pNoNameData->HasAutoFilter())
228
0
            {
229
0
                bSheetLocal = false;
230
0
                pNoNameData = m_pDocument->GetAnonymousDBData();
231
0
                if (!pNoNameData)
232
0
                {
233
0
                    m_pDocument->SetAnonymousDBData( std::unique_ptr<ScDBData>(new ScDBData( STR_DB_LOCAL_NONAME,
234
0
                            nTab, nStartCol, nStartRow, nEndCol, nEndRow, true, bHasHeader) ) );
235
0
                    pNoNameData = m_pDocument->GetAnonymousDBData();
236
0
                }
237
                // ScDocShell::CancelAutoDBRange() would restore the
238
                // sheet-local anonymous DBData from pOldAutoDBRange, unset so
239
                // that won't happen with data of a previous sheet-local
240
                // DBData.
241
0
                m_pOldAutoDBRange.reset();
242
0
            }
243
0
            else if (!m_pOldAutoDBRange)
244
0
            {
245
                // store the old unnamed database range with its settings for undo
246
                // (store at the first change, get the state before all changes)
247
0
                m_pOldAutoDBRange.reset( new ScDBData( *pNoNameData ) );
248
0
            }
249
0
            else if (m_pOldAutoDBRange->GetTab() != pNoNameData->GetTab())
250
0
            {
251
                // Different sheet-local unnamed DB range than the previous one.
252
0
                *m_pOldAutoDBRange = *pNoNameData;
253
0
            }
254
255
0
            SCCOL nOldX1;                                   // take old range away cleanly
256
0
            SCROW nOldY1;                                   //! (UNDO ???)
257
0
            SCCOL nOldX2;
258
0
            SCROW nOldY2;
259
0
            SCTAB nOldTab;
260
0
            pNoNameData->GetArea( nOldTab, nOldX1, nOldY1, nOldX2, nOldY2 );
261
262
            // If previously bHasHeader was set and the new range starts on the
263
            // same row and intersects the old column range, then don't reset
264
            // bHasHeader but assume that the new range still has headers, just
265
            // some are empty or numeric.
266
0
            if (!bHasHeader && pNoNameData->HasHeader() && nTab == nOldTab && nStartRow == nOldY1 &&
267
0
                    nStartCol <= nOldY2 && nOldY1 <= nEndCol)
268
0
                bHasHeader = true;
269
270
            // Remove AutoFilter button flags only for sheet-local DB range,
271
            // not if a temporary is used.
272
0
            if (bSheetLocal)
273
0
                DBAreaDeleted( nOldTab, nOldX1, nOldY1, nOldX2 );
274
275
0
            pNoNameData->SetSortParam( ScSortParam() );             // reset parameter
276
0
            pNoNameData->SetQueryParam( ScQueryParam() );
277
0
            pNoNameData->SetSubTotalParam( ScSubTotalParam() );
278
279
0
            pNoNameData->SetArea( nTab, nStartCol,nStartRow, nEndCol,nEndRow );     // set anew
280
0
            pNoNameData->SetByRow( true );
281
0
            pNoNameData->SetHeader( bHasHeader );
282
0
            pNoNameData->SetAutoFilter( false );
283
0
        }
284
0
        else
285
0
        {
286
0
            std::unique_ptr<ScDBCollection> pUndoColl;
287
288
0
            if (eMode==SC_DB_IMPORT)
289
0
            {
290
0
                m_pDocument->PreprocessDBDataUpdate();
291
0
                pUndoColl.reset( new ScDBCollection( *pColl ) );   // Undo for import range
292
293
0
                OUString aImport = ScResId( STR_DBNAME_IMPORT );
294
0
                tools::Long nCount = 0;
295
0
                const ScDBData* pDummy = nullptr;
296
0
                ScDBCollection::NamedDBs& rDBs = pColl->getNamedDBs();
297
0
                OUString aNewName;
298
0
                do
299
0
                {
300
0
                    ++nCount;
301
0
                    aNewName = aImport + OUString::number( nCount );
302
0
                    pDummy = rDBs.findByUpperName(ScGlobal::getCharClass().uppercase(aNewName));
303
0
                }
304
0
                while (pDummy);
305
0
                pNoNameData = new ScDBData( aNewName, nTab,
306
0
                                nStartCol,nStartRow, nEndCol,nEndRow,
307
0
                                true, bHasHeader );
308
0
                bool ins = rDBs.insert(std::unique_ptr<ScDBData>(pNoNameData));
309
0
                assert(ins); (void)ins;
310
0
            }
311
0
            else
312
0
            {
313
0
                pNoNameData = new ScDBData(STR_DB_LOCAL_NONAME, nTab,
314
0
                                nStartCol,nStartRow, nEndCol,nEndRow,
315
0
                                true, bHasHeader );
316
0
                m_pDocument->SetAnonymousDBData(nTab, std::unique_ptr<ScDBData>(pNoNameData));
317
0
            }
318
319
0
            if ( pUndoColl )
320
0
            {
321
0
                m_pDocument->CompileHybridFormula();
322
323
0
                GetUndoManager()->AddUndoAction( std::make_unique<ScUndoDBData>( *this, u""_ustr,
324
0
                        std::move(pUndoColl), pNoNameData ? pNoNameData->GetName() : u""_ustr,
325
0
                        std::make_unique<ScDBCollection>( *pColl ) ) );
326
0
            }
327
328
            //  no longer needed to register new range at the Sba
329
330
            //  announce "Import1", etc., at the Navigator
331
0
            if (eMode==SC_DB_IMPORT)
332
0
                SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
333
0
        }
334
0
        pData = pNoNameData;
335
0
    }
336
337
0
    return pData;
338
0
}
339
340
ScDBData* ScDocShell::GetAnonymousDBData(const ScRange& rRange)
341
0
{
342
0
    ScDBCollection* pColl = m_pDocument->GetDBCollection();
343
0
    if (!pColl)
344
0
        return nullptr;
345
346
0
    ScDBData* pData = pColl->getAnonDBs().getByRange(rRange);
347
0
    if (!pData)
348
0
        return nullptr;
349
350
0
    if (!pData->HasHeader())
351
0
    {
352
0
        bool bHasHeader = m_pDocument->HasColHeader(
353
0
                rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab());
354
0
        pData->SetHeader(bHasHeader);
355
0
    }
356
357
0
    return pData;
358
0
}
359
360
std::unique_ptr<ScDBData> ScDocShell::GetOldAutoDBRange()
361
0
{
362
0
    return std::move(m_pOldAutoDBRange);
363
0
}
364
365
void ScDocShell::CancelAutoDBRange()
366
0
{
367
    // called when dialog is cancelled
368
//moggi:TODO
369
0
    if ( !m_pOldAutoDBRange )
370
0
        return;
371
372
0
    SCTAB nTab = GetCurTab();
373
0
    ScDBData* pDBData = m_pDocument->GetAnonymousDBData(nTab);
374
0
    if ( pDBData )
375
0
    {
376
0
        SCCOL nRangeX1;
377
0
        SCROW nRangeY1;
378
0
        SCCOL nRangeX2;
379
0
        SCROW nRangeY2;
380
0
        SCTAB nRangeTab;
381
0
        pDBData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
382
0
        DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
383
384
0
        *pDBData = *m_pOldAutoDBRange;    // restore old settings
385
386
0
        if ( m_pOldAutoDBRange->HasAutoFilter() )
387
0
        {
388
            // restore AutoFilter buttons
389
0
            m_pOldAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
390
0
            m_pDocument->ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
391
0
            PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PaintPartFlags::Grid );
392
0
        }
393
0
    }
394
395
0
    m_pOldAutoDBRange.reset();
396
0
}
397
398
        //  adjust height
399
        //! merge with docfunc
400
401
bool ScDocShell::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab )
402
0
{
403
0
    ScSizeDeviceProvider aProv(*this);
404
0
    double fZoom(1.0);
405
0
    sc::RowHeightContext aCxt(m_pDocument->MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), fZoom, fZoom, aProv.GetDevice());
406
0
    bool bChange = m_pDocument->SetOptimalHeight(aCxt, nStartRow,nEndRow, nTab, true);
407
408
0
    if (bChange)
409
0
    {
410
        // tdf#76183: recalculate objects' positions
411
0
        m_pDocument->SetDrawPageSize(nTab);
412
413
0
        PostPaint( 0,nStartRow,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid|PaintPartFlags::Left );
414
0
    }
415
416
0
    return bChange;
417
0
}
418
419
void ScDocShell::UpdateAllRowHeights( const ScMarkData* pTabMark )
420
0
{
421
    // update automatic row heights
422
423
0
    ScSizeDeviceProvider aProv(*this);
424
0
    double fZoom(1.0);
425
0
    sc::RowHeightContext aCxt(m_pDocument->MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), fZoom, fZoom, aProv.GetDevice());
426
0
    m_pDocument->UpdateAllRowHeights(aCxt, pTabMark);
427
0
}
428
429
void ScDocShell::UpdateAllRowHeights(const bool bOnlyUsedRows)
430
4.00k
{
431
    // update automatic row heights on all sheets using the newer ScDocRowHeightUpdater
432
4.00k
    ScSizeDeviceProvider aProv(*this);
433
4.00k
    ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(),
434
4.00k
                                   aProv.GetPPTY(), nullptr);
435
4.00k
    aUpdater.update(bOnlyUsedRows);
436
4.00k
}
437
438
void ScDocShell::UpdatePendingRowHeights( SCTAB nUpdateTab, bool bBefore )
439
43.0k
{
440
43.0k
    bool bIsUndoEnabled = m_pDocument->IsUndoEnabled();
441
43.0k
    m_pDocument->EnableUndo( false );
442
43.0k
    m_pDocument->LockStreamValid( true );      // ignore draw page size (but not formula results)
443
43.0k
    if ( bBefore )          // check all sheets up to nUpdateTab
444
0
    {
445
0
        SCTAB nTabCount = m_pDocument->GetTableCount();
446
0
        if ( nUpdateTab >= nTabCount )
447
0
            nUpdateTab = nTabCount-1;     // nUpdateTab is inclusive
448
449
0
        ScMarkData aUpdateSheets(m_pDocument->GetSheetLimits());
450
0
        SCTAB nTab;
451
0
        for (nTab=0; nTab<=nUpdateTab; ++nTab)
452
0
            if ( m_pDocument->IsPendingRowHeights( nTab ) )
453
0
                aUpdateSheets.SelectTable( nTab, true );
454
455
0
        if (aUpdateSheets.GetSelectCount())
456
0
            UpdateAllRowHeights(&aUpdateSheets);        // update with a single progress bar
457
458
0
        for (nTab=0; nTab<=nUpdateTab; ++nTab)
459
0
            if ( aUpdateSheets.GetTableSelect( nTab ) )
460
0
            {
461
0
                m_pDocument->UpdatePageBreaks( nTab );
462
0
                m_pDocument->SetPendingRowHeights( nTab, false );
463
0
            }
464
0
    }
465
43.0k
    else                    // only nUpdateTab
466
43.0k
    {
467
43.0k
        if ( m_pDocument->IsPendingRowHeights( nUpdateTab ) )
468
0
        {
469
0
            AdjustRowHeight( 0, m_pDocument->MaxRow(), nUpdateTab );
470
0
            m_pDocument->UpdatePageBreaks( nUpdateTab );
471
0
            m_pDocument->SetPendingRowHeights( nUpdateTab, false );
472
0
        }
473
43.0k
    }
474
43.0k
    m_pDocument->LockStreamValid( false );
475
43.0k
    m_pDocument->EnableUndo( bIsUndoEnabled );
476
43.0k
}
477
478
void ScDocShell::RefreshPivotTables( const ScRange& rSource )
479
0
{
480
0
    ScDPCollection* pColl = m_pDocument->GetDPCollection();
481
0
    if (!pColl)
482
0
        return;
483
484
0
    ScDBDocFunc aFunc(*this);
485
0
    for (size_t i = 0, n = pColl->GetCount(); i < n; ++i)
486
0
    {
487
0
        ScDPObject& rOld = (*pColl)[i];
488
489
0
        const ScSheetSourceDesc* pSheetDesc = rOld.GetSheetDesc();
490
0
        if (pSheetDesc && pSheetDesc->GetSourceRange().Intersects(rSource))
491
0
            aFunc.UpdatePivotTable(rOld, true, false);
492
0
    }
493
0
}
494
495
static OUString lcl_GetAreaName( ScDocument* pDoc, const ScArea* pArea )
496
0
{
497
0
    ScDBData* pData = pDoc->GetDBAtArea( pArea->nTab, pArea->nColStart, pArea->nRowStart,
498
0
                                                        pArea->nColEnd, pArea->nRowEnd );
499
0
    if (pData)
500
0
        return pData->GetName();
501
502
0
    OUString aName;
503
0
    pDoc->GetName( pArea->nTab, aName );
504
0
    return aName;
505
0
}
506
507
static ScDBData* getUndoData(const ScDBData* pDestData)
508
0
{
509
0
    if (!pDestData)
510
0
        return nullptr;
511
0
    return new ScDBData(*pDestData);
512
0
}
513
514
void ScDocShell::DoConsolidate( const ScConsolidateParam& rParam, bool bRecord )
515
0
{
516
0
    ScConsData aData;
517
518
0
    sal_uInt16 nPos;
519
0
    SCCOL nColSize = 0;
520
0
    SCROW nRowSize = 0;
521
0
    bool bErr = false;
522
0
    for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
523
0
    {
524
0
        ScArea const & rArea = rParam.pDataAreas[nPos];
525
0
        nColSize = std::max( nColSize, SCCOL( rArea.nColEnd - rArea.nColStart + 1 ) );
526
0
        nRowSize = std::max( nRowSize, SCROW( rArea.nRowEnd - rArea.nRowStart + 1 ) );
527
528
                                        // test if source data were moved
529
0
        if (rParam.bReferenceData)
530
0
            if (rArea.nTab == rParam.nTab && rArea.nRowEnd >= rParam.nRow)
531
0
                bErr = true;
532
0
    }
533
534
0
    if (bErr)
535
0
    {
536
0
        std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
537
0
                                                      VclMessageType::Info, VclButtonsType::Ok,
538
0
                                                      ScResId(STR_CONSOLIDATE_ERR1)));
539
0
        xInfoBox->run();
540
0
        return;
541
0
    }
542
543
    //      execute
544
545
0
    weld::WaitObject aWait( GetActiveDialogParent() );
546
0
    ScDocShellModificator aModificator( *this );
547
548
0
    ScRange aOldDest;
549
0
    ScDBData* pDestData = m_pDocument->GetDBAtCursor( rParam.nCol, rParam.nRow, rParam.nTab, ScDBDataPortion::TOP_LEFT );
550
0
    if (pDestData)
551
0
        pDestData->GetArea(aOldDest);
552
553
0
    aData.SetSize( nColSize, nRowSize );
554
0
    aData.SetFlags( rParam.eFunction, rParam.bByCol, rParam.bByRow, rParam.bReferenceData );
555
0
    if ( rParam.bByCol || rParam.bByRow )
556
0
        for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
557
0
        {
558
0
            ScArea const & rArea = rParam.pDataAreas[nPos];
559
0
            aData.AddFields( m_pDocument.get(), rArea.nTab, rArea.nColStart, rArea.nRowStart,
560
0
                                                       rArea.nColEnd, rArea.nRowEnd );
561
0
        }
562
0
    aData.DoneFields();
563
0
    for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
564
0
    {
565
0
        ScArea const & rArea = rParam.pDataAreas[nPos];
566
0
        aData.AddData( m_pDocument.get(), rArea.nTab, rArea.nColStart, rArea.nRowStart,
567
0
                                                 rArea.nColEnd, rArea.nRowEnd );
568
0
        aData.AddName( lcl_GetAreaName(m_pDocument.get(), &rArea) );
569
0
    }
570
571
0
    aData.GetSize( nColSize, nRowSize );
572
0
    if (bRecord && nColSize > 0 && nRowSize > 0)
573
0
    {
574
0
        std::unique_ptr<ScDBData> pUndoData(getUndoData(pDestData));
575
576
0
        SCTAB nDestTab = rParam.nTab;
577
0
        ScArea aDestArea( rParam.nTab, rParam.nCol, rParam.nRow,
578
0
                            rParam.nCol+nColSize-1, rParam.nRow+nRowSize-1 );
579
0
        if (rParam.bByCol) ++aDestArea.nColEnd;
580
0
        if (rParam.bByRow) ++aDestArea.nRowEnd;
581
582
0
        if (rParam.bReferenceData)
583
0
        {
584
0
            SCTAB nTabCount = m_pDocument->GetTableCount();
585
0
            SCROW nInsertCount = aData.GetInsertCount();
586
587
            // old outlines
588
0
            ScOutlineTable* pTable = m_pDocument->GetOutlineTable( nDestTab );
589
0
            std::unique_ptr<ScOutlineTable> pUndoTab(pTable ? new ScOutlineTable( *pTable ) : nullptr);
590
591
0
            ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
592
0
            pUndoDoc->InitUndo( *m_pDocument, 0, nTabCount-1, false, true );
593
594
            // row state
595
0
            m_pDocument->CopyToDocument(0, 0, nDestTab, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nDestTab,
596
0
                                     InsertDeleteFlags::NONE, false, *pUndoDoc);
597
598
            // all formulas
599
0
            m_pDocument->CopyToDocument(0, 0, 0, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nTabCount-1,
600
0
                                     InsertDeleteFlags::FORMULA, false, *pUndoDoc);
601
602
            // complete output rows
603
0
            m_pDocument->CopyToDocument(0, aDestArea.nRowStart, nDestTab,
604
0
                                     m_pDocument->MaxCol(),aDestArea.nRowEnd, nDestTab,
605
0
                                     InsertDeleteFlags::ALL, false, *pUndoDoc);
606
607
            // old output range
608
0
            if (pDestData)
609
0
                m_pDocument->CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, *pUndoDoc);
610
611
0
            GetUndoManager()->AddUndoAction(
612
0
                    std::make_unique<ScUndoConsolidate>( *this, aDestArea, rParam, std::move(pUndoDoc),
613
0
                                            true, nInsertCount, std::move(pUndoTab), std::move(pUndoData) ) );
614
0
        }
615
0
        else
616
0
        {
617
0
            ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
618
0
            pUndoDoc->InitUndo( *m_pDocument, aDestArea.nTab, aDestArea.nTab );
619
620
0
            m_pDocument->CopyToDocument(aDestArea.nColStart, aDestArea.nRowStart, aDestArea.nTab,
621
0
                                     aDestArea.nColEnd, aDestArea.nRowEnd, aDestArea.nTab,
622
0
                                     InsertDeleteFlags::ALL, false, *pUndoDoc);
623
624
            // old output range
625
0
            if (pDestData)
626
0
                m_pDocument->CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, *pUndoDoc);
627
628
0
            GetUndoManager()->AddUndoAction(
629
0
                    std::make_unique<ScUndoConsolidate>( *this, aDestArea, rParam, std::move(pUndoDoc),
630
0
                                            false, 0, nullptr, std::move(pUndoData) ) );
631
0
        }
632
0
    }
633
634
0
    if (pDestData)                                      // delete / adjust destination range
635
0
    {
636
0
        m_pDocument->DeleteAreaTab(aOldDest, InsertDeleteFlags::CONTENTS);
637
0
        pDestData->SetArea( rParam.nTab, rParam.nCol, rParam.nRow,
638
0
                            rParam.nCol + nColSize - 1, rParam.nRow + nRowSize - 1 );
639
0
        pDestData->SetHeader( rParam.bByRow );
640
0
    }
641
642
0
    aData.OutputToDocument( *m_pDocument, rParam.nCol, rParam.nRow, rParam.nTab );
643
644
0
    SCCOL nPaintStartCol = rParam.nCol;
645
0
    SCROW nPaintStartRow = rParam.nRow;
646
0
    SCCOL nPaintEndCol = nPaintStartCol + nColSize - 1;
647
0
    SCROW nPaintEndRow = nPaintStartRow + nRowSize - 1;
648
0
    PaintPartFlags nPaintFlags = PaintPartFlags::Grid;
649
0
    if (rParam.bByCol)
650
0
        ++nPaintEndRow;
651
0
    if (rParam.bByRow)
652
0
        ++nPaintEndCol;
653
0
    if (rParam.bReferenceData)
654
0
    {
655
0
        nPaintStartCol = 0;
656
0
        nPaintEndCol = m_pDocument->MaxCol();
657
0
        nPaintEndRow = m_pDocument->MaxRow();
658
0
        nPaintFlags |= PaintPartFlags::Left | PaintPartFlags::Size;
659
0
    }
660
0
    if (pDestData)
661
0
    {
662
0
        if ( aOldDest.aEnd.Col() > nPaintEndCol )
663
0
            nPaintEndCol = aOldDest.aEnd.Col();
664
0
        if ( aOldDest.aEnd.Row() > nPaintEndRow )
665
0
            nPaintEndRow = aOldDest.aEnd.Row();
666
0
    }
667
0
    PostPaint( nPaintStartCol, nPaintStartRow, rParam.nTab,
668
0
                nPaintEndCol, nPaintEndRow, rParam.nTab, nPaintFlags );
669
0
    aModificator.SetDocumentModified();
670
0
}
671
672
void ScDocShell::UseScenario( SCTAB nTab, const OUString& rName, bool bRecord )
673
0
{
674
0
    if (!m_pDocument->IsScenario(nTab))
675
0
    {
676
0
        SCTAB   nTabCount = m_pDocument->GetTableCount();
677
0
        SCTAB   nSrcTab = SCTAB_MAX;
678
0
        SCTAB   nEndTab = nTab;
679
0
        OUString aCompare;
680
0
        while ( nEndTab+1 < nTabCount && m_pDocument->IsScenario(nEndTab+1) )
681
0
        {
682
0
            ++nEndTab;
683
0
            if (nSrcTab > MAXTAB)           // still searching for the scenario?
684
0
            {
685
0
                m_pDocument->GetName( nEndTab, aCompare );
686
0
                if (aCompare == rName)
687
0
                    nSrcTab = nEndTab;      // found
688
0
            }
689
0
        }
690
0
        if (ValidTab(nSrcTab))
691
0
        {
692
0
            if ( m_pDocument->TestCopyScenario( nSrcTab, nTab ) )          // test cell protection
693
0
            {
694
0
                ScDocShellModificator aModificator( *this );
695
0
                ScMarkData aScenMark(m_pDocument->GetSheetLimits());
696
0
                m_pDocument->MarkScenario( nSrcTab, nTab, aScenMark );
697
0
                const ScRange& aMultiRange = aScenMark.GetMultiMarkArea();
698
0
                SCCOL nStartCol = aMultiRange.aStart.Col();
699
0
                SCROW nStartRow = aMultiRange.aStart.Row();
700
0
                SCCOL nEndCol = aMultiRange.aEnd.Col();
701
0
                SCROW nEndRow = aMultiRange.aEnd.Row();
702
703
0
                if (bRecord)
704
0
                {
705
0
                    ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
706
0
                    pUndoDoc->InitUndo( *m_pDocument, nTab,nEndTab );             // also all scenarios
707
                    //  shown table:
708
0
                    m_pDocument->CopyToDocument(nStartCol, nStartRow, nTab,
709
0
                                             nEndCol, nEndRow, nTab, InsertDeleteFlags::ALL,
710
0
                                             true, *pUndoDoc, &aScenMark);
711
                    //  scenarios
712
0
                    for (SCTAB i=nTab+1; i<=nEndTab; i++)
713
0
                    {
714
0
                        pUndoDoc->SetScenario( i, true );
715
0
                        OUString aComment;
716
0
                        Color  aColor;
717
0
                        ScScenarioFlags nScenFlags;
718
0
                        m_pDocument->GetScenarioData( i, aComment, aColor, nScenFlags );
719
0
                        pUndoDoc->SetScenarioData( i, aComment, aColor, nScenFlags );
720
0
                        bool bActive = m_pDocument->IsActiveScenario( i );
721
0
                        pUndoDoc->SetActiveScenario( i, bActive );
722
                        //  At copy-back scenarios also contents
723
0
                        if ( nScenFlags & ScScenarioFlags::TwoWay )
724
0
                            m_pDocument->CopyToDocument(0, 0, i, m_pDocument->MaxCol(), m_pDocument->MaxRow(), i,
725
0
                                                     InsertDeleteFlags::ALL, false, *pUndoDoc );
726
0
                    }
727
728
0
                    GetUndoManager()->AddUndoAction(
729
0
                        std::make_unique<ScUndoUseScenario>( *this, aScenMark,
730
0
                                        ScArea( nTab,nStartCol,nStartRow,nEndCol,nEndRow ),
731
0
                                        std::move(pUndoDoc), rName ) );
732
0
                }
733
734
0
                m_pDocument->CopyScenario( nSrcTab, nTab );
735
736
0
                sc::SetFormulaDirtyContext aCxt;
737
0
                m_pDocument->SetAllFormulasDirty(aCxt);
738
739
                //  paint all, because the active scenario may be modified in other ranges;
740
                //! only if there are visible frames?
741
0
                PostPaint( 0,0,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid );
742
0
                aModificator.SetDocumentModified();
743
0
            }
744
0
            else
745
0
            {
746
0
                std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
747
0
                                                              VclMessageType::Info, VclButtonsType::Ok,
748
0
                                                              ScResId(STR_PROTECTIONERR)));
749
0
                xInfoBox->run();
750
0
            }
751
0
        }
752
0
        else
753
0
        {
754
0
            std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
755
0
                                                          VclMessageType::Info, VclButtonsType::Ok,
756
0
                                                          ScResId(STR_SCENARIO_NOTFOUND)));
757
0
            xInfoBox->run();
758
0
        }
759
0
    }
760
0
    else
761
0
    {
762
0
        OSL_FAIL( "UseScenario on Scenario-Sheet" );
763
0
    }
764
0
}
765
766
void ScDocShell::ModifyScenario( SCTAB nTab, const OUString& rName, const OUString& rComment,
767
                                    const Color& rColor, ScScenarioFlags nFlags )
768
80
{
769
    //  Undo
770
80
    OUString aOldName;
771
80
    m_pDocument->GetName( nTab, aOldName );
772
80
    OUString aOldComment;
773
80
    Color aOldColor;
774
80
    ScScenarioFlags nOldFlags;
775
80
    m_pDocument->GetScenarioData( nTab, aOldComment, aOldColor, nOldFlags );
776
80
    GetUndoManager()->AddUndoAction(
777
80
        std::make_unique<ScUndoScenarioFlags>(*this, nTab,
778
80
                aOldName, rName, aOldComment, rComment,
779
80
                aOldColor, rColor, nOldFlags, nFlags) );
780
781
    //  execute
782
80
    ScDocShellModificator aModificator( *this );
783
80
    m_pDocument->RenameTab( nTab, rName );
784
80
    m_pDocument->SetScenarioData( nTab, rComment, rColor, nFlags );
785
80
    PostPaintGridAll();
786
80
    aModificator.SetDocumentModified();
787
788
80
    if (aOldName != rName)
789
0
        SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
790
791
80
    SfxBindings* pBindings = GetViewBindings();
792
80
    if (pBindings)
793
0
        pBindings->Invalidate( SID_SELECT_SCENARIO );
794
80
}
795
796
SCTAB ScDocShell::MakeScenario( SCTAB nTab, const OUString& rName, const OUString& rComment,
797
                                    const Color& rColor, ScScenarioFlags nFlags,
798
                                    ScMarkData& rMark, bool bRecord )
799
20
{
800
20
    rMark.MarkToMulti();
801
20
    if (rMark.IsMultiMarked())
802
20
    {
803
20
        SCTAB nNewTab = nTab + 1;
804
30
        while (m_pDocument->IsScenario(nNewTab))
805
10
            ++nNewTab;
806
807
20
        bool bCopyAll = ( (nFlags & ScScenarioFlags::CopyAll) != ScScenarioFlags::NONE );
808
20
        const ScMarkData* pCopyMark = nullptr;
809
20
        if (!bCopyAll)
810
20
            pCopyMark = &rMark;
811
812
20
        ScDocShellModificator aModificator( *this );
813
814
20
        if (bRecord)
815
20
            m_pDocument->BeginDrawUndo();      // drawing layer must do its own undo actions
816
817
20
        if (m_pDocument->CopyTab( nTab, nNewTab, pCopyMark ))
818
20
        {
819
20
            if (bRecord)
820
20
            {
821
20
                GetUndoManager()->AddUndoAction(
822
20
                        std::make_unique<ScUndoMakeScenario>( *this, nTab, nNewTab,
823
20
                                                rName, rComment, rColor, nFlags, rMark ));
824
20
            }
825
826
20
            m_pDocument->RenameTab( nNewTab, rName);
827
20
            m_pDocument->SetScenario( nNewTab, true );
828
20
            m_pDocument->SetScenarioData( nNewTab, rComment, rColor, nFlags );
829
830
20
            ScMarkData aDestMark = rMark;
831
20
            aDestMark.SelectOneTable( nNewTab );
832
833
            //!     test for filter / buttons / merging
834
835
20
            ScPatternAttr aProtPattern(m_pDocument->getCellAttributeHelper());
836
20
            aProtPattern.ItemSetPut(ScProtectionAttr(true));
837
20
            m_pDocument->ApplyPatternAreaTab( 0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(), nNewTab, aProtPattern );
838
839
20
            ScPatternAttr aPattern(m_pDocument->getCellAttributeHelper());
840
20
            aPattern.ItemSetPut(ScMergeFlagAttr(ScMF::Scenario));
841
20
            aPattern.ItemSetPut(ScProtectionAttr(true));
842
20
            m_pDocument->ApplySelectionPattern( aPattern, aDestMark );
843
844
20
            if (!bCopyAll)
845
20
                m_pDocument->SetVisible( nNewTab, false );
846
847
            //  this is the active scenario, then
848
20
            m_pDocument->CopyScenario( nNewTab, nTab, true );  // sal_True - don't copy anything from scenario
849
850
20
            if (nFlags & ScScenarioFlags::ShowFrame)
851
20
                PostPaint( 0,0,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid );  // paint frames
852
20
            PostPaintExtras();                                          // table tab
853
20
            aModificator.SetDocumentModified();
854
855
            // A scenario tab is like a hidden sheet, broadcasting also
856
            // notifies ScTabViewShell to add an ScViewData::maTabData entry.
857
20
            Broadcast( ScTablesHint( SC_TAB_INSERTED, nNewTab ));
858
20
            SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
859
860
20
            return nNewTab;
861
20
        }
862
20
    }
863
0
    return nTab;
864
20
}
865
866
bool ScDocShell::TransferTab( ScDocShell& rSrcDocShell, SCTAB nSrcPos,
867
                                SCTAB nDestPos, bool bInsertNew,
868
                                bool bNotifyAndPaint )
869
0
{
870
0
    ScDocument& rSrcDoc = rSrcDocShell.GetDocument();
871
872
    // set the transferred area to the copyparam to make adjusting formulas possible
873
0
    ScClipParam aParam;
874
0
    ScRange aRange(0, 0, nSrcPos, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nSrcPos);
875
0
    aParam.maRanges.push_back(aRange);
876
0
    rSrcDoc.SetClipParam(aParam);
877
878
0
    bool bValid =  m_pDocument->TransferTab( rSrcDoc, nSrcPos, nDestPos,
879
0
                    bInsertNew );       // no insert
880
881
    // TransferTab doesn't copy drawing objects with bInsertNew=FALSE
882
0
    if ( bValid && !bInsertNew)
883
0
        m_pDocument->TransferDrawPage( rSrcDoc, nSrcPos, nDestPos );
884
885
0
    if(bValid && rSrcDoc.IsScenario( nSrcPos ))
886
0
    {
887
0
        OUString aComment;
888
0
        Color  aColor;
889
0
        ScScenarioFlags nFlags;
890
891
0
        rSrcDoc.GetScenarioData( nSrcPos, aComment,aColor, nFlags);
892
0
        m_pDocument->SetScenario(nDestPos,true);
893
0
        m_pDocument->SetScenarioData(nDestPos,aComment,aColor,nFlags);
894
0
        bool bActive = rSrcDoc.IsActiveScenario(nSrcPos);
895
0
        m_pDocument->SetActiveScenario(nDestPos, bActive );
896
897
0
        bool bVisible = rSrcDoc.IsVisible(nSrcPos);
898
0
        m_pDocument->SetVisible(nDestPos,bVisible );
899
900
0
    }
901
902
0
    if ( bValid && rSrcDoc.IsTabProtected( nSrcPos ) )
903
0
        m_pDocument->SetTabProtection(nDestPos, rSrcDoc.GetTabProtection(nSrcPos));
904
0
    if ( bNotifyAndPaint )
905
0
    {
906
0
            Broadcast( ScTablesHint( SC_TAB_INSERTED, nDestPos ) );
907
0
            PostPaintExtras();
908
0
            PostPaintGridAll();
909
0
    }
910
0
    return bValid;
911
0
}
912
913
bool ScDocShell::MoveTable( SCTAB nSrcTab, SCTAB nDestTab, bool bCopy, bool bRecord )
914
0
{
915
0
    ScDocShellModificator aModificator( *this );
916
917
    // #i92477# be consistent with ScDocFunc::InsertTable: any index past the last sheet means "append"
918
    // #i101139# nDestTab must be the target position, not APPEND (for CopyTabProtection etc.)
919
0
    if ( nDestTab >= m_pDocument->GetTableCount() )
920
0
        nDestTab = m_pDocument->GetTableCount();
921
922
0
    if (bCopy)
923
0
    {
924
0
        if (bRecord)
925
0
            m_pDocument->BeginDrawUndo();          // drawing layer must do its own undo actions
926
927
0
        OUString sSrcCodeName;
928
0
        m_pDocument->GetCodeName( nSrcTab, sSrcCodeName );
929
0
        if (!m_pDocument->CopyTab( nSrcTab, nDestTab ))
930
0
        {
931
            //! EndDrawUndo?
932
0
            return false;
933
0
        }
934
0
        else
935
0
        {
936
0
            SCTAB nAdjSource = nSrcTab;
937
0
            if ( nDestTab <= nSrcTab )
938
0
                ++nAdjSource;               // new position of source table after CopyTab
939
940
0
            if ( m_pDocument->IsTabProtected( nAdjSource ) )
941
0
                m_pDocument->CopyTabProtection(nAdjSource, nDestTab);
942
943
0
            if (bRecord)
944
0
            {
945
0
                std::unique_ptr<std::vector<SCTAB>> pSrcList(new std::vector<SCTAB>(1, nSrcTab));
946
0
                std::unique_ptr<std::vector<SCTAB>> pDestList(new std::vector<SCTAB>(1, nDestTab));
947
0
                GetUndoManager()->AddUndoAction(
948
0
                        std::make_unique<ScUndoCopyTab>(*this, std::move(pSrcList), std::move(pDestList)));
949
0
            }
950
951
0
            bool bVbaEnabled = m_pDocument->IsInVBAMode();
952
0
            if ( bVbaEnabled )
953
0
            {
954
0
                OUString aLibName( u"Standard"_ustr );
955
0
                Reference< XLibraryContainer > xLibContainer = GetBasicContainer();
956
0
                Reference< XVBACompatibility > xVBACompat( xLibContainer, UNO_QUERY );
957
958
0
                if ( xVBACompat.is() )
959
0
                {
960
0
                    aLibName = xVBACompat->getProjectName();
961
0
                }
962
963
0
                SCTAB nTabToUse = nDestTab;
964
0
                if ( nDestTab == SC_TAB_APPEND )
965
0
                    nTabToUse = m_pDocument->GetMaxTableNumber() - 1;
966
0
                OUString sSource;
967
0
                try
968
0
                {
969
0
                    Reference< XNameContainer > xLib;
970
0
                    if( xLibContainer.is() )
971
0
                    {
972
0
                        css::uno::Any aLibAny = xLibContainer->getByName( aLibName );
973
0
                        aLibAny >>= xLib;
974
0
                    }
975
0
                    if( xLib.is() )
976
0
                    {
977
0
                        xLib->getByName( sSrcCodeName ) >>= sSource;
978
0
                    }
979
0
                }
980
0
                catch ( const css::uno::Exception& )
981
0
                {
982
0
                }
983
0
                VBA_InsertModule( *m_pDocument, nTabToUse, sSource );
984
0
            }
985
0
        }
986
0
        Broadcast( ScTablesHint( SC_TAB_COPIED, nSrcTab, nDestTab ) );
987
0
    }
988
0
    else
989
0
    {
990
0
        if ( m_pDocument->GetChangeTrack() )
991
0
            return false;
992
993
0
        if ( nSrcTab == nDestTab )
994
0
        {
995
            //! allow only for api calls?
996
0
            return true;    // nothing to do, but valid
997
0
        }
998
999
0
        std::optional<ScProgress> pProgress(std::in_place, this, ScResId(STR_UNDO_MOVE_TAB),
1000
0
                                                m_pDocument->GetCodeCount(), true);
1001
0
        bool bDone = m_pDocument->MoveTab( nSrcTab, nDestTab, &*pProgress );
1002
0
        pProgress.reset();
1003
0
        if (!bDone)
1004
0
        {
1005
0
            return false;
1006
0
        }
1007
0
        else if (bRecord)
1008
0
        {
1009
0
            std::unique_ptr<std::vector<SCTAB>> pSrcList(new std::vector<SCTAB>(1, nSrcTab));
1010
0
            std::unique_ptr<std::vector<SCTAB>> pDestList(new std::vector<SCTAB>(1, nDestTab));
1011
0
            GetUndoManager()->AddUndoAction(
1012
0
                    std::make_unique<ScUndoMoveTab>(*this, std::move(pSrcList), std::move(pDestList)));
1013
0
        }
1014
1015
0
        Broadcast( ScTablesHint( SC_TAB_MOVED, nSrcTab, nDestTab ) );
1016
0
    }
1017
1018
0
    PostPaintGridAll();
1019
0
    PostPaintExtras();
1020
0
    aModificator.SetDocumentModified();
1021
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
1022
1023
0
    return true;
1024
0
}
1025
1026
IMPL_LINK( ScDocShell, RefreshDBDataHdl, Timer*, pRefreshTimer, void )
1027
0
{
1028
0
    ScDBDocFunc aFunc(*this);
1029
1030
0
    ScDBData* pDBData = static_cast<ScDBData*>(pRefreshTimer);
1031
0
    ScImportParam aImportParam;
1032
0
    pDBData->GetImportParam( aImportParam );
1033
0
    if (aImportParam.bImport && !pDBData->HasImportSelection())
1034
0
    {
1035
0
        ScRange aRange;
1036
0
        pDBData->GetArea( aRange );
1037
0
        bool bContinue = aFunc.DoImport( aRange.aStart.Tab(), aImportParam, nullptr ); //! Api-Flag as parameter
1038
        // internal operations (sort, query, subtotal) only if no error
1039
0
        if (bContinue)
1040
0
        {
1041
0
            aFunc.RepeatDB( pDBData->GetName(), true, true );
1042
0
            RefreshPivotTables(aRange);
1043
0
        }
1044
0
    }
1045
0
}
1046
1047
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */