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/docshell/dbdocfun.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 <sfx2/app.hxx>
21
#include <vcl/svapp.hxx>
22
#include <vcl/weld/MessageDialog.hxx>
23
#include <vcl/weld/weld.hxx>
24
#include <svx/dataaccessdescriptor.hxx>
25
#include <svx/svdpage.hxx>
26
#include <svx/svdoole2.hxx>
27
#include <com/sun/star/sdb/CommandType.hpp>
28
#include <unotools/charclass.hxx>
29
#include <comphelper/lok.hxx>
30
#include <osl/diagnose.h>
31
32
#include <dbdocfun.hxx>
33
#include <dbdata.hxx>
34
#include <undodat.hxx>
35
#include <docsh.hxx>
36
#include <docfunc.hxx>
37
#include <globstr.hrc>
38
#include <scresid.hxx>
39
#include <globalnames.hxx>
40
#include <tabvwsh.hxx>
41
#include <patattr.hxx>
42
#include <rangenam.hxx>
43
#include <olinetab.hxx>
44
#include <dpobject.hxx>
45
#include <dpsave.hxx>
46
#include <dociter.hxx>
47
#include <editable.hxx>
48
#include <attrib.hxx>
49
#include <drwlayer.hxx>
50
#include <dpshttab.hxx>
51
#include <hints.hxx>
52
#include <queryentry.hxx>
53
#include <markdata.hxx>
54
#include <progress.hxx>
55
#include <undosort.hxx>
56
#include <inputopt.hxx>
57
#include <scmod.hxx>
58
59
#include <chartlis.hxx>
60
#include <ChartTools.hxx>
61
#include <SheetViewOperationsTester.hxx>
62
63
#include <memory>
64
65
using namespace ::com::sun::star;
66
67
bool ScDBDocFunc::CheckSheetViewProtection(sc::Operation eOperation)
68
310
{
69
310
    sc::SheetViewOperationsTester aSheetViewTester(ScDocShell::GetViewData());
70
310
    return aSheetViewTester.check(eOperation);
71
310
}
72
73
bool ScDBDocFunc::AddDBTable(const OUString& rName, const ScRange& rRange, bool bHeader,
74
                             bool bRecord, bool bApi, const OUString& rStyleName)
75
0
{
76
0
    ScDocShellModificator aModificator(rDocShell);
77
78
0
    ScDocument& rDoc = rDocShell.GetDocument();
79
0
    ScDBCollection* pDocColl = rDoc.GetDBCollection();
80
0
    if (bRecord && !rDoc.IsUndoEnabled())
81
0
        bRecord = false;
82
83
0
    if (rStyleName.isEmpty())
84
0
    {
85
0
        if (!bApi)
86
0
            rDocShell.ErrorMessage(STR_TABLE_ERR_ADD);
87
0
        return false;
88
0
    }
89
90
0
    std::unique_ptr<ScDBCollection> pUndoColl;
91
0
    if (bRecord)
92
0
        pUndoColl.reset(new ScDBCollection(*pDocColl));
93
94
0
    std::unique_ptr<ScDBData> pNew(new ScDBData(rName, rRange.aStart.Tab(), rRange.aStart.Col(),
95
0
                                                rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(),
96
0
                                                true, bHeader, false, u""_ustr, rStyleName));
97
0
    if (pNew)
98
0
    {
99
0
        pNew->SetAutoFilter(true);
100
0
        rDoc.ApplyFlagsTab(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(),
101
0
                           rRange.aStart.Row(), rRange.aStart.Tab(), ScMF::Auto);
102
0
    }
103
104
0
    bool bCompile = !rDoc.IsImportingXML();
105
0
    if (bCompile)
106
0
        rDoc.PreprocessDBDataUpdate();
107
108
0
    bool bOk = pDocColl->getNamedDBs().insert(std::move(pNew));
109
0
    if (bCompile)
110
0
        rDoc.CompileHybridFormula();
111
112
0
    if (!bOk && !bApi)
113
0
    {
114
0
        rDocShell.ErrorMessage(STR_TABLE_ERR_ADD);
115
0
        return false;
116
0
    }
117
118
0
    rDocShell.PostPaint(rRange, PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size);
119
120
0
    if (bRecord)
121
0
    {
122
0
        rDocShell.GetUndoManager()->AddUndoAction(
123
0
            std::make_unique<ScUndoDBTable>(rDocShell, rName, true/*bInsert*/, std::move(pUndoColl),
124
0
                                           std::make_unique<ScDBCollection>(*pDocColl)));
125
0
    }
126
127
0
    aModificator.SetDocumentModified();
128
0
    SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScDbAreasChanged));
129
0
    return true;
130
0
}
131
132
bool ScDBDocFunc::DeleteDBTable(const ScDBData* pDBObj, bool bRecord, bool bApi)
133
0
{
134
0
    bool bDone = false;
135
0
    ScDocument& rDoc = rDocShell.GetDocument();
136
0
    ScDBCollection* pDocColl = rDoc.GetDBCollection();
137
0
    if (bRecord && !rDoc.IsUndoEnabled())
138
0
        bRecord = false;
139
140
0
    ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
141
0
    auto const iter = rDBs.findByPointer(pDBObj);
142
0
    if (iter != rDBs.end())
143
0
    {
144
0
        ScDocShellModificator aModificator(rDocShell);
145
0
        std::unique_ptr<ScDBCollection> pUndoColl;
146
0
        if (bRecord)
147
0
            pUndoColl.reset(new ScDBCollection(*pDocColl));
148
149
0
        OUString aTableName = iter->get()->GetName();
150
0
        ScRange aRange;
151
0
        iter->get()->GetArea(aRange);
152
153
0
        rDoc.PreprocessDBDataUpdate();
154
0
        rDBs.erase(iter);
155
0
        rDoc.CompileHybridFormula();
156
157
0
        if (aRange.IsValid())
158
0
        {
159
0
            rDoc.RemoveFlagsTab(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(),
160
0
                                aRange.aStart.Row(), aRange.aStart.Tab(), ScMF::Auto);
161
0
            rDocShell.PostPaint(aRange, PaintPartFlags::Grid | PaintPartFlags::Left
162
0
                                            | PaintPartFlags::Top | PaintPartFlags::Size);
163
0
        }
164
165
0
        if (bRecord)
166
0
        {
167
0
            rDocShell.GetUndoManager()->AddUndoAction(
168
0
                std::make_unique<ScUndoDBTable>(rDocShell, aTableName, false/*bInsert*/, std::move(pUndoColl),
169
0
                                                std::make_unique<ScDBCollection>(*pDocColl)));
170
0
        }
171
172
0
        aModificator.SetDocumentModified();
173
0
        SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScDbAreasChanged));
174
0
        bDone = true;
175
0
    }
176
0
    else if (!bApi)
177
0
    {
178
0
        rDocShell.ErrorMessage(STR_TABLE_ERR_DEL);
179
0
    }
180
181
0
    return bDone;
