bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / ui / docshell / dbdocfun.cxx
blobcd4e38aa7ff611c403cff0bf8fda30d75e92304d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sfx2/app.hxx>
21 #include <vcl/msgbox.hxx>
22 #include <vcl/waitobj.hxx>
23 #include <svx/dataaccessdescriptor.hxx>
25 #include <com/sun/star/sdb/CommandType.hpp>
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" // for lcl_EmptyExcept
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"
51 #include <set>
52 #include <memory>
54 using namespace ::com::sun::star;
56 // -----------------------------------------------------------------
58 bool ScDBDocFunc::AddDBRange( const OUString& rName, const ScRange& rRange, sal_Bool /* bApi */ )
61 ScDocShellModificator aModificator( rDocShell );
63 ScDocument* pDoc = rDocShell.GetDocument();
64 ScDBCollection* pDocColl = pDoc->GetDBCollection();
65 sal_Bool bUndo (pDoc->IsUndoEnabled());
67 ScDBCollection* pUndoColl = NULL;
68 if (bUndo)
69 pUndoColl = new ScDBCollection( *pDocColl );
71 ScDBData* pNew = new ScDBData( rName, rRange.aStart.Tab(),
72 rRange.aStart.Col(), rRange.aStart.Row(),
73 rRange.aEnd.Col(), rRange.aEnd.Row() );
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 bool bCompile = !pDoc->IsImportingXML();
79 bool bOk;
80 if ( bCompile )
81 pDoc->CompileDBFormula( sal_True ); // CreateFormulaString
82 if ( rName == STR_DB_LOCAL_NONAME )
84 pDoc->SetAnonymousDBData(rRange.aStart.Tab() , pNew);
85 bOk = true;
87 else
89 bOk = pDocColl->getNamedDBs().insert(pNew);
91 if ( bCompile )
92 pDoc->CompileDBFormula( false ); // CompileFormulaString
94 if (!bOk)
96 delete pNew;
97 delete pUndoColl;
98 return false;
101 if (bUndo)
103 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
104 rDocShell.GetUndoManager()->AddUndoAction(
105 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
108 aModificator.SetDocumentModified();
109 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
110 return true;
113 bool ScDBDocFunc::DeleteDBRange(const OUString& rName)
115 bool bDone = false;
116 ScDocument* pDoc = rDocShell.GetDocument();
117 ScDBCollection* pDocColl = pDoc->GetDBCollection();
118 bool bUndo = pDoc->IsUndoEnabled();
120 ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
121 const ScDBData* p = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rName));
122 if (p)
124 ScDocShellModificator aModificator( rDocShell );
126 ScDBCollection* pUndoColl = NULL;
127 if (bUndo)
128 pUndoColl = new ScDBCollection( *pDocColl );
130 pDoc->CompileDBFormula( true ); // CreateFormulaString
131 rDBs.erase(*p);
132 pDoc->CompileDBFormula( false ); // CompileFormulaString
134 if (bUndo)
136 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
137 rDocShell.GetUndoManager()->AddUndoAction(
138 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
141 aModificator.SetDocumentModified();
142 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
143 bDone = true;
146 return bDone;
149 bool ScDBDocFunc::RenameDBRange( const String& rOld, const String& rNew )
151 bool bDone = false;
152 ScDocument* pDoc = rDocShell.GetDocument();
153 ScDBCollection* pDocColl = pDoc->GetDBCollection();
154 bool bUndo = pDoc->IsUndoEnabled();
155 ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
156 const ScDBData* pOld = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rOld));
157 const ScDBData* pNew = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rNew));
158 if (pOld && !pNew)
160 ScDocShellModificator aModificator( rDocShell );
162 ScDBData* pNewData = new ScDBData(rNew, *pOld);
164 ScDBCollection* pUndoColl = new ScDBCollection( *pDocColl );
166 pDoc->CompileDBFormula(true); // CreateFormulaString
167 rDBs.erase(*pOld);
168 bool bInserted = rDBs.insert(pNewData);
169 if (!bInserted) // Fehler -> alten Zustand wiederherstellen
170 pDoc->SetDBCollection(pUndoColl); // gehoert dann dem Dokument
172 pDoc->CompileDBFormula( false ); // CompileFormulaString
174 if (bInserted) // Einfuegen hat geklappt
176 if (bUndo)
178 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
179 rDocShell.GetUndoManager()->AddUndoAction(
180 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
182 else
183 delete pUndoColl;
185 aModificator.SetDocumentModified();
186 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
187 bDone = true;
191 return bDone;
194 bool ScDBDocFunc::ModifyDBData( const ScDBData& rNewData )
196 bool bDone = false;
197 ScDocument* pDoc = rDocShell.GetDocument();
198 ScDBCollection* pDocColl = pDoc->GetDBCollection();
199 bool bUndo = pDoc->IsUndoEnabled();
201 ScDBData* pData = NULL;
202 if (rNewData.GetName().equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(STR_DB_LOCAL_NONAME)))
204 ScRange aRange;
205 rNewData.GetArea(aRange);
206 SCTAB nTab = aRange.aStart.Tab();
207 pData = pDoc->GetAnonymousDBData(nTab);
209 else
210 pData = pDocColl->getNamedDBs().findByUpperName(rNewData.GetUpperName());
212 if (pData)
214 ScDocShellModificator aModificator( rDocShell );
215 ScRange aOldRange, aNewRange;
216 pData->GetArea(aOldRange);
217 rNewData.GetArea(aNewRange);
218 bool bAreaChanged = ( aOldRange != aNewRange ); // dann muss neu compiliert werden
220 ScDBCollection* pUndoColl = NULL;
221 if (bUndo)
222 pUndoColl = new ScDBCollection( *pDocColl );
224 *pData = rNewData;
225 if (bAreaChanged)
226 pDoc->CompileDBFormula();
228 if (bUndo)
230 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
231 rDocShell.GetUndoManager()->AddUndoAction(
232 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
235 aModificator.SetDocumentModified();
236 bDone = true;
239 return bDone;
242 // -----------------------------------------------------------------
244 bool ScDBDocFunc::RepeatDB( const OUString& rDBName, bool bRecord, bool bApi, bool bIsUnnamed, SCTAB aTab )
246 //! auch fuer ScDBFunc::RepeatDB benutzen!
248 bool bDone = false;
249 ScDocument* pDoc = rDocShell.GetDocument();
250 if (bRecord && !pDoc->IsUndoEnabled())
251 bRecord = false;
252 ScDBData* pDBData = NULL;
253 if (bIsUnnamed)
255 pDBData = pDoc->GetAnonymousDBData( aTab );
257 else
259 ScDBCollection* pColl = pDoc->GetDBCollection();
260 if (pColl)
261 pDBData = pColl->getNamedDBs().findByUpperName(ScGlobal::pCharClass->uppercase(rDBName));
264 if ( pDBData )
266 ScQueryParam aQueryParam;
267 pDBData->GetQueryParam( aQueryParam );
268 sal_Bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
270 ScSortParam aSortParam;
271 pDBData->GetSortParam( aSortParam );
272 sal_Bool bSort = aSortParam.maKeyState[0].bDoSort;
274 ScSubTotalParam aSubTotalParam;
275 pDBData->GetSubTotalParam( aSubTotalParam );
276 sal_Bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
278 if ( bQuery || bSort || bSubTotal )
280 sal_Bool bQuerySize = false;
281 ScRange aOldQuery;
282 ScRange aNewQuery;
283 if (bQuery && !aQueryParam.bInplace)
285 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
286 aQueryParam.nDestTab, sal_True );
287 if (pDest && pDest->IsDoSize())
289 pDest->GetArea( aOldQuery );
290 bQuerySize = sal_True;
294 SCTAB nTab;
295 SCCOL nStartCol;
296 SCROW nStartRow;
297 SCCOL nEndCol;
298 SCROW nEndRow;
299 pDBData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
301 //! Undo nur benoetigte Daten ?
303 ScDocument* pUndoDoc = NULL;
304 ScOutlineTable* pUndoTab = NULL;
305 ScRangeName* pUndoRange = NULL;
306 ScDBCollection* pUndoDB = NULL;
308 if (bRecord)
310 SCTAB nTabCount = pDoc->GetTableCount();
311 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
312 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
313 if (pTable)
315 pUndoTab = new ScOutlineTable( *pTable );
317 // column/row state
318 SCCOLROW nOutStartCol, nOutEndCol;
319 SCCOLROW nOutStartRow, nOutEndRow;
320 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
321 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
323 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True );
324 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0,
325 nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab,
326 IDF_NONE, false, pUndoDoc );
327 pDoc->CopyToDocument( 0, static_cast<SCROW>(nOutStartRow),
328 nTab, MAXCOL, static_cast<SCROW>(nOutEndRow), nTab,
329 IDF_NONE, false, pUndoDoc );
331 else
332 pUndoDoc->InitUndo( pDoc, nTab, nTab, false, sal_True );
334 // Datenbereich sichern - incl. Filter-Ergebnis
335 pDoc->CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, false, pUndoDoc );
337 // alle Formeln wegen Referenzen
338 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, false, pUndoDoc );
340 // DB- und andere Bereiche
341 ScRangeName* pDocRange = pDoc->GetRangeName();
342 if (!pDocRange->empty())
343 pUndoRange = new ScRangeName( *pDocRange );
344 ScDBCollection* pDocDB = pDoc->GetDBCollection();
345 if (!pDocDB->empty())
346 pUndoDB = new ScDBCollection( *pDocDB );
349 if (bSort && bSubTotal)
351 // Sortieren ohne SubTotals
353 aSubTotalParam.bRemoveOnly = sal_True; // wird unten wieder zurueckgesetzt
354 DoSubTotals( nTab, aSubTotalParam, NULL, false, bApi );
357 if (bSort)
359 pDBData->GetSortParam( aSortParam ); // Bereich kann sich geaendert haben
360 Sort( nTab, aSortParam, false, false, bApi );
362 if (bQuery)
364 pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geaendert haben
365 ScRange aAdvSource;
366 if (pDBData->GetAdvancedQuerySource(aAdvSource))
367 Query( nTab, aQueryParam, &aAdvSource, false, bApi );
368 else
369 Query( nTab, aQueryParam, NULL, false, bApi );
371 // bei nicht-inplace kann die Tabelle umgestellt worden sein
372 // if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
373 // SetTabNo( nTab );
375 if (bSubTotal)
377 pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geaendert haben
378 aSubTotalParam.bRemoveOnly = false;
379 DoSubTotals( nTab, aSubTotalParam, NULL, false, bApi );
382 if (bRecord)
384 SCTAB nDummyTab;
385 SCCOL nDummyCol;
386 SCROW nDummyRow;
387 SCROW nNewEndRow;
388 pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
390 const ScRange* pOld = NULL;
391 const ScRange* pNew = NULL;
392 if (bQuerySize)
394 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
395 aQueryParam.nDestTab, sal_True );
396 if (pDest)
398 pDest->GetArea( aNewQuery );
399 pOld = &aOldQuery;
400 pNew = &aNewQuery;
404 rDocShell.GetUndoManager()->AddUndoAction(
405 new ScUndoRepeatDB( &rDocShell, nTab,
406 nStartCol, nStartRow, nEndCol, nEndRow,
407 nNewEndRow,
408 //nCurX, nCurY,
409 nStartCol, nStartRow,
410 pUndoDoc, pUndoTab,
411 pUndoRange, pUndoDB,
412 pOld, pNew ) );
415 rDocShell.PostPaint(ScRange(0, 0, nTab, MAXCOL, MAXROW, nTab),
416 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE);
417 bDone = sal_True;
419 else if (!bApi) // "Keine Operationen auszufuehren"
420 rDocShell.ErrorMessage(STR_MSSG_REPEATDB_0);
423 return bDone;
426 // -----------------------------------------------------------------
428 sal_Bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
429 sal_Bool bRecord, sal_Bool bPaint, sal_Bool bApi )
431 ScDocShellModificator aModificator( rDocShell );
433 ScDocument* pDoc = rDocShell.GetDocument();
434 if (bRecord && !pDoc->IsUndoEnabled())
435 bRecord = false;
436 SCTAB nSrcTab = nTab;
437 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
439 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
440 rSortParam.nCol2, rSortParam.nRow2 );
441 if (!pDBData)
443 OSL_FAIL( "Sort: keine DBData" );
444 return false;
447 ScDBData* pDestData = NULL;
448 ScRange aOldDest;
449 sal_Bool bCopy = !rSortParam.bInplace;
450 if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 &&
451 rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab )
452 bCopy = false;
453 ScSortParam aLocalParam( rSortParam );
454 if ( bCopy )
456 aLocalParam.MoveToDest();
457 if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
459 if (!bApi)
460 rDocShell.ErrorMessage(STR_PASTE_FULL);
461 return false;
464 nTab = rSortParam.nDestTab;
465 pDestData = pDoc->GetDBAtCursor( rSortParam.nDestCol, rSortParam.nDestRow,
466 rSortParam.nDestTab, sal_True );
467 if (pDestData)
468 pDestData->GetArea(aOldDest);
471 ScEditableTester aTester( pDoc, nTab, aLocalParam.nCol1,aLocalParam.nRow1,
472 aLocalParam.nCol2,aLocalParam.nRow2 );
473 if (!aTester.IsEditable())
475 if (!bApi)
476 rDocShell.ErrorMessage(aTester.GetMessageId());
477 return false;
480 if ( aLocalParam.bIncludePattern && pDoc->HasAttrib(
481 aLocalParam.nCol1, aLocalParam.nRow1, nTab,
482 aLocalParam.nCol2, aLocalParam.nRow2, nTab,
483 HASATTR_MERGED | HASATTR_OVERLAPPED ) )
485 // Merge-Attribute wuerden beim Sortieren durcheinanderkommen
486 if (!bApi)
487 rDocShell.ErrorMessage(STR_SORT_ERR_MERGED);
488 return false;
492 // ausfuehren
494 WaitObject aWait( rDocShell.GetActiveDialogParent() );
496 sal_Bool bRepeatQuery = false; // bestehenden Filter wiederholen?
497 ScQueryParam aQueryParam;
498 pDBData->GetQueryParam( aQueryParam );
499 if ( aQueryParam.GetEntry(0).bDoQuery )
500 bRepeatQuery = sal_True;
502 if (bRepeatQuery && bCopy)
504 if ( aQueryParam.bInplace ||
505 aQueryParam.nDestCol != rSortParam.nDestCol ||
506 aQueryParam.nDestRow != rSortParam.nDestRow ||
507 aQueryParam.nDestTab != rSortParam.nDestTab ) // Query auf selben Zielbereich?
508 bRepeatQuery = false;
511 ScUndoSort* pUndoAction = 0;
512 if ( bRecord )
514 // Referenzen ausserhalb des Bereichs werden nicht veraendert !
516 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
517 // Zeilenhoehen immer (wegen automatischer Anpassung)
518 //! auf ScBlockUndo umstellen
519 pUndoDoc->InitUndo( pDoc, nTab, nTab, false, sal_True );
521 /* #i59745# Do not copy note captions to undo document. All existing
522 caption objects will be repositioned while sorting which is tracked
523 in drawing undo. When undo is executed, the old positions will be
524 restored, and the cells with the old notes (which still refer to the
525 existing captions) will be copied back into the source document. */
526 pDoc->CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
527 aLocalParam.nCol2, aLocalParam.nRow2, nTab,
528 IDF_ALL|IDF_NOCAPTIONS, false, pUndoDoc );
530 const ScRange* pR = 0;
531 if (pDestData)
533 /* #i59745# Do not copy note captions from destination range to
534 undo document. All existing caption objects will be removed
535 which is tracked in drawing undo. When undo is executed, the
536 caption objects are reinserted with drawing undo, and the cells
537 with the old notes (which still refer to the existing captions)
538 will be copied back into the source document. */
539 pDoc->CopyToDocument( aOldDest, IDF_ALL|IDF_NOCAPTIONS, false, pUndoDoc );
540 pR = &aOldDest;
543 // Zeilenhoehen immer (wegen automatischer Anpassung)
544 //! auf ScBlockUndo umstellen
545 // if (bRepeatQuery)
546 pDoc->CopyToDocument( 0, aLocalParam.nRow1, nTab, MAXCOL, aLocalParam.nRow2, nTab,
547 IDF_NONE, false, pUndoDoc );
549 ScDBCollection* pUndoDB = NULL;
550 ScDBCollection* pDocDB = pDoc->GetDBCollection();
551 if (!pDocDB->empty())
552 pUndoDB = new ScDBCollection( *pDocDB );
554 pUndoAction = new ScUndoSort( &rDocShell, nTab, rSortParam, pUndoDoc, pUndoDB, pR );
555 rDocShell.GetUndoManager()->AddUndoAction( pUndoAction );
557 // #i59745# collect all drawing undo actions affecting cell note captions
558 if( pDrawLayer )
559 pDrawLayer->BeginCalcUndo();
562 if ( bCopy )
564 if (pDestData)
565 pDoc->DeleteAreaTab(aOldDest, IDF_CONTENTS); // Zielbereich vorher loeschen
567 ScRange aSource( rSortParam.nCol1,rSortParam.nRow1,nSrcTab,
568 rSortParam.nCol2,rSortParam.nRow2,nSrcTab );
569 ScAddress aDest( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab );
571 rDocShell.GetDocFunc().MoveBlock( aSource, aDest, false, false, false, sal_True );
574 // don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set)
575 if (aLocalParam.GetSortKeyCount() && aLocalParam.maKeyState[0].bDoSort)
577 ScProgress aProgress(&rDocShell, ScGlobal::GetRscString(STR_PROGRESS_SORTING), 0);
578 pDoc->Sort( nTab, aLocalParam, bRepeatQuery, &aProgress );
581 sal_Bool bSave = sal_True;
582 if (bCopy)
584 ScSortParam aOldSortParam;
585 pDBData->GetSortParam( aOldSortParam );
586 if (aOldSortParam.GetSortKeyCount() &&
587 aOldSortParam.maKeyState[0].bDoSort && aOldSortParam.bInplace)
589 bSave = false;
590 aOldSortParam.nDestCol = rSortParam.nDestCol;
591 aOldSortParam.nDestRow = rSortParam.nDestRow;
592 aOldSortParam.nDestTab = rSortParam.nDestTab;
593 pDBData->SetSortParam( aOldSortParam ); // dann nur DestPos merken
596 if (bSave) // Parameter merken
598 pDBData->SetSortParam( rSortParam );
599 pDBData->SetHeader( rSortParam.bHasHeader ); //! ???
600 pDBData->SetByRow( rSortParam.bByRow ); //! ???
603 if (bCopy) // neuen DB-Bereich merken
605 // Tabelle umschalten von aussen (View)
606 //! SetCursor ??!?!
608 ScRange aDestPos( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
609 aLocalParam.nCol2, aLocalParam.nRow2, nTab );
610 ScDBData* pNewData;
611 if (pDestData)
612 pNewData = pDestData; // Bereich vorhanden -> anpassen
613 else // Bereich ab Cursor/Markierung wird angelegt
614 pNewData = rDocShell.GetDBData(aDestPos, SC_DB_MAKE, SC_DBSEL_FORCE_MARK );
615 if (pNewData)
617 pNewData->SetArea( nTab,
618 aLocalParam.nCol1,aLocalParam.nRow1,
619 aLocalParam.nCol2,aLocalParam.nRow2 );
620 pNewData->SetSortParam( aLocalParam );
621 pNewData->SetHeader( aLocalParam.bHasHeader ); //! ???
622 pNewData->SetByRow( aLocalParam.bByRow );
624 else
626 OSL_FAIL("Zielbereich nicht da");
630 ScRange aDirtyRange( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
631 aLocalParam.nCol2, aLocalParam.nRow2, nTab );
632 pDoc->SetDirty( aDirtyRange );
634 if (bPaint)
636 sal_uInt16 nPaint = PAINT_GRID;
637 SCCOL nStartX = aLocalParam.nCol1;
638 SCROW nStartY = aLocalParam.nRow1;
639 SCCOL nEndX = aLocalParam.nCol2;
640 SCROW nEndY = aLocalParam.nRow2;
641 if ( bRepeatQuery )
643 nPaint |= PAINT_LEFT;
644 nStartX = 0;
645 nEndX = MAXCOL;
647 if (pDestData)
649 if ( nEndX < aOldDest.aEnd.Col() )
650 nEndX = aOldDest.aEnd.Col();
651 if ( nEndY < aOldDest.aEnd.Row() )
652 nEndY = aOldDest.aEnd.Row();
654 rDocShell.PostPaint(ScRange(nStartX, nStartY, nTab, nEndX, nEndY, nTab), nPaint);
657 // AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, bPaint );
658 rDocShell.AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, nTab );
660 // #i59745# set collected drawing undo actions at sorting undo action
661 if( pUndoAction && pDrawLayer )
662 pUndoAction->SetDrawUndoAction( pDrawLayer->GetCalcUndo() );
664 aModificator.SetDocumentModified();
666 return sal_True;
669 // -----------------------------------------------------------------
671 sal_Bool ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam,
672 const ScRange* pAdvSource, sal_Bool bRecord, sal_Bool bApi )
674 ScDocShellModificator aModificator( rDocShell );
676 ScDocument* pDoc = rDocShell.GetDocument();
677 if (bRecord && !pDoc->IsUndoEnabled())
678 bRecord = false;
679 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rQueryParam.nCol1, rQueryParam.nRow1,
680 rQueryParam.nCol2, rQueryParam.nRow2 );
681 if (!pDBData)
683 OSL_FAIL( "Query: keine DBData" );
684 return false;
687 // Wechsel von Inplace auf nicht-Inplace, dann erst Inplace aufheben:
688 // (nur, wenn im Dialog "Persistent" ausgewaehlt ist)
690 if ( !rQueryParam.bInplace && pDBData->HasQueryParam() && rQueryParam.bDestPers )
692 ScQueryParam aOldQuery;
693 pDBData->GetQueryParam(aOldQuery);
694 if (aOldQuery.bInplace)
696 // alte Filterung aufheben
698 SCSIZE nEC = aOldQuery.GetEntryCount();
699 for (SCSIZE i=0; i<nEC; i++)
700 aOldQuery.GetEntry(i).bDoQuery = false;
701 aOldQuery.bDuplicate = sal_True;
702 Query( nTab, aOldQuery, NULL, bRecord, bApi );
706 ScQueryParam aLocalParam( rQueryParam ); // fuer Paint / Zielbereich
707 sal_Bool bCopy = !rQueryParam.bInplace; // kopiert wird in Table::Query
708 ScDBData* pDestData = NULL; // Bereich, in den kopiert wird
709 sal_Bool bDoSize = false; // Zielgroesse anpassen (einf./loeschen)
710 SCCOL nFormulaCols = 0; // nur bei bDoSize
711 sal_Bool bKeepFmt = false;
712 ScRange aOldDest;
713 ScRange aDestTotal;
714 if ( bCopy && rQueryParam.nDestCol == rQueryParam.nCol1 &&
715 rQueryParam.nDestRow == rQueryParam.nRow1 && rQueryParam.nDestTab == nTab )
716 bCopy = false;
717 SCTAB nDestTab = nTab;
718 if ( bCopy )
720 aLocalParam.MoveToDest();
721 nDestTab = rQueryParam.nDestTab;
722 if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
724 if (!bApi)
725 rDocShell.ErrorMessage(STR_PASTE_FULL);
726 return false;
729 ScEditableTester aTester( pDoc, nDestTab, aLocalParam.nCol1,aLocalParam.nRow1,
730 aLocalParam.nCol2,aLocalParam.nRow2);
731 if (!aTester.IsEditable())
733 if (!bApi)
734 rDocShell.ErrorMessage(aTester.GetMessageId());
735 return false;
738 pDestData = pDoc->GetDBAtCursor( rQueryParam.nDestCol, rQueryParam.nDestRow,
739 rQueryParam.nDestTab, sal_True );
740 if (pDestData)
742 pDestData->GetArea( aOldDest );
743 aDestTotal=ScRange( rQueryParam.nDestCol,
744 rQueryParam.nDestRow,
745 nDestTab,
746 rQueryParam.nDestCol + rQueryParam.nCol2 - rQueryParam.nCol1,
747 rQueryParam.nDestRow + rQueryParam.nRow2 - rQueryParam.nRow1,
748 nDestTab );
750 bDoSize = pDestData->IsDoSize();
751 // Test, ob Formeln aufgefuellt werden muessen (nFormulaCols):
752 if ( bDoSize && aOldDest.aEnd.Col() == aDestTotal.aEnd.Col() )
754 SCCOL nTestCol = aOldDest.aEnd.Col() + 1; // neben dem Bereich
755 SCROW nTestRow = rQueryParam.nDestRow +
756 ( aLocalParam.bHasHeader ? 1 : 0 );
757 while ( nTestCol <= MAXCOL &&
758 pDoc->GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA )
759 ++nTestCol, ++nFormulaCols;
762 bKeepFmt = pDestData->IsKeepFmt();
763 if ( bDoSize && !pDoc->CanFitBlock( aOldDest, aDestTotal ) )
765 if (!bApi)
766 rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2); // kann keine Zeilen einfuegen
767 return false;
772 // ausfuehren
774 WaitObject aWait( rDocShell.GetActiveDialogParent() );
776 sal_Bool bKeepSub = false; // bestehende Teilergebnisse wiederholen?
777 ScSubTotalParam aSubTotalParam;
778 if (rQueryParam.GetEntry(0).bDoQuery) // nicht beim Aufheben
780 pDBData->GetSubTotalParam( aSubTotalParam ); // Teilergebnisse vorhanden?
782 if ( aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly )
783 bKeepSub = sal_True;
786 ScDocument* pUndoDoc = NULL;
787 ScDBCollection* pUndoDB = NULL;
788 const ScRange* pOld = NULL;
790 if ( bRecord )
792 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
793 if (bCopy)
795 pUndoDoc->InitUndo( pDoc, nDestTab, nDestTab, false, sal_True );
796 pDoc->CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
797 aLocalParam.nCol2, aLocalParam.nRow2, nDestTab,
798 IDF_ALL, false, pUndoDoc );
799 // Attribute sichern, falls beim Filtern mitkopiert
801 if (pDestData)
803 pDoc->CopyToDocument( aOldDest, IDF_ALL, false, pUndoDoc );
804 pOld = &aOldDest;
807 else
809 pUndoDoc->InitUndo( pDoc, nTab, nTab, false, sal_True );
810 pDoc->CopyToDocument( 0, rQueryParam.nRow1, nTab, MAXCOL, rQueryParam.nRow2, nTab,
811 IDF_NONE, false, pUndoDoc );
814 ScDBCollection* pDocDB = pDoc->GetDBCollection();
815 if (!pDocDB->empty())
816 pUndoDB = new ScDBCollection( *pDocDB );
818 pDoc->BeginDrawUndo();
821 ScDocument* pAttribDoc = NULL;
822 ScRange aAttribRange;
823 if (pDestData) // Zielbereich loeschen
825 if ( bKeepFmt )
827 // kleinere der End-Spalten, Header+1 Zeile
828 aAttribRange = aOldDest;
829 if ( aAttribRange.aEnd.Col() > aDestTotal.aEnd.Col() )
830 aAttribRange.aEnd.SetCol( aDestTotal.aEnd.Col() );
831 aAttribRange.aEnd.SetRow( aAttribRange.aStart.Row() +
832 ( aLocalParam.bHasHeader ? 1 : 0 ) );
834 // auch fuer aufgefuellte Formeln
835 aAttribRange.aEnd.SetCol( aAttribRange.aEnd.Col() + nFormulaCols );
837 pAttribDoc = new ScDocument( SCDOCMODE_UNDO );
838 pAttribDoc->InitUndo( pDoc, nDestTab, nDestTab, false, sal_True );
839 pDoc->CopyToDocument( aAttribRange, IDF_ATTRIB, false, pAttribDoc );
842 if ( bDoSize )
843 pDoc->FitBlock( aOldDest, aDestTotal );
844 else
845 pDoc->DeleteAreaTab(aOldDest, IDF_ALL); // einfach loeschen
848 // Filtern am Dokument ausfuehren
849 SCSIZE nCount = pDoc->Query( nTab, rQueryParam, bKeepSub );
850 if (bCopy)
852 aLocalParam.nRow2 = aLocalParam.nRow1 + nCount;
853 if (!aLocalParam.bHasHeader && nCount > 0)
854 --aLocalParam.nRow2;
856 if ( bDoSize )
858 // auf wirklichen Ergebnis-Bereich anpassen
859 // (das hier ist immer eine Verkleinerung)
861 ScRange aNewDest( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
862 aLocalParam.nCol2, aLocalParam.nRow2, nDestTab );
863 pDoc->FitBlock( aDestTotal, aNewDest, false ); // sal_False - nicht loeschen
865 if ( nFormulaCols > 0 )
867 // Formeln ausfuellen
868 //! Undo (Query und Repeat) !!!
870 ScRange aNewForm( aLocalParam.nCol2+1, aLocalParam.nRow1, nDestTab,
871 aLocalParam.nCol2+nFormulaCols, aLocalParam.nRow2, nDestTab );
872 ScRange aOldForm = aNewForm;
873 aOldForm.aEnd.SetRow( aOldDest.aEnd.Row() );
874 pDoc->FitBlock( aOldForm, aNewForm, false );
876 ScMarkData aMark;
877 aMark.SelectOneTable(nDestTab);
878 SCROW nFStartY = aLocalParam.nRow1 + ( aLocalParam.bHasHeader ? 1 : 0 );
880 sal_uLong nProgCount = nFormulaCols;
881 nProgCount *= aLocalParam.nRow2 - nFStartY;
882 ScProgress aProgress( pDoc->GetDocumentShell(),
883 ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount );
885 pDoc->Fill( aLocalParam.nCol2+1, nFStartY,
886 aLocalParam.nCol2+nFormulaCols, nFStartY, &aProgress, aMark,
887 aLocalParam.nRow2 - nFStartY,
888 FILL_TO_BOTTOM, FILL_SIMPLE );
892 if ( pAttribDoc ) // gemerkte Attribute zurueckkopieren
894 // Header
895 if (aLocalParam.bHasHeader)
897 ScRange aHdrRange = aAttribRange;
898 aHdrRange.aEnd.SetRow( aHdrRange.aStart.Row() );
899 pAttribDoc->CopyToDocument( aHdrRange, IDF_ATTRIB, false, pDoc );
902 // Daten
903 SCCOL nAttrEndCol = aAttribRange.aEnd.Col();
904 SCROW nAttrRow = aAttribRange.aStart.Row() + ( aLocalParam.bHasHeader ? 1 : 0 );
905 for (SCCOL nCol = aAttribRange.aStart.Col(); nCol<=nAttrEndCol; nCol++)
907 const ScPatternAttr* pSrcPattern = pAttribDoc->GetPattern(
908 nCol, nAttrRow, nDestTab );
909 OSL_ENSURE(pSrcPattern,"Pattern ist 0");
910 if (pSrcPattern)
912 pDoc->ApplyPatternAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
913 nDestTab, *pSrcPattern );
914 const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet();
915 if (pStyle)
916 pDoc->ApplyStyleAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
917 nDestTab, *pStyle );
921 delete pAttribDoc;
925 // speichern: Inplace immer, sonst je nach Einstellung
926 // alter Inplace-Filter ist ggf. schon aufgehoben
928 sal_Bool bSave = rQueryParam.bInplace || rQueryParam.bDestPers;
929 if (bSave) // merken
931 pDBData->SetQueryParam( rQueryParam );
932 pDBData->SetHeader( rQueryParam.bHasHeader ); //! ???
933 pDBData->SetAdvancedQuerySource( pAdvSource ); // after SetQueryParam
936 if (bCopy) // neuen DB-Bereich merken
938 // selektieren wird hinterher von aussen (dbfunc)
939 // momentan ueber DB-Bereich an der Zielposition, darum muss dort
940 // auf jeden Fall ein Bereich angelegt werden.
942 ScDBData* pNewData;
943 if (pDestData)
944 pNewData = pDestData; // Bereich vorhanden -> anpassen (immer!)
945 else // Bereich anlegen
946 pNewData = rDocShell.GetDBData(
947 ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
948 aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ),
949 SC_DB_MAKE, SC_DBSEL_FORCE_MARK );
951 if (pNewData)
953 pNewData->SetArea( nDestTab, aLocalParam.nCol1, aLocalParam.nRow1,
954 aLocalParam.nCol2, aLocalParam.nRow2 );
956 // Query-Param wird am Ziel nicht mehr eingestellt, fuehrt nur zu Verwirrung
957 // und Verwechslung mit dem Query-Param am Quellbereich (#37187#)
959 else
961 OSL_FAIL("Zielbereich nicht da");
965 if (!bCopy)
967 pDoc->InvalidatePageBreaks(nTab);
968 pDoc->UpdatePageBreaks( nTab );
971 // #i23299# Subtotal functions depend on cell's filtered states.
972 ScRange aDirtyRange(0 , aLocalParam.nRow1, nDestTab, MAXCOL, aLocalParam.nRow2, nDestTab);
973 pDoc->SetSubTotalCellsDirty(aDirtyRange);
975 if ( bRecord )
977 // create undo action after executing, because of drawing layer undo
978 rDocShell.GetUndoManager()->AddUndoAction(
979 new ScUndoQuery( &rDocShell, nTab, rQueryParam, pUndoDoc, pUndoDB,
980 pOld, bDoSize, pAdvSource ) );
984 if (bCopy)
986 SCCOL nEndX = aLocalParam.nCol2;
987 SCROW nEndY = aLocalParam.nRow2;
988 if (pDestData)
990 if ( aOldDest.aEnd.Col() > nEndX )
991 nEndX = aOldDest.aEnd.Col();
992 if ( aOldDest.aEnd.Row() > nEndY )
993 nEndY = aOldDest.aEnd.Row();
995 if (bDoSize)
996 nEndY = MAXROW;
997 rDocShell.PostPaint(
998 ScRange(aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, nEndX, nEndY, nDestTab),
999 PAINT_GRID);
1001 else
1002 rDocShell.PostPaint(
1003 ScRange(0, rQueryParam.nRow1, nTab, MAXCOL, MAXROW, nTab),
1004 PAINT_GRID | PAINT_LEFT);
1005 aModificator.SetDocumentModified();
1007 return sal_True;
1010 // -----------------------------------------------------------------
1012 sal_Bool ScDBDocFunc::DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam,
1013 const ScSortParam* pForceNewSort, sal_Bool bRecord, sal_Bool bApi )
1015 //! auch fuer ScDBFunc::DoSubTotals benutzen!
1016 // dann bleibt aussen:
1017 // - neuen Bereich (aus DBData) markieren
1018 // - SelectionChanged (?)
1020 sal_Bool bDo = !rParam.bRemoveOnly; // sal_False = nur loeschen
1021 sal_Bool bRet = false;
1023 ScDocument* pDoc = rDocShell.GetDocument();
1024 if (bRecord && !pDoc->IsUndoEnabled())
1025 bRecord = false;
1026 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
1027 rParam.nCol2, rParam.nRow2 );
1028 if (!pDBData)
1030 OSL_FAIL( "SubTotals: keine DBData" );
1031 return false;
1034 ScEditableTester aTester( pDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW );
1035 if (!aTester.IsEditable())
1037 if (!bApi)
1038 rDocShell.ErrorMessage(aTester.GetMessageId());
1039 return false;
1042 if (pDoc->HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
1043 rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
1045 if (!bApi)
1046 rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen
1047 return false;
1050 sal_Bool bOk = true;
1051 if (rParam.bReplace)
1052 if (pDoc->TestRemoveSubTotals( nTab, rParam ))
1054 bOk = ( MessBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1055 // "StarCalc" "Daten loeschen?"
1056 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
1057 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) ).Execute()
1058 == RET_YES );
1061 if (bOk)
1063 WaitObject aWait( rDocShell.GetActiveDialogParent() );
1064 ScDocShellModificator aModificator( rDocShell );
1066 ScSubTotalParam aNewParam( rParam ); // Bereichsende wird veraendert
1067 ScDocument* pUndoDoc = NULL;
1068 ScOutlineTable* pUndoTab = NULL;
1069 ScRangeName* pUndoRange = NULL;
1070 ScDBCollection* pUndoDB = NULL;
1072 if (bRecord) // alte Daten sichern
1074 sal_Bool bOldFilter = bDo && rParam.bDoSort;
1076 SCTAB nTabCount = pDoc->GetTableCount();
1077 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1078 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
1079 if (pTable)
1081 pUndoTab = new ScOutlineTable( *pTable );
1083 // column/row state
1084 SCCOLROW nOutStartCol, nOutEndCol;
1085 SCCOLROW nOutStartRow, nOutEndRow;
1086 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
1087 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
1089 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True );
1090 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, false, pUndoDoc );
1091 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, false, pUndoDoc );
1093 else
1094 pUndoDoc->InitUndo( pDoc, nTab, nTab, false, bOldFilter );
1096 // Datenbereich sichern - incl. Filter-Ergebnis
1097 pDoc->CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab,
1098 IDF_ALL, false, pUndoDoc );
1100 // alle Formeln wegen Referenzen
1101 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
1102 IDF_FORMULA, false, pUndoDoc );
1104 // DB- und andere Bereiche
1105 ScRangeName* pDocRange = pDoc->GetRangeName();
1106 if (!pDocRange->empty())
1107 pUndoRange = new ScRangeName( *pDocRange );
1108 ScDBCollection* pDocDB = pDoc->GetDBCollection();
1109 if (!pDocDB->empty())
1110 pUndoDB = new ScDBCollection( *pDocDB );
1113 // pDoc->SetOutlineTable( nTab, NULL );
1114 ScOutlineTable* pOut = pDoc->GetOutlineTable( nTab );
1115 if (pOut)
1116 pOut->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen
1118 if (rParam.bReplace)
1119 pDoc->RemoveSubTotals( nTab, aNewParam );
1120 sal_Bool bSuccess = sal_True;
1121 if (bDo)
1123 // Sortieren
1124 if ( rParam.bDoSort || pForceNewSort )
1126 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
1128 // Teilergebnis-Felder vor die Sortierung setzen
1129 // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
1131 ScSortParam aOldSort;
1132 pDBData->GetSortParam( aOldSort );
1133 ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
1134 Sort( nTab, aSortParam, false, false, bApi );
1137 pDoc->InitializeNoteCaptions(nTab);
1138 bSuccess = pDoc->DoSubTotals( nTab, aNewParam );
1139 pDoc->SetDrawPageSize(nTab);
1141 ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
1142 aNewParam.nCol2, aNewParam.nRow2, nTab );
1143 pDoc->SetDirty( aDirtyRange );
1145 if (bRecord)
1147 // ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
1148 rDocShell.GetUndoManager()->AddUndoAction(
1149 new ScUndoSubTotals( &rDocShell, nTab,
1150 rParam, aNewParam.nRow2,
1151 pUndoDoc, pUndoTab, // pUndoDBData,
1152 pUndoRange, pUndoDB ) );
1155 if (!bSuccess)
1157 // "Kann keine Zeilen einfuegen"
1158 if (!bApi)
1159 rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
1162 // merken
1163 pDBData->SetSubTotalParam( aNewParam );
1164 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
1165 pDoc->CompileDBFormula();
1167 rDocShell.PostPaint(ScRange(0, 0, nTab, MAXCOL,MAXROW,nTab),
1168 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE);
1169 aModificator.SetDocumentModified();
1171 bRet = bSuccess;
1173 return bRet;
1176 namespace {
1178 bool lcl_EmptyExcept( ScDocument* pDoc, const ScRange& rRange, const ScRange& rExcept )
1180 ScCellIterator aIter( pDoc, rRange );
1181 for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
1183 if (!aIter.isEmpty()) // real content?
1185 if (!rExcept.In(aIter.GetPos()))
1186 return false; // cell found
1190 return true; // nothing found - empty
1193 bool isEditable(ScDocShell& rDocShell, const ScRangeList& rRanges, bool bApi)
1195 ScDocument* pDoc = rDocShell.GetDocument();
1196 if (!rDocShell.IsEditable() || pDoc->GetChangeTrack())
1198 // not recorded -> disallow
1199 if (!bApi)
1200 rDocShell.ErrorMessage(STR_PROTECTIONERR);
1202 return false;
1205 for (size_t i = 0, n = rRanges.size(); i < n; ++i)
1207 const ScRange* p = rRanges[i];
1208 ScEditableTester aTester(pDoc, *p);
1209 if (!aTester.IsEditable())
1211 if (!bApi)
1212 rDocShell.ErrorMessage(aTester.GetMessageId());
1214 return false;
1218 return true;
1221 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1222 void createUndoDoc(std::auto_ptr<ScDocument>& pUndoDoc, ScDocument* pDoc, const ScRange& rRange)
1224 SCTAB nTab = rRange.aStart.Tab();
1225 pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1226 pUndoDoc->InitUndo(pDoc, nTab, nTab);
1227 pDoc->CopyToDocument(rRange, IDF_ALL, false, pUndoDoc.get());
1229 SAL_WNODEPRECATED_DECLARATIONS_POP
1231 bool checkNewOutputRange(ScDPObject& rDPObj, ScDocShell& rDocShell, ScRange& rNewOut, bool bApi)
1233 ScDocument* pDoc = rDocShell.GetDocument();
1235 bool bOverflow = false;
1236 rNewOut = rDPObj.GetNewOutputRange(bOverflow);
1238 // Test for overlap with source data range.
1239 // TODO: Check with other pivot tables as well.
1240 const ScSheetSourceDesc* pSheetDesc = rDPObj.GetSheetDesc();
1241 if (pSheetDesc && pSheetDesc->GetSourceRange().Intersects(rNewOut))
1243 // New output range intersepts with the source data. Move it up to
1244 // where the old range is and see if that works.
1245 ScRange aOldRange = rDPObj.GetOutRange();
1246 SCsROW nDiff = aOldRange.aStart.Row() - rNewOut.aStart.Row();
1247 rNewOut.aStart.SetRow(aOldRange.aStart.Row());
1248 rNewOut.aEnd.IncRow(nDiff);
1249 if (!ValidRow(rNewOut.aStart.Row()) || !ValidRow(rNewOut.aEnd.Row()))
1250 bOverflow = true;
1253 if (bOverflow)
1255 if (!bApi)
1256 rDocShell.ErrorMessage(STR_PIVOT_ERROR);
1258 return false;
1261 ScEditableTester aTester(pDoc, rNewOut);
1262 if (!aTester.IsEditable())
1264 // destination area isn't editable
1265 if (!bApi)
1266 rDocShell.ErrorMessage(aTester.GetMessageId());
1268 return false;
1271 return true;
1276 bool ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj,
1277 bool bRecord, bool bApi, bool bAllowMove )
1279 if (!pOldObj)
1281 if (!pNewObj)
1282 return false;
1284 return CreatePivotTable(*pNewObj, bRecord, bApi);
1287 if (pOldObj)
1289 if (!pNewObj)
1290 return RemovePivotTable(*pOldObj, bRecord, bApi);
1292 if (pOldObj == pNewObj)
1293 return UpdatePivotTable(*pOldObj, bRecord, bApi);
1296 OSL_ASSERT(pOldObj && pNewObj && pOldObj != pNewObj);
1298 ScDocShellModificator aModificator( rDocShell );
1299 WaitObject aWait( rDocShell.GetActiveDialogParent() );
1301 ScRangeList aRanges;
1302 aRanges.Append(pOldObj->GetOutRange());
1303 aRanges.Append(pNewObj->GetOutRange().aStart); // at least one cell in the output position must be editable.
1304 if (!isEditable(rDocShell, aRanges, bApi))
1305 return false;
1307 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1308 std::auto_ptr<ScDocument> pOldUndoDoc;
1309 std::auto_ptr<ScDocument> pNewUndoDoc;
1310 SAL_WNODEPRECATED_DECLARATIONS_POP
1312 ScDPObject aUndoDPObj(*pOldObj); // for undo or revert on failure
1314 ScDocument* pDoc = rDocShell.GetDocument();
1315 if (bRecord && !pDoc->IsUndoEnabled())
1316 bRecord = false;
1318 if (bRecord)
1319 createUndoDoc(pOldUndoDoc, pDoc, pOldObj->GetOutRange());
1321 pNewObj->WriteSourceDataTo(*pOldObj); // copy source data
1323 ScDPSaveData* pData = pNewObj->GetSaveData();
1324 OSL_ENSURE( pData, "no SaveData from living DPObject" );
1325 if (pData)
1326 pOldObj->SetSaveData(*pData); // copy SaveData
1328 pOldObj->SetAllowMove(bAllowMove);
1329 pOldObj->ReloadGroupTableData();
1330 pOldObj->SyncAllDimensionMembers();
1331 pOldObj->InvalidateData(); // before getting the new output area
1333 // make sure the table has a name (not set by dialog)
1334 if (pOldObj->GetName().isEmpty())
1335 pOldObj->SetName( pDoc->GetDPCollection()->CreateNewName() );
1337 ScRange aNewOut;
1338 if (!checkNewOutputRange(*pOldObj, rDocShell, aNewOut, bApi))
1340 *pOldObj = aUndoDPObj;
1341 return false;
1344 // test if new output area is empty except for old area
1345 if (!bApi)
1347 // OutRange of pOldObj (pDestObj) is still old area
1348 if (!lcl_EmptyExcept(pDoc, aNewOut, pOldObj->GetOutRange()))
1350 QueryBox aBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1351 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) );
1352 if (aBox.Execute() == RET_NO)
1354 //! like above (not editable)
1355 *pOldObj = aUndoDPObj;
1356 return false;
1361 if (bRecord)
1362 createUndoDoc(pNewUndoDoc, pDoc, aNewOut);
1364 pOldObj->Output(aNewOut.aStart);
1365 rDocShell.PostPaintGridAll(); //! only necessary parts
1367 if (bRecord)
1369 rDocShell.GetUndoManager()->AddUndoAction(
1370 new ScUndoDataPilot(
1371 &rDocShell, pOldUndoDoc.release(), pNewUndoDoc.release(), &aUndoDPObj, pOldObj, bAllowMove));
1374 // notify API objects
1375 pDoc->BroadcastUno( ScDataPilotModifiedHint(pOldObj->GetName()) );
1376 aModificator.SetDocumentModified();
1378 return true;
1381 bool ScDBDocFunc::RemovePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi)
1383 ScDocShellModificator aModificator(rDocShell);
1384 WaitObject aWait(rDocShell.GetActiveDialogParent());
1386 if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
1387 return false;
1389 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1390 std::auto_ptr<ScDocument> pOldUndoDoc;
1391 std::auto_ptr<ScDPObject> pUndoDPObj;
1392 SAL_WNODEPRECATED_DECLARATIONS_POP
1394 if (bRecord)
1395 pUndoDPObj.reset(new ScDPObject(rDPObj)); // copy old settings for undo
1397 ScDocument* pDoc = rDocShell.GetDocument();
1398 if (bRecord && !pDoc->IsUndoEnabled())
1399 bRecord = false;
1401 // delete table
1403 ScRange aRange = rDPObj.GetOutRange();
1404 SCTAB nTab = aRange.aStart.Tab();
1406 if (bRecord)
1407 createUndoDoc(pOldUndoDoc, pDoc, aRange);
1409 pDoc->DeleteAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
1410 aRange.aEnd.Col(), aRange.aEnd.Row(),
1411 nTab, IDF_ALL );
1412 pDoc->RemoveFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
1413 aRange.aEnd.Col(), aRange.aEnd.Row(),
1414 nTab, SC_MF_AUTO );
1416 pDoc->GetDPCollection()->FreeTable(&rDPObj); // object is deleted here
1418 rDocShell.PostPaintGridAll(); //! only necessary parts
1419 rDocShell.PostPaint(aRange, PAINT_GRID);
1421 if (bRecord)
1423 rDocShell.GetUndoManager()->AddUndoAction(
1424 new ScUndoDataPilot(
1425 &rDocShell, pOldUndoDoc.release(), NULL, pUndoDPObj.get(), NULL, false));
1427 // pUndoDPObj is copied
1430 aModificator.SetDocumentModified();
1431 return true;
1434 bool ScDBDocFunc::CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi)
1436 ScDocShellModificator aModificator(rDocShell);
1437 WaitObject aWait(rDocShell.GetActiveDialogParent());
1439 // At least one cell in the output range should be editable. Check in advance.
1440 if (!isEditable(rDocShell, ScRange(rDPObj.GetOutRange().aStart), bApi))
1441 return false;
1443 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1444 std::auto_ptr<ScDocument> pNewUndoDoc;
1445 SAL_WNODEPRECATED_DECLARATIONS_POP
1447 ScDocument* pDoc = rDocShell.GetDocument();
1448 if (bRecord && !pDoc->IsUndoEnabled())
1449 bRecord = false;
1451 // output range must be set at pNewObj
1452 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1453 std::auto_ptr<ScDPObject> pDestObj(new ScDPObject(rDPObj));
1454 SAL_WNODEPRECATED_DECLARATIONS_POP
1456 ScDPObject& rDestObj = *pDestObj;
1458 // #i94570# When changing the output position in the dialog, a new table is created
1459 // with the settings from the old table, including the name.
1460 // So we have to check for duplicate names here (before inserting).
1461 if (pDoc->GetDPCollection()->GetByName(rDestObj.GetName()))
1462 rDestObj.SetName(OUString()); // ignore the invalid name, create a new name below
1464 if (!pDoc->GetDPCollection()->InsertNewTable(pDestObj.release()))
1465 // Insertion into collection failed.
1466 return false;
1468 rDestObj.ReloadGroupTableData();
1469 rDestObj.SyncAllDimensionMembers();
1470 rDestObj.InvalidateData(); // before getting the new output area
1472 // make sure the table has a name (not set by dialog)
1473 if (rDestObj.GetName().isEmpty())
1474 rDestObj.SetName(pDoc->GetDPCollection()->CreateNewName());
1476 bool bOverflow = false;
1477 ScRange aNewOut = rDestObj.GetNewOutputRange(bOverflow);
1479 if (bOverflow)
1481 if (!bApi)
1482 rDocShell.ErrorMessage(STR_PIVOT_ERROR);
1484 return false;
1488 ScEditableTester aTester(pDoc, aNewOut);
1489 if (!aTester.IsEditable())
1491 // destination area isn't editable
1492 if (!bApi)
1493 rDocShell.ErrorMessage(aTester.GetMessageId());
1495 return false;
1499 // test if new output area is empty except for old area
1500 if (!bApi)
1502 bool bEmpty = pDoc->IsBlockEmpty(
1503 aNewOut.aStart.Tab(), aNewOut.aStart.Col(), aNewOut.aStart.Row(),
1504 aNewOut.aEnd.Col(), aNewOut.aEnd.Row());
1506 if (!bEmpty)
1508 QueryBox aBox(
1509 rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1510 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY));
1512 if (aBox.Execute() == RET_NO)
1514 //! like above (not editable)
1515 return false;
1520 if (bRecord)
1521 createUndoDoc(pNewUndoDoc, pDoc, aNewOut);
1523 rDestObj.Output(aNewOut.aStart);
1524 rDocShell.PostPaintGridAll(); //! only necessary parts
1526 if (bRecord)
1528 rDocShell.GetUndoManager()->AddUndoAction(
1529 new ScUndoDataPilot(&rDocShell, NULL, pNewUndoDoc.release(), NULL, &rDestObj, false));
1532 // notify API objects
1533 pDoc->BroadcastUno(ScDataPilotModifiedHint(rDestObj.GetName()));
1534 aModificator.SetDocumentModified();
1536 return true;
1539 bool ScDBDocFunc::UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi)
1541 ScDocShellModificator aModificator( rDocShell );
1542 WaitObject aWait( rDocShell.GetActiveDialogParent() );
1544 if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
1545 return false;
1547 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1548 std::auto_ptr<ScDocument> pOldUndoDoc;
1549 std::auto_ptr<ScDocument> pNewUndoDoc;
1550 SAL_WNODEPRECATED_DECLARATIONS_POP
1552 ScDPObject aUndoDPObj(rDPObj); // For undo or revert on failure.
1554 ScDocument* pDoc = rDocShell.GetDocument();
1555 if (bRecord && !pDoc->IsUndoEnabled())
1556 bRecord = false;
1558 if (bRecord)
1559 createUndoDoc(pOldUndoDoc, pDoc, rDPObj.GetOutRange());
1561 rDPObj.SetAllowMove(false);
1562 rDPObj.ReloadGroupTableData();
1563 if (!rDPObj.SyncAllDimensionMembers())
1564 return false;
1566 rDPObj.InvalidateData(); // before getting the new output area
1568 // make sure the table has a name (not set by dialog)
1569 if (rDPObj.GetName().isEmpty())
1570 rDPObj.SetName( pDoc->GetDPCollection()->CreateNewName() );
1572 ScRange aNewOut;
1573 if (!checkNewOutputRange(rDPObj, rDocShell, aNewOut, bApi))
1575 rDPObj = aUndoDPObj;
1576 return false;
1579 // test if new output area is empty except for old area
1580 if (!bApi)
1582 if (!lcl_EmptyExcept(pDoc, aNewOut, rDPObj.GetOutRange()))
1584 QueryBox aBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1585 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) );
1586 if (aBox.Execute() == RET_NO)
1588 rDPObj = aUndoDPObj;
1589 return false;
1594 if (bRecord)
1595 createUndoDoc(pNewUndoDoc, pDoc, aNewOut);
1597 rDPObj.Output(aNewOut.aStart);
1598 rDocShell.PostPaintGridAll(); //! only necessary parts
1600 if (bRecord)
1602 rDocShell.GetUndoManager()->AddUndoAction(
1603 new ScUndoDataPilot(
1604 &rDocShell, pOldUndoDoc.release(), pNewUndoDoc.release(), &aUndoDPObj, &rDPObj, false));
1607 // notify API objects
1608 pDoc->BroadcastUno( ScDataPilotModifiedHint(rDPObj.GetName()) );
1609 aModificator.SetDocumentModified();
1610 return true;
1613 sal_uLong ScDBDocFunc::RefreshPivotTables(ScDPObject* pDPObj, bool bApi)
1615 ScDPCollection* pDPs = rDocShell.GetDocument()->GetDPCollection();
1616 if (!pDPs)
1617 return 0;
1619 std::set<ScDPObject*> aRefs;
1620 sal_uLong nErrId = pDPs->ReloadCache(pDPObj, aRefs);
1621 if (nErrId)
1622 return nErrId;
1624 std::set<ScDPObject*>::iterator it = aRefs.begin(), itEnd = aRefs.end();
1625 for (; it != itEnd; ++it)
1627 ScDPObject* pObj = *it;
1629 // This action is intentionally not undoable since it modifies cache.
1630 UpdatePivotTable(*pObj, false, bApi);
1633 return 0;
1636 void ScDBDocFunc::RefreshPivotTableGroups(ScDPObject* pDPObj)
1638 if (!pDPObj)
1639 return;
1641 ScDPCollection* pDPs = rDocShell.GetDocument()->GetDPCollection();
1642 if (!pDPs)
1643 return;
1645 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1646 if (!pSaveData)
1647 return;
1649 std::set<ScDPObject*> aRefs;
1650 if (!pDPs->ReloadGroupsInCache(pDPObj, aRefs))
1651 return;
1653 // We allow pDimData being NULL.
1654 const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
1655 std::set<ScDPObject*>::iterator it = aRefs.begin(), itEnd = aRefs.end();
1656 for (; it != itEnd; ++it)
1658 ScDPObject* pObj = *it;
1659 if (pObj != pDPObj)
1661 pSaveData = pObj->GetSaveData();
1662 if (pSaveData)
1663 pSaveData->SetDimensionData(pDimData);
1666 // This action is intentionally not undoable since it modifies cache.
1667 UpdatePivotTable(*pObj, false, false);
1671 //==================================================================
1673 // database import
1675 void ScDBDocFunc::UpdateImport( const String& rTarget, const svx::ODataAccessDescriptor& rDescriptor )
1677 // rTarget is the name of a database range
1679 ScDocument* pDoc = rDocShell.GetDocument();
1680 ScDBCollection& rDBColl = *pDoc->GetDBCollection();
1681 const ScDBData* pData = rDBColl.getNamedDBs().findByUpperName(ScGlobal::pCharClass->uppercase(rTarget));
1682 if (!pData)
1684 InfoBox aInfoBox(rDocShell.GetActiveDialogParent(),
1685 ScGlobal::GetRscString( STR_TARGETNOTFOUND ) );
1686 aInfoBox.Execute();
1687 return;
1690 SCTAB nTab;
1691 SCCOL nDummyCol;
1692 SCROW nDummyRow;
1693 pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
1695 ScImportParam aImportParam;
1696 pData->GetImportParam( aImportParam );
1698 OUString sDBName;
1699 OUString sDBTable;
1700 sal_Int32 nCommandType = 0;
1701 sDBName = rDescriptor.getDataSource();
1702 rDescriptor[svx::daCommand] >>= sDBTable;
1703 rDescriptor[svx::daCommandType] >>= nCommandType;
1705 aImportParam.aDBName = sDBName;
1706 aImportParam.bSql = ( nCommandType == sdb::CommandType::COMMAND );
1707 aImportParam.aStatement = sDBTable;
1708 aImportParam.bNative = false;
1709 aImportParam.nType = static_cast<sal_uInt8>( ( nCommandType == sdb::CommandType::QUERY ) ? ScDbQuery : ScDbTable );
1710 aImportParam.bImport = true;
1712 bool bContinue = DoImport( nTab, aImportParam, &rDescriptor, true );
1714 // DB-Operationen wiederholen
1716 ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
1717 if (pViewSh)
1719 ScRange aRange;
1720 pData->GetArea(aRange);
1721 pViewSh->MarkRange(aRange); // selektieren
1723 if ( bContinue ) // Fehler beim Import -> Abbruch
1725 // interne Operationen, wenn welche gespeichert
1727 if ( pData->HasQueryParam() || pData->HasSortParam() || pData->HasSubTotalParam() )
1728 pViewSh->RepeatDB();
1730 // Pivottabellen die den Bereich als Quelldaten haben
1732 rDocShell.RefreshPivotTables(aRange);
1740 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */