LCOV - code coverage report
Current view: top level - sc/source/ui/docshell - dbdocfun.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 515 856 60.2 %
Date: 2015-06-13 12:38:46 Functions: 20 22 90.9 %
Legend: Lines: hit not hit

          Line data    Source code
       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/msgbox.hxx>
      22             : #include <vcl/waitobj.hxx>
      23             : #include <svx/dataaccessdescriptor.hxx>
      24             : 
      25             : #include <com/sun/star/sdb/CommandType.hpp>
      26             : 
      27             : #include "dbdocfun.hxx"
      28             : #include "sc.hrc"
      29             : #include "dbdata.hxx"
      30             : #include "undodat.hxx"
      31             : #include "docsh.hxx"
      32             : #include "docfunc.hxx"
      33             : #include "globstr.hrc"
      34             : #include "globalnames.hxx"
      35             : #include "tabvwsh.hxx"
      36             : #include "patattr.hxx"
      37             : #include "rangenam.hxx"
      38             : #include "olinetab.hxx"
      39             : #include "dpobject.hxx"
      40             : #include "dpsave.hxx"
      41             : #include "dociter.hxx"
      42             : #include "editable.hxx"
      43             : #include "attrib.hxx"
      44             : #include "drwlayer.hxx"
      45             : #include "dpshttab.hxx"
      46             : #include "hints.hxx"
      47             : #include "queryentry.hxx"
      48             : #include "markdata.hxx"
      49             : #include "progress.hxx"
      50             : #include <undosort.hxx>
      51             : #include <inputopt.hxx>
      52             : 
      53             : #include <set>
      54             : #include <memory>
      55             : 
      56             : using namespace ::com::sun::star;
      57             : 
      58           4 : bool ScDBDocFunc::AddDBRange( const OUString& rName, const ScRange& rRange, bool /* bApi */ )
      59             : {
      60             : 
      61           4 :     ScDocShellModificator aModificator( rDocShell );
      62             : 
      63           4 :     ScDocument& rDoc = rDocShell.GetDocument();
      64           4 :     ScDBCollection* pDocColl = rDoc.GetDBCollection();
      65           4 :     bool bUndo (rDoc.IsUndoEnabled());
      66             : 
      67           4 :     ScDBCollection* pUndoColl = NULL;
      68           4 :     if (bUndo)
      69           4 :         pUndoColl = new ScDBCollection( *pDocColl );
      70             : 
      71           4 :     ScDBData* pNew = new ScDBData( rName, rRange.aStart.Tab(),
      72           8 :                                     rRange.aStart.Col(), rRange.aStart.Row(),
      73          12 :                                     rRange.aEnd.Col(), rRange.aEnd.Row() );
      74             : 
      75             :     // #i55926# While loading XML, formula cells only have a single string token,
      76             :     // so CompileDBFormula would never find any name (index) tokens, and would
      77             :     // unnecessarily loop through all cells.
      78           4 :     bool bCompile = !rDoc.IsImportingXML();
      79             :     bool bOk;
      80           4 :     if ( bCompile )
      81           4 :         rDoc.PreprocessDBDataUpdate();
      82           4 :     if ( rName == STR_DB_LOCAL_NONAME )
      83             :     {
      84           1 :         rDoc.SetAnonymousDBData(rRange.aStart.Tab() , pNew);
      85           1 :         bOk = true;
      86             :     }
      87             :     else
      88             :     {
      89           3 :         bOk = pDocColl->getNamedDBs().insert(pNew);
      90             :     }
      91           4 :     if ( bCompile )
      92           4 :         rDoc.CompileHybridFormula();
      93             : 
      94           4 :     if (!bOk)
      95             :     {
      96           0 :         delete pNew;
      97           0 :         delete pUndoColl;
      98           0 :         return false;
      99             :     }
     100             : 
     101           4 :     if (bUndo)
     102             :     {
     103           4 :         ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
     104           4 :         rDocShell.GetUndoManager()->AddUndoAction(
     105           4 :                         new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
     106             :     }
     107             : 
     108           4 :     aModificator.SetDocumentModified();
     109           4 :     SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
     110           4 :     return true;
     111             : }
     112             : 
     113           0 : bool ScDBDocFunc::DeleteDBRange(const OUString& rName)
     114             : {
     115           0 :     bool bDone = false;
     116           0 :     ScDocument& rDoc = rDocShell.GetDocument();
     117           0 :     ScDBCollection* pDocColl = rDoc.GetDBCollection();
     118           0 :     bool bUndo = rDoc.IsUndoEnabled();
     119             : 
     120           0 :     ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
     121           0 :     const ScDBData* p = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rName));
     122           0 :     if (p)
     123             :     {
     124           0 :         ScDocShellModificator aModificator( rDocShell );
     125             : 
     126           0 :         ScDBCollection* pUndoColl = NULL;
     127           0 :         if (bUndo)
     128           0 :             pUndoColl = new ScDBCollection( *pDocColl );
     129             : 
     130           0 :         rDoc.PreprocessDBDataUpdate();
     131           0 :         rDBs.erase(*p);
     132           0 :         rDoc.CompileHybridFormula();
     133             : 
     134           0 :         if (bUndo)
     135             :         {
     136           0 :             ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
     137           0 :             rDocShell.GetUndoManager()->AddUndoAction(
     138           0 :                             new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
     139             :         }
     140             : 
     141           0 :         aModificator.SetDocumentModified();
     142           0 :         SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
     143           0 :         bDone = true;
     144             :     }
     145             : 
     146           0 :     return bDone;
     147             : }
     148             : 
     149           2 : bool ScDBDocFunc::RenameDBRange( const OUString& rOld, const OUString& rNew )
     150             : {
     151           2 :     bool bDone = false;
     152           2 :     ScDocument& rDoc = rDocShell.GetDocument();
     153           2 :     ScDBCollection* pDocColl = rDoc.GetDBCollection();
     154           2 :     bool bUndo = rDoc.IsUndoEnabled();
     155           2 :     ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
     156           2 :     const ScDBData* pOld = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rOld));
     157           2 :     const ScDBData* pNew = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rNew));
     158           2 :     if (pOld && !pNew)
     159             :     {
     160           2 :         ScDocShellModificator aModificator( rDocShell );
     161             : 
     162           2 :         ScDBData* pNewData = new ScDBData(rNew, *pOld);
     163             : 
     164           2 :         ScDBCollection* pUndoColl = new ScDBCollection( *pDocColl );
     165             : 
     166           2 :         rDoc.PreprocessDBDataUpdate();
     167           2 :         rDBs.erase(*pOld);
     168           2 :         bool bInserted = rDBs.insert(pNewData);
     169           2 :         if (!bInserted)                             // Fehler -> alten Zustand wiederherstellen
     170             :         {
     171           0 :             delete pNewData;
     172           0 :             rDoc.SetDBCollection(pUndoColl);       // gehoert dann dem Dokument
     173             :         }
     174             : 
     175           2 :         rDoc.CompileHybridFormula();
     176             : 
     177           2 :         if (bInserted)                              // Einfuegen hat geklappt
     178             :         {
     179           2 :             if (bUndo)
     180             :             {
     181           2 :                 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
     182           2 :                 rDocShell.GetUndoManager()->AddUndoAction(
     183           2 :                                 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
     184             :             }
     185             :             else
     186           0 :                 delete pUndoColl;
     187             : 
     188           2 :             aModificator.SetDocumentModified();
     189           2 :             SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
     190           2 :             bDone = true;
     191           2 :         }
     192             :     }
     193             : 
     194           2 :     return bDone;
     195             : }
     196             : 
     197          51 : bool ScDBDocFunc::ModifyDBData( const ScDBData& rNewData )
     198             : {
     199          51 :     bool bDone = false;
     200          51 :     ScDocument& rDoc = rDocShell.GetDocument();
     201          51 :     ScDBCollection* pDocColl = rDoc.GetDBCollection();
     202          51 :     bool bUndo = rDoc.IsUndoEnabled();
     203             : 
     204          51 :     ScDBData* pData = NULL;
     205          51 :     if (rNewData.GetName() == STR_DB_LOCAL_NONAME)
     206             :     {
     207          26 :         ScRange aRange;
     208          26 :         rNewData.GetArea(aRange);
     209          26 :         SCTAB nTab = aRange.aStart.Tab();
     210          26 :         pData = rDoc.GetAnonymousDBData(nTab);
     211             :     }
     212             :     else
     213          25 :         pData = pDocColl->getNamedDBs().findByUpperName(rNewData.GetUpperName());
     214             : 
     215          51 :     if (pData)
     216             :     {
     217          51 :         ScDocShellModificator aModificator( rDocShell );
     218          51 :         ScRange aOldRange, aNewRange;
     219          51 :         pData->GetArea(aOldRange);
     220          51 :         rNewData.GetArea(aNewRange);
     221          51 :         bool bAreaChanged = ( aOldRange != aNewRange );     // dann muss neu compiliert werden
     222             : 
     223          51 :         ScDBCollection* pUndoColl = NULL;
     224          51 :         if (bUndo)
     225          43 :             pUndoColl = new ScDBCollection( *pDocColl );
     226             : 
     227          51 :         *pData = rNewData;
     228          51 :         if (bAreaChanged)
     229           1 :             rDoc.CompileDBFormula();
     230             : 
     231          51 :         if (bUndo)
     232             :         {
     233          43 :             ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
     234          43 :             rDocShell.GetUndoManager()->AddUndoAction(
     235          43 :                             new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
     236             :         }
     237             : 
     238          51 :         aModificator.SetDocumentModified();
     239          51 :         bDone = true;
     240             :     }
     241             : 
     242          51 :     return bDone;
     243             : }
     244             : 
     245           1 : void ScDBDocFunc::ModifyAllDBData( const ScDBCollection& rNewColl, const std::vector<ScRange>& rDelAreaList )
     246             : {
     247           1 :     ScDocShellModificator aModificator(rDocShell);
     248           1 :     ScDocument& rDoc = rDocShell.GetDocument();
     249           1 :     ScDBCollection* pOldColl = rDoc.GetDBCollection();
     250           1 :     ScDBCollection* pUndoColl = NULL;
     251           1 :     bool bRecord = rDoc.IsUndoEnabled();
     252             : 
     253           1 :     std::vector<ScRange>::const_iterator iter;
     254           1 :     for (iter = rDelAreaList.begin(); iter != rDelAreaList.end(); ++iter)
     255             :     {
     256             :         // unregistering target in SBA no longer necessary
     257           0 :         const ScAddress& rStart = iter->aStart;
     258           0 :         const ScAddress& rEnd   = iter->aEnd;
     259             :         rDocShell.DBAreaDeleted(
     260           0 :             rStart.Tab(), rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row());
     261             :     }
     262             : 
     263           1 :     if (bRecord)
     264           1 :         pUndoColl = new ScDBCollection( *pOldColl );
     265             : 
     266             :     //  register target in SBA no longer necessary
     267             : 
     268           1 :     rDoc.PreprocessDBDataUpdate();
     269           1 :     rDoc.SetDBCollection( new ScDBCollection( rNewColl ) );
     270           1 :     rDoc.CompileHybridFormula();
     271           1 :     pOldColl = NULL;
     272           1 :     rDocShell.PostPaint(ScRange(0, 0, 0, MAXCOL, MAXROW, MAXTAB), PAINT_GRID);
     273           1 :     aModificator.SetDocumentModified();
     274           1 :     SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
     275             : 
     276           1 :     if (bRecord)
     277             :     {
     278           1 :         ScDBCollection* pRedoColl = new ScDBCollection(rNewColl);
     279           1 :         rDocShell.GetUndoManager()->AddUndoAction(
     280           1 :             new ScUndoDBData(&rDocShell, pUndoColl, pRedoColl));
     281           1 :     }
     282           1 : }
     283             : 
     284          10 : bool ScDBDocFunc::RepeatDB( const OUString& rDBName, bool bRecord, bool bApi, bool bIsUnnamed, SCTAB aTab )
     285             : {
     286             :     //! auch fuer ScDBFunc::RepeatDB benutzen!
     287             : 
     288          10 :     bool bDone = false;
     289          10 :     ScDocument& rDoc = rDocShell.GetDocument();
     290          10 :     if (bRecord && !rDoc.IsUndoEnabled())
     291           0 :         bRecord = false;
     292          10 :     ScDBData* pDBData = NULL;
     293          10 :     if (bIsUnnamed)
     294             :     {
     295           9 :         pDBData = rDoc.GetAnonymousDBData( aTab );
     296             :     }
     297             :     else
     298             :     {
     299           1 :         ScDBCollection* pColl = rDoc.GetDBCollection();
     300           1 :         if (pColl)
     301           1 :             pDBData = pColl->getNamedDBs().findByUpperName(ScGlobal::pCharClass->uppercase(rDBName));
     302             :     }
     303             : 
     304          10 :     if ( pDBData )
     305             :     {
     306          10 :         ScQueryParam aQueryParam;
     307          10 :         pDBData->GetQueryParam( aQueryParam );
     308          10 :         bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
     309             : 
     310          20 :         ScSortParam aSortParam;
     311          10 :         pDBData->GetSortParam( aSortParam );
     312          10 :         bool bSort = aSortParam.maKeyState[0].bDoSort;
     313             : 
     314          10 :         ScSubTotalParam aSubTotalParam;
     315          10 :         pDBData->GetSubTotalParam( aSubTotalParam );
     316          10 :         bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
     317             : 
     318          10 :         if ( bQuery || bSort || bSubTotal )
     319             :         {
     320          10 :             bool bQuerySize = false;
     321          10 :             ScRange aOldQuery;
     322          10 :             ScRange aNewQuery;
     323          10 :             if (bQuery && !aQueryParam.bInplace)
     324             :             {
     325             :                 ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
     326           0 :                                                         aQueryParam.nDestTab, true );
     327           0 :                 if (pDest && pDest->IsDoSize())
     328             :                 {
     329           0 :                     pDest->GetArea( aOldQuery );
     330           0 :                     bQuerySize = true;
     331             :                 }
     332             :             }
     333             : 
     334             :             SCTAB nTab;
     335             :             SCCOL nStartCol;
     336             :             SCROW nStartRow;
     337             :             SCCOL nEndCol;
     338             :             SCROW nEndRow;
     339          10 :             pDBData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
     340             : 
     341             :             //!     Undo nur benoetigte Daten ?
     342             : 
     343          10 :             ScDocument* pUndoDoc = NULL;
     344          10 :             ScOutlineTable* pUndoTab = NULL;
     345          10 :             ScRangeName* pUndoRange = NULL;
     346          10 :             ScDBCollection* pUndoDB = NULL;
     347             : 
     348          10 :             if (bRecord)
     349             :             {
     350          10 :                 SCTAB nTabCount = rDoc.GetTableCount();
     351          10 :                 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
     352          10 :                 ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
     353          10 :                 if (pTable)
     354             :                 {
     355           9 :                     pUndoTab = new ScOutlineTable( *pTable );
     356             : 
     357             :                     // column/row state
     358             :                     SCCOLROW nOutStartCol, nOutEndCol;
     359             :                     SCCOLROW nOutStartRow, nOutEndRow;
     360           9 :                     pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
     361           9 :                     pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
     362             : 
     363           9 :                     pUndoDoc->InitUndo( &rDoc, nTab, nTab, true, true );
     364             :                     rDoc.CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0,
     365             :                             nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab,
     366           9 :                             IDF_NONE, false, pUndoDoc );
     367             :                     rDoc.CopyToDocument( 0, static_cast<SCROW>(nOutStartRow),
     368             :                             nTab, MAXCOL, static_cast<SCROW>(nOutEndRow), nTab,
     369           9 :                             IDF_NONE, false, pUndoDoc );
     370             :                 }
     371             :                 else
     372           1 :                     pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, true );
     373             : 
     374             :                 //  Datenbereich sichern - incl. Filter-Ergebnis
     375          10 :                 rDoc.CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, false, pUndoDoc );
     376             : 
     377             :                 //  alle Formeln wegen Referenzen
     378          10 :                 rDoc.CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, false, pUndoDoc );
     379             : 
     380             :                 //  DB- und andere Bereiche
     381          10 :                 ScRangeName* pDocRange = rDoc.GetRangeName();
     382          10 :                 if (!pDocRange->empty())
     383           0 :                     pUndoRange = new ScRangeName( *pDocRange );
     384          10 :                 ScDBCollection* pDocDB = rDoc.GetDBCollection();
     385          10 :                 if (!pDocDB->empty())
     386           1 :                     pUndoDB = new ScDBCollection( *pDocDB );
     387             :             }
     388             : 
     389          10 :             if (bSort && bSubTotal)
     390             :             {
     391             :                 //  Sortieren ohne SubTotals
     392             : 
     393           0 :                 aSubTotalParam.bRemoveOnly = true;      // wird unten wieder zurueckgesetzt
     394           0 :                 DoSubTotals( nTab, aSubTotalParam, NULL, false, bApi );
     395             :             }
     396             : 
     397          10 :             if (bSort)
     398             :             {
     399           0 :                 pDBData->GetSortParam( aSortParam );            // Bereich kann sich geaendert haben
     400           0 :                 (void)Sort( nTab, aSortParam, false, false, bApi );
     401             :             }
     402          10 :             if (bQuery)
     403             :             {
     404          10 :                 pDBData->GetQueryParam( aQueryParam );          // Bereich kann sich geaendert haben
     405          10 :                 ScRange aAdvSource;
     406          10 :                 if (pDBData->GetAdvancedQuerySource(aAdvSource))
     407           0 :                     Query( nTab, aQueryParam, &aAdvSource, false, bApi );
     408             :                 else
     409          10 :                     Query( nTab, aQueryParam, NULL, false, bApi );
     410             : 
     411             :                 //  bei nicht-inplace kann die Tabelle umgestellt worden sein
     412             : //              if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
     413             : //                  SetTabNo( nTab );
     414             :             }
     415          10 :             if (bSubTotal)
     416             :             {
     417           0 :                 pDBData->GetSubTotalParam( aSubTotalParam );    // Bereich kann sich geaendert haben
     418           0 :                 aSubTotalParam.bRemoveOnly = false;
     419           0 :                 DoSubTotals( nTab, aSubTotalParam, NULL, false, bApi );
     420             :             }
     421             : 
     422          10 :             if (bRecord)
     423             :             {
     424             :                 SCTAB nDummyTab;
     425             :                 SCCOL nDummyCol;
     426             :                 SCROW nDummyRow;
     427             :                 SCROW nNewEndRow;
     428          10 :                 pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
     429             : 
     430          10 :                 const ScRange* pOld = NULL;
     431          10 :                 const ScRange* pNew = NULL;
     432          10 :                 if (bQuerySize)
     433             :                 {
     434             :                     ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
     435           0 :                                                             aQueryParam.nDestTab, true );
     436           0 :                     if (pDest)
     437             :                     {
     438           0 :                         pDest->GetArea( aNewQuery );
     439           0 :                         pOld = &aOldQuery;
     440           0 :                         pNew = &aNewQuery;
     441             :                     }
     442             :                 }
     443             : 
     444          10 :                 rDocShell.GetUndoManager()->AddUndoAction(
     445             :                     new ScUndoRepeatDB( &rDocShell, nTab,
     446             :                                             nStartCol, nStartRow, nEndCol, nEndRow,
     447             :                                             nNewEndRow,
     448             :                                             //nCurX, nCurY,
     449             :                                             nStartCol, nStartRow,
     450             :                                             pUndoDoc, pUndoTab,
     451             :                                             pUndoRange, pUndoDB,
     452          10 :                                             pOld, pNew ) );
     453             :             }
     454             : 
     455             :             rDocShell.PostPaint(ScRange(0, 0, nTab, MAXCOL, MAXROW, nTab),
     456          10 :                                 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE);
     457          10 :             bDone = true;
     458             :         }
     459           0 :         else if (!bApi)     // "Keine Operationen auszufuehren"
     460          10 :             rDocShell.ErrorMessage(STR_MSSG_REPEATDB_0);
     461             :     }
     462             : 
     463          10 :     return bDone;
     464             : }
     465             : 
     466          29 : bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
     467             :                             bool bRecord, bool bPaint, bool bApi )
     468             : {
     469          29 :     ScDocShellModificator aModificator( rDocShell );
     470             : 
     471          29 :     ScDocument& rDoc = rDocShell.GetDocument();
     472          29 :     if (bRecord && !rDoc.IsUndoEnabled())
     473           0 :         bRecord = false;
     474             : 
     475             :     ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
     476          29 :                                                     rSortParam.nCol2, rSortParam.nRow2 );
     477          29 :     if (!pDBData)
     478             :     {
     479             :         OSL_FAIL( "Sort: keine DBData" );
     480           0 :         return false;
     481             :     }
     482             : 
     483          29 :     bool bCopy = !rSortParam.bInplace;
     484          29 :     if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 &&
     485           0 :                   rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab )
     486           0 :         bCopy = false;
     487             : 
     488          58 :     ScSortParam aLocalParam( rSortParam );
     489          29 :     if ( bCopy )
     490             :     {
     491             :         // Copy the data range to the destination then move the sort range to it.
     492           1 :         ScRange aSrcRange(rSortParam.nCol1, rSortParam.nRow1, nTab, rSortParam.nCol2, rSortParam.nRow2, nTab);
     493           1 :         ScAddress aDestPos(rSortParam.nDestCol,rSortParam.nDestRow,rSortParam.nDestTab);
     494             : 
     495           1 :         ScDocFunc& rDocFunc = rDocShell.GetDocFunc();
     496           1 :         bool bRet = rDocFunc.MoveBlock(aSrcRange, aDestPos, false, bRecord, bPaint, bApi);
     497             : 
     498           1 :         if (!bRet)
     499           0 :             return false;
     500             : 
     501           1 :         aLocalParam.MoveToDest();
     502           1 :         nTab = aLocalParam.nDestTab;
     503             :     }
     504             : 
     505             :     ScEditableTester aTester( &rDoc, nTab, aLocalParam.nCol1,aLocalParam.nRow1,
     506          29 :                                         aLocalParam.nCol2,aLocalParam.nRow2 );
     507          29 :     if (!aTester.IsEditable())
     508             :     {
     509           0 :         if (!bApi)
     510           0 :             rDocShell.ErrorMessage(aTester.GetMessageId());
     511           0 :         return false;
     512             :     }
     513             : 
     514          57 :     if ( aLocalParam.bIncludePattern && rDoc.HasAttrib(
     515             :                                         aLocalParam.nCol1, aLocalParam.nRow1, nTab,
     516             :                                         aLocalParam.nCol2, aLocalParam.nRow2, nTab,
     517          28 :                                         HASATTR_MERGED | HASATTR_OVERLAPPED ) )
     518             :     {
     519             :         //  Merge-Attribute wuerden beim Sortieren durcheinanderkommen
     520           0 :         if (!bApi)
     521           0 :             rDocShell.ErrorMessage(STR_SORT_ERR_MERGED);
     522           0 :         return false;
     523             :     }
     524             : 
     525             :     //      ausfuehren
     526             : 
     527          58 :     WaitObject aWait( ScDocShell::GetActiveDialogParent() );
     528             : 
     529             :     // Adjust aLocalParam cols/rows to used data area. Keep sticky top row or
     530             :     // column (depending on direction) in any case, not just if it has headers,
     531             :     // so empty leading cells will be sorted to the end.
     532          29 :     bool bShrunk = false;
     533             :     rDoc.ShrinkToUsedDataArea( bShrunk, nTab, aLocalParam.nCol1, aLocalParam.nRow1,
     534          29 :             aLocalParam.nCol2, aLocalParam.nRow2, false, aLocalParam.bByRow, !aLocalParam.bByRow);
     535             : 
     536          29 :     SCROW nStartRow = aLocalParam.nRow1;
     537          29 :     if (aLocalParam.bByRow && aLocalParam.bHasHeader && nStartRow < aLocalParam.nRow2)
     538          16 :         ++nStartRow;
     539             : 
     540             :     // Calculate the script types for all cells in the sort range beforehand.
     541             :     // This will speed up the row height adjustment that takes place after the
     542             :     // sort.
     543             :     rDoc.UpdateScriptTypes(
     544             :         ScAddress(aLocalParam.nCol1,nStartRow,nTab),
     545             :         aLocalParam.nCol2-aLocalParam.nCol1+1,
     546          29 :         aLocalParam.nRow2-nStartRow+1);
     547             : 
     548             :     // No point adjusting row heights after the sort when all rows have the same height.
     549             :     bool bUniformRowHeight =
     550          29 :         rDoc.HasUniformRowHeight(nTab, nStartRow, aLocalParam.nRow2);
     551             : 
     552          29 :     bool bRepeatQuery = false;                          // bestehenden Filter wiederholen?
     553          58 :     ScQueryParam aQueryParam;
     554          29 :     pDBData->GetQueryParam( aQueryParam );
     555          29 :     if ( aQueryParam.GetEntry(0).bDoQuery )
     556           0 :         bRepeatQuery = true;
     557             : 
     558          58 :     sc::ReorderParam aUndoParam;
     559             : 
     560             :     // don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set)
     561          29 :     if (aLocalParam.GetSortKeyCount() && aLocalParam.maKeyState[0].bDoSort)
     562             :     {
     563          29 :         ScInputOptions aInputOption = SC_MOD()->GetInputOptions();
     564          29 :         bool bUpdateRefs = aInputOption.GetSortRefUpdate();
     565          58 :         ScProgress aProgress(&rDocShell, ScGlobal::GetRscString(STR_PROGRESS_SORTING), 0);
     566          58 :         rDoc.Sort(nTab, aLocalParam, bRepeatQuery, bUpdateRefs, &aProgress, &aUndoParam);
     567             :     }
     568             : 
     569          29 :     if (bRecord)
     570             :     {
     571             :         // Set up an undo object.
     572          28 :         sc::UndoSort* pUndoAction = new sc::UndoSort(&rDocShell, aUndoParam);
     573          28 :         rDocShell.GetUndoManager()->AddUndoAction(pUndoAction);
     574             :     }
     575             : 
     576          29 :     pDBData->SetSortParam(rSortParam);
     577             : 
     578          29 :     if (nStartRow <= aLocalParam.nRow2)
     579             :     {
     580             :         ScRange aDirtyRange(
     581             :                 aLocalParam.nCol1, nStartRow, nTab,
     582          29 :                 aLocalParam.nCol2, aLocalParam.nRow2, nTab);
     583          29 :         rDoc.SetDirty( aDirtyRange, true );
     584             :     }
     585             : 
     586          29 :     if (bPaint)
     587             :     {
     588          27 :         sal_uInt16 nPaint = PAINT_GRID;
     589          27 :         SCCOL nStartX = aLocalParam.nCol1;
     590          27 :         SCROW nStartY = aLocalParam.nRow1;
     591          27 :         SCCOL nEndX = aLocalParam.nCol2;
     592          27 :         SCROW nEndY = aLocalParam.nRow2;
     593          27 :         if ( bRepeatQuery )
     594             :         {
     595           0 :             nPaint |= PAINT_LEFT;
     596           0 :             nStartX = 0;
     597           0 :             nEndX = MAXCOL;
     598             :         }
     599          27 :         rDocShell.PostPaint(ScRange(nStartX, nStartY, nTab, nEndX, nEndY, nTab), nPaint);
     600             :     }
     601             : 
     602          29 :     if (!bUniformRowHeight && nStartRow <= aLocalParam.nRow2)
     603           0 :         rDocShell.AdjustRowHeight(nStartRow, aLocalParam.nRow2, nTab);
     604             : 
     605          29 :     aModificator.SetDocumentModified();
     606             : 
     607          58 :     return true;
     608             : }
     609             : 
     610          14 : bool ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam,
     611             :                         const ScRange* pAdvSource, bool bRecord, bool bApi )
     612             : {
     613          14 :     ScDocShellModificator aModificator( rDocShell );
     614             : 
     615          14 :     ScDocument& rDoc = rDocShell.GetDocument();
     616          14 :     if (bRecord && !rDoc.IsUndoEnabled())
     617           0 :         bRecord = false;
     618             :     ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rQueryParam.nCol1, rQueryParam.nRow1,
     619          14 :                                                     rQueryParam.nCol2, rQueryParam.nRow2 );
     620          14 :     if (!pDBData)
     621             :     {
     622             :         OSL_FAIL( "Query: keine DBData" );
     623           0 :         return false;
     624             :     }
     625             : 
     626             :     //  Wechsel von Inplace auf nicht-Inplace, dann erst Inplace aufheben:
     627             :     //  (nur, wenn im Dialog "Persistent" ausgewaehlt ist)
     628             : 
     629          14 :     if ( !rQueryParam.bInplace && pDBData->HasQueryParam() && rQueryParam.bDestPers )
     630             :     {
     631           0 :         ScQueryParam aOldQuery;
     632           0 :         pDBData->GetQueryParam(aOldQuery);
     633           0 :         if (aOldQuery.bInplace)
     634             :         {
     635             :             //  alte Filterung aufheben
     636             : 
     637           0 :             SCSIZE nEC = aOldQuery.GetEntryCount();
     638           0 :             for (SCSIZE i=0; i<nEC; i++)
     639           0 :                 aOldQuery.GetEntry(i).bDoQuery = false;
     640           0 :             aOldQuery.bDuplicate = true;
     641           0 :             Query( nTab, aOldQuery, NULL, bRecord, bApi );
     642           0 :         }
     643             :     }
     644             : 
     645          28 :     ScQueryParam aLocalParam( rQueryParam );        // fuer Paint / Zielbereich
     646          14 :     bool bCopy = !rQueryParam.bInplace;             // kopiert wird in Table::Query
     647          14 :     ScDBData* pDestData = NULL;                     // Bereich, in den kopiert wird
     648          14 :     bool bDoSize = false;                           // Zielgroesse anpassen (einf./loeschen)
     649          14 :     SCCOL nFormulaCols = 0;                     // nur bei bDoSize
     650          14 :     bool bKeepFmt = false;
     651          14 :     ScRange aOldDest;
     652          14 :     ScRange aDestTotal;
     653          14 :     if ( bCopy && rQueryParam.nDestCol == rQueryParam.nCol1 &&
     654           0 :                   rQueryParam.nDestRow == rQueryParam.nRow1 && rQueryParam.nDestTab == nTab )
     655           0 :         bCopy = false;
     656          14 :     SCTAB nDestTab = nTab;
     657          14 :     if ( bCopy )
     658             :     {
     659           0 :         aLocalParam.MoveToDest();
     660           0 :         nDestTab = rQueryParam.nDestTab;
     661           0 :         if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
     662             :         {
     663           0 :             if (!bApi)
     664           0 :                 rDocShell.ErrorMessage(STR_PASTE_FULL);
     665           0 :             return false;
     666             :         }
     667             : 
     668             :         ScEditableTester aTester( &rDoc, nDestTab, aLocalParam.nCol1,aLocalParam.nRow1,
     669           0 :                                                 aLocalParam.nCol2,aLocalParam.nRow2);
     670           0 :         if (!aTester.IsEditable())
     671             :         {
     672           0 :             if (!bApi)
     673           0 :                 rDocShell.ErrorMessage(aTester.GetMessageId());
     674           0 :             return false;
     675             :         }
     676             : 
     677             :         pDestData = rDoc.GetDBAtCursor( rQueryParam.nDestCol, rQueryParam.nDestRow,
     678           0 :                                             rQueryParam.nDestTab, true );
     679           0 :         if (pDestData)
     680             :         {
     681           0 :             pDestData->GetArea( aOldDest );
     682           0 :             aDestTotal=ScRange( rQueryParam.nDestCol,
     683             :                                 rQueryParam.nDestRow,
     684             :                                 nDestTab,
     685             :                                 rQueryParam.nDestCol + rQueryParam.nCol2 - rQueryParam.nCol1,
     686           0 :                                 rQueryParam.nDestRow + rQueryParam.nRow2 - rQueryParam.nRow1,
     687           0 :                                 nDestTab );
     688             : 
     689           0 :             bDoSize = pDestData->IsDoSize();
     690             :             //  Test, ob Formeln aufgefuellt werden muessen (nFormulaCols):
     691           0 :             if ( bDoSize && aOldDest.aEnd.Col() == aDestTotal.aEnd.Col() )
     692             :             {
     693           0 :                 SCCOL nTestCol = aOldDest.aEnd.Col() + 1;       // neben dem Bereich
     694           0 :                 SCROW nTestRow = rQueryParam.nDestRow +
     695           0 :                                     ( aLocalParam.bHasHeader ? 1 : 0 );
     696           0 :                 while ( nTestCol <= MAXCOL &&
     697           0 :                         rDoc.GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA )
     698           0 :                     ++nTestCol, ++nFormulaCols;
     699             :             }
     700             : 
     701           0 :             bKeepFmt = pDestData->IsKeepFmt();
     702           0 :             if ( bDoSize && !rDoc.CanFitBlock( aOldDest, aDestTotal ) )
     703             :             {
     704           0 :                 if (!bApi)
     705           0 :                     rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);     // kann keine Zeilen einfuegen
     706           0 :                 return false;
     707             :             }
     708             :         }
     709             :     }
     710             : 
     711             :     //      ausfuehren
     712             : 
     713          28 :     WaitObject aWait( ScDocShell::GetActiveDialogParent() );
     714             : 
     715          14 :     bool bKeepSub = false;                          // bestehende Teilergebnisse wiederholen?
     716          14 :     ScSubTotalParam aSubTotalParam;
     717          14 :     if (rQueryParam.GetEntry(0).bDoQuery)           // nicht beim Aufheben
     718             :     {
     719          11 :         pDBData->GetSubTotalParam( aSubTotalParam );    // Teilergebnisse vorhanden?
     720             : 
     721          11 :         if ( aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly )
     722           0 :             bKeepSub = true;
     723             :     }
     724             : 
     725          14 :     ScDocument* pUndoDoc = NULL;
     726          14 :     ScDBCollection* pUndoDB = NULL;
     727          14 :     const ScRange* pOld = NULL;
     728             : 
     729          14 :     if ( bRecord )
     730             :     {
     731           4 :         pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
     732           4 :         if (bCopy)
     733             :         {
     734           0 :             pUndoDoc->InitUndo( &rDoc, nDestTab, nDestTab, false, true );
     735             :             rDoc.CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
     736             :                                     aLocalParam.nCol2, aLocalParam.nRow2, nDestTab,
     737           0 :                                     IDF_ALL, false, pUndoDoc );
     738             :             //  Attribute sichern, falls beim Filtern mitkopiert
     739             : 
     740           0 :             if (pDestData)
     741             :             {
     742           0 :                 rDoc.CopyToDocument( aOldDest, IDF_ALL, false, pUndoDoc );
     743           0 :                 pOld = &aOldDest;
     744             :             }
     745             :         }
     746             :         else
     747             :         {
     748           4 :             pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, true );
     749             :             rDoc.CopyToDocument( 0, rQueryParam.nRow1, nTab, MAXCOL, rQueryParam.nRow2, nTab,
     750           4 :                                         IDF_NONE, false, pUndoDoc );
     751             :         }
     752             : 
     753           4 :         ScDBCollection* pDocDB = rDoc.GetDBCollection();
     754           4 :         if (!pDocDB->empty())
     755           0 :             pUndoDB = new ScDBCollection( *pDocDB );
     756             : 
     757           4 :         rDoc.BeginDrawUndo();
     758             :     }
     759             : 
     760          14 :     ScDocument* pAttribDoc = NULL;
     761          14 :     ScRange aAttribRange;
     762          14 :     if (pDestData)                                      // Zielbereich loeschen
     763             :     {
     764           0 :         if ( bKeepFmt )
     765             :         {
     766             :             //  kleinere der End-Spalten, Header+1 Zeile
     767           0 :             aAttribRange = aOldDest;
     768           0 :             if ( aAttribRange.aEnd.Col() > aDestTotal.aEnd.Col() )
     769           0 :                 aAttribRange.aEnd.SetCol( aDestTotal.aEnd.Col() );
     770           0 :             aAttribRange.aEnd.SetRow( aAttribRange.aStart.Row() +
     771           0 :                                         ( aLocalParam.bHasHeader ? 1 : 0 ) );
     772             : 
     773             :             //  auch fuer aufgefuellte Formeln
     774           0 :             aAttribRange.aEnd.SetCol( aAttribRange.aEnd.Col() + nFormulaCols );
     775             : 
     776           0 :             pAttribDoc = new ScDocument( SCDOCMODE_UNDO );
     777           0 :             pAttribDoc->InitUndo( &rDoc, nDestTab, nDestTab, false, true );
     778           0 :             rDoc.CopyToDocument( aAttribRange, IDF_ATTRIB, false, pAttribDoc );
     779             :         }
     780             : 
     781           0 :         if ( bDoSize )
     782           0 :             rDoc.FitBlock( aOldDest, aDestTotal );
     783             :         else
     784           0 :             rDoc.DeleteAreaTab(aOldDest, IDF_ALL);         // einfach loeschen
     785             :     }
     786             : 
     787             :     //  Filtern am Dokument ausfuehren
     788          14 :     SCSIZE nCount = rDoc.Query( nTab, rQueryParam, bKeepSub );
     789          14 :     if (bCopy)
     790             :     {
     791           0 :         aLocalParam.nRow2 = aLocalParam.nRow1 + nCount;
     792           0 :         if (!aLocalParam.bHasHeader && nCount > 0)
     793           0 :             --aLocalParam.nRow2;
     794             : 
     795           0 :         if ( bDoSize )
     796             :         {
     797             :             //  auf wirklichen Ergebnis-Bereich anpassen
     798             :             //  (das hier ist immer eine Verkleinerung)
     799             : 
     800             :             ScRange aNewDest( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
     801           0 :                                 aLocalParam.nCol2, aLocalParam.nRow2, nDestTab );
     802           0 :             rDoc.FitBlock( aDestTotal, aNewDest, false );      // sal_False - nicht loeschen
     803             : 
     804           0 :             if ( nFormulaCols > 0 )
     805             :             {
     806             :                 //  Formeln ausfuellen
     807             :                 //! Undo (Query und Repeat) !!!
     808             : 
     809             :                 ScRange aNewForm( aLocalParam.nCol2+1, aLocalParam.nRow1, nDestTab,
     810           0 :                                   aLocalParam.nCol2+nFormulaCols, aLocalParam.nRow2, nDestTab );
     811           0 :                 ScRange aOldForm = aNewForm;
     812           0 :                 aOldForm.aEnd.SetRow( aOldDest.aEnd.Row() );
     813           0 :                 rDoc.FitBlock( aOldForm, aNewForm, false );
     814             : 
     815           0 :                 ScMarkData aMark;
     816           0 :                 aMark.SelectOneTable(nDestTab);
     817           0 :                 SCROW nFStartY = aLocalParam.nRow1 + ( aLocalParam.bHasHeader ? 1 : 0 );
     818             : 
     819           0 :                 sal_uLong nProgCount = nFormulaCols;
     820           0 :                 nProgCount *= aLocalParam.nRow2 - nFStartY;
     821             :                 ScProgress aProgress( rDoc.GetDocumentShell(),
     822           0 :                         ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount );
     823             : 
     824             :                 rDoc.Fill( aLocalParam.nCol2+1, nFStartY,
     825             :                             aLocalParam.nCol2+nFormulaCols, nFStartY, &aProgress, aMark,
     826           0 :                             aLocalParam.nRow2 - nFStartY,
     827           0 :                             FILL_TO_BOTTOM, FILL_SIMPLE );
     828             :             }
     829             :         }
     830             : 
     831           0 :         if ( pAttribDoc )       // gemerkte Attribute zurueckkopieren
     832             :         {
     833             :             //  Header
     834           0 :             if (aLocalParam.bHasHeader)
     835             :             {
     836           0 :                 ScRange aHdrRange = aAttribRange;
     837           0 :                 aHdrRange.aEnd.SetRow( aHdrRange.aStart.Row() );
     838           0 :                 pAttribDoc->CopyToDocument( aHdrRange, IDF_ATTRIB, false, &rDoc );
     839             :             }
     840             : 
     841             :             //  Daten
     842           0 :             SCCOL nAttrEndCol = aAttribRange.aEnd.Col();
     843           0 :             SCROW nAttrRow = aAttribRange.aStart.Row() + ( aLocalParam.bHasHeader ? 1 : 0 );
     844           0 :             for (SCCOL nCol = aAttribRange.aStart.Col(); nCol<=nAttrEndCol; nCol++)
     845             :             {
     846             :                 const ScPatternAttr* pSrcPattern = pAttribDoc->GetPattern(
     847           0 :                                                     nCol, nAttrRow, nDestTab );
     848             :                 OSL_ENSURE(pSrcPattern,"Pattern ist 0");
     849           0 :                 if (pSrcPattern)
     850             :                 {
     851             :                     rDoc.ApplyPatternAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
     852           0 :                                                     nDestTab, *pSrcPattern );
     853           0 :                     const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet();
     854           0 :                     if (pStyle)
     855             :                         rDoc.ApplyStyleAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
     856           0 :                                                     nDestTab, *pStyle );
     857             :                 }
     858             :             }
     859             : 
     860           0 :             delete pAttribDoc;
     861             :         }
     862             :     }
     863             : 
     864             :     //  speichern: Inplace immer, sonst je nach Einstellung
     865             :     //             alter Inplace-Filter ist ggf. schon aufgehoben
     866             : 
     867          14 :     bool bSave = rQueryParam.bInplace || rQueryParam.bDestPers;
     868          14 :     if (bSave)                                                  // merken
     869             :     {
     870          14 :         pDBData->SetQueryParam( rQueryParam );
     871          14 :         pDBData->SetHeader( rQueryParam.bHasHeader );       //! ???
     872          14 :         pDBData->SetAdvancedQuerySource( pAdvSource );      // after SetQueryParam
     873             :     }
     874             : 
     875          14 :     if (bCopy)                                              // neuen DB-Bereich merken
     876             :     {
     877             :         //  selektieren wird hinterher von aussen (dbfunc)
     878             :         //  momentan ueber DB-Bereich an der Zielposition, darum muss dort
     879             :         //  auf jeden Fall ein Bereich angelegt werden.
     880             : 
     881             :         ScDBData* pNewData;
     882           0 :         if (pDestData)
     883           0 :             pNewData = pDestData;               // Bereich vorhanden -> anpassen (immer!)
     884             :         else                                    // Bereich anlegen
     885             :             pNewData = rDocShell.GetDBData(
     886             :                             ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
     887             :                                      aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ),
     888           0 :                             SC_DB_MAKE, SC_DBSEL_FORCE_MARK );
     889             : 
     890           0 :         if (pNewData)
     891             :         {
     892             :             pNewData->SetArea( nDestTab, aLocalParam.nCol1, aLocalParam.nRow1,
     893           0 :                                             aLocalParam.nCol2, aLocalParam.nRow2 );
     894             : 
     895             :             //  Query-Param wird am Ziel nicht mehr eingestellt, fuehrt nur zu Verwirrung
     896             :             //  und Verwechslung mit dem Query-Param am Quellbereich (#37187#)
     897             :         }
     898             :         else
     899             :         {
     900             :             OSL_FAIL("Zielbereich nicht da");
     901             :         }
     902             :     }
     903             : 
     904          14 :     if (!bCopy)
     905             :     {
     906          14 :         rDoc.InvalidatePageBreaks(nTab);
     907          14 :         rDoc.UpdatePageBreaks( nTab );
     908             :     }
     909             : 
     910             :     // #i23299# Subtotal functions depend on cell's filtered states.
     911          14 :     ScRange aDirtyRange(0 , aLocalParam.nRow1, nDestTab, MAXCOL, aLocalParam.nRow2, nDestTab);
     912          14 :     rDoc.SetSubTotalCellsDirty(aDirtyRange);
     913             : 
     914          14 :     if ( bRecord )
     915             :     {
     916             :         // create undo action after executing, because of drawing layer undo
     917           4 :         rDocShell.GetUndoManager()->AddUndoAction(
     918             :                     new ScUndoQuery( &rDocShell, nTab, rQueryParam, pUndoDoc, pUndoDB,
     919           4 :                                         pOld, bDoSize, pAdvSource ) );
     920             :     }
     921             : 
     922          14 :     if (bCopy)
     923             :     {
     924           0 :         SCCOL nEndX = aLocalParam.nCol2;
     925           0 :         SCROW nEndY = aLocalParam.nRow2;
     926           0 :         if (pDestData)
     927             :         {
     928           0 :             if ( aOldDest.aEnd.Col() > nEndX )
     929           0 :                 nEndX = aOldDest.aEnd.Col();
     930           0 :             if ( aOldDest.aEnd.Row() > nEndY )
     931           0 :                 nEndY = aOldDest.aEnd.Row();
     932             :         }
     933           0 :         if (bDoSize)
     934           0 :             nEndY = MAXROW;
     935             :         rDocShell.PostPaint(
     936             :             ScRange(aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, nEndX, nEndY, nDestTab),
     937           0 :             PAINT_GRID);
     938             :     }
     939             :     else
     940             :         rDocShell.PostPaint(
     941             :             ScRange(0, rQueryParam.nRow1, nTab, MAXCOL, MAXROW, nTab),
     942          14 :             PAINT_GRID | PAINT_LEFT);
     943          14 :     aModificator.SetDocumentModified();
     944             : 
     945          28 :     return true;
     946             : }
     947             : 
     948           2 : bool ScDBDocFunc::DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam,
     949             :                                 const ScSortParam* pForceNewSort, bool bRecord, bool bApi )
     950             : {
     951             :     //! auch fuer ScDBFunc::DoSubTotals benutzen!
     952             :     //  dann bleibt aussen:
     953             :     //  - neuen Bereich (aus DBData) markieren
     954             :     //  - SelectionChanged (?)
     955             : 
     956           2 :     bool bDo = !rParam.bRemoveOnly;                         // sal_False = nur loeschen
     957           2 :     bool bRet = false;
     958             : 
     959           2 :     ScDocument& rDoc = rDocShell.GetDocument();
     960           2 :     if (bRecord && !rDoc.IsUndoEnabled())
     961           0 :         bRecord = false;
     962             :     ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
     963           2 :                                                 rParam.nCol2, rParam.nRow2 );
     964           2 :     if (!pDBData)
     965             :     {
     966             :         OSL_FAIL( "SubTotals: keine DBData" );
     967           0 :         return false;
     968             :     }
     969             : 
     970           2 :     ScEditableTester aTester( &rDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW );
     971           2 :     if (!aTester.IsEditable())
     972             :     {
     973           0 :         if (!bApi)
     974           0 :             rDocShell.ErrorMessage(aTester.GetMessageId());
     975           0 :         return false;
     976             :     }
     977             : 
     978           2 :     if (rDoc.HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
     979           2 :                          rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
     980             :     {
     981           0 :         if (!bApi)
     982           0 :             rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen
     983           0 :         return false;
     984             :     }
     985             : 
     986           2 :     bool bOk = true;
     987           2 :     if (rParam.bReplace)
     988           2 :         if (rDoc.TestRemoveSubTotals( nTab, rParam ))
     989             :         {
     990           0 :             bOk = ( ScopedVclPtr<MessBox>::Create( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
     991             :                 // "StarCalc" "Daten loeschen?"
     992           0 :                 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
     993           0 :                 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) )->Execute()
     994           0 :                 == RET_YES );
     995             :         }
     996             : 
     997           2 :     if (bOk)
     998             :     {
     999           2 :         WaitObject aWait( ScDocShell::GetActiveDialogParent() );
    1000           4 :         ScDocShellModificator aModificator( rDocShell );
    1001             : 
    1002           2 :         ScSubTotalParam aNewParam( rParam );        // Bereichsende wird veraendert
    1003           2 :         ScDocument*     pUndoDoc = NULL;
    1004           2 :         ScOutlineTable* pUndoTab = NULL;
    1005           2 :         ScRangeName*    pUndoRange = NULL;
    1006           2 :         ScDBCollection* pUndoDB = NULL;
    1007             : 
    1008           2 :         if (bRecord)                                        // alte Daten sichern
    1009             :         {
    1010           2 :             bool bOldFilter = bDo && rParam.bDoSort;
    1011             : 
    1012           2 :             SCTAB nTabCount = rDoc.GetTableCount();
    1013           2 :             pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
    1014           2 :             ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
    1015           2 :             if (pTable)
    1016             :             {
    1017           1 :                 pUndoTab = new ScOutlineTable( *pTable );
    1018             : 
    1019             :                 // column/row state
    1020             :                 SCCOLROW nOutStartCol, nOutEndCol;
    1021             :                 SCCOLROW nOutStartRow, nOutEndRow;
    1022           1 :                 pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
    1023           1 :                 pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
    1024             : 
    1025           1 :                 pUndoDoc->InitUndo( &rDoc, nTab, nTab, true, true );
    1026           1 :                 rDoc.CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, false, pUndoDoc );
    1027           1 :                 rDoc.CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, false, pUndoDoc );
    1028             :             }
    1029             :             else
    1030           1 :                 pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, bOldFilter );
    1031             : 
    1032             :             //  Datenbereich sichern - incl. Filter-Ergebnis
    1033             :             rDoc.CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab,
    1034           2 :                                     IDF_ALL, false, pUndoDoc );
    1035             : 
    1036             :             //  alle Formeln wegen Referenzen
    1037             :             rDoc.CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
    1038           2 :                                         IDF_FORMULA, false, pUndoDoc );
    1039             : 
    1040             :             //  DB- und andere Bereiche
    1041           2 :             ScRangeName* pDocRange = rDoc.GetRangeName();
    1042           2 :             if (!pDocRange->empty())
    1043           0 :                 pUndoRange = new ScRangeName( *pDocRange );
    1044           2 :             ScDBCollection* pDocDB = rDoc.GetDBCollection();
    1045           2 :             if (!pDocDB->empty())
    1046           0 :                 pUndoDB = new ScDBCollection( *pDocDB );
    1047             :         }
    1048             : 
    1049             : //      rDoc.SetOutlineTable( nTab, NULL );
    1050           2 :         ScOutlineTable* pOut = rDoc.GetOutlineTable( nTab );
    1051           2 :         if (pOut)
    1052           1 :             pOut->GetRowArray().RemoveAll();       // nur Zeilen-Outlines loeschen
    1053             : 
    1054           2 :         if (rParam.bReplace)
    1055           2 :             rDoc.RemoveSubTotals( nTab, aNewParam );
    1056           2 :         bool bSuccess = true;
    1057           2 :         if (bDo)
    1058             :         {
    1059             :             // Sortieren
    1060           1 :             if ( rParam.bDoSort || pForceNewSort )
    1061             :             {
    1062           1 :                 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
    1063             : 
    1064             :                 //  Teilergebnis-Felder vor die Sortierung setzen
    1065             :                 //  (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
    1066             : 
    1067           1 :                 ScSortParam aOldSort;
    1068           1 :                 pDBData->GetSortParam( aOldSort );
    1069           2 :                 ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
    1070           2 :                 Sort( nTab, aSortParam, false, false, bApi );
    1071             :             }
    1072             : 
    1073           1 :             bSuccess = rDoc.DoSubTotals( nTab, aNewParam );
    1074           1 :             rDoc.SetDrawPageSize(nTab);
    1075             :         }
    1076             :         ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
    1077           2 :             aNewParam.nCol2, aNewParam.nRow2, nTab );
    1078           2 :         rDoc.SetDirty( aDirtyRange, true );
    1079             : 
    1080           2 :         if (bRecord)
    1081             :         {
    1082             : //          ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
    1083           2 :             rDocShell.GetUndoManager()->AddUndoAction(
    1084             :                 new ScUndoSubTotals( &rDocShell, nTab,
    1085             :                                         rParam, aNewParam.nRow2,
    1086             :                                         pUndoDoc, pUndoTab, // pUndoDBData,
    1087           2 :                                         pUndoRange, pUndoDB ) );
    1088             :         }
    1089             : 
    1090           2 :         if (!bSuccess)
    1091             :         {
    1092             :             // "Kann keine Zeilen einfuegen"
    1093           0 :             if (!bApi)
    1094           0 :                 rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
    1095             :         }
    1096             : 
    1097             :                                                     // merken
    1098           2 :         pDBData->SetSubTotalParam( aNewParam );
    1099           2 :         pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
    1100           2 :         rDoc.CompileDBFormula();
    1101             : 
    1102             :         rDocShell.PostPaint(ScRange(0, 0, nTab, MAXCOL,MAXROW,nTab),
    1103           2 :                             PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE);
    1104           2 :         aModificator.SetDocumentModified();
    1105             : 
    1106           4 :         bRet = bSuccess;
    1107             :     }
    1108           2 :     return bRet;
    1109             : }
    1110             : 
    1111             : namespace {
    1112             : 
    1113           4 : bool lcl_EmptyExcept( ScDocument* pDoc, const ScRange& rRange, const ScRange& rExcept )
    1114             : {
    1115           4 :     ScCellIterator aIter( pDoc, rRange );
    1116         128 :     for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
    1117             :     {
    1118         124 :         if (!aIter.isEmpty())      // real content?
    1119             :         {
    1120         124 :             if (!rExcept.In(aIter.GetPos()))
    1121           0 :                 return false;       // cell found
    1122             :         }
    1123             :     }
    1124             : 
    1125           4 :     return true;        // nothing found - empty
    1126             : }
    1127             : 
    1128          53 : bool isEditable(ScDocShell& rDocShell, const ScRangeList& rRanges, bool bApi)
    1129             : {
    1130          53 :     ScDocument& rDoc = rDocShell.GetDocument();
    1131          53 :     if (!rDocShell.IsEditable() || rDoc.GetChangeTrack())
    1132             :     {
    1133             :         //  not recorded -> disallow
    1134           0 :         if (!bApi)
    1135           0 :             rDocShell.ErrorMessage(STR_PROTECTIONERR);
    1136             : 
    1137           0 :         return false;
    1138             :     }
    1139             : 
    1140         106 :     for (size_t i = 0, n = rRanges.size(); i < n; ++i)
    1141             :     {
    1142          53 :         const ScRange* p = rRanges[i];
    1143          53 :         ScEditableTester aTester(&rDoc, *p);
    1144          53 :         if (!aTester.IsEditable())
    1145             :         {
    1146           0 :             if (!bApi)
    1147           0 :                 rDocShell.ErrorMessage(aTester.GetMessageId());
    1148             : 
    1149           0 :             return false;
    1150             :         }
    1151             :     }
    1152             : 
    1153          53 :     return true;
    1154             : }
    1155             : 
    1156          60 : void createUndoDoc(std::unique_ptr<ScDocument>& pUndoDoc, ScDocument* pDoc, const ScRange& rRange)
    1157             : {
    1158          60 :     SCTAB nTab = rRange.aStart.Tab();
    1159          60 :     pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
    1160          60 :     pUndoDoc->InitUndo(pDoc, nTab, nTab);
    1161          60 :     pDoc->CopyToDocument(rRange, IDF_ALL, false, pUndoDoc.get());
    1162          60 : }
    1163             : 
    1164          29 : bool checkNewOutputRange(ScDPObject& rDPObj, ScDocShell& rDocShell, ScRange& rNewOut, bool bApi)
    1165             : {
    1166          29 :     ScDocument& rDoc = rDocShell.GetDocument();
    1167             : 
    1168          29 :     bool bOverflow = false;
    1169          29 :     rNewOut = rDPObj.GetNewOutputRange(bOverflow);
    1170             : 
    1171             :     // Test for overlap with source data range.
    1172             :     // TODO: Check with other pivot tables as well.
    1173          29 :     const ScSheetSourceDesc* pSheetDesc = rDPObj.GetSheetDesc();
    1174          29 :     if (pSheetDesc && pSheetDesc->GetSourceRange().Intersects(rNewOut))
    1175             :     {
    1176             :         // New output range intersepts with the source data. Move it up to
    1177             :         // where the old range is and see if that works.
    1178           0 :         ScRange aOldRange = rDPObj.GetOutRange();
    1179           0 :         SCsROW nDiff = aOldRange.aStart.Row() - rNewOut.aStart.Row();
    1180           0 :         rNewOut.aStart.SetRow(aOldRange.aStart.Row());
    1181           0 :         rNewOut.aEnd.IncRow(nDiff);
    1182           0 :         if (!ValidRow(rNewOut.aStart.Row()) || !ValidRow(rNewOut.aEnd.Row()))
    1183           0 :             bOverflow = true;
    1184             :     }
    1185             : 
    1186          29 :     if (bOverflow)
    1187             :     {
    1188           0 :         if (!bApi)
    1189           0 :             rDocShell.ErrorMessage(STR_PIVOT_ERROR);
    1190             : 
    1191           0 :         return false;
    1192             :     }
    1193             : 
    1194          29 :     ScEditableTester aTester(&rDoc, rNewOut);
    1195          29 :     if (!aTester.IsEditable())
    1196             :     {
    1197             :         //  destination area isn't editable
    1198           0 :         if (!bApi)
    1199           0 :             rDocShell.ErrorMessage(aTester.GetMessageId());
    1200             : 
    1201           0 :         return false;
    1202             :     }
    1203             : 
    1204          29 :     return true;
    1205             : }
    1206             : 
    1207             : }
    1208             : 
    1209          21 : bool ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj,
    1210             :                                    bool bRecord, bool bApi, bool bAllowMove )
    1211             : {
    1212          21 :     if (!pOldObj)
    1213             :     {
    1214           0 :         if (!pNewObj)
    1215           0 :             return false;
    1216             : 
    1217           0 :         return CreatePivotTable(*pNewObj, bRecord, bApi);
    1218             :     }
    1219             : 
    1220          21 :     if (pOldObj)
    1221             :     {
    1222          21 :         if (!pNewObj)
    1223           0 :             return RemovePivotTable(*pOldObj, bRecord, bApi);
    1224             : 
    1225          21 :         if (pOldObj == pNewObj)
    1226          21 :             return UpdatePivotTable(*pOldObj, bRecord, bApi);
    1227             :     }
    1228             : 
    1229             :     OSL_ASSERT(pOldObj && pNewObj && pOldObj != pNewObj);
    1230             : 
    1231           0 :     ScDocShellModificator aModificator( rDocShell );
    1232           0 :     WaitObject aWait( ScDocShell::GetActiveDialogParent() );
    1233             : 
    1234           0 :     ScRangeList aRanges;
    1235           0 :     aRanges.Append(pOldObj->GetOutRange());
    1236           0 :     aRanges.Append(pNewObj->GetOutRange().aStart); // at least one cell in the output position must be editable.
    1237           0 :     if (!isEditable(rDocShell, aRanges, bApi))
    1238           0 :         return false;
    1239             : 
    1240           0 :     std::unique_ptr<ScDocument> pOldUndoDoc;
    1241           0 :     std::unique_ptr<ScDocument> pNewUndoDoc;
    1242             : 
    1243           0 :     ScDPObject aUndoDPObj(*pOldObj); // for undo or revert on failure
    1244             : 
    1245           0 :     ScDocument& rDoc = rDocShell.GetDocument();
    1246           0 :     if (bRecord && !rDoc.IsUndoEnabled())
    1247           0 :         bRecord = false;
    1248             : 
    1249           0 :     if (bRecord)
    1250           0 :         createUndoDoc(pOldUndoDoc, &rDoc, pOldObj->GetOutRange());
    1251             : 
    1252           0 :     pNewObj->WriteSourceDataTo(*pOldObj);     // copy source data
    1253             : 
    1254           0 :     ScDPSaveData* pData = pNewObj->GetSaveData();
    1255             :     OSL_ENSURE( pData, "no SaveData from living DPObject" );
    1256           0 :     if (pData)
    1257           0 :         pOldObj->SetSaveData(*pData);     // copy SaveData
    1258             : 
    1259           0 :     pOldObj->SetAllowMove(bAllowMove);
    1260           0 :     pOldObj->ReloadGroupTableData();
    1261           0 :     pOldObj->SyncAllDimensionMembers();
    1262           0 :     pOldObj->InvalidateData();             // before getting the new output area
    1263             : 
    1264             :     //  make sure the table has a name (not set by dialog)
    1265           0 :     if (pOldObj->GetName().isEmpty())
    1266           0 :         pOldObj->SetName( rDoc.GetDPCollection()->CreateNewName() );
    1267             : 
    1268           0 :     ScRange aNewOut;
    1269           0 :     if (!checkNewOutputRange(*pOldObj, rDocShell, aNewOut, bApi))
    1270             :     {
    1271           0 :         *pOldObj = aUndoDPObj;
    1272           0 :         return false;
    1273             :     }
    1274             : 
    1275             :     //  test if new output area is empty except for old area
    1276           0 :     if (!bApi)
    1277             :     {
    1278             :         // OutRange of pOldObj (pDestObj) is still old area
    1279           0 :         if (!lcl_EmptyExcept(&rDoc, aNewOut, pOldObj->GetOutRange()))
    1280             :         {
    1281           0 :             ScopedVclPtrInstance<QueryBox> aBox( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
    1282           0 :                              ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) );
    1283           0 :             if (aBox->Execute() == RET_NO)
    1284             :             {
    1285             :                 //! like above (not editable)
    1286           0 :                 *pOldObj = aUndoDPObj;
    1287           0 :                 return false;
    1288           0 :             }
    1289             :         }
    1290             :     }
    1291             : 
    1292           0 :     if (bRecord)
    1293           0 :         createUndoDoc(pNewUndoDoc, &rDoc, aNewOut);
    1294             : 
    1295           0 :     pOldObj->Output(aNewOut.aStart);
    1296           0 :     rDocShell.PostPaintGridAll();           //! only necessary parts
    1297             : 
    1298           0 :     if (bRecord)
    1299             :     {
    1300           0 :         rDocShell.GetUndoManager()->AddUndoAction(
    1301             :             new ScUndoDataPilot(
    1302           0 :                 &rDocShell, pOldUndoDoc.release(), pNewUndoDoc.release(), &aUndoDPObj, pOldObj, bAllowMove));
    1303             :     }
    1304             : 
    1305             :     // notify API objects
    1306           0 :     rDoc.BroadcastUno( ScDataPilotModifiedHint(pOldObj->GetName()) );
    1307           0 :     aModificator.SetDocumentModified();
    1308             : 
    1309           0 :     return true;
    1310             : }
    1311             : 
    1312           2 : bool ScDBDocFunc::RemovePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi)
    1313             : {
    1314           2 :     ScDocShellModificator aModificator(rDocShell);
    1315           4 :     WaitObject aWait(ScDocShell::GetActiveDialogParent());
    1316             : 
    1317           2 :     if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
    1318           0 :         return false;
    1319             : 
    1320           4 :     std::unique_ptr<ScDocument> pOldUndoDoc;
    1321           4 :     std::unique_ptr<ScDPObject> pUndoDPObj;
    1322             : 
    1323           2 :     if (bRecord)
    1324           1 :         pUndoDPObj.reset(new ScDPObject(rDPObj));    // copy old settings for undo
    1325             : 
    1326           2 :     ScDocument& rDoc = rDocShell.GetDocument();
    1327           2 :     if (bRecord && !rDoc.IsUndoEnabled())
    1328           0 :         bRecord = false;
    1329             : 
    1330             :     //  delete table
    1331             : 
    1332           2 :     ScRange aRange = rDPObj.GetOutRange();
    1333           2 :     SCTAB nTab = aRange.aStart.Tab();
    1334             : 
    1335           2 :     if (bRecord)
    1336           1 :         createUndoDoc(pOldUndoDoc, &rDoc, aRange);
    1337             : 
    1338           2 :     rDoc.DeleteAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
    1339           2 :                          aRange.aEnd.Col(),   aRange.aEnd.Row(),
    1340           6 :                          nTab, IDF_ALL );
    1341           2 :     rDoc.RemoveFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
    1342           2 :                           aRange.aEnd.Col(),   aRange.aEnd.Row(),
    1343           6 :                           nTab, SC_MF_AUTO );
    1344             : 
    1345           2 :     rDoc.GetDPCollection()->FreeTable(&rDPObj);  // object is deleted here
    1346             : 
    1347           2 :     rDocShell.PostPaintGridAll();   //! only necessary parts
    1348           2 :     rDocShell.PostPaint(aRange, PAINT_GRID);
    1349             : 
    1350           2 :     if (bRecord)
    1351             :     {
    1352           1 :         rDocShell.GetUndoManager()->AddUndoAction(
    1353             :             new ScUndoDataPilot(
    1354           1 :                 &rDocShell, pOldUndoDoc.release(), NULL, pUndoDPObj.get(), NULL, false));
    1355             : 
    1356             :         // pUndoDPObj is copied
    1357             :     }
    1358             : 
    1359           2 :     aModificator.SetDocumentModified();
    1360           4 :     return true;
    1361             : }
    1362             : 
    1363          22 : bool ScDBDocFunc::CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi)
    1364             : {
    1365          22 :     ScDocShellModificator aModificator(rDocShell);
    1366          44 :     WaitObject aWait(ScDocShell::GetActiveDialogParent());
    1367             : 
    1368             :     // At least one cell in the output range should be editable. Check in advance.
    1369          22 :     if (!isEditable(rDocShell, ScRange(rDPObj.GetOutRange().aStart), bApi))
    1370           0 :         return false;
    1371             : 
    1372          44 :     std::unique_ptr<ScDocument> pNewUndoDoc;
    1373             : 
    1374          22 :     ScDocument& rDoc = rDocShell.GetDocument();
    1375          22 :     if (bRecord && !rDoc.IsUndoEnabled())
    1376           4 :         bRecord = false;
    1377             : 
    1378             :     //  output range must be set at pNewObj
    1379          44 :     std::unique_ptr<ScDPObject> pDestObj(new ScDPObject(rDPObj));
    1380             : 
    1381          22 :     ScDPObject& rDestObj = *pDestObj;
    1382             : 
    1383             :     // #i94570# When changing the output position in the dialog, a new table is created
    1384             :     // with the settings from the old table, including the name.
    1385             :     // So we have to check for duplicate names here (before inserting).
    1386          22 :     if (rDoc.GetDPCollection()->GetByName(rDestObj.GetName()))
    1387           0 :         rDestObj.SetName(OUString());      // ignore the invalid name, create a new name below
    1388             : 
    1389          22 :     if (!rDoc.GetDPCollection()->InsertNewTable(pDestObj.release()))
    1390             :         // Insertion into collection failed.
    1391           0 :         return false;
    1392             : 
    1393          22 :     rDestObj.ReloadGroupTableData();
    1394          22 :     rDestObj.SyncAllDimensionMembers();
    1395          22 :     rDestObj.InvalidateData();             // before getting the new output area
    1396             : 
    1397             :     //  make sure the table has a name (not set by dialog)
    1398          22 :     if (rDestObj.GetName().isEmpty())
    1399           1 :         rDestObj.SetName(rDoc.GetDPCollection()->CreateNewName());
    1400             : 
    1401          22 :     bool bOverflow = false;
    1402          22 :     ScRange aNewOut = rDestObj.GetNewOutputRange(bOverflow);
    1403             : 
    1404          22 :     if (bOverflow)
    1405             :     {
    1406           0 :         if (!bApi)
    1407           0 :             rDocShell.ErrorMessage(STR_PIVOT_ERROR);
    1408             : 
    1409           0 :         return false;
    1410             :     }
    1411             : 
    1412             :     {
    1413          22 :         ScEditableTester aTester(&rDoc, aNewOut);
    1414          22 :         if (!aTester.IsEditable())
    1415             :         {
    1416             :             //  destination area isn't editable
    1417           0 :             if (!bApi)
    1418           0 :                 rDocShell.ErrorMessage(aTester.GetMessageId());
    1419             : 
    1420           0 :             return false;
    1421             :         }
    1422             :     }
    1423             : 
    1424             :     //  test if new output area is empty except for old area
    1425          22 :     if (!bApi)
    1426             :     {
    1427             :         bool bEmpty = rDoc.IsBlockEmpty(
    1428           0 :             aNewOut.aStart.Tab(), aNewOut.aStart.Col(), aNewOut.aStart.Row(),
    1429           0 :             aNewOut.aEnd.Col(), aNewOut.aEnd.Row());
    1430             : 
    1431           0 :         if (!bEmpty)
    1432             :         {
    1433             :             ScopedVclPtrInstance<QueryBox> aBox(
    1434           0 :                 ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
    1435           0 :                 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY));
    1436             : 
    1437           0 :             if (aBox->Execute() == RET_NO)
    1438             :             {
    1439             :                 //! like above (not editable)
    1440           0 :                 return false;
    1441           0 :             }
    1442             :         }
    1443             :     }
    1444             : 
    1445          22 :     if (bRecord)
    1446          17 :         createUndoDoc(pNewUndoDoc, &rDoc, aNewOut);
    1447             : 
    1448          22 :     rDestObj.Output(aNewOut.aStart);
    1449          22 :     rDocShell.PostPaintGridAll();           //! only necessary parts
    1450             : 
    1451          22 :     if (bRecord)
    1452             :     {
    1453          17 :         rDocShell.GetUndoManager()->AddUndoAction(
    1454          17 :             new ScUndoDataPilot(&rDocShell, NULL, pNewUndoDoc.release(), NULL, &rDestObj, false));
    1455             :     }
    1456             : 
    1457             :     // notify API objects
    1458          22 :     rDoc.BroadcastUno(ScDataPilotModifiedHint(rDestObj.GetName()));
    1459          22 :     aModificator.SetDocumentModified();
    1460             : 
    1461          44 :     return true;
    1462             : }
    1463             : 
    1464          29 : bool ScDBDocFunc::UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi)
    1465             : {
    1466          29 :     ScDocShellModificator aModificator( rDocShell );
    1467          58 :     WaitObject aWait( ScDocShell::GetActiveDialogParent() );
    1468             : 
    1469          29 :     if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
    1470           0 :         return false;
    1471             : 
    1472          58 :     std::unique_ptr<ScDocument> pOldUndoDoc;
    1473          58 :     std::unique_ptr<ScDocument> pNewUndoDoc;
    1474             : 
    1475          58 :     ScDPObject aUndoDPObj(rDPObj); // For undo or revert on failure.
    1476             : 
    1477          29 :     ScDocument& rDoc = rDocShell.GetDocument();
    1478          29 :     if (bRecord && !rDoc.IsUndoEnabled())
    1479           0 :         bRecord = false;
    1480             : 
    1481          29 :     if (bRecord)
    1482          21 :         createUndoDoc(pOldUndoDoc, &rDoc, rDPObj.GetOutRange());
    1483             : 
    1484          29 :     rDPObj.SetAllowMove(false);
    1485          29 :     rDPObj.ReloadGroupTableData();
    1486          29 :     if (!rDPObj.SyncAllDimensionMembers())
    1487           0 :         return false;
    1488             : 
    1489          29 :     rDPObj.InvalidateData();             // before getting the new output area
    1490             : 
    1491             :     //  make sure the table has a name (not set by dialog)
    1492          29 :     if (rDPObj.GetName().isEmpty())
    1493           0 :         rDPObj.SetName( rDoc.GetDPCollection()->CreateNewName() );
    1494             : 
    1495          29 :     ScRange aNewOut;
    1496          29 :     if (!checkNewOutputRange(rDPObj, rDocShell, aNewOut, bApi))
    1497             :     {
    1498           0 :         rDPObj = aUndoDPObj;
    1499           0 :         return false;
    1500             :     }
    1501             : 
    1502             :     //  test if new output area is empty except for old area
    1503          29 :     if (!bApi)
    1504             :     {
    1505           4 :         if (!lcl_EmptyExcept(&rDoc, aNewOut, rDPObj.GetOutRange()))
    1506             :         {
    1507           0 :             ScopedVclPtrInstance<QueryBox> aBox( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
    1508           0 :                                                  ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) );
    1509           0 :             if (aBox->Execute() == RET_NO)
    1510             :             {
    1511           0 :                 rDPObj = aUndoDPObj;
    1512           0 :                 return false;
    1513           0 :             }
    1514             :         }
    1515             :     }
    1516             : 
    1517          29 :     if (bRecord)
    1518          21 :         createUndoDoc(pNewUndoDoc, &rDoc, aNewOut);
    1519             : 
    1520          29 :     rDPObj.Output(aNewOut.aStart);
    1521          29 :     rDocShell.PostPaintGridAll();           //! only necessary parts
    1522             : 
    1523          29 :     if (bRecord)
    1524             :     {
    1525          21 :         rDocShell.GetUndoManager()->AddUndoAction(
    1526             :             new ScUndoDataPilot(
    1527          21 :                 &rDocShell, pOldUndoDoc.release(), pNewUndoDoc.release(), &aUndoDPObj, &rDPObj, false));
    1528             :     }
    1529             : 
    1530             :     // notify API objects
    1531          29 :     rDoc.BroadcastUno( ScDataPilotModifiedHint(rDPObj.GetName()) );
    1532          29 :     aModificator.SetDocumentModified();
    1533          58 :     return true;
    1534             : }
    1535             : 
    1536           2 : sal_uLong ScDBDocFunc::RefreshPivotTables(ScDPObject* pDPObj, bool bApi)
    1537             : {
    1538           2 :     ScDPCollection* pDPs = rDocShell.GetDocument().GetDPCollection();
    1539           2 :     if (!pDPs)
    1540           0 :         return 0;
    1541             : 
    1542           2 :     std::set<ScDPObject*> aRefs;
    1543           2 :     sal_uLong nErrId = pDPs->ReloadCache(pDPObj, aRefs);
    1544           2 :     if (nErrId)
    1545           0 :         return nErrId;
    1546             : 
    1547           2 :     std::set<ScDPObject*>::iterator it = aRefs.begin(), itEnd = aRefs.end();
    1548           6 :     for (; it != itEnd; ++it)
    1549             :     {
    1550           4 :         ScDPObject* pObj = *it;
    1551             : 
    1552             :         // This action is intentionally not undoable since it modifies cache.
    1553           4 :         UpdatePivotTable(*pObj, false, bApi);
    1554             :     }
    1555             : 
    1556           2 :     return 0;
    1557             : }
    1558             : 
    1559           4 : void ScDBDocFunc::RefreshPivotTableGroups(ScDPObject* pDPObj)
    1560             : {
    1561           4 :     if (!pDPObj)
    1562           0 :         return;
    1563             : 
    1564           4 :     ScDPCollection* pDPs = rDocShell.GetDocument().GetDPCollection();
    1565           4 :     if (!pDPs)
    1566           0 :         return;
    1567             : 
    1568           4 :     ScDPSaveData* pSaveData = pDPObj->GetSaveData();
    1569           4 :     if (!pSaveData)
    1570           0 :         return;
    1571             : 
    1572           4 :     std::set<ScDPObject*> aRefs;
    1573           4 :     if (!pDPs->ReloadGroupsInCache(pDPObj, aRefs))
    1574           0 :         return;
    1575             : 
    1576             :     // We allow pDimData being NULL.
    1577           4 :     const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
    1578           4 :     std::set<ScDPObject*>::iterator it = aRefs.begin(), itEnd = aRefs.end();
    1579           8 :     for (; it != itEnd; ++it)
    1580             :     {
    1581           4 :         ScDPObject* pObj = *it;
    1582           4 :         if (pObj != pDPObj)
    1583             :         {
    1584           0 :             pSaveData = pObj->GetSaveData();
    1585           0 :             if (pSaveData)
    1586           0 :                 pSaveData->SetDimensionData(pDimData);
    1587             :         }
    1588             : 
    1589             :         // This action is intentionally not undoable since it modifies cache.
    1590           4 :         UpdatePivotTable(*pObj, false, false);
    1591           4 :     }
    1592             : }
    1593             : 
    1594             : //      database import
    1595             : 
    1596           0 : void ScDBDocFunc::UpdateImport( const OUString& rTarget, const svx::ODataAccessDescriptor& rDescriptor )
    1597             : {
    1598             :     // rTarget is the name of a database range
    1599             : 
    1600           0 :     ScDocument& rDoc = rDocShell.GetDocument();
    1601           0 :     ScDBCollection& rDBColl = *rDoc.GetDBCollection();
    1602           0 :     const ScDBData* pData = rDBColl.getNamedDBs().findByUpperName(ScGlobal::pCharClass->uppercase(rTarget));
    1603           0 :     if (!pData)
    1604             :     {
    1605           0 :         ScopedVclPtrInstance<InfoBox> aInfoBox( ScDocShell::GetActiveDialogParent(),
    1606           0 :                                                 ScGlobal::GetRscString( STR_TARGETNOTFOUND ) );
    1607           0 :         aInfoBox->Execute();
    1608           0 :         return;
    1609             :     }
    1610             : 
    1611             :     SCTAB nTab;
    1612             :     SCCOL nDummyCol;
    1613             :     SCROW nDummyRow;
    1614           0 :     pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
    1615             : 
    1616           0 :     ScImportParam aImportParam;
    1617           0 :     pData->GetImportParam( aImportParam );
    1618             : 
    1619           0 :     OUString sDBName;
    1620           0 :     OUString sDBTable;
    1621           0 :     sal_Int32 nCommandType = 0;
    1622           0 :     sDBName = rDescriptor.getDataSource();
    1623           0 :     rDescriptor[svx::daCommand]     >>= sDBTable;
    1624           0 :     rDescriptor[svx::daCommandType] >>= nCommandType;
    1625             : 
    1626           0 :     aImportParam.aDBName    = sDBName;
    1627           0 :     aImportParam.bSql       = ( nCommandType == sdb::CommandType::COMMAND );
    1628           0 :     aImportParam.aStatement = sDBTable;
    1629           0 :     aImportParam.bNative    = false;
    1630           0 :     aImportParam.nType      = static_cast<sal_uInt8>( ( nCommandType == sdb::CommandType::QUERY ) ? ScDbQuery : ScDbTable );
    1631           0 :     aImportParam.bImport    = true;
    1632             : 
    1633           0 :     bool bContinue = DoImport( nTab, aImportParam, &rDescriptor, true );
    1634             : 
    1635             :     //  DB-Operationen wiederholen
    1636             : 
    1637           0 :     ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
    1638           0 :     if (pViewSh)
    1639             :     {
    1640           0 :         ScRange aRange;
    1641           0 :         pData->GetArea(aRange);
    1642           0 :         pViewSh->MarkRange(aRange);         // selektieren
    1643             : 
    1644           0 :         if ( bContinue )        // Fehler beim Import -> Abbruch
    1645             :         {
    1646             :             //  interne Operationen, wenn welche gespeichert
    1647             : 
    1648           0 :             if ( pData->HasQueryParam() || pData->HasSortParam() || pData->HasSubTotalParam() )
    1649           0 :                 pViewSh->RepeatDB();
    1650             : 
    1651             :             //  Pivottabellen die den Bereich als Quelldaten haben
    1652             : 
    1653           0 :             rDocShell.RefreshPivotTables(aRange);
    1654             :         }
    1655           0 :     }
    1656         156 : }
    1657             : 
    1658             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11