182
0
}
183
184
bool ScDBDocFunc::AddDBRange( const OUString& rName, const ScRange& rRange )
185
232
{
186
187
232
    ScDocShellModificator aModificator( rDocShell );
188
189
232
    ScDocument& rDoc = rDocShell.GetDocument();
190
232
    ScDBCollection* pDocColl = rDoc.GetDBCollection();
191
232
    bool bUndo (rDoc.IsUndoEnabled());
192
193
232
    std::unique_ptr<ScDBCollection> pUndoColl;
194
232
    if (bUndo)
195
0
        pUndoColl.reset( new ScDBCollection( *pDocColl ) );
196
197
232
    std::unique_ptr<ScDBData> pNew(new ScDBData( rName, rRange.aStart.Tab(),
198
232
                                    rRange.aStart.Col(), rRange.aStart.Row(),
199
232
                                    rRange.aEnd.Col(), rRange.aEnd.Row() ));
200
201
    // #i55926# While loading XML, formula cells only have a single string token,
202
    // so CompileDBFormula would never find any name (index) tokens, and would
203
    // unnecessarily loop through all cells.
204
232
    bool bCompile = !rDoc.IsImportingXML();
205
232
    bool bOk;
206
232
    if ( bCompile )
207
232
        rDoc.PreprocessDBDataUpdate();
208
232
    if ( rName == STR_DB_LOCAL_NONAME )
209
0
    {
210
0
        rDoc.SetAnonymousDBData(rRange.aStart.Tab(), std::move(pNew));
211
0
        bOk = true;
212
0
    }
213
232
    else
214
232
    {
215
232
        bOk = pDocColl->getNamedDBs().insert(std::move(pNew));
216
232
    }
217
232
    if ( bCompile )
218
232
        rDoc.CompileHybridFormula();
219
220
232
    if (!bOk)
221
0
    {
222
0
        return false;
223
0
    }
224
225
232
    if (bUndo)
226
0
    {
227
0
        rDocShell.GetUndoManager()->AddUndoAction(
228
0
                        std::make_unique<ScUndoDBData>( rDocShell, rName, std::move(pUndoColl),
229
0
                            rName, std::make_unique<ScDBCollection>( *pDocColl ) ) );
230
0
    }
231
232
232
    aModificator.SetDocumentModified();
233
232
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
234
232
    return true;
235
232
}
236
237
bool ScDBDocFunc::DeleteDBRange(const OUString& rName)
238
0
{
239
0
    bool bDone = false;
240
0
    ScDocument& rDoc = rDocShell.GetDocument();
241
0
    ScDBCollection* pDocColl = rDoc.GetDBCollection();
242
0
    bool bUndo = rDoc.IsUndoEnabled();
243
244
0
    ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
245
0
    auto const iter = rDBs.findByUpperName2(ScGlobal::getCharClass().uppercase(rName));
246
0
    if (iter != rDBs.end())
247
0
    {
248
0
        ScDocShellModificator aModificator( rDocShell );
249
250
0
        std::unique_ptr<ScDBCollection> pUndoColl;
251
0
        if (bUndo)
252
0
            pUndoColl.reset( new ScDBCollection( *pDocColl ) );
253
254
0
        ScRange aRange;
255
0
        iter->get()->GetArea(aRange);
256
257
0
        rDoc.PreprocessDBDataUpdate();
258
0
        rDBs.erase(iter);
259
0
        rDoc.CompileHybridFormula();
260
261
0
        if (bUndo)
262
0
        {
263
0
            rDocShell.GetUndoManager()->AddUndoAction(
264
0
                            std::make_unique<ScUndoDBData>( rDocShell, rName, std::move(pUndoColl),
265
0
                                rName, std::make_unique<ScDBCollection>( *pDocColl ) ) );
266
0
        }
267
268
0
        aModificator.SetDocumentModified();
269
0
        SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
270
0
        bDone = true;
271
0
    }
272
273
0
    return bDone;
274
0
}
275
276
bool ScDBDocFunc::RenameDBRange( const OUString& rOld, const OUString& rNew )
277
0
{
278
0
    bool bDone = false;
279
0
    ScDocument& rDoc = rDocShell.GetDocument();
280
0
    ScDBCollection* pDocColl = rDoc.GetDBCollection();
281
0
    bool bUndo = rDoc.IsUndoEnabled();
282
0
    ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
283
0
    auto const iterOld = rDBs.findByUpperName2(ScGlobal::getCharClass().uppercase(rOld));
284
0
    const ScDBData* pNew = rDBs.findByUpperName(ScGlobal::getCharClass().uppercase(rNew));
285
0
    if (iterOld != rDBs.end() && !pNew)
286
0
    {
287
0
        ScDocShellModificator aModificator( rDocShell );
288
289
0
        std::unique_ptr<ScDBData> pNewData(new ScDBData(rNew, **iterOld));
290
0
        OUString aUndoName = rOld;
291
0
        std::unique_ptr<ScDBCollection> pUndoColl( new ScDBCollection( *pDocColl ) );
292
293
0
        rDoc.PreprocessDBDataUpdate();
294
0
        rDBs.erase(iterOld);
295
0
        bool bInserted = rDBs.insert(std::move(pNewData));
296
0
        if (!bInserted)                             // error -> restore old state
297
0
        {
298
0
            rDoc.SetDBCollection(std::move(pUndoColl));       // belongs to the document then
299
0
        }
300
301
0
        rDoc.CompileHybridFormula();
302
303
0
        if (bInserted)                              // insertion worked
304
0
        {
305
0
            if (bUndo)
306
0
            {
307
0
                rDocShell.GetUndoManager()->AddUndoAction(
308
0
                                std::make_unique<ScUndoDBData>( rDocShell, aUndoName, std::move(pUndoColl),
309
0
                                    rNew, std::make_unique<ScDBCollection>( *pDocColl ) ) );
310
0
            }
311
0
            else
312
0
                pUndoColl.reset();
313
314
0
            aModificator.SetDocumentModified();
315
0
            SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
316
0
            bDone = true;
317
0
        }
318
0
    }
319
320
0
    return bDone;
321
0
}
322
323
void ScDBDocFunc::ModifyDBData( const ScDBData& rNewData )
324
2.95k
{
325
2.95k
    ScDocument& rDoc = rDocShell.GetDocument();
326
2.95k
    ScDBCollection* pDocColl = rDoc.GetDBCollection();
327
2.95k
    bool bUndo = rDoc.IsUndoEnabled();
328
329
2.95k
    ScDBData* pData = nullptr;
330
2.95k
    if (rNewData.GetName() == STR_DB_LOCAL_NONAME)
331
746
    {
332
746
        ScRange aRange;
333
746
        rNewData.GetArea(aRange);
334
746
        SCTAB nTab = aRange.aStart.Tab();
335
746
        pData = rDoc.GetAnonymousDBData(nTab);
336
746
    }
337
2.21k
    else
338
2.21k
        pData = pDocColl->getNamedDBs().findByUpperName(rNewData.GetUpperName());
339
340
2.95k
    if (!pData)
341
0
        return;
342
343
2.95k
    ScDocShellModificator aModificator( rDocShell );
344
2.95k
    ScRange aOldRange, aNewRange;
345
2.95k
    pData->GetArea(aOldRange);
346
2.95k
    rNewData.GetArea(aNewRange);
347
2.95k
    bool bAreaChanged = ( aOldRange != aNewRange );     // then a recompilation is needed
348
2.95k
    bool bOldAutoFilter = pData->HasAutoFilter();
349
2.95k
    bool bNewAutoFilter = rNewData.HasAutoFilter();
350
351
2.95k
    std::unique_ptr<ScDBCollection> pUndoColl;
352
2.95k
    OUString sOldName;
353
2.95k
    if (bUndo)
354
0
    {
355
0
        pUndoColl.reset( new ScDBCollection( *pDocColl ) );
356
0
        sOldName = pData->GetName();
357
0
    }
358
359
2.95k
    *pData = rNewData;
360
2.95k
    if (bAreaChanged || bOldAutoFilter != bNewAutoFilter) {
361
444
        if (bAreaChanged)
362
0
            rDoc.CompileDBFormula();
363
444
        if (bOldAutoFilter && !bNewAutoFilter)
364
0
        {
365
0
            rDoc.RemoveFlagsTab(aOldRange.aStart.Col(), aOldRange.aStart.Row(), aOldRange.aEnd.Col(), aOldRange.aEnd.Row(), aOldRange.aStart.Tab(), ScMF::Auto);
366
0
        }
367
444
        else if (bOldAutoFilter && bNewAutoFilter)
368
0
        {
369
0
            rDoc.RemoveFlagsTab(aOldRange.aStart.Col(), aOldRange.aStart.Row(), aOldRange.aEnd.Col(), aOldRange.aEnd.Row(), aOldRange.aStart.Tab(), ScMF::Auto);
370
0
            rDoc.ApplyFlagsTab(aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aEnd.Col(), aNewRange.aStart.Row(), aNewRange.aStart.Tab(), ScMF::Auto);
371
0
        }
372
444
        else if (!bOldAutoFilter && bNewAutoFilter)
373
444
        {
374
444
            rDoc.ApplyFlagsTab(aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aEnd.Col(), aNewRange.aStart.Row(), aNewRange.aStart.Tab(), ScMF::Auto);
375
444
        }
376
444
    }
377
378
2.95k
    rDocShell.PostPaint(ScRange(0, 0, aOldRange.aStart.Tab(), rDoc.MaxCol(), rDoc.MaxRow(), aOldRange.aEnd.Tab()),
379
2.95k
        PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size);
380
381
2.95k
    if (bUndo)
382
0
    {
383
0
        rDocShell.GetUndoManager()->AddUndoAction(
384
0
                        std::make_unique<ScUndoDBData>( rDocShell, sOldName, std::move(pUndoColl),
385
0
                            rNewData.GetName(), std::make_unique<ScDBCollection>( *pDocColl ) ) );
386
0
    }
387
388
2.95k
    aModificator.SetDocumentModified();
389
2.95k
}
390
391
void ScDBDocFunc::ModifyAllDBData( const ScDBCollection& rNewColl, const std::vector<ScRange>& rDelAreaList )
392
0
{
393
0
    ScDocShellModificator aModificator(rDocShell);
394
0
    ScDocument& rDoc = rDocShell.GetDocument();
395
0
    ScDBCollection* pOldColl = rDoc.GetDBCollection();
396
0
    std::unique_ptr<ScDBCollection> pUndoColl;
397
0
    bool bRecord = rDoc.IsUndoEnabled();
398
399
0
    for (const auto& rDelArea : rDelAreaList)
400
0
    {
401
        // unregistering target in SBA no longer necessary
402
0
        const ScAddress& rStart = rDelArea.aStart;
403
0
        const ScAddress& rEnd   = rDelArea.aEnd;
404
0
        rDocShell.DBAreaDeleted(
405
0
            rStart.Tab(), rStart.Col(), rStart.Row(), rEnd.Col());
406
0
    }
407
408
0
    if (bRecord)
409
0
        pUndoColl.reset( new ScDBCollection( *pOldColl ) );
410
411
    //  register target in SBA no longer necessary
412
413
0
    rDoc.PreprocessDBDataUpdate();
414
0
    rDoc.SetDBCollection( std::unique_ptr<ScDBCollection>(new ScDBCollection( rNewColl )) );
415
0
    rDoc.CompileHybridFormula();
416
0
    pOldColl = nullptr;
417
0
    rDocShell.PostPaint(ScRange(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB), PaintPartFlags::Grid);
418
0
    aModificator.SetDocumentModified();
419
0
    SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
420
421
0
    if (bRecord)
422
0
    {
423
0
        rDocShell.GetUndoManager()->AddUndoAction(
424
0
            std::make_unique<ScUndoDBData>(rDocShell, u""_ustr, std::move(pUndoColl),
425
0
                 u""_ustr, std::make_unique<ScDBCollection>(rNewColl)));
426
0
    }
427
0
}
428
429
bool ScDBDocFunc::RepeatDB( const OUString& rDBName, bool bApi, bool bIsUnnamed, SCTAB aTab )
430
0
{
431
    //! use also for ScDBFunc::RepeatDB !
432
433
0
    bool bDone = false;
434
0
    ScDocument& rDoc = rDocShell.GetDocument();
435
0
    bool bRecord = true;
436
0
    if (!rDoc.IsUndoEnabled())
437
0
        bRecord = false;
438
0
    ScDBData* pDBData = nullptr;
439
0
    if (bIsUnnamed)
440
0
    {
441
0
        pDBData = rDoc.GetAnonymousDBData( aTab );
442
0
    }
443
0
    else
444
0
    {
445
0
        ScDBCollection* pColl = rDoc.GetDBCollection();
446
0
        if (pColl)
447
0
            pDBData = pColl->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName));
448
0
    }
449
450
0
    if ( pDBData )
451
0
    {
452
0
        ScQueryParam aQueryParam;
453
0
        pDBData->GetQueryParam( aQueryParam );
454
0
        bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
455
456
0
        ScSortParam aSortParam;
457
0
        pDBData->GetSortParam( aSortParam );
458
0
        bool bSort = aSortParam.maKeyState[0].bDoSort;
459
460
0
        ScSubTotalParam aSubTotalParam;
461
0
        pDBData->GetSubTotalParam( aSubTotalParam );
462
0
        bool bSubTotal = aSubTotalParam.aGroups[0].bActive && !aSubTotalParam.bRemoveOnly;
463
464
0
        if ( bQuery || bSort || bSubTotal )
465
0
        {
466
0
            bool bQuerySize = false;
467
0
            ScRange aOldQuery;
468
0
            ScRange aNewQuery;
469
0
            if (bQuery && !aQueryParam.bInplace)
470
0
            {
471
0
                ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
472
0
                                                        aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
473
0
                if (pDest && pDest->IsDoSize())
474
0
                {
475
0
                    pDest->GetArea( aOldQuery );
476
0
                    bQuerySize = true;
477
0
                }
478
0
            }
479
480
0
            SCTAB nTab;
481
0
            SCCOL nStartCol;
482
0
            SCROW nStartRow;
483
0
            SCCOL nEndCol;
484
0
            SCROW nEndRow;
485
0
            pDBData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
486
487
            //!     Undo needed data only ?
488
489
0
            ScDocumentUniquePtr pUndoDoc;
490
0
            std::unique_ptr<ScOutlineTable> pUndoTab;
491
0
            std::unique_ptr<ScRangeName> pUndoRange;
492
0
            std::unique_ptr<ScDBCollection> pUndoDB;
493
494
0
            if (bRecord)
495
0
            {
496
0
                SCTAB nTabCount = rDoc.GetTableCount();
497
0
                pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
498
0
                ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
499
0
                if (pTable)
500
0
                {
501
0
                    pUndoTab.reset(new ScOutlineTable( *pTable ));
502
503
                    // column/row state
504
0
                    SCCOLROW nOutStartCol, nOutEndCol;
505
0
                    SCCOLROW nOutStartRow, nOutEndRow;
506
0
                    pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
507
0
                    pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
508
509
0
                    pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
510
0
                    rDoc.CopyToDocument(static_cast<SCCOL>(nOutStartCol), 0,
511
0
                                        nTab, static_cast<SCCOL>(nOutEndCol), rDoc.MaxRow(), nTab,
512
0
                                        InsertDeleteFlags::NONE, false, *pUndoDoc);
513
0
                    rDoc.CopyToDocument(0, static_cast<SCROW>(nOutStartRow),
514
0
                                        nTab, rDoc.MaxCol(), static_cast<SCROW>(nOutEndRow), nTab,
515
0
                                        InsertDeleteFlags::NONE, false, *pUndoDoc);
516
0
                }
517
0
                else
518
0
                    pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
519
520
                //  secure data range - incl. filtering result
521
0
                rDoc.CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::ALL, false, *pUndoDoc);
522
523
                //  all formulas because of references
524
0
                rDoc.CopyToDocument(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), nTabCount-1, InsertDeleteFlags::FORMULA, false, *pUndoDoc);
525
526
                //  ranges of DB and other
527
0
                ScRangeName* pDocRange = rDoc.GetRangeName();
528
0
                if (!pDocRange->empty())
529
0
                    pUndoRange.reset(new ScRangeName( *pDocRange ));
530
0
                ScDBCollection* pDocDB = rDoc.GetDBCollection();
531
0
                if (!pDocDB->empty())
532
0
                    pUndoDB.reset(new ScDBCollection( *pDocDB ));
533
0
            }
534
535
0
            if (bSort && bSubTotal)
536
0
            {
537
                //  sort without SubTotals
538
539
0
                aSubTotalParam.bRemoveOnly = true;      // will be reset again further down
540
0
                DoSubTotals( nTab, aSubTotalParam, false, bApi );
541
0
            }
542
543
0
            if (bSort)
544
0
            {
545
0
                pDBData->GetSortParam( aSortParam );            // range may have changed
546
0
                (void)Sort( nTab, aSortParam, false, false, bApi );
547
0
            }
548
0
            if (bQuery)
549
0
            {
550
0
                pDBData->GetQueryParam( aQueryParam );          // range may have changed
551
0
                ScRange aAdvSource;
552
0
                if (pDBData->GetAdvancedQuerySource(aAdvSource))
553
0
                    Query( nTab, aQueryParam, &aAdvSource, false, bApi );
554
0
                else
555
0
                    Query( nTab, aQueryParam, nullptr, false, bApi );
556
557
                //  at not-inplace the table may have been converted
558
//              if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
559
//                  SetTabNo( nTab );
560
0
            }
561
0
            if (bSubTotal)
562
0
            {
563
0
                pDBData->GetSubTotalParam( aSubTotalParam );    // range may have changed
564
0
                aSubTotalParam.bRemoveOnly = false;
565
0
                DoSubTotals( nTab, aSubTotalParam, false, bApi );
566
0
            }
567
568
0
            if (bRecord)
569
0
            {
570
0
                SCTAB nDummyTab;
571
0
                SCCOL nDummyCol;
572
0
                SCROW nDummyRow;
573
0
                SCROW nNewEndRow;
574
0
                pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
575
576
0
                const ScRange* pOld = nullptr;
577
0
                const ScRange* pNew = nullptr;
578
0
                if (bQuerySize)
579
0
                {
580
0
                    ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
581
0
                                                            aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
582
0
                    if (pDest)
583
0
                    {
584
0
                        pDest->GetArea( aNewQuery );
585
0
                        pOld = &aOldQuery;
586
0
                        pNew = &aNewQuery;
587
0
                    }
588
0
                }
589
590
0
                rDocShell.GetUndoManager()->AddUndoAction(
591
0
                    std::make_unique<ScUndoRepeatDB>( rDocShell, nTab,
592
0
                                            nStartCol, nStartRow, nEndCol, nEndRow,
593
0
                                            nNewEndRow,
594
                                            //nCurX, nCurY,
595
0
                                            nStartCol, nStartRow,
596
0
                                            std::move(pUndoDoc), std::move(pUndoTab),
597
0
                                            std::move(pUndoRange), std::move(pUndoDB),
598
0
                                            pOld, pNew ) );
599
0
            }
600
601
0
            rDocShell.PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
602
0
                                PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size);
603
0
            bDone = true;
604
0
        }
605
0
        else if (!bApi)     // "Don't execute any operations"
606
0
            rDocShell.ErrorMessage(STR_MSSG_REPEATDB_0);
607
0
    }
608
609
0
    return bDone;
610
0
}
611
612
bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
613
                            bool bRecord, bool bPaint, bool bApi )
614
0
{
615
0
    ScDocShellModificator aModificator( rDocShell );
616
617
0
    ScDocument& rDoc = rDocShell.GetDocument();
618
0
    if (bRecord && !rDoc.IsUndoEnabled())
619
0
        bRecord = false;
620
621
0
    ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
622
0
                                                    rSortParam.nCol2, rSortParam.nRow2 );
623
0
    if (!pDBData)
624
0
    {
625
0
        OSL_FAIL( "Sort: no DBData" );
626
0
        return false;
627
0
    }
628
629
0
    bool bCopy = !rSortParam.bInplace;
630
0
    if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 &&
631
0
                  rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab )
632
0
        bCopy = false;
633
634
0
    ScSortParam aLocalParam( rSortParam );
635
0
    if ( bCopy )
636
0
    {
637
        // Copy the data range to the destination then move the sort range to it.
638
0
        ScRange aSrcRange(rSortParam.nCol1, rSortParam.nRow1, nTab, rSortParam.nCol2, rSortParam.nRow2, nTab);
639
0
        ScAddress aDestPos(rSortParam.nDestCol,rSortParam.nDestRow,rSortParam.nDestTab);
640
641
0
        ScDocFunc& rDocFunc = rDocShell.GetDocFunc();
642
0
        bool bRet = rDocFunc.MoveBlock(aSrcRange, aDestPos, false, bRecord, bPaint, bApi);
643
644
0
        if (!bRet)
645
0
            return false;
646
647
0
        aLocalParam.MoveToDest();
648
0
        nTab = aLocalParam.nDestTab;
649
0
    }
650
651
    // tdf#119804: If there is a header row/column, it won't be affected by
652
    // sorting; so we can exclude it from the test.
653
0
    SCROW nStartingRowToEdit = aLocalParam.nRow1;
654
0
    SCCOL nStartingColToEdit = aLocalParam.nCol1;
655
0
    if ( aLocalParam.bHasHeader )
656
0
    {
657
0
        if ( aLocalParam.bByRow )
658
0
            nStartingRowToEdit++;
659
0
        else
660
0
            nStartingColToEdit++;
661
0
    }
662
663
0
    if (!CheckSheetViewProtection(sc::Operation::Sort))
664
0
        return false;
665
666
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(
667
0
            rDoc, nTab, nStartingColToEdit, nStartingRowToEdit,
668
0
            aLocalParam.nCol2, aLocalParam.nRow2, true /*bNoMatrixAtAll*/);
669
0
    if (!aTester.IsEditable())
670
0
    {
671
0
        if (!bApi)
672
0
            rDocShell.ErrorMessage(aTester.GetMessageId());
673
0
        return false;
674
0
    }
675
676
0
    const ScInputOptions aInputOption = ScModule::get()->GetInputOptions();
677
0
    const bool bUpdateRefs = aInputOption.GetSortRefUpdate();
678
679
    // Adjust aLocalParam cols/rows to used data area. Keep sticky top row or
680
    // column (depending on direction) in any case, not just if it has headers,
681
    // so empty leading cells will be sorted to the end.
682
    // aLocalParam.nCol/Row will encompass data content only, extras in
683
    // aLocalParam.aDataAreaExtras.
684
0
    bool bShrunk = false;
685
0
    aLocalParam.aDataAreaExtras.resetArea();
686
0
    rDoc.ShrinkToUsedDataArea(bShrunk, nTab, aLocalParam.nCol1, aLocalParam.nRow1,
687
0
                              aLocalParam.nCol2, aLocalParam.nRow2, false, aLocalParam.bByRow,
688
0
                              !aLocalParam.bByRow,
689
0
                              (aLocalParam.aDataAreaExtras.anyExtrasWanted() ?
690
0
                               &aLocalParam.aDataAreaExtras : nullptr));
691
692
0
    SCROW nStartRow = aLocalParam.nRow1;
693
0
    if (aLocalParam.bByRow && aLocalParam.bHasHeader && nStartRow < aLocalParam.nRow2)
694
0
        ++nStartRow;
695
696
0
    SCCOL nOverallCol1 = aLocalParam.nCol1;
697
0
    SCROW nOverallRow1 = aLocalParam.nRow1;
698
0
    SCCOL nOverallCol2 = aLocalParam.nCol2;
699
0
    SCROW nOverallRow2 = aLocalParam.nRow2;
700
0
    if (aLocalParam.aDataAreaExtras.anyExtrasWanted())
701
0
    {
702
        // Trailing empty excess columns/rows are excluded from being sorted,
703
        // they stick at the end. Clip them.
704
0
        const ScDataAreaExtras::Clip eClip = (aLocalParam.bByRow ?
705
0
                ScDataAreaExtras::Clip::Row : ScDataAreaExtras::Clip::Col);
706
0
        aLocalParam.aDataAreaExtras.GetOverallRange( nOverallCol1, nOverallRow1, nOverallCol2, nOverallRow2, eClip);
707
        // Make it permanent.
708
0
        aLocalParam.aDataAreaExtras.SetOverallRange( nOverallCol1, nOverallRow1, nOverallCol2, nOverallRow2);
709
710
0
        if (bUpdateRefs)
711
0
        {
712
            // With update references the entire range needs to be handled as
713
            // one entity for references pointing within to be moved along,
714
            // even when there's no data content. For huge ranges we may be
715
            // DOOMed then.
716
0
            aLocalParam.nCol1 = nOverallCol1;
717
0
            aLocalParam.nRow1 = nOverallRow1;
718
0
            aLocalParam.nCol2 = nOverallCol2;
719
0
            aLocalParam.nRow2 = nOverallRow2;
720
0
        }
721
0
    }
722
723
0
    if (aLocalParam.aDataAreaExtras.mbCellFormats
724
0
            && rDoc.HasAttrib( nOverallCol1, nStartRow, nTab, nOverallCol2, nOverallRow2, nTab,
725
0
                HasAttrFlags::Merged | HasAttrFlags::Overlapped))
726
0
    {
727
        // Merge attributes would be mixed up during sorting.
728
0
        if (!bApi)
729
0
            rDocShell.ErrorMessage(STR_SORT_ERR_MERGED);
730
0
        return false;
731
0
    }
732
733
    //      execute
734
735
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
736
737
    // Calculate the script types for all cells in the sort range beforehand.
738
    // This will speed up the row height adjustment that takes place after the
739
    // sort.
740
0
    rDoc.UpdateScriptTypes(
741
0
        ScAddress(aLocalParam.nCol1,nStartRow,nTab),
742
0
        aLocalParam.nCol2-aLocalParam.nCol1+1,
743
0
        aLocalParam.nRow2-nStartRow+1);
744
745
    // No point adjusting row heights after the sort when all rows have the same height.
746
0
    bool bUniformRowHeight = rDoc.HasUniformRowHeight(nTab, nStartRow, nOverallRow2);
747
748
0
    bool bRepeatQuery = false;                          // repeat existing filter?
749
0
    ScQueryParam aQueryParam;
750
0
    pDBData->GetQueryParam( aQueryParam );
751
0
    if ( aQueryParam.GetEntry(0).bDoQuery )
752
0
        bRepeatQuery = true;
753
754
0
    sc::ReorderParam aUndoParam;
755
756
    // don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set),
757
    // but always call it for random shuffle which doesn't need sort keys
758
0
    if (aLocalParam.meSortOrderType == SortOrderType::Random
759
0
        || (aLocalParam.GetSortKeyCount() && aLocalParam.maKeyState[0].bDoSort))
760
0
    {
761
0
        ScProgress aProgress(&rDocShell, ScResId(STR_PROGRESS_SORTING), 0, true);
762
0
        if (!bRepeatQuery)
763
0
            bRepeatQuery = rDoc.HasHiddenRows(aLocalParam.nRow1, aLocalParam.nRow2, nTab);
764
0
        rDoc.Sort(nTab, aLocalParam, bRepeatQuery, bUpdateRefs, &aProgress, &aUndoParam);
765
0
    }
766
767
0
    if (bRecord)
768
0
    {
769
        // Set up an undo object.
770
0
        rDocShell.GetUndoManager()->AddUndoAction(
771
0
            std::make_unique<sc::UndoSort>(rDocShell, aUndoParam));
772
0
    }
773
774
0
    ScSortParam aSortParamData(rSortParam);
775
0
    aSortParamData.meSortOrderType = SortOrderType::Ordered;
776
0
    pDBData->SetSortParam(aSortParamData);
777
    // Remember additional settings on anonymous database ranges.
778
0
    if (pDBData == rDoc.GetAnonymousDBData( nTab) || rDoc.GetDBCollection()->getAnonDBs().has( pDBData))
779
0
        pDBData->UpdateFromSortParam(aSortParamData);
780
781
0
    if (SfxViewShell* pKitSomeViewForThisDoc = comphelper::LibreOfficeKit::isActive() ?
782
0
                                               rDocShell.GetBestViewShell(false) : nullptr)
783
0
    {
784
0
        SfxViewShell* pViewShell = SfxViewShell::GetFirst();
785
0
        while (pViewShell)
786
0
        {
787
0
            ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
788
0
            if (pTabViewShell && pTabViewShell->GetDocId() == pKitSomeViewForThisDoc->GetDocId())
789
0
            {
790
0
                if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nTab))
791
0
                    pPosHelper->invalidateByIndex(nStartRow);
792
0
            }
793
0
            pViewShell = SfxViewShell::GetNext(*pViewShell);
794
0
        }
795
796
0
        ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
797
0
            pKitSomeViewForThisDoc, false /* bColumns */, true /* bRows */, true /* bSizes*/,
798
0
            true /* bHidden */, true /* bFiltered */, true /* bGroups */, nTab);
799
0
    }
800
801
0
    if (nStartRow <= aLocalParam.nRow2)
802
0
    {
803
0
        ScRange aDirtyRange(
804
0
                aLocalParam.nCol1, nStartRow, nTab,
805
0
                aLocalParam.nCol2, aLocalParam.nRow2, nTab);
806
0
        rDoc.SetDirty( aDirtyRange, true );
807
0
    }
808
809
0
    if (bPaint)
810
0
    {
811
0
        PaintPartFlags nPaint = PaintPartFlags::Grid;
812
0
        SCCOL nStartX = nOverallCol1;
813
0
        SCROW nStartY = nOverallRow1;
814
0
        SCCOL nEndX = nOverallCol2;
815
0
        SCROW nEndY = nOverallRow2;
816
0
        if ( bRepeatQuery )
817
0
        {
818
0
            nPaint |= PaintPartFlags::Left;
819
0
            nStartX = 0;
820
0
            nEndX = rDoc.MaxCol();
821
0
        }
822
0
        rDocShell.PostPaint(ScRange(nStartX, nStartY, nTab, nEndX, nEndY, nTab), nPaint);
823
0
    }
824
825
0
    if (!bUniformRowHeight && nStartRow <= nOverallRow2)
826
0
        rDocShell.AdjustRowHeight(nStartRow, nOverallRow2, nTab);
827
828
0
    aModificator.SetDocumentModified();
829
830
0
    return true;
831
0
}
832
833
bool ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam,
834
                        const ScRange* pAdvSource, bool bRecord, bool bApi )
835
0
{
836
0
    ScDocShellModificator aModificator( rDocShell );
837
838
0
    ScDocument& rDoc = rDocShell.GetDocument();
839
840
0
    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
841
0
    if (pViewSh && ScTabViewShell::isAnyEditViewInRange(pViewSh, /*bColumns*/ false, rQueryParam.nRow1, rQueryParam.nRow2))
842
0
    {
843
0
        return false;
844
0
    }
845
846
0
    if (bRecord && !rDoc.IsUndoEnabled())
847
0
        bRecord = false;
848
0
    ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rQueryParam.nCol1, rQueryParam.nRow1,
849
0
                                                    rQueryParam.nCol2, rQueryParam.nRow2 );
850
0
    if (!pDBData)
851
0
    {
852
0
        OSL_FAIL( "Query: no DBData" );
853
0
        return false;
854
0
    }
855
856
    //  Change from Inplace to non-Inplace, only then cancel Inplace:
857
    //  (only if "Persistent"  is selected in the dialog)
858
859
0
    if ( !rQueryParam.bInplace && pDBData->HasQueryParam() && rQueryParam.bDestPers )
860
0
    {
861
0
        ScQueryParam aOldQuery;
862
0
        pDBData->GetQueryParam(aOldQuery);
863
0
        if (aOldQuery.bInplace)
864
0
        {
865
            //  cancel old filtering
866
867
0
            SCSIZE nEC = aOldQuery.GetEntryCount();
868
0
            for (SCSIZE i=0; i<nEC; i++)
869
0
                aOldQuery.GetEntry(i).bDoQuery = false;
870
0
            aOldQuery.bDuplicate = true;
871
0
            Query( nTab, aOldQuery, nullptr, bRecord, bApi );
872
0
        }
873
0
    }
874
875
0
    ScQueryParam aLocalParam( rQueryParam );        // for Paint / destination range
876
0
    bool bCopy = !rQueryParam.bInplace;             // copied in Table::Query
877
0
    ScDBData* pDestData = nullptr;                  // range to be copied to
878
0
    bool bDoSize = false;                           // adjust destination size (insert/delete)
879
0
    SCCOL nFormulaCols = 0;                         // only at bDoSize
880
0
    bool bKeepFmt = false;
881
0
    ScRange aOldDest;
882
0
    ScRange aDestTotal;
883
0
    if ( bCopy && rQueryParam.nDestCol == rQueryParam.nCol1 &&
884
0
                  rQueryParam.nDestRow == rQueryParam.nRow1 && rQueryParam.nDestTab == nTab )
885
0
        bCopy = false;
886
0
    SCTAB nDestTab = nTab;
887
0
    if ( bCopy )
888
0
    {
889
0
        aLocalParam.MoveToDest();
890
0
        nDestTab = rQueryParam.nDestTab;
891
0
        if ( !rDoc.ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
892
0
        {
893
0
            if (!bApi)
894
0
                rDocShell.ErrorMessage(STR_PASTE_FULL);
895
0
            return false;
896
0
        }
897
898
0
        if (!CheckSheetViewProtection(sc::Operation::Query))
899
0
            return false;
900
901
0
        ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(rDoc, nDestTab,
902
0
                                    aLocalParam.nCol1, aLocalParam.nRow1,
903
0
                                    aLocalParam.nCol2,aLocalParam.nRow2);
904
0
        if (!aTester.IsEditable())
905
0
        {
906
0
            if (!bApi)
907
0
                rDocShell.ErrorMessage(aTester.GetMessageId());
908
0
            return false;
909
0
        }
910
911
0
        pDestData = rDoc.GetDBAtCursor( rQueryParam.nDestCol, rQueryParam.nDestRow,
912
0
                                            rQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
913
0
        if (pDestData)
914
0
        {
915
0
            pDestData->GetArea( aOldDest );
916
0
            aDestTotal=ScRange( rQueryParam.nDestCol,
917
0
                                rQueryParam.nDestRow,
918
0
                                nDestTab,
919
0
                                rQueryParam.nDestCol + rQueryParam.nCol2 - rQueryParam.nCol1,
920
0
                                rQueryParam.nDestRow + rQueryParam.nRow2 - rQueryParam.nRow1,
921
0
                                nDestTab );
922
923
0
            bDoSize = pDestData->IsDoSize();
924
            //  test if formulas need to be filled in (nFormulaCols):
925
0
            if ( bDoSize && aOldDest.aEnd.Col() == aDestTotal.aEnd.Col() )
926
0
            {
927
0
                SCCOL nTestCol = aOldDest.aEnd.Col() + 1;       // next to the range
928
0
                SCROW nTestRow = rQueryParam.nDestRow +
929
0
                                    ( aLocalParam.bHasHeader ? 1 : 0 );
930
0
                while ( nTestCol <= rDoc.MaxCol() &&
931
0
                        rDoc.GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA )
932
0
                {
933
0
                    ++nTestCol;
934
0
                    ++nFormulaCols;
935
0
                }
936
0
            }
937
938
0
            bKeepFmt = pDestData->IsKeepFmt();
939
0
            if ( bDoSize && !rDoc.CanFitBlock( aOldDest, aDestTotal ) )
940
0
            {
941
0
                if (!bApi)
942
0
                    rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);     // cannot insert rows
943
0
                return false;
944
0
            }
945
0
        }
946
0
    }
947
948
    //      execute
949
950
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
951
952
0
    bool bKeepSub = false;                          // repeat existing partial results?
953
0
    bool bKeepTotals = false;
954
0
    if (rQueryParam.GetEntry(0).bDoQuery)           // not at cancellation
955
0
    {
956
0
        ScSubTotalParam aSubTotalParam;
957
0
        pDBData->GetSubTotalParam( aSubTotalParam );    // partial results exist?
958
959
0
        if (aSubTotalParam.aGroups[0].bActive && !aSubTotalParam.bRemoveOnly)
960
0
            bKeepSub = true;
961
962
0
        if (pDBData->HasTotals() && pDBData->GetTableStyleInfo())
963
0
            bKeepTotals = true;
964
0
    }
965
966
0
    ScDocumentUniquePtr pUndoDoc;
967
0
    std::unique_ptr<ScDBCollection> pUndoDB;
968
0
    const ScRange* pOld = nullptr;
969
970
0
    if ( bRecord )
971
0
    {
972
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
973
0
        if (bCopy)
974
0
        {
975
0
            pUndoDoc->InitUndo( rDoc, nDestTab, nDestTab, false, true );
976
0
            rDoc.CopyToDocument(aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
977
0
                                aLocalParam.nCol2, aLocalParam.nRow2, nDestTab,
978
0
                                InsertDeleteFlags::ALL, false, *pUndoDoc);
979
            //  secure attributes in case they were copied along
980
981
0
            if (pDestData)
982
0
            {
983
0
                rDoc.CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, *pUndoDoc);
984
0
                pOld = &aOldDest;
985
0
            }
986
0
        }
987
0
        else
988
0
        {
989
0
            pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
990
0
            rDoc.CopyToDocument(0, rQueryParam.nRow1, nTab, rDoc.MaxCol(), rQueryParam.nRow2, nTab,
991
0
                                InsertDeleteFlags::NONE, false, *pUndoDoc);
992
0
        }
993
994
0
        ScDBCollection* pDocDB = rDoc.GetDBCollection();
995
0
        if (!pDocDB->empty())
996
0
            pUndoDB.reset(new ScDBCollection( *pDocDB ));
997
998
0
        rDoc.BeginDrawUndo();
999
0
    }
1000
1001
0
    std::unique_ptr<ScDocument> pAttribDoc;
1002
0
    ScRange aAttribRange;
1003
0
    if (pDestData)                                      // delete destination range
1004
0
    {
1005
0
        if ( bKeepFmt )
1006
0
        {
1007
            //  smaller of the end columns, header+1 row
1008
0
            aAttribRange = aOldDest;
1009
0
            if ( aAttribRange.aEnd.Col() > aDestTotal.aEnd.Col() )
1010
0
                aAttribRange.aEnd.SetCol( aDestTotal.aEnd.Col() );
1011
0
            aAttribRange.aEnd.SetRow( aAttribRange.aStart.Row() +
1012
0
                                        ( aLocalParam.bHasHeader ? 1 : 0 ) );
1013
1014
            //  also for filled-in formulas
1015
0
            aAttribRange.aEnd.SetCol( aAttribRange.aEnd.Col() + nFormulaCols );
1016
1017
0
            pAttribDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1018
0
            pAttribDoc->InitUndo( rDoc, nDestTab, nDestTab, false, true );
1019
0
            rDoc.CopyToDocument(aAttribRange, InsertDeleteFlags::ATTRIB, false, *pAttribDoc);
1020
0
        }
1021
1022
0
        if ( bDoSize )
1023
0
            rDoc.FitBlock( aOldDest, aDestTotal );
1024
0
        else
1025
0
            rDoc.DeleteAreaTab(aOldDest, InsertDeleteFlags::ALL);         // simply delete
1026
0
    }
1027
1028
    //  execute filtering on the document
1029
0
    SCSIZE nCount = rDoc.Query( nTab, rQueryParam, bKeepSub, bKeepTotals );
1030
0
    pDBData->CalcSaveFilteredCount( nCount );
1031
0
    if (bCopy)
1032
0
    {
1033
0
        aLocalParam.nRow2 = aLocalParam.nRow1 + nCount;
1034
0
        if (!aLocalParam.bHasHeader && nCount > 0)
1035
0
            --aLocalParam.nRow2;
1036
1037
0
        if ( bDoSize )
1038
0
        {
1039
            //  adjust to the real result range
1040
            //  (this here is always a reduction)
1041
1042
0
            ScRange aNewDest( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
1043
0
                                aLocalParam.nCol2, aLocalParam.nRow2, nDestTab );
1044
0
            rDoc.FitBlock( aDestTotal, aNewDest, false );      // sal_False - don't delete
1045
1046
0
            if ( nFormulaCols > 0 )
1047
0
            {
1048
                //  fill in formulas
1049
                //! Undo (Query and Repeat) !!!
1050
1051
0
                ScRange aNewForm( aLocalParam.nCol2+1, aLocalParam.nRow1, nDestTab,
1052
0
                                  aLocalParam.nCol2+nFormulaCols, aLocalParam.nRow2, nDestTab );
1053
0
                ScRange aOldForm = aNewForm;
1054
0
                aOldForm.aEnd.SetRow( aOldDest.aEnd.Row() );
1055
0
                rDoc.FitBlock( aOldForm, aNewForm, false );
1056
1057
0
                ScMarkData aMark(rDoc.GetSheetLimits());
1058
0
                aMark.SelectOneTable(nDestTab);
1059
0
                SCROW nFStartY = aLocalParam.nRow1 + ( aLocalParam.bHasHeader ? 1 : 0 );
1060
1061
0
                sal_uLong nProgCount = nFormulaCols;
1062
0
                nProgCount *= aLocalParam.nRow2 - nFStartY;
1063
0
                ScProgress aProgress( rDoc.GetDocumentShell(),
1064
0
                        ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
1065
1066
0
                rDoc.Fill( aLocalParam.nCol2+1, nFStartY,
1067
0
                            aLocalParam.nCol2+nFormulaCols, nFStartY, &aProgress, aMark,
1068
0
                            aLocalParam.nRow2 - nFStartY,
1069
0
                            FILL_TO_BOTTOM, FILL_SIMPLE );
1070
0
            }
1071
0
        }
1072
1073
0
        if ( pAttribDoc )       // copy back the memorized attributes
1074
0
        {
1075
            //  Header
1076
0
            if (aLocalParam.bHasHeader)
1077
0
            {
1078
0
                ScRange aHdrRange = aAttribRange;
1079
0
                aHdrRange.aEnd.SetRow( aHdrRange.aStart.Row() );
1080
0
                pAttribDoc->CopyToDocument(aHdrRange, InsertDeleteFlags::ATTRIB, false, rDoc);
1081
0
            }
1082
1083
            //  Data
1084
0
            SCCOL nAttrEndCol = aAttribRange.aEnd.Col();
1085
0
            SCROW nAttrRow = aAttribRange.aStart.Row() + ( aLocalParam.bHasHeader ? 1 : 0 );
1086
0
            for (SCCOL nCol = aAttribRange.aStart.Col(); nCol<=nAttrEndCol; nCol++)
1087
0
            {
1088
0
                const ScPatternAttr* pSrcPattern = pAttribDoc->GetPattern(
1089
0
                                                    nCol, nAttrRow, nDestTab );
1090
0
                OSL_ENSURE(pSrcPattern,"Pattern is 0");
1091
0
                if (pSrcPattern)
1092
0
                {
1093
0
                    rDoc.ApplyPatternAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
1094
0
                                                    nDestTab, *pSrcPattern );
1095
0
                    const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet();
1096
0
                    if (pStyle)
1097
0
                        rDoc.ApplyStyleAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
1098
0
                                                    nDestTab, *pStyle );
1099
0
                }
1100
0
            }
1101
0
        }
1102
0
    }
1103
1104
    //  saving: Inplace always, otherwise depending on setting
1105
    //          old Inplace-Filter may have already been removed
1106
1107
0
    bool bSave = rQueryParam.bInplace || rQueryParam.bDestPers;
1108
0
    if (bSave)                                                  // memorize
1109
0
    {
1110
0
        pDBData->SetQueryParam( rQueryParam );
1111
0
        pDBData->SetHeader( rQueryParam.bHasHeader );       //! ???
1112
0
        pDBData->SetAdvancedQuerySource( pAdvSource );      // after SetQueryParam
1113
0
    }
1114
1115
0
    if (bCopy)                                              // memorize new DB range
1116
0
    {
1117
        //  Selection is done afterwards from outside (dbfunc).
1118
        //  Currently through the DB area at the destination position,
1119
        //  so a range must be created there in any case.
1120
1121
0
        ScDBData* pNewData;
1122
0
        if (pDestData)
1123
0
            pNewData = pDestData;               // range exists -> adjust (always!)
1124
0
        else                                    // create range
1125
0
            pNewData = rDocShell.GetDBData(
1126
0
                            ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
1127
0
                                     aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ),
1128
0
                            SC_DB_MAKE, ScGetDBSelection::ForceMark );
1129
1130
0
        if (pNewData)
1131
0
        {
1132
0
            pNewData->SetArea( nDestTab, aLocalParam.nCol1, aLocalParam.nRow1,
1133
0
                                            aLocalParam.nCol2, aLocalParam.nRow2 );
1134
1135
            //  query parameter is no longer set at the destination, only leads to confusion
1136
            //  and mistakes with the query parameter at the source range (#37187#)
1137
0
        }
1138
0
        else
1139
0
        {
1140
0
            OSL_FAIL("Target are not available");
1141
0
        }
1142
0
    }
1143
1144
0
    if (!bCopy)
1145
0
    {
1146
0
        rDoc.InvalidatePageBreaks(nTab);
1147
0
        rDoc.UpdatePageBreaks( nTab );
1148
0
    }
1149
1150
    // #i23299# Subtotal functions depend on cell's filtered states.
1151
0
    ScRange aDirtyRange(0 , aLocalParam.nRow1, nDestTab, rDoc.MaxCol(), aLocalParam.nRow2, nDestTab);
1152
0
    rDoc.SetSubTotalCellsDirty(aDirtyRange);
1153
1154
0
    if ( bRecord )
1155
0
    {
1156
        // create undo action after executing, because of drawing layer undo
1157
0
        rDocShell.GetUndoManager()->AddUndoAction(
1158
0
                    std::make_unique<ScUndoQuery>( rDocShell, nTab, rQueryParam, std::move(pUndoDoc), std::move(pUndoDB),
1159
0
                                        pOld, bDoSize, pAdvSource ) );
1160
0
    }
1161
1162
0
    if ( pViewSh )
1163
0
    {
1164
        // could there be horizontal autofilter ?
1165
        // maybe it would be better to set bColumns to !rQueryParam.bByRow ?
1166
        // anyway at the beginning the value of bByRow is 'false'
1167
        // then after the first sort action it becomes 'true'
1168
0
        pViewSh->OnLOKShowHideColRow(/*bColumns*/ false, rQueryParam.nRow1 - 1);
1169
0
    }
1170
1171
0
    if (bCopy)
1172
0
    {
1173
0
        SCCOL nEndX = aLocalParam.nCol2;
1174
0
        SCROW nEndY = aLocalParam.nRow2;
1175
0
        if (pDestData)
1176
0
        {
1177
0
            if ( aOldDest.aEnd.Col() > nEndX )
1178
0
                nEndX = aOldDest.aEnd.Col();
1179
0
            if ( aOldDest.aEnd.Row() > nEndY )
1180
0
                nEndY = aOldDest.aEnd.Row();
1181
0
        }
1182
0
        if (bDoSize)
1183
0
            nEndY = rDoc.MaxRow();
1184
1185
        // remove AutoFilter button flags
1186
0
        rDocShell.DBAreaDeleted(nDestTab, aLocalParam.nCol1, aLocalParam.nRow1, aLocalParam.nCol2);
1187
1188
0
        rDocShell.PostPaint(
1189
0
            ScRange(aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, nEndX, nEndY, nDestTab),
1190
0
            PaintPartFlags::Grid);
1191
0
    }
1192
0
    else
1193
0
        rDocShell.PostPaint(
1194
0
            ScRange(0, rQueryParam.nRow1, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
1195
0
            PaintPartFlags::Grid | PaintPartFlags::Left);
1196
0
    aModificator.SetDocumentModified();
1197
1198
0
    return true;
1199
0
}
1200
1201
void ScDBDocFunc::DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam,
1202
                               bool bRecord, bool bApi )
1203
0
{
1204
    //! use also for ScDBFunc::DoSubTotals !
1205
    //  then stays outside:
1206
    //  - mark new range (from DBData)
1207
    //  - SelectionChanged (?)
1208
1209
0
    bool bDo = !rParam.bRemoveOnly;                         // sal_False = only delete
1210
1211
0
    ScDocument& rDoc = rDocShell.GetDocument();
1212
0
    if (bRecord && !rDoc.IsUndoEnabled())
1213
0
        bRecord = false;
1214
0
    ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
1215
0
                                                rParam.nCol2, rParam.nRow2 );
1216
0
    if (!pDBData)
1217
0
    {
1218
0
        OSL_FAIL( "SubTotals: no DBData" );
1219
0
        return;
1220
0
    }
1221
1222
0
    if (!CheckSheetViewProtection(sc::Operation::SubTotals))
1223
0
        return;
1224
1225
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(rDoc, nTab, 0, rParam.nRow1 + 1, rDoc.MaxCol(), rDoc.MaxRow());
1226
0
    if (!aTester.IsEditable())
1227
0
    {
1228
0
        if (!bApi)
1229
0
            rDocShell.ErrorMessage(aTester.GetMessageId());
1230
0
        return;
1231
0
    }
1232
1233
0
    if (rDoc.HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
1234
0
                         rParam.nCol2, rParam.nRow2, nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
1235
0
    {
1236
0
        if (!bApi)
1237
0
            rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // don't insert into merged
1238
0
        return;
1239
0
    }
1240
1241
0
    bool bOk = true;
1242
0
    if (rParam.bReplace)
1243
0
    {
1244
0
        if (rDoc.TestRemoveSubTotals( nTab, rParam ))
1245
0
        {
1246
0
            std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
1247
0
                                                      VclMessageType::Question,
1248
0
                                                      VclButtonsType::YesNo, ScResId(STR_MSSG_DOSUBTOTALS_1))); // "Delete Data?"
1249
0
            xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0)); // "StarCalc"
1250
0
            bOk = xBox->run() == RET_YES;
1251
0
        }
1252
0
    }
1253
1254
0
    if (!bOk)
1255
0
        return;
1256
1257
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
1258
0
    ScDocShellModificator aModificator( rDocShell );
1259
1260
0
    ScSubTotalParam aNewParam( rParam );        // end of range is being changed
1261
0
    ScDocumentUniquePtr pUndoDoc;
1262
0
    std::unique_ptr<ScOutlineTable> pUndoTab;
1263
0
    std::unique_ptr<ScRangeName> pUndoRange;
1264
0
    std::unique_ptr<ScDBCollection> pUndoDB;
1265
1266
0
    if (bRecord)                                        // secure old data
1267
0
    {
1268
0
        bool bOldFilter = bDo && rParam.bDoSort;
1269
1270
0
        SCTAB nTabCount = rDoc.GetTableCount();
1271
0
        pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
1272
0
        ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
1273
0
        if (pTable)
1274
0
        {
1275
0
            pUndoTab.reset(new ScOutlineTable( *pTable ));
1276
1277
            // column/row state
1278
0
            SCCOLROW nOutStartCol, nOutEndCol;
1279
0
            SCCOLROW nOutStartRow, nOutEndRow;
1280
0
            pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
1281
0
            pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
1282
1283
0
            pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
1284
0
            rDoc.CopyToDocument(static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
1285
0
            rDoc.CopyToDocument(0, nOutStartRow, nTab, rDoc.MaxCol(), nOutEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
1286
0
        }
1287
0
        else
1288
0
            pUndoDoc->InitUndo( rDoc, nTab, nTab, false, bOldFilter );
1289
1290
        //  secure data range - incl. filtering result
1291
0
        rDoc.CopyToDocument(0, rParam.nRow1+1,nTab, rDoc.MaxCol(),rParam.nRow2,nTab,
1292
0
                            InsertDeleteFlags::ALL, false, *pUndoDoc);
1293
1294
        //  all formulas because of references
1295
0
        rDoc.CopyToDocument(0, 0, 0, rDoc.MaxCol(),rDoc.MaxRow(),nTabCount-1,
1296
0
                            InsertDeleteFlags::FORMULA, false, *pUndoDoc);
1297
1298
        //  ranges of DB and other
1299
0
        ScRangeName* pDocRange = rDoc.GetRangeName();
1300
0
        if (!pDocRange->empty())
1301
0
            pUndoRange.reset(new ScRangeName( *pDocRange ));
1302
0
        ScDBCollection* pDocDB = rDoc.GetDBCollection();
1303
0
        if (!pDocDB->empty())
1304
0
            pUndoDB.reset(new ScDBCollection( *pDocDB ));
1305
0
    }
1306
1307
//      rDoc.SetOutlineTable( nTab, NULL );
1308
0
    ScOutlineTable* pOut = rDoc.GetOutlineTable( nTab );
1309
0
    if (pOut)
1310
0
        pOut->GetRowArray().RemoveAll();       // only delete row outlines
1311
1312
0
    if (rParam.bReplace)
1313
0
        rDoc.RemoveSubTotals( nTab, aNewParam );
1314
0
    bool bSuccess = true;
1315
0
    if (bDo)
1316
0
    {
1317
        // sort
1318
0
        if ( rParam.bDoSort )
1319
0
        {
1320
0
            pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
1321
1322
            //  set partial result field to before the sorting
1323
            //  (Duplicates are omitted, so can be called again)
1324
1325
0
            ScSortParam aOldSort;
1326
0
            pDBData->GetSortParam( aOldSort );
1327
0
            ScSortParam aSortParam( aNewParam, aOldSort );
1328
0
            Sort( nTab, aSortParam, false, false, bApi );
1329
0
        }
1330
1331
0
        bSuccess = rDoc.DoSubTotals( nTab, aNewParam );
1332
0
        rDoc.SetDrawPageSize(nTab);
1333
0
    }
1334
0
    ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
1335
0
        aNewParam.nCol2, aNewParam.nRow2, nTab );
1336
0
    rDoc.SetDirty( aDirtyRange, true );
1337
1338
0
    if (bRecord)
1339
0
    {
1340
//          ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
1341
0
        rDocShell.GetUndoManager()->AddUndoAction(
1342
0
            std::make_unique<ScUndoSubTotals>( rDocShell, nTab,
1343
0
                                    rParam, aNewParam.nRow2,
1344
0
                                    std::move(pUndoDoc), std::move(pUndoTab), // pUndoDBData,
1345
0
                                    std::move(pUndoRange), std::move(pUndoDB) ) );
1346
0
    }
1347
1348
0
    if (!bSuccess)
1349
0
    {
1350
        // "Cannot insert rows"
1351
0
        if (!bApi)
1352
0
            rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
1353
0
    }
1354
1355
                                                // memorize
1356
0
    pDBData->SetSubTotalParam( aNewParam );
1357
0
    pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
1358
0
    rDoc.CompileDBFormula();
1359
1360
0
    rDocShell.PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab),
1361
0
                        PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size);
1362
0
    aModificator.SetDocumentModified();
1363
0
}
1364
1365
void ScDBDocFunc::DoTableSubTotals( SCTAB nTab, const ScDBData& rNewData, const ScSubTotalParam& rParam,
1366
                                    bool bRecord, bool bApi )
1367
0
{
1368
0
    bool bDo = !rParam.bRemoveOnly; // sal_False = only delete
1369
1370
0
    ScDocument& rDoc = rDocShell.GetDocument();
1371
0
    if (bRecord && !rDoc.IsUndoEnabled())
1372
0
        bRecord = false;
1373
1374
0
    ScDBData* pDBData = rDoc.GetDBAtArea(nTab, rParam.nCol1, rParam.nRow1, rParam.nCol2, rParam.nRow2);
1375
0
    if (!pDBData)
1376
0
    {
1377
0
        OSL_FAIL("SubTotals: no DBData");
1378
0
        return;
1379
0
    }
1380
1381
0
    ScEditableTester aTester = ScEditableTester::CreateAndTestBlock(rDoc, nTab, 0, rParam.nRow1 + 1, rDoc.MaxCol(), rDoc.MaxRow());
1382
0
    if (!aTester.IsEditable())
1383
0
    {
1384
0
        if (!bApi)
1385
0
            rDocShell.ErrorMessage(aTester.GetMessageId());
1386
0
        return;
1387
0
    }
1388
1389
0
    if (rDoc.HasAttrib(rParam.nCol1, rParam.nRow1 + 1, nTab, rParam.nCol2, rParam.nRow2, nTab,
1390
0
                       HasAttrFlags::Merged | HasAttrFlags::Overlapped))
1391
0
    {
1392
0
        if (!bApi)
1393
0
            rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // don't insert into merged
1394
0
        return;
1395
0
    }
1396
1397
0
    weld::WaitObject aWait(ScDocShell::GetActiveDialogParent());
1398
0
    ScDocShellModificator aModificator(rDocShell);
1399
1400
0
    ScSubTotalParam aNewParam;
1401
0
    rNewData.GetSubTotalParam(aNewParam); // end of range is being changed
1402
0
    ScDocumentUniquePtr pUndoDoc;
1403
0
    std::unique_ptr<ScDBCollection> pUndoDB;
1404
1405
0
    if (bRecord) // secure old data
1406
0
    {
1407
0
        bool bOldFilter = bDo && rParam.bDoSort;
1408
1409
0
        SCTAB nTabCount = rDoc.GetTableCount();
1410
0
        pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1411
0
        pUndoDoc->InitUndo(rDoc, nTab, nTab, false, bOldFilter);
1412
1413
        //  secure data range - incl. filtering result
1414
0
        rDoc.CopyToDocument(rParam.nCol1, rParam.nRow1 + 1, nTab, rParam.nCol2, rParam.nRow2, nTab,
1415
0
                            InsertDeleteFlags::ALL, false, *pUndoDoc);
1416
1417
        //  all formulas because of references
1418
0
        rDoc.CopyToDocument(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), nTabCount - 1,
1419
0
                            InsertDeleteFlags::FORMULA, false, *pUndoDoc);
1420
1421
        //  ranges of DB
1422
0
        ScDBCollection* pDocDB = rDoc.GetDBCollection();
1423
0
        if (!pDocDB->empty())
1424
0
            pUndoDB.reset(new ScDBCollection(*pDocDB));
1425
0
    }
1426
1427
0
    if (rParam.bReplace)
1428
0
        rDoc.RemoveTableSubTotals(nTab, aNewParam, rParam);
1429
0
    bool bSuccess = true;
1430
0
    if (bDo)
1431
0
    {
1432
0
        bSuccess = rDoc.DoTableSubTotals(nTab, aNewParam);
1433
0
        rDoc.SetDrawPageSize(nTab);
1434
0
    }
1435
0
    ScRange aDirtyRange(aNewParam.nCol1, aNewParam.nRow1, nTab, aNewParam.nCol2, aNewParam.nRow2,
1436
0
                        nTab);
1437
0
    rDoc.SetDirty(aDirtyRange, true);
1438
1439
    // Need to store with the new values
1440
0
    *pDBData = rNewData;
1441
0
    if (bRecord)
1442
0
    {
1443
0
        ScDBCollection* pDocDB = rDoc.GetDBCollection();
1444
0
        rDocShell.GetUndoManager()->AddUndoAction(std::make_unique<ScUndoTableTotals>(
1445
0
            rDocShell, nTab, rParam, aNewParam.nRow2, std::move(pUndoDoc),
1446
0
            std::move(pUndoDB), std::make_unique<ScDBCollection>(*pDocDB)));
1447
0
    }
1448
1449
0
    if (!bSuccess)
1450
0
    {
1451
        // "Cannot insert rows"
1452
0
        if (!bApi)
1453
0
            rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
1454
0
    }
1455
1456
    // store
1457
0
    pDBData->SetSubTotalParam(aNewParam);
1458
0
    pDBData->SetArea(nTab, aNewParam.nCol1, aNewParam.nRow1, aNewParam.nCol2, aNewParam.nRow2);
1459
0
    rDoc.CompileDBFormula();
1460
1461
0
    rDocShell.PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
1462
0
                        PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top
1463
0
                            | PaintPartFlags::Size);
1464
0
    aModificator.SetDocumentModified();
1465
0
}
1466
1467
namespace {
1468
1469
bool lcl_EmptyExcept( ScDocument& rDoc, const ScRange& rRange, const ScRange& rExcept )
1470
0
{
1471
0
    ScCellIterator aIter( rDoc, rRange );
1472
0
    for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
1473
0
    {
1474
0
        if (!aIter.isEmpty())      // real content?
1475
0
        {
1476
0
            if (!rExcept.Contains(aIter.GetPos()))
1477
0
                return false;       // cell found
1478
0
        }
1479
0
    }
1480
1481
0
    return true;        // nothing found - empty
1482
0
}
1483
1484
bool isEditable(ScDocShell& rDocShell, const ScRangeList& rRanges, bool bApi,
1485
    sc::EditAction eAction = sc::EditAction::Unknown)
1486
0
{
1487
0
    ScDocument& rDoc = rDocShell.GetDocument();
1488
0
    if (!rDocShell.IsEditable() || rDoc.GetChangeTrack())
1489
0
    {
1490
        //  not recorded -> disallow
1491
0
        if (!bApi)
1492
0
            rDocShell.ErrorMessage(STR_PROTECTIONERR);
1493
1494
0
        return false;
1495
0
    }
1496
1497
0
    for (size_t i = 0, n = rRanges.size(); i < n; ++i)
1498
0
    {
1499
0
        const ScRange & r = rRanges[i];
1500
0
        ScEditableTester aTester = ScEditableTester::CreateAndTestRange(rDoc, r, eAction);
1501
0
        if (!aTester.IsEditable())
1502
0
        {
1503
0
            if (!bApi)
1504
0
                rDocShell.ErrorMessage(aTester.GetMessageId());
1505
1506
0
            return false;
1507
0
        }
1508
0
    }
1509
1510
0
    return true;
1511
0
}
1512
1513
void createUndoDoc(ScDocumentUniquePtr& pUndoDoc, ScDocument& rDoc, const ScRange& rRange)
1514
0
{
1515
0
    SCTAB nTab = rRange.aStart.Tab();
1516
0
    pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1517
0
    pUndoDoc->InitUndo(rDoc, nTab, nTab);
1518
0
    rDoc.CopyToDocument(rRange, InsertDeleteFlags::ALL, false, *pUndoDoc);
1519
0
}
1520
1521
bool checkNewOutputRange(ScDPObject& rDPObj, ScDocShell& rDocShell, ScRange& rNewOut, bool bApi,
1522
    sc::EditAction eAction = sc::EditAction::Unknown)
1523
0
{
1524
0
    ScDocument& rDoc = rDocShell.GetDocument();
1525
1526
0
    bool bOverflow = false;
1527
0
    rNewOut = rDPObj.GetNewOutputRange(bOverflow);
1528
1529
    // Test for overlap with source data range.
1530
    // TODO: Check with other pivot tables as well.
1531
0
    const ScSheetSourceDesc* pSheetDesc = rDPObj.GetSheetDesc();
1532
0
    if (pSheetDesc && pSheetDesc->GetSourceRange().Intersects(rNewOut))
1533
0
    {
1534
        // New output range intersteps with the source data. Move it up to
1535
        // where the old range is and see if that works.
1536
0
        ScRange aOldRange = rDPObj.GetOutRange();
1537
0
        SCROW nDiff = aOldRange.aStart.Row() - rNewOut.aStart.Row();
1538
0
        rNewOut.aStart.SetRow(aOldRange.aStart.Row());
1539
0
        rNewOut.aEnd.IncRow(nDiff);
1540
0
        if (!rDoc.ValidRow(rNewOut.aStart.Row()) || !rDoc.ValidRow(rNewOut.aEnd.Row()))
1541
0
            bOverflow = true;
1542
0
    }
1543
1544
0
    if (bOverflow)
1545
0
    {
1546
0
        if (!bApi)
1547
0
            rDocShell.ErrorMessage(STR_PIVOT_ERROR);
1548
1549
0
        return false;
1550
0
    }
1551
1552
0
    if (!rDoc.IsImportingXML())
1553
0
    {
1554
0
        ScEditableTester aTester = ScEditableTester::CreateAndTestRange(rDoc, rNewOut, eAction);
1555
0
        if (!aTester.IsEditable())
1556
0
        {
1557
            //  destination area isn't editable
1558
0
            if (!bApi)
1559
0
                rDocShell.ErrorMessage(aTester.GetMessageId());
1560
1561
0
            return false;
1562
0
        }
1563
0
    }
1564
1565
0
    return true;
1566
0
}
1567
1568
}
1569
1570
bool ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj,
1571
                                   bool bRecord, bool bApi, bool bAllowMove )
1572
0
{
1573
0
    if (!pOldObj)
1574
0
    {
1575
0
        if (!pNewObj)
1576
0
            return false;
1577
1578
0
        return CreatePivotTable(*pNewObj, bRecord, bApi);
1579
0
    }
1580
1581
0
    if (!pNewObj)
1582
0
        return RemovePivotTable(*pOldObj, bRecord, bApi);
1583
1584
0
    if (pOldObj == pNewObj)
1585
0
        return UpdatePivotTable(*pOldObj, bRecord, bApi);
1586
1587
0
    OSL_ASSERT(pOldObj && pNewObj && pOldObj != pNewObj);
1588
1589
0
    ScDocShellModificator aModificator( rDocShell );
1590
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
1591
1592
0
    ScRangeList aRanges;
1593
0
    aRanges.push_back(pOldObj->GetOutRange());
1594
0
    aRanges.push_back(ScRange(pNewObj->GetOutRange().aStart)); // at least one cell in the output position must be editable.
1595
1596
0
    if (!CheckSheetViewProtection(sc::Operation::PivotTableUpdate))
1597
0
       return false;
1598
1599
0
    if (!isEditable(rDocShell, aRanges, bApi))
1600
0
        return false;
1601
1602
0
    ScDocumentUniquePtr pOldUndoDoc;
1603
0
    ScDocumentUniquePtr pNewUndoDoc;
1604
1605
0
    ScDPObject aUndoDPObj(*pOldObj); // for undo or revert on failure
1606
1607
0
    ScDocument& rDoc = rDocShell.GetDocument();
1608
0
    if (bRecord && !rDoc.IsUndoEnabled())
1609
0
        bRecord = false;
1610
1611
0
    if (bRecord)
1612
0
        createUndoDoc(pOldUndoDoc, rDoc, pOldObj->GetOutRange());
1613
1614
0
    pNewObj->WriteSourceDataTo(*pOldObj);     // copy source data
1615
1616
0
    ScDPSaveData* pData = pNewObj->GetSaveData();
1617
0
    OSL_ENSURE( pData, "no SaveData from living DPObject" );
1618
0
    if (pData)
1619
0
        pOldObj->SetSaveData(*pData);     // copy SaveData
1620
1621
0
    pOldObj->SetAllowMove(bAllowMove);
1622
0
    pOldObj->ReloadGroupTableData();
1623
0
    pOldObj->SyncAllDimensionMembers();
1624
0
    pOldObj->InvalidateData();             // before getting the new output area
1625
1626
    //  make sure the table has a name (not set by dialog)
1627
0
    if (pOldObj->GetName().isEmpty())
1628
0
        pOldObj->SetName( rDoc.GetDPCollection()->CreateNewName() );
1629
1630
0
    ScRange aNewOut;
1631
0
    if (!checkNewOutputRange(*pOldObj, rDocShell, aNewOut, bApi))
1632
0
    {
1633
0
        *pOldObj = aUndoDPObj;
1634
0
        return false;
1635
0
    }
1636
1637
    //  test if new output area is empty except for old area
1638
0
    if (!bApi)
1639
0
    {
1640
        // OutRange of pOldObj (pDestObj) is still old area
1641
0
        if (!lcl_EmptyExcept(rDoc, aNewOut, pOldObj->GetOutRange()))
1642
0
        {
1643
0
            std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
1644
0
                                                           VclMessageType::Question, VclButtonsType::YesNo,
1645
0
                                                           ScResId(STR_PIVOT_NOTEMPTY)));
1646
0
            xQueryBox->set_default_response(RET_YES);
1647
0
            if (xQueryBox->run() == RET_NO)
1648
0
            {
1649
                //! like above (not editable)
1650
0
                *pOldObj = aUndoDPObj;
1651
0
                return false;
1652
0
            }
1653
0
        }
1654
0
    }
1655
1656
0
    if (bRecord)
1657
0
        createUndoDoc(pNewUndoDoc, rDoc, aNewOut);
1658
1659
0
    pOldObj->Output(aNewOut.aStart);
1660
0
    rDocShell.PostPaintGridAll();           //! only necessary parts
1661
1662
0
    if (bRecord)
1663
0
    {
1664
0
        rDocShell.GetUndoManager()->AddUndoAction(
1665
0
            std::make_unique<ScUndoDataPilot>(
1666
0
                rDocShell, std::move(pOldUndoDoc), std::move(pNewUndoDoc), &aUndoDPObj, pOldObj, bAllowMove));
1667
0
    }
1668
1669
    // notify API objects
1670
0
    rDoc.BroadcastUno( ScDataPilotModifiedHint(pOldObj->GetName()) );
1671
0
    aModificator.SetDocumentModified();
1672
1673
0
    return true;
1674
0
}
1675
1676
bool ScDBDocFunc::RemovePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi)
1677
0
{
1678
0
    ScDocShellModificator aModificator(rDocShell);
1679
0
    weld::WaitObject aWait(ScDocShell::GetActiveDialogParent());
1680
1681
0
    if (!CheckSheetViewProtection(sc::Operation::PivotTableRemove))
1682
0
        return false;
1683
1684
0
    if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
1685
0
        return false;
1686
1687
0
    ScDocument& rDoc = rDocShell.GetDocument();
1688
1689
0
    if (!bApi)
1690
0
    {
1691
        // If we come from GUI - ask to delete the associated pivot charts too...
1692
0
        std::vector<SdrOle2Obj*> aListOfObjects =
1693
0
                    sctools::getAllPivotChartsConnectedTo(rDPObj.GetName(), rDocShell);
1694
1695
0
        ScDrawLayer* pModel = rDoc.GetDrawLayer();
1696
1697
0
        if (pModel && !aListOfObjects.empty())
1698
0
        {
1699
0
            std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
1700
0
                                                           VclMessageType::Question, VclButtonsType::YesNo,
1701
0
                                                           ScResId(STR_PIVOT_REMOVE_PIVOTCHART)));
1702
0
            xQueryBox->set_default_response(RET_YES);
1703
0
            if (xQueryBox->run() == RET_NO)
1704
0
            {
1705
0
                return false;
1706
0
            }
1707
0
            else
1708
0
            {
1709
0
                for (SdrOle2Obj* pChartObject : aListOfObjects)
1710
0
                {
1711
0
                    rDoc.GetChartListenerCollection()->removeByName(pChartObject->GetName());
1712
0
                    pModel->AddUndo(std::make_unique<SdrUndoDelObj>(*pChartObject));
1713
0
                    pChartObject->getSdrPageFromSdrObject()->RemoveObject(pChartObject->GetOrdNum());
1714
0
                }
1715
0
            }
1716
0
        }
1717
0
    }
1718
1719
0
    ScDocumentUniquePtr pOldUndoDoc;
1720
0
    std::unique_ptr<ScDPObject> pUndoDPObj;
1721
1722
0
    if (bRecord)
1723
0
        pUndoDPObj.reset(new ScDPObject(rDPObj));    // copy old settings for undo
1724
1725
0
    if (bRecord && !rDoc.IsUndoEnabled())
1726
0
        bRecord = false;
1727
1728
    //  delete table
1729
1730
0
    ScRange aRange = rDPObj.GetOutRange();
1731
0
    SCTAB nTab = aRange.aStart.Tab();
1732
1733
0
    if (bRecord)
1734
0
        createUndoDoc(pOldUndoDoc, rDoc, aRange);
1735
1736
0
    rDoc.DeleteAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
1737
0
                         aRange.aEnd.Col(),   aRange.aEnd.Row(),
1738
0
                         nTab, InsertDeleteFlags::ALL );
1739
0
    rDoc.RemoveFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
1740
0
                          aRange.aEnd.Col(),   aRange.aEnd.Row(),
1741
0
                          nTab, ScMF::Auto );
1742
1743
0
    rDoc.GetDPCollection()->FreeTable(&rDPObj);  // object is deleted here
1744
1745
0
    rDocShell.PostPaintGridAll();   //! only necessary parts
1746
0
    rDocShell.PostPaint(aRange, PaintPartFlags::Grid);
1747
1748
0
    if (bRecord)
1749
0
    {
1750
0
        rDocShell.GetUndoManager()->AddUndoAction(
1751
0
            std::make_unique<ScUndoDataPilot>(
1752
0
                rDocShell, std::move(pOldUndoDoc), nullptr, pUndoDPObj.get(), nullptr, false));
1753
1754
        // pUndoDPObj is copied
1755
0
    }
1756
1757
0
    aModificator.SetDocumentModified();
1758
0
    return true;
1759
0
}
1760
1761
bool ScDBDocFunc::CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi)
1762
310
{
1763
310
    ScDocShellModificator aModificator(rDocShell);
1764
310
    weld::WaitObject aWait(ScDocShell::GetActiveDialogParent());
1765
1766
310
    if (!CheckSheetViewProtection(sc::Operation::PivotTableCreate))
1767
0
        return false;
1768
1769
    // At least one cell in the output range should be editable. Check in advance.
1770
310
    ScDocument& rDoc = rDocShell.GetDocument();
1771
310
    if (!rDoc.IsImportingXML() && !isEditable(rDocShell, ScRange(rDPObj.GetOutRange().aStart), bApi))
1772
0
        return false;
1773
1774
310
    ScDocumentUniquePtr pNewUndoDoc;
1775
1776
310
    if (bRecord && !rDoc.IsUndoEnabled())
1777
310
        bRecord = false;
1778
1779
    //  output range must be set at pNewObj
1780
310
    std::unique_ptr<ScDPObject> pDestObj(new ScDPObject(rDPObj));
1781
1782
310
    ScDPObject& rDestObj = *pDestObj;
1783
1784
    // #i94570# When changing the output position in the dialog, a new table is created
1785
    // with the settings from the old table, including the name.
1786
    // So we have to check for duplicate names here (before inserting).
1787
310
    if (rDoc.GetDPCollection()->GetByName(rDestObj.GetName()))
1788
14
        rDestObj.SetName(OUString());      // ignore the invalid name, create a new name below
1789
1790
    // Synchronize groups between linked tables
1791
310
    {
1792
310
        const ScDPDimensionSaveData* pGroups = nullptr;
1793
310
        bool bRefFound = rDoc.GetDPCollection()->GetReferenceGroups(rDestObj, &pGroups);
1794
310
        if (bRefFound)
1795
73
        {
1796
73
            ScDPSaveData* pSaveData = rDestObj.GetSaveData();
1797
73
            if (pSaveData)
1798
73
                pSaveData->SetDimensionData(pGroups);
1799
73
        }
1800
310
    }
1801
1802
310
    rDoc.GetDPCollection()->InsertNewTable(std::move(pDestObj));
1803
1804
310
    rDestObj.ReloadGroupTableData();
1805
310
    rDestObj.SyncAllDimensionMembers();
1806
310
    rDestObj.InvalidateData();             // before getting the new output area
1807
1808
    //  make sure the table has a name (not set by dialog)
1809
310
    if (rDestObj.GetName().isEmpty())
1810
14
        rDestObj.SetName(rDoc.GetDPCollection()->CreateNewName());
1811
1812
310
    bool bOverflow = false;
1813
310
    ScRange aNewOut = rDestObj.GetNewOutputRange(bOverflow);
1814
1815
310
    if (bOverflow)
1816
0
    {
1817
0
        if (!bApi)
1818
0
            rDocShell.ErrorMessage(STR_PIVOT_ERROR);
1819
1820
0
        return false;
1821
0
    }
1822
1823
310
    if (!rDoc.IsImportingXML())
1824
0
    {
1825
0
        ScEditableTester aTester = ScEditableTester::CreateAndTestRange(rDoc, aNewOut, sc::EditAction::Unknown);
1826
0
        if (!aTester.IsEditable())
1827
0
        {
1828
            //  destination area isn't editable
1829
0
            if (!bApi)
1830
0
                rDocShell.ErrorMessage(aTester.GetMessageId());
1831
1832
0
            return false;
1833
0
        }
1834
0
    }
1835
1836
    //  test if new output area is empty except for old area
1837
310
    if (!bApi)
1838
0
    {
1839
0
        bool bEmpty = rDoc.IsBlockEmpty(
1840
0
            aNewOut.aStart.Col(), aNewOut.aStart.Row(),
1841
0
            aNewOut.aEnd.Col(), aNewOut.aEnd.Row(), aNewOut.aStart.Tab() );
1842
1843
0
        if (!bEmpty)
1844
0
        {
1845
0
            std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
1846
0
                                                           VclMessageType::Question, VclButtonsType::YesNo,
1847
0
                                                           ScResId(STR_PIVOT_NOTEMPTY)));
1848
0
            xQueryBox->set_default_response(RET_YES);
1849
0
            if (xQueryBox->run() == RET_NO)
1850
0
            {
1851
                //! like above (not editable)
1852
0
                return false;
1853
0
            }
1854
0
        }
1855
0
    }
1856
1857
310
    if (bRecord)
1858
0
        createUndoDoc(pNewUndoDoc, rDoc, aNewOut);
1859
1860
310
    rDestObj.Output(aNewOut.aStart);
1861
310
    rDocShell.PostPaintGridAll();           //! only necessary parts
1862
1863
310
    if (bRecord)
1864
0
    {
1865
0
        rDocShell.GetUndoManager()->AddUndoAction(
1866
0
            std::make_unique<ScUndoDataPilot>(rDocShell, nullptr, std::move(pNewUndoDoc), nullptr, &rDestObj, false));
1867
0
    }
1868
1869
    // notify API objects
1870
310
    rDoc.BroadcastUno(ScDataPilotModifiedHint(rDestObj.GetName()));
1871
310
    aModificator.SetDocumentModified();
1872
1873
310
    return true;
1874
310
}
1875
1876
bool ScDBDocFunc::UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi)
1877
0
{
1878
0
    ScDocShellModificator aModificator( rDocShell );
1879
0
    weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
1880
1881
0
    if (!CheckSheetViewProtection(sc::Operation::PivotTableUpdate))
1882
0
        return false;
1883
1884
0
    if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi, sc::EditAction::UpdatePivotTable))
1885
0
        return false;
1886
1887
0
    ScDocumentUniquePtr pOldUndoDoc;
1888
0
    ScDocumentUniquePtr pNewUndoDoc;
1889
1890
0
    ScDPObject aUndoDPObj(rDPObj); // For undo or revert on failure.
1891
1892
0
    ScDocument& rDoc = rDocShell.GetDocument();
1893
0
    if (bRecord && !rDoc.IsUndoEnabled())
1894
0
        bRecord = false;
1895
1896
0
    if (bRecord)
1897
0
        createUndoDoc(pOldUndoDoc, rDoc, rDPObj.GetOutRange());
1898
1899
0
    rDPObj.SetAllowMove(false);
1900
0
    rDPObj.ReloadGroupTableData();
1901
0
    if (!rDPObj.SyncAllDimensionMembers())
1902
0
        return false;
1903
1904
0
    rDPObj.InvalidateData();             // before getting the new output area
1905
1906
    //  make sure the table has a name (not set by dialog)
1907
0
    if (rDPObj.GetName().isEmpty())
1908
0
        rDPObj.SetName( rDoc.GetDPCollection()->CreateNewName() );
1909
1910
0
    ScRange aNewOut;
1911
0
    if (!checkNewOutputRange(rDPObj, rDocShell, aNewOut, bApi, sc::EditAction::UpdatePivotTable))
1912
0
    {
1913
0
        rDPObj = aUndoDPObj;
1914
0
        return false;
1915
0
    }
1916
1917
    //  test if new output area is empty except for old area
1918
0
    if (!bApi)
1919
0
    {
1920
0
        if (!lcl_EmptyExcept(rDoc, aNewOut, rDPObj.GetOutRange()))
1921
0
        {
1922
0
            std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
1923
0
                                                           VclMessageType::Question, VclButtonsType::YesNo,
1924
0
                                                           ScResId(STR_PIVOT_NOTEMPTY)));
1925
0
            xQueryBox->set_default_response(RET_YES);
1926
0
            if (xQueryBox->run() == RET_NO)
1927
0
            {
1928
0
                rDPObj = aUndoDPObj;
1929
0
                return false;
1930
0
            }
1931
0
        }
1932
0
    }
1933
1934
0
    if (bRecord)
1935
0
        createUndoDoc(pNewUndoDoc, rDoc, aNewOut);
1936
1937
0
    rDPObj.Output(aNewOut.aStart);
1938
0
    rDocShell.PostPaintGridAll();           //! only necessary parts
1939
1940
0
    if (bRecord)
1941
0
    {
1942
0
        rDocShell.GetUndoManager()->AddUndoAction(
1943
0
            std::make_unique<ScUndoDataPilot>(
1944
0
                rDocShell, std::move(pOldUndoDoc), std::move(pNewUndoDoc), &aUndoDPObj, &rDPObj, false));
1945
0
    }
1946
1947
    // notify API objects
1948
0
    rDoc.BroadcastUno( ScDataPilotModifiedHint(rDPObj.GetName()) );
1949
0
    aModificator.SetDocumentModified();
1950
0
    return true;
1951
0
}
1952
1953
void ScDBDocFunc::RefreshPivotTables(const ScDPObject* pDPObj, bool bApi)
1954
0
{
1955
0
    ScDPCollection* pDPs = rDocShell.GetDocument().GetDPCollection();
1956
0
    if (!pDPs)
1957
0
        return;
1958
1959
0
    o3tl::sorted_vector<ScDPObject*> aRefs;
1960
0
    TranslateId pErrId = pDPs->ReloadCache(pDPObj, aRefs);
1961
0
    if (pErrId)
1962
0
        return;
1963
1964
0
    for (ScDPObject* pObj : aRefs)
1965
0
    {
1966
        // This action is intentionally not undoable since it modifies cache.
1967
0
        UpdatePivotTable(*pObj, false, bApi);
1968
0
    }
1969
0
}
1970
1971
void ScDBDocFunc::RefreshPivotTableGroups(ScDPObject* pDPObj)
1972
18
{
1973
18
    if (!pDPObj)
1974
0
        return;
1975
1976
18
    ScDPCollection* pDPs = rDocShell.GetDocument().GetDPCollection();
1977
18
    if (!pDPs)
1978
0
        return;
1979
1980
18
    ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1981
18
    if (!pSaveData)
1982
0
        return;
1983
1984
18
    if (!pDPs->HasTable(pDPObj))
1985
18
    {
1986
        // This table is under construction so no need for a whole update (UpdatePivotTable()).
1987
18
        pDPObj->ReloadGroupTableData();
1988
18
        return;
1989
18
    }
1990
1991
    // Update all linked tables, if this table is part of the cache (ScDPCollection)
1992
0
    o3tl::sorted_vector<ScDPObject*> aRefs;
1993
0
    if (!pDPs->ReloadGroupsInCache(pDPObj, aRefs))
1994
0
        return;
1995
1996
    // We allow pDimData being NULL.
1997
0
    const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
1998
0
    for (ScDPObject* pObj : aRefs)
1999
0
    {
2000
0
        if (pObj != pDPObj)
2001
0
        {
2002
0
            pSaveData = pObj->GetSaveData();
2003
0
            if (pSaveData)
2004
0
                pSaveData->SetDimensionData(pDimData);
2005
0
        }
2006
2007
        // This action is intentionally not undoable since it modifies cache.
2008
0
        UpdatePivotTable(*pObj, false, false);
2009
0
    }
2010
0
}
2011
2012
//      database import
2013
2014
void ScDBDocFunc::UpdateImport( const OUString& rTarget, const svx::ODataAccessDescriptor& rDescriptor )
2015
0
{
2016
    // rTarget is the name of a database range
2017
2018
0
    ScDocument& rDoc = rDocShell.GetDocument();
2019
0
    ScDBCollection& rDBColl = *rDoc.GetDBCollection();
2020
0
    const ScDBData* pData = rDBColl.getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rTarget));
2021
0
    if (!pData)
2022
0
    {
2023
0
        std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
2024
0
                                                      VclMessageType::Info, VclButtonsType::Ok,
2025
0
                                                      ScResId(STR_TARGETNOTFOUND)));
2026
0
        xInfoBox->run();
2027
0
        return;
2028
0
    }
2029
2030
0
    SCTAB nTab;
2031
0
    SCCOL nDummyCol;
2032
0
    SCROW nDummyRow;
2033
0
    pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
2034
2035
0
    ScImportParam aImportParam;
2036
0
    pData->GetImportParam( aImportParam );
2037
2038
0
    OUString sDBName;
2039
0
    OUString sDBTable;
2040
0
    sal_Int32 nCommandType = 0;
2041
0
    sDBName = rDescriptor.getDataSource();
2042
0
    rDescriptor[svx::DataAccessDescriptorProperty::Command]     >>= sDBTable;
2043
0
    rDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= nCommandType;
2044
2045
0
    aImportParam.aDBName    = sDBName;
2046
0
    aImportParam.bSql       = ( nCommandType == sdb::CommandType::COMMAND );
2047
0
    aImportParam.aStatement = sDBTable;
2048
0
    aImportParam.bNative    = false;
2049
0
    aImportParam.nType      = static_cast<sal_uInt8>( ( nCommandType == sdb::CommandType::QUERY ) ? ScDbQuery : ScDbTable );
2050
0
    aImportParam.bImport    = true;
2051
2052
0
    bool bContinue = DoImport( nTab, aImportParam, &rDescriptor );
2053
2054
    //  repeat DB operations
2055
2056
0
    ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
2057
0
    if (!pViewSh)
2058
0
        return;
2059
2060
0
    ScRange aRange;
2061
0
    pData->GetArea(aRange);
2062
0
    pViewSh->MarkRange(aRange);         // select
2063
2064
0
    if ( bContinue )        // error at import -> abort
2065
0
    {
2066
        //  internal operations, if some are saved
2067
2068
0
        if ( pData->HasQueryParam() || pData->HasSortParam() || pData->HasSubTotalParam() )
2069
0
            pViewSh->RepeatDB();
2070
2071
        //  pivot tables which have the range as source data
2072
2073
0
        rDocShell.RefreshPivotTables(aRange);
2074
0
    }
2075
0
}
2076
2077
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */