merge the formfield patch from ooo-build
[ooovba.git] / sc / source / ui / docshell / dbdocfun.cxx
blob4180060d84091292c7772259b5b3a656cb9d2c71
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dbdocfun.cxx,v $
10 * $Revision: 1.20.128.4 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include <sfx2/app.hxx>
39 #include <vcl/msgbox.hxx>
40 #include <vcl/waitobj.hxx>
42 #include <com/sun/star/sdbc/XResultSet.hpp>
44 #include "dbdocfun.hxx"
45 #include "sc.hrc"
46 #include "dbcolect.hxx"
47 #include "undodat.hxx"
48 #include "docsh.hxx"
49 #include "docfunc.hxx"
50 #include "globstr.hrc"
51 #include "tabvwsh.hxx"
52 #include "patattr.hxx"
53 #include "rangenam.hxx"
54 #include "olinetab.hxx"
55 #include "dpobject.hxx"
56 #include "dociter.hxx" // for lcl_EmptyExcept
57 #include "cell.hxx" // for lcl_EmptyExcept
58 #include "editable.hxx"
59 #include "attrib.hxx"
60 #include "drwlayer.hxx"
61 #include "dpshttab.hxx"
63 // -----------------------------------------------------------------
65 BOOL ScDBDocFunc::AddDBRange( const String& rName, const ScRange& rRange, BOOL /* bApi */ )
68 ScDocShellModificator aModificator( rDocShell );
70 ScDocument* pDoc = rDocShell.GetDocument();
71 ScDBCollection* pDocColl = pDoc->GetDBCollection();
72 BOOL bUndo (pDoc->IsUndoEnabled());
74 ScDBCollection* pUndoColl = NULL;
75 if (bUndo)
76 pUndoColl = new ScDBCollection( *pDocColl );
78 ScDBData* pNew = new ScDBData( rName, rRange.aStart.Tab(),
79 rRange.aStart.Col(), rRange.aStart.Row(),
80 rRange.aEnd.Col(), rRange.aEnd.Row() );
82 // #i55926# While loading XML, formula cells only have a single string token,
83 // so CompileDBFormula would never find any name (index) tokens, and would
84 // unnecessarily loop through all cells.
85 BOOL bCompile = !pDoc->IsImportingXML();
87 if ( bCompile )
88 pDoc->CompileDBFormula( TRUE ); // CreateFormulaString
89 BOOL bOk = pDocColl->Insert( pNew );
90 if ( bCompile )
91 pDoc->CompileDBFormula( FALSE ); // CompileFormulaString
93 if (!bOk)
95 delete pNew;
96 delete pUndoColl;
97 return FALSE;
100 if (bUndo)
102 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
103 rDocShell.GetUndoManager()->AddUndoAction(
104 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
107 aModificator.SetDocumentModified();
108 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
109 return TRUE;
112 BOOL ScDBDocFunc::DeleteDBRange( const String& rName, BOOL /* bApi */ )
114 BOOL bDone = FALSE;
115 ScDocument* pDoc = rDocShell.GetDocument();
116 ScDBCollection* pDocColl = pDoc->GetDBCollection();
117 BOOL bUndo (pDoc->IsUndoEnabled());
119 USHORT nPos = 0;
120 if (pDocColl->SearchName( rName, nPos ))
122 ScDocShellModificator aModificator( rDocShell );
124 ScDBCollection* pUndoColl = NULL;
125 if (bUndo)
126 pUndoColl = new ScDBCollection( *pDocColl );
128 pDoc->CompileDBFormula( TRUE ); // CreateFormulaString
129 pDocColl->AtFree( nPos );
130 pDoc->CompileDBFormula( FALSE ); // CompileFormulaString
132 if (bUndo)
134 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
135 rDocShell.GetUndoManager()->AddUndoAction(
136 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
139 aModificator.SetDocumentModified();
140 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
141 bDone = TRUE;
144 return bDone;
147 BOOL ScDBDocFunc::RenameDBRange( const String& rOld, const String& rNew, BOOL /* bApi */ )
149 BOOL bDone = FALSE;
150 ScDocument* pDoc = rDocShell.GetDocument();
151 ScDBCollection* pDocColl = pDoc->GetDBCollection();
152 BOOL bUndo (pDoc->IsUndoEnabled());
154 USHORT nPos = 0;
155 USHORT nDummy = 0;
156 if ( pDocColl->SearchName( rOld, nPos ) &&
157 !pDocColl->SearchName( rNew, nDummy ) )
159 ScDocShellModificator aModificator( rDocShell );
161 ScDBData* pData = (*pDocColl)[nPos];
162 ScDBData* pNewData = new ScDBData(*pData);
163 pNewData->SetName(rNew);
165 ScDBCollection* pUndoColl = new ScDBCollection( *pDocColl );
167 pDoc->CompileDBFormula( TRUE ); // CreateFormulaString
168 pDocColl->AtFree( nPos );
169 BOOL bInserted = pDocColl->Insert( pNewData );
170 if (!bInserted) // Fehler -> alten Zustand wiederherstellen
172 delete pNewData;
173 pDoc->SetDBCollection( pUndoColl ); // gehoert dann dem Dokument
175 pDoc->CompileDBFormula( FALSE ); // CompileFormulaString
177 if (bInserted) // Einfuegen hat geklappt
179 if (bUndo)
181 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
182 rDocShell.GetUndoManager()->AddUndoAction(
183 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
185 else
186 delete pUndoColl;
188 aModificator.SetDocumentModified();
189 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
190 bDone = TRUE;
194 return bDone;
197 BOOL ScDBDocFunc::ModifyDBData( const ScDBData& rNewData, BOOL /* bApi */ )
199 BOOL bDone = FALSE;
200 ScDocument* pDoc = rDocShell.GetDocument();
201 ScDBCollection* pDocColl = pDoc->GetDBCollection();
202 BOOL bUndo (pDoc->IsUndoEnabled());
204 USHORT nPos = 0;
205 if (pDocColl->SearchName( rNewData.GetName(), nPos ))
207 ScDocShellModificator aModificator( rDocShell );
209 ScDBData* pData = (*pDocColl)[nPos];
211 ScRange aOldRange, aNewRange;
212 pData->GetArea(aOldRange);
213 rNewData.GetArea(aNewRange);
214 BOOL bAreaChanged = ( aOldRange != aNewRange ); // dann muss neu compiliert werden
216 ScDBCollection* pUndoColl = NULL;
217 if (bUndo)
218 pUndoColl = new ScDBCollection( *pDocColl );
220 *pData = rNewData;
221 if (bAreaChanged)
222 pDoc->CompileDBFormula();
224 if (bUndo)
226 ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
227 rDocShell.GetUndoManager()->AddUndoAction(
228 new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
231 aModificator.SetDocumentModified();
232 bDone = TRUE;
235 return bDone;
238 // -----------------------------------------------------------------
240 BOOL ScDBDocFunc::RepeatDB( const String& rDBName, BOOL bRecord, BOOL bApi )
242 //! auch fuer ScDBFunc::RepeatDB benutzen!
244 BOOL bDone = FALSE;
245 ScDocument* pDoc = rDocShell.GetDocument();
246 if (bRecord && !pDoc->IsUndoEnabled())
247 bRecord = FALSE;
248 ScDBCollection* pColl = pDoc->GetDBCollection();
249 USHORT nIndex;
250 if ( pColl && pColl->SearchName( rDBName, nIndex ) )
252 ScDBData* pDBData = (*pColl)[nIndex];
254 ScQueryParam aQueryParam;
255 pDBData->GetQueryParam( aQueryParam );
256 BOOL bQuery = aQueryParam.GetEntry(0).bDoQuery;
258 ScSortParam aSortParam;
259 pDBData->GetSortParam( aSortParam );
260 BOOL bSort = aSortParam.bDoSort[0];
262 ScSubTotalParam aSubTotalParam;
263 pDBData->GetSubTotalParam( aSubTotalParam );
264 BOOL bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
266 if ( bQuery || bSort || bSubTotal )
268 BOOL bQuerySize = FALSE;
269 ScRange aOldQuery;
270 ScRange aNewQuery;
271 if (bQuery && !aQueryParam.bInplace)
273 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
274 aQueryParam.nDestTab, TRUE );
275 if (pDest && pDest->IsDoSize())
277 pDest->GetArea( aOldQuery );
278 bQuerySize = TRUE;
282 SCTAB nTab;
283 SCCOL nStartCol;
284 SCROW nStartRow;
285 SCCOL nEndCol;
286 SCROW nEndRow;
287 pDBData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
289 //! Undo nur benoetigte Daten ?
291 ScDocument* pUndoDoc = NULL;
292 ScOutlineTable* pUndoTab = NULL;
293 ScRangeName* pUndoRange = NULL;
294 ScDBCollection* pUndoDB = NULL;
296 if (bRecord)
298 SCTAB nTabCount = pDoc->GetTableCount();
299 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
300 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
301 if (pTable)
303 pUndoTab = new ScOutlineTable( *pTable );
305 // column/row state
306 SCCOLROW nOutStartCol, nOutEndCol;
307 SCCOLROW nOutStartRow, nOutEndRow;
308 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
309 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
311 pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE );
312 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0,
313 nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab,
314 IDF_NONE, FALSE, pUndoDoc );
315 pDoc->CopyToDocument( 0, static_cast<SCROW>(nOutStartRow),
316 nTab, MAXCOL, static_cast<SCROW>(nOutEndRow), nTab,
317 IDF_NONE, FALSE, pUndoDoc );
319 else
320 pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE );
322 // Datenbereich sichern - incl. Filter-Ergebnis
323 pDoc->CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, FALSE, pUndoDoc );
325 // alle Formeln wegen Referenzen
326 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, FALSE, pUndoDoc );
328 // DB- und andere Bereiche
329 ScRangeName* pDocRange = pDoc->GetRangeName();
330 if (pDocRange->GetCount())
331 pUndoRange = new ScRangeName( *pDocRange );
332 ScDBCollection* pDocDB = pDoc->GetDBCollection();
333 if (pDocDB->GetCount())
334 pUndoDB = new ScDBCollection( *pDocDB );
337 if (bSort && bSubTotal)
339 // Sortieren ohne SubTotals
341 aSubTotalParam.bRemoveOnly = TRUE; // wird unten wieder zurueckgesetzt
342 DoSubTotals( nTab, aSubTotalParam, NULL, FALSE, bApi );
345 if (bSort)
347 pDBData->GetSortParam( aSortParam ); // Bereich kann sich geaendert haben
348 Sort( nTab, aSortParam, FALSE, FALSE, bApi );
350 if (bQuery)
352 pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geaendert haben
353 ScRange aAdvSource;
354 if (pDBData->GetAdvancedQuerySource(aAdvSource))
355 Query( nTab, aQueryParam, &aAdvSource, FALSE, bApi );
356 else
357 Query( nTab, aQueryParam, NULL, FALSE, bApi );
359 // bei nicht-inplace kann die Tabelle umgestellt worden sein
360 // if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
361 // SetTabNo( nTab );
363 if (bSubTotal)
365 pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geaendert haben
366 aSubTotalParam.bRemoveOnly = FALSE;
367 DoSubTotals( nTab, aSubTotalParam, NULL, FALSE, bApi );
370 if (bRecord)
372 SCTAB nDummyTab;
373 SCCOL nDummyCol;
374 SCROW nDummyRow;
375 SCROW nNewEndRow;
376 pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
378 const ScRange* pOld = NULL;
379 const ScRange* pNew = NULL;
380 if (bQuerySize)
382 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
383 aQueryParam.nDestTab, TRUE );
384 if (pDest)
386 pDest->GetArea( aNewQuery );
387 pOld = &aOldQuery;
388 pNew = &aNewQuery;
392 rDocShell.GetUndoManager()->AddUndoAction(
393 new ScUndoRepeatDB( &rDocShell, nTab,
394 nStartCol, nStartRow, nEndCol, nEndRow,
395 nNewEndRow,
396 //nCurX, nCurY,
397 nStartCol, nStartRow,
398 pUndoDoc, pUndoTab,
399 pUndoRange, pUndoDB,
400 pOld, pNew ) );
403 rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
404 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE );
405 bDone = TRUE;
407 else if (!bApi) // "Keine Operationen auszufuehren"
408 rDocShell.ErrorMessage(STR_MSSG_REPEATDB_0);
411 return bDone;
414 // -----------------------------------------------------------------
416 BOOL ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
417 BOOL bRecord, BOOL bPaint, BOOL bApi )
419 ScDocShellModificator aModificator( rDocShell );
421 ScDocument* pDoc = rDocShell.GetDocument();
422 if (bRecord && !pDoc->IsUndoEnabled())
423 bRecord = FALSE;
424 SCTAB nSrcTab = nTab;
425 ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
427 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
428 rSortParam.nCol2, rSortParam.nRow2 );
429 if (!pDBData)
431 DBG_ERROR( "Sort: keine DBData" );
432 return FALSE;
435 ScDBData* pDestData = NULL;
436 ScRange aOldDest;
437 BOOL bCopy = !rSortParam.bInplace;
438 if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 &&
439 rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab )
440 bCopy = FALSE;
441 ScSortParam aLocalParam( rSortParam );
442 if ( bCopy )
444 aLocalParam.MoveToDest();
445 if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
447 if (!bApi)
448 rDocShell.ErrorMessage(STR_PASTE_FULL);
449 return FALSE;
452 nTab = rSortParam.nDestTab;
453 pDestData = pDoc->GetDBAtCursor( rSortParam.nDestCol, rSortParam.nDestRow,
454 rSortParam.nDestTab, TRUE );
455 if (pDestData)
456 pDestData->GetArea(aOldDest);
459 ScEditableTester aTester( pDoc, nTab, aLocalParam.nCol1,aLocalParam.nRow1,
460 aLocalParam.nCol2,aLocalParam.nRow2 );
461 if (!aTester.IsEditable())
463 if (!bApi)
464 rDocShell.ErrorMessage(aTester.GetMessageId());
465 return FALSE;
468 if ( aLocalParam.bIncludePattern && pDoc->HasAttrib(
469 aLocalParam.nCol1, aLocalParam.nRow1, nTab,
470 aLocalParam.nCol2, aLocalParam.nRow2, nTab,
471 HASATTR_MERGED | HASATTR_OVERLAPPED ) )
473 // Merge-Attribute wuerden beim Sortieren durcheinanderkommen
474 if (!bApi)
475 rDocShell.ErrorMessage(STR_SORT_ERR_MERGED);
476 return FALSE;
480 // ausfuehren
482 WaitObject aWait( rDocShell.GetActiveDialogParent() );
484 BOOL bRepeatQuery = FALSE; // bestehenden Filter wiederholen?
485 ScQueryParam aQueryParam;
486 pDBData->GetQueryParam( aQueryParam );
487 if ( aQueryParam.GetEntry(0).bDoQuery )
488 bRepeatQuery = TRUE;
490 if (bRepeatQuery && bCopy)
492 if ( aQueryParam.bInplace ||
493 aQueryParam.nDestCol != rSortParam.nDestCol ||
494 aQueryParam.nDestRow != rSortParam.nDestRow ||
495 aQueryParam.nDestTab != rSortParam.nDestTab ) // Query auf selben Zielbereich?
496 bRepeatQuery = FALSE;
499 ScUndoSort* pUndoAction = 0;
500 if ( bRecord )
502 // Referenzen ausserhalb des Bereichs werden nicht veraendert !
504 ScDocument* pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
505 // Zeilenhoehen immer (wegen automatischer Anpassung)
506 //! auf ScBlockUndo umstellen
507 pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE );
509 /* #i59745# Do not copy note captions to undo document. All existing
510 caption objects will be repositioned while sorting which is tracked
511 in drawing undo. When undo is executed, the old positions will be
512 restored, and the cells with the old notes (which still refer to the
513 existing captions) will be copied back into the source document. */
514 pDoc->CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
515 aLocalParam.nCol2, aLocalParam.nRow2, nTab,
516 IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc );
518 const ScRange* pR = 0;
519 if (pDestData)
521 /* #i59745# Do not copy note captions from destination range to
522 undo document. All existing caption objects will be removed
523 which is tracked in drawing undo. When undo is executed, the
524 caption objects are reinserted with drawing undo, and the cells
525 with the old notes (which still refer to the existing captions)
526 will be copied back into the source document. */
527 pDoc->CopyToDocument( aOldDest, IDF_ALL|IDF_NOCAPTIONS, FALSE, pUndoDoc );
528 pR = &aOldDest;
531 // Zeilenhoehen immer (wegen automatischer Anpassung)
532 //! auf ScBlockUndo umstellen
533 // if (bRepeatQuery)
534 pDoc->CopyToDocument( 0, aLocalParam.nRow1, nTab, MAXCOL, aLocalParam.nRow2, nTab,
535 IDF_NONE, FALSE, pUndoDoc );
537 ScDBCollection* pUndoDB = NULL;
538 ScDBCollection* pDocDB = pDoc->GetDBCollection();
539 if (pDocDB->GetCount())
540 pUndoDB = new ScDBCollection( *pDocDB );
542 pUndoAction = new ScUndoSort( &rDocShell, nTab, rSortParam, bRepeatQuery, pUndoDoc, pUndoDB, pR );
543 rDocShell.GetUndoManager()->AddUndoAction( pUndoAction );
545 // #i59745# collect all drawing undo actions affecting cell note captions
546 if( pDrawLayer )
547 pDrawLayer->BeginCalcUndo();
550 if ( bCopy )
552 if (pDestData)
553 pDoc->DeleteAreaTab(aOldDest, IDF_CONTENTS); // Zielbereich vorher loeschen
555 ScRange aSource( rSortParam.nCol1,rSortParam.nRow1,nSrcTab,
556 rSortParam.nCol2,rSortParam.nRow2,nSrcTab );
557 ScAddress aDest( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab );
559 rDocShell.GetDocFunc().MoveBlock( aSource, aDest, FALSE, FALSE, FALSE, TRUE );
562 // #105780# don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set)
563 if ( aLocalParam.bDoSort[0] )
564 pDoc->Sort( nTab, aLocalParam, bRepeatQuery );
566 BOOL bSave = TRUE;
567 if (bCopy)
569 ScSortParam aOldSortParam;
570 pDBData->GetSortParam( aOldSortParam );
571 if ( aOldSortParam.bDoSort[0] && aOldSortParam.bInplace ) // Inplace-Sortierung gemerkt?
573 bSave = FALSE;
574 aOldSortParam.nDestCol = rSortParam.nDestCol;
575 aOldSortParam.nDestRow = rSortParam.nDestRow;
576 aOldSortParam.nDestTab = rSortParam.nDestTab;
577 pDBData->SetSortParam( aOldSortParam ); // dann nur DestPos merken
580 if (bSave) // Parameter merken
582 pDBData->SetSortParam( rSortParam );
583 pDBData->SetHeader( rSortParam.bHasHeader ); //! ???
584 pDBData->SetByRow( rSortParam.bByRow ); //! ???
587 if (bCopy) // neuen DB-Bereich merken
589 // Tabelle umschalten von aussen (View)
590 //! SetCursor ??!?!
592 ScRange aDestPos( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
593 aLocalParam.nCol2, aLocalParam.nRow2, nTab );
594 ScDBData* pNewData;
595 if (pDestData)
596 pNewData = pDestData; // Bereich vorhanden -> anpassen
597 else // Bereich ab Cursor/Markierung wird angelegt
598 pNewData = rDocShell.GetDBData(aDestPos, SC_DB_MAKE, TRUE );
599 if (pNewData)
601 pNewData->SetArea( nTab,
602 aLocalParam.nCol1,aLocalParam.nRow1,
603 aLocalParam.nCol2,aLocalParam.nRow2 );
604 pNewData->SetSortParam( aLocalParam );
605 pNewData->SetHeader( aLocalParam.bHasHeader ); //! ???
606 pNewData->SetByRow( aLocalParam.bByRow );
608 else
610 DBG_ERROR("Zielbereich nicht da");
614 ScRange aDirtyRange( aLocalParam.nCol1, aLocalParam.nRow1, nTab,
615 aLocalParam.nCol2, aLocalParam.nRow2, nTab );
616 pDoc->SetDirty( aDirtyRange );
618 if (bPaint)
620 USHORT nPaint = PAINT_GRID;
621 SCCOL nStartX = aLocalParam.nCol1;
622 SCROW nStartY = aLocalParam.nRow1;
623 SCCOL nEndX = aLocalParam.nCol2;
624 SCROW nEndY = aLocalParam.nRow2;
625 if ( bRepeatQuery )
627 nPaint |= PAINT_LEFT;
628 nStartX = 0;
629 nEndX = MAXCOL;
631 if (pDestData)
633 if ( nEndX < aOldDest.aEnd.Col() )
634 nEndX = aOldDest.aEnd.Col();
635 if ( nEndY < aOldDest.aEnd.Row() )
636 nEndY = aOldDest.aEnd.Row();
638 rDocShell.PostPaint( nStartX, nStartY, nTab, nEndX, nEndY, nTab, nPaint );
641 // AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, bPaint );
642 rDocShell.AdjustRowHeight( aLocalParam.nRow1, aLocalParam.nRow2, nTab );
644 // #i59745# set collected drawing undo actions at sorting undo action
645 if( pUndoAction && pDrawLayer )
646 pUndoAction->SetDrawUndoAction( pDrawLayer->GetCalcUndo() );
648 aModificator.SetDocumentModified();
650 return TRUE;
653 // -----------------------------------------------------------------
655 BOOL ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam,
656 const ScRange* pAdvSource, BOOL bRecord, BOOL bApi )
658 ScDocShellModificator aModificator( rDocShell );
660 ScDocument* pDoc = rDocShell.GetDocument();
661 if (bRecord && !pDoc->IsUndoEnabled())
662 bRecord = FALSE;
663 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rQueryParam.nCol1, rQueryParam.nRow1,
664 rQueryParam.nCol2, rQueryParam.nRow2 );
665 if (!pDBData)
667 DBG_ERROR( "Query: keine DBData" );
668 return FALSE;
671 // Wechsel von Inplace auf nicht-Inplace, dann erst Inplace aufheben:
672 // (nur, wenn im Dialog "Persistent" ausgewaehlt ist)
674 if ( !rQueryParam.bInplace && pDBData->HasQueryParam() && rQueryParam.bDestPers )
676 ScQueryParam aOldQuery;
677 pDBData->GetQueryParam(aOldQuery);
678 if (aOldQuery.bInplace)
680 // alte Filterung aufheben
682 SCSIZE nEC = aOldQuery.GetEntryCount();
683 for (SCSIZE i=0; i<nEC; i++)
684 aOldQuery.GetEntry(i).bDoQuery = FALSE;
685 aOldQuery.bDuplicate = TRUE;
686 Query( nTab, aOldQuery, NULL, bRecord, bApi );
690 ScQueryParam aLocalParam( rQueryParam ); // fuer Paint / Zielbereich
691 BOOL bCopy = !rQueryParam.bInplace; // kopiert wird in Table::Query
692 ScDBData* pDestData = NULL; // Bereich, in den kopiert wird
693 BOOL bDoSize = FALSE; // Zielgroesse anpassen (einf./loeschen)
694 SCCOL nFormulaCols = 0; // nur bei bDoSize
695 BOOL bKeepFmt = FALSE;
696 ScRange aOldDest;
697 ScRange aDestTotal;
698 if ( bCopy && rQueryParam.nDestCol == rQueryParam.nCol1 &&
699 rQueryParam.nDestRow == rQueryParam.nRow1 && rQueryParam.nDestTab == nTab )
700 bCopy = FALSE;
701 SCTAB nDestTab = nTab;
702 if ( bCopy )
704 aLocalParam.MoveToDest();
705 nDestTab = rQueryParam.nDestTab;
706 if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
708 if (!bApi)
709 rDocShell.ErrorMessage(STR_PASTE_FULL);
710 return FALSE;
713 ScEditableTester aTester( pDoc, nDestTab, aLocalParam.nCol1,aLocalParam.nRow1,
714 aLocalParam.nCol2,aLocalParam.nRow2);
715 if (!aTester.IsEditable())
717 if (!bApi)
718 rDocShell.ErrorMessage(aTester.GetMessageId());
719 return FALSE;
722 pDestData = pDoc->GetDBAtCursor( rQueryParam.nDestCol, rQueryParam.nDestRow,
723 rQueryParam.nDestTab, TRUE );
724 if (pDestData)
726 pDestData->GetArea( aOldDest );
727 aDestTotal=ScRange( rQueryParam.nDestCol,
728 rQueryParam.nDestRow,
729 nDestTab,
730 rQueryParam.nDestCol + rQueryParam.nCol2 - rQueryParam.nCol1,
731 rQueryParam.nDestRow + rQueryParam.nRow2 - rQueryParam.nRow1,
732 nDestTab );
734 bDoSize = pDestData->IsDoSize();
735 // Test, ob Formeln aufgefuellt werden muessen (nFormulaCols):
736 if ( bDoSize && aOldDest.aEnd.Col() == aDestTotal.aEnd.Col() )
738 SCCOL nTestCol = aOldDest.aEnd.Col() + 1; // neben dem Bereich
739 SCROW nTestRow = rQueryParam.nDestRow +
740 ( aLocalParam.bHasHeader ? 1 : 0 );
741 while ( nTestCol <= MAXCOL &&
742 pDoc->GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA )
743 ++nTestCol, ++nFormulaCols;
746 bKeepFmt = pDestData->IsKeepFmt();
747 if ( bDoSize && !pDoc->CanFitBlock( aOldDest, aDestTotal ) )
749 if (!bApi)
750 rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2); // kann keine Zeilen einfuegen
751 return FALSE;
756 // ausfuehren
758 WaitObject aWait( rDocShell.GetActiveDialogParent() );
760 BOOL bKeepSub = FALSE; // bestehende Teilergebnisse wiederholen?
761 ScSubTotalParam aSubTotalParam;
762 if (rQueryParam.GetEntry(0).bDoQuery) // nicht beim Aufheben
764 pDBData->GetSubTotalParam( aSubTotalParam ); // Teilergebnisse vorhanden?
766 if ( aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly )
767 bKeepSub = TRUE;
770 ScDocument* pUndoDoc = NULL;
771 ScDBCollection* pUndoDB = NULL;
772 const ScRange* pOld = NULL;
774 if ( bRecord )
776 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
777 if (bCopy)
779 pUndoDoc->InitUndo( pDoc, nDestTab, nDestTab, FALSE, TRUE );
780 pDoc->CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
781 aLocalParam.nCol2, aLocalParam.nRow2, nDestTab,
782 IDF_ALL, FALSE, pUndoDoc );
783 // Attribute sichern, falls beim Filtern mitkopiert
785 if (pDestData)
787 pDoc->CopyToDocument( aOldDest, IDF_ALL, FALSE, pUndoDoc );
788 pOld = &aOldDest;
791 else
793 pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE );
794 pDoc->CopyToDocument( 0, rQueryParam.nRow1, nTab, MAXCOL, rQueryParam.nRow2, nTab,
795 IDF_NONE, FALSE, pUndoDoc );
798 ScDBCollection* pDocDB = pDoc->GetDBCollection();
799 if (pDocDB->GetCount())
800 pUndoDB = new ScDBCollection( *pDocDB );
802 pDoc->BeginDrawUndo();
805 ScDocument* pAttribDoc = NULL;
806 ScRange aAttribRange;
807 if (pDestData) // Zielbereich loeschen
809 if ( bKeepFmt )
811 // kleinere der End-Spalten, Header+1 Zeile
812 aAttribRange = aOldDest;
813 if ( aAttribRange.aEnd.Col() > aDestTotal.aEnd.Col() )
814 aAttribRange.aEnd.SetCol( aDestTotal.aEnd.Col() );
815 aAttribRange.aEnd.SetRow( aAttribRange.aStart.Row() +
816 ( aLocalParam.bHasHeader ? 1 : 0 ) );
818 // auch fuer aufgefuellte Formeln
819 aAttribRange.aEnd.SetCol( aAttribRange.aEnd.Col() + nFormulaCols );
821 pAttribDoc = new ScDocument( SCDOCMODE_UNDO );
822 pAttribDoc->InitUndo( pDoc, nDestTab, nDestTab, FALSE, TRUE );
823 pDoc->CopyToDocument( aAttribRange, IDF_ATTRIB, FALSE, pAttribDoc );
826 if ( bDoSize )
827 pDoc->FitBlock( aOldDest, aDestTotal );
828 else
829 pDoc->DeleteAreaTab(aOldDest, IDF_ALL); // einfach loeschen
832 // Filtern am Dokument ausfuehren
833 SCSIZE nCount = pDoc->Query( nTab, rQueryParam, bKeepSub );
834 if (bCopy)
836 aLocalParam.nRow2 = aLocalParam.nRow1 + nCount;
837 if (!aLocalParam.bHasHeader && nCount > 0)
838 --aLocalParam.nRow2;
840 if ( bDoSize )
842 // auf wirklichen Ergebnis-Bereich anpassen
843 // (das hier ist immer eine Verkleinerung)
845 ScRange aNewDest( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
846 aLocalParam.nCol2, aLocalParam.nRow2, nDestTab );
847 pDoc->FitBlock( aDestTotal, aNewDest, FALSE ); // FALSE - nicht loeschen
849 if ( nFormulaCols > 0 )
851 // Formeln ausfuellen
852 //! Undo (Query und Repeat) !!!
854 ScRange aNewForm( aLocalParam.nCol2+1, aLocalParam.nRow1, nDestTab,
855 aLocalParam.nCol2+nFormulaCols, aLocalParam.nRow2, nDestTab );
856 ScRange aOldForm = aNewForm;
857 aOldForm.aEnd.SetRow( aOldDest.aEnd.Row() );
858 pDoc->FitBlock( aOldForm, aNewForm, FALSE );
860 ScMarkData aMark;
861 aMark.SelectOneTable(nDestTab);
862 SCROW nFStartY = aLocalParam.nRow1 + ( aLocalParam.bHasHeader ? 1 : 0 );
863 pDoc->Fill( aLocalParam.nCol2+1, nFStartY,
864 aLocalParam.nCol2+nFormulaCols, nFStartY, aMark,
865 aLocalParam.nRow2 - nFStartY,
866 FILL_TO_BOTTOM, FILL_SIMPLE );
870 if ( pAttribDoc ) // gemerkte Attribute zurueckkopieren
872 // Header
873 if (aLocalParam.bHasHeader)
875 ScRange aHdrRange = aAttribRange;
876 aHdrRange.aEnd.SetRow( aHdrRange.aStart.Row() );
877 pAttribDoc->CopyToDocument( aHdrRange, IDF_ATTRIB, FALSE, pDoc );
880 // Daten
881 SCCOL nAttrEndCol = aAttribRange.aEnd.Col();
882 SCROW nAttrRow = aAttribRange.aStart.Row() + ( aLocalParam.bHasHeader ? 1 : 0 );
883 for (SCCOL nCol = aAttribRange.aStart.Col(); nCol<=nAttrEndCol; nCol++)
885 const ScPatternAttr* pSrcPattern = pAttribDoc->GetPattern(
886 nCol, nAttrRow, nDestTab );
887 DBG_ASSERT(pSrcPattern,"Pattern ist 0");
888 if (pSrcPattern)
889 pDoc->ApplyPatternAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
890 nDestTab, *pSrcPattern );
891 const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet();
892 if (pStyle)
893 pDoc->ApplyStyleAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
894 nDestTab, *pStyle );
897 delete pAttribDoc;
901 // speichern: Inplace immer, sonst je nach Einstellung
902 // alter Inplace-Filter ist ggf. schon aufgehoben
904 BOOL bSave = rQueryParam.bInplace || rQueryParam.bDestPers;
905 if (bSave) // merken
907 pDBData->SetQueryParam( rQueryParam );
908 pDBData->SetHeader( rQueryParam.bHasHeader ); //! ???
909 pDBData->SetAdvancedQuerySource( pAdvSource ); // after SetQueryParam
912 if (bCopy) // neuen DB-Bereich merken
914 // selektieren wird hinterher von aussen (dbfunc)
915 // momentan ueber DB-Bereich an der Zielposition, darum muss dort
916 // auf jeden Fall ein Bereich angelegt werden.
918 ScDBData* pNewData;
919 if (pDestData)
920 pNewData = pDestData; // Bereich vorhanden -> anpassen (immer!)
921 else // Bereich anlegen
922 pNewData = rDocShell.GetDBData(
923 ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
924 aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ),
925 SC_DB_MAKE, TRUE );
927 if (pNewData)
929 pNewData->SetArea( nDestTab, aLocalParam.nCol1, aLocalParam.nRow1,
930 aLocalParam.nCol2, aLocalParam.nRow2 );
932 // Query-Param wird am Ziel nicht mehr eingestellt, fuehrt nur zu Verwirrung
933 // und Verwechslung mit dem Query-Param am Quellbereich (#37187#)
935 else
937 DBG_ERROR("Zielbereich nicht da");
941 if (!bCopy)
943 pDoc->InvalidatePageBreaks(nTab);
944 pDoc->UpdatePageBreaks( nTab );
947 // #i23299# because of Subtotal functions, the whole rows must be set dirty
948 ScRange aDirtyRange( 0 , aLocalParam.nRow1, nDestTab,
949 MAXCOL, aLocalParam.nRow2, nDestTab );
950 pDoc->SetDirty( aDirtyRange );
952 if ( bRecord )
954 // create undo action after executing, because of drawing layer undo
955 rDocShell.GetUndoManager()->AddUndoAction(
956 new ScUndoQuery( &rDocShell, nTab, rQueryParam, pUndoDoc, pUndoDB,
957 pOld, bDoSize, pAdvSource ) );
961 if (bCopy)
963 SCCOL nEndX = aLocalParam.nCol2;
964 SCROW nEndY = aLocalParam.nRow2;
965 if (pDestData)
967 if ( aOldDest.aEnd.Col() > nEndX )
968 nEndX = aOldDest.aEnd.Col();
969 if ( aOldDest.aEnd.Row() > nEndY )
970 nEndY = aOldDest.aEnd.Row();
972 if (bDoSize)
973 nEndY = MAXROW;
974 rDocShell.PostPaint( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
975 nEndX, nEndY, nDestTab, PAINT_GRID );
977 else
978 rDocShell.PostPaint( 0, rQueryParam.nRow1, nTab, MAXCOL, MAXROW, nTab,
979 PAINT_GRID | PAINT_LEFT );
980 aModificator.SetDocumentModified();
982 return TRUE;
985 // -----------------------------------------------------------------
987 BOOL ScDBDocFunc::DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam,
988 const ScSortParam* pForceNewSort, BOOL bRecord, BOOL bApi )
990 //! auch fuer ScDBFunc::DoSubTotals benutzen!
991 // dann bleibt aussen:
992 // - neuen Bereich (aus DBData) markieren
993 // - SelectionChanged (?)
995 BOOL bDo = !rParam.bRemoveOnly; // FALSE = nur loeschen
996 BOOL bRet = FALSE;
998 ScDocument* pDoc = rDocShell.GetDocument();
999 if (bRecord && !pDoc->IsUndoEnabled())
1000 bRecord = FALSE;
1001 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
1002 rParam.nCol2, rParam.nRow2 );
1003 if (!pDBData)
1005 DBG_ERROR( "SubTotals: keine DBData" );
1006 return FALSE;
1009 ScEditableTester aTester( pDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW );
1010 if (!aTester.IsEditable())
1012 if (!bApi)
1013 rDocShell.ErrorMessage(aTester.GetMessageId());
1014 return FALSE;
1017 if (pDoc->HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
1018 rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
1020 if (!bApi)
1021 rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen
1022 return FALSE;
1025 BOOL bOk = TRUE;
1026 BOOL bDelete = FALSE;
1027 if (rParam.bReplace)
1028 if (pDoc->TestRemoveSubTotals( nTab, rParam ))
1030 bDelete = TRUE;
1031 bOk = ( MessBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1032 // "StarCalc" "Daten loeschen?"
1033 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
1034 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) ).Execute()
1035 == RET_YES );
1038 if (bOk)
1040 WaitObject aWait( rDocShell.GetActiveDialogParent() );
1041 ScDocShellModificator aModificator( rDocShell );
1043 ScSubTotalParam aNewParam( rParam ); // Bereichsende wird veraendert
1044 ScDocument* pUndoDoc = NULL;
1045 ScOutlineTable* pUndoTab = NULL;
1046 ScRangeName* pUndoRange = NULL;
1047 ScDBCollection* pUndoDB = NULL;
1048 SCTAB nTabCount = 0; // fuer Referenz-Undo
1050 if (bRecord) // alte Daten sichern
1052 BOOL bOldFilter = bDo && rParam.bDoSort;
1054 nTabCount = pDoc->GetTableCount();
1055 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1056 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
1057 if (pTable)
1059 pUndoTab = new ScOutlineTable( *pTable );
1061 // column/row state
1062 SCCOLROW nOutStartCol, nOutEndCol;
1063 SCCOLROW nOutStartRow, nOutEndRow;
1064 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
1065 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
1067 pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE );
1068 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc );
1069 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, FALSE, pUndoDoc );
1071 else
1072 pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, bOldFilter );
1074 // Datenbereich sichern - incl. Filter-Ergebnis
1075 pDoc->CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab,
1076 IDF_ALL, FALSE, pUndoDoc );
1078 // alle Formeln wegen Referenzen
1079 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
1080 IDF_FORMULA, FALSE, pUndoDoc );
1082 // DB- und andere Bereiche
1083 ScRangeName* pDocRange = pDoc->GetRangeName();
1084 if (pDocRange->GetCount())
1085 pUndoRange = new ScRangeName( *pDocRange );
1086 ScDBCollection* pDocDB = pDoc->GetDBCollection();
1087 if (pDocDB->GetCount())
1088 pUndoDB = new ScDBCollection( *pDocDB );
1091 // pDoc->SetOutlineTable( nTab, NULL );
1092 ScOutlineTable* pOut = pDoc->GetOutlineTable( nTab );
1093 if (pOut)
1094 pOut->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen
1096 if (rParam.bReplace)
1097 pDoc->RemoveSubTotals( nTab, aNewParam );
1098 BOOL bSuccess = TRUE;
1099 if (bDo)
1101 // Sortieren
1102 if ( rParam.bDoSort || pForceNewSort )
1104 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
1106 // Teilergebnis-Felder vor die Sortierung setzen
1107 // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
1109 ScSortParam aOldSort;
1110 pDBData->GetSortParam( aOldSort );
1111 ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
1112 Sort( nTab, aSortParam, FALSE, FALSE, bApi );
1115 bSuccess = pDoc->DoSubTotals( nTab, aNewParam );
1117 ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
1118 aNewParam.nCol2, aNewParam.nRow2, nTab );
1119 pDoc->SetDirty( aDirtyRange );
1121 if (bRecord)
1123 // ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
1124 rDocShell.GetUndoManager()->AddUndoAction(
1125 new ScUndoSubTotals( &rDocShell, nTab,
1126 rParam, aNewParam.nRow2,
1127 pUndoDoc, pUndoTab, // pUndoDBData,
1128 pUndoRange, pUndoDB ) );
1131 if (!bSuccess)
1133 // "Kann keine Zeilen einfuegen"
1134 if (!bApi)
1135 rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
1138 // merken
1139 pDBData->SetSubTotalParam( aNewParam );
1140 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
1141 pDoc->CompileDBFormula();
1143 rDocShell.PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
1144 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE );
1145 aModificator.SetDocumentModified();
1147 bRet = bSuccess;
1149 return bRet;
1152 //==================================================================
1154 BOOL lcl_EmptyExcept( ScDocument* pDoc, const ScRange& rRange, const ScRange& rExcept )
1156 ScCellIterator aIter( pDoc, rRange );
1157 ScBaseCell* pCell = aIter.GetFirst();
1158 while (pCell)
1160 if ( !pCell->IsBlank() ) // real content?
1162 if ( !rExcept.In( ScAddress( aIter.GetCol(), aIter.GetRow(), aIter.GetTab() ) ) )
1163 return FALSE; // cell found
1165 pCell = aIter.GetNext();
1168 return TRUE; // nothing found - empty
1171 BOOL ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj,
1172 BOOL bRecord, BOOL bApi, BOOL bAllowMove )
1174 ScDocShellModificator aModificator( rDocShell );
1175 WaitObject aWait( rDocShell.GetActiveDialogParent() );
1177 BOOL bDone = FALSE;
1178 BOOL bUndoSelf = FALSE;
1179 USHORT nErrId = 0;
1181 ScDocument* pOldUndoDoc = NULL;
1182 ScDocument* pNewUndoDoc = NULL;
1183 ScDPObject* pUndoDPObj = NULL;
1184 if ( bRecord && pOldObj )
1185 pUndoDPObj = new ScDPObject( *pOldObj ); // copy old settings for undo
1187 ScDocument* pDoc = rDocShell.GetDocument();
1188 if (bRecord && !pDoc->IsUndoEnabled())
1189 bRecord = FALSE;
1190 if ( !rDocShell.IsEditable() || pDoc->GetChangeTrack() )
1192 // not recorded -> disallow
1193 //! different error messages?
1195 nErrId = STR_PROTECTIONERR;
1197 if ( pOldObj && !nErrId )
1199 ScRange aOldOut = pOldObj->GetOutRange();
1200 ScEditableTester aTester( pDoc, aOldOut );
1201 if ( !aTester.IsEditable() )
1202 nErrId = aTester.GetMessageId();
1204 if ( pNewObj && !nErrId )
1206 // at least one cell at the output position must be editable
1207 // -> check in advance
1208 // (start of output range in pNewObj is valid)
1210 ScRange aNewStart( pNewObj->GetOutRange().aStart );
1211 ScEditableTester aTester( pDoc, aNewStart );
1212 if ( !aTester.IsEditable() )
1213 nErrId = aTester.GetMessageId();
1216 ScDPObject* pDestObj = NULL;
1217 if ( !nErrId )
1219 if ( pOldObj && !pNewObj )
1221 // delete table
1223 ScRange aRange = pOldObj->GetOutRange();
1224 SCTAB nTab = aRange.aStart.Tab();
1226 if ( bRecord )
1228 pOldUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1229 pOldUndoDoc->InitUndo( pDoc, nTab, nTab );
1230 pDoc->CopyToDocument( aRange, IDF_ALL, FALSE, pOldUndoDoc );
1233 pDoc->DeleteAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
1234 aRange.aEnd.Col(), aRange.aEnd.Row(),
1235 nTab, IDF_ALL );
1236 pDoc->RemoveFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
1237 aRange.aEnd.Col(), aRange.aEnd.Row(),
1238 nTab, SC_MF_AUTO );
1240 pDoc->GetDPCollection()->FreeTable( pOldObj ); // object is deleted here
1242 rDocShell.PostPaintGridAll(); //! only necessary parts
1243 rDocShell.PostPaint( aRange.aStart.Col(), aRange.aStart.Row(), nTab,
1244 aRange.aEnd.Col(), aRange.aEnd.Row(), nTab,
1245 PAINT_GRID );
1246 bDone = TRUE;
1248 else if ( pNewObj )
1250 if ( pOldObj )
1252 if ( bRecord )
1254 ScRange aRange = pOldObj->GetOutRange();
1255 SCTAB nTab = aRange.aStart.Tab();
1256 pOldUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1257 pOldUndoDoc->InitUndo( pDoc, nTab, nTab );
1258 pDoc->CopyToDocument( aRange, IDF_ALL, FALSE, pOldUndoDoc );
1261 if ( pNewObj == pOldObj )
1263 // refresh only - no settings modified
1265 else
1267 pNewObj->WriteSourceDataTo( *pOldObj ); // copy source data
1269 ScDPSaveData* pData = pNewObj->GetSaveData();
1270 DBG_ASSERT( pData, "no SaveData from living DPObject" );
1271 if ( pData )
1272 pOldObj->SetSaveData( *pData ); // copy SaveData
1275 pDestObj = pOldObj;
1276 pDestObj->SetAllowMove( bAllowMove );
1278 else
1280 // output range must be set at pNewObj
1282 pDestObj = new ScDPObject( *pNewObj );
1283 pDestObj->SetAlive(TRUE);
1284 if ( !pDoc->GetDPCollection()->InsertNewTable(pDestObj) )
1286 DBG_ERROR("cannot insert DPObject");
1287 DELETEZ( pDestObj );
1290 if ( pDestObj )
1292 // #78541# create new database connection for "refresh"
1293 // (and re-read column entry collections)
1294 // so all changes take effect
1295 if ( pNewObj == pOldObj && pDestObj->IsImportData() )
1296 pDestObj->InvalidateSource();
1298 pDestObj->InvalidateData(); // before getting the new output area
1300 // make sure the table has a name (not set by dialog)
1301 if ( !pDestObj->GetName().Len() )
1302 pDestObj->SetName( pDoc->GetDPCollection()->CreateNewName() );
1304 BOOL bOverflow = FALSE;
1305 ScRange aNewOut = pDestObj->GetNewOutputRange( bOverflow );
1307 //! test for overlap with other data pilot tables
1308 if( pOldObj )
1310 const ScSheetSourceDesc* pSheetDesc = pOldObj->GetSheetDesc();
1311 if( pSheetDesc && pSheetDesc->aSourceRange.Intersects( aNewOut ) )
1313 ScRange aOldRange = pOldObj->GetOutRange();
1314 SCsROW nDiff = aOldRange.aStart.Row()-aNewOut.aStart.Row();
1315 aNewOut.aStart.SetRow( aOldRange.aStart.Row() );
1316 aNewOut.aEnd.SetRow( aNewOut.aEnd.Row()+nDiff );
1317 if( !ValidRow( aNewOut.aStart.Row() ) || !ValidRow( aNewOut.aEnd.Row() ) )
1318 bOverflow = TRUE;
1322 if ( bOverflow )
1324 // like with STR_PROTECTIONERR, use undo to reverse everything
1325 DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" );
1326 bUndoSelf = TRUE;
1327 nErrId = STR_PIVOT_ERROR;
1329 else
1331 ScEditableTester aTester( pDoc, aNewOut );
1332 if ( !aTester.IsEditable() )
1334 // destination area isn't editable
1335 //! reverse everything done so far, don't proceed
1337 // quick solution: proceed to end, use undo action
1338 // to reverse everything:
1339 DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" );
1340 bUndoSelf = TRUE;
1341 nErrId = aTester.GetMessageId();
1345 // test if new output area is empty except for old area
1346 if ( !bApi )
1348 BOOL bEmpty;
1349 if ( pOldObj ) // OutRange of pOldObj (pDestObj) is still old area
1350 bEmpty = lcl_EmptyExcept( pDoc, aNewOut, pOldObj->GetOutRange() );
1351 else
1352 bEmpty = pDoc->IsBlockEmpty( aNewOut.aStart.Tab(),
1353 aNewOut.aStart.Col(), aNewOut.aStart.Row(),
1354 aNewOut.aEnd.Col(), aNewOut.aEnd.Row() );
1356 if ( !bEmpty )
1358 QueryBox aBox( rDocShell.GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1359 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) );
1360 if (aBox.Execute() == RET_NO)
1362 //! like above (not editable), use undo to reverse everything
1363 DBG_ASSERT( bRecord, "DataPilotUpdate: can't undo" );
1364 bUndoSelf = TRUE;
1369 if ( bRecord )
1371 SCTAB nTab = aNewOut.aStart.Tab();
1372 pNewUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1373 pNewUndoDoc->InitUndo( pDoc, nTab, nTab );
1374 pDoc->CopyToDocument( aNewOut, IDF_ALL, FALSE, pNewUndoDoc );
1377 pDestObj->Output( aNewOut.aStart );
1379 rDocShell.PostPaintGridAll(); //! only necessary parts
1380 bDone = TRUE;
1383 // else nothing (no old, no new)
1386 if ( bRecord && bDone )
1388 SfxUndoAction* pAction = new ScUndoDataPilot( &rDocShell,
1389 pOldUndoDoc, pNewUndoDoc, pUndoDPObj, pDestObj, bAllowMove );
1390 pOldUndoDoc = NULL;
1391 pNewUndoDoc = NULL; // pointers are used in undo action
1392 // pUndoDPObj is copied
1394 if (bUndoSelf)
1396 // use undo action to restore original state
1397 //! prevent setting the document modified? (ScDocShellModificator)
1399 pAction->Undo();
1400 delete pAction;
1401 bDone = FALSE;
1403 else
1404 rDocShell.GetUndoManager()->AddUndoAction( pAction );
1407 delete pOldUndoDoc; // if not used for undo
1408 delete pNewUndoDoc;
1409 delete pUndoDPObj;
1411 if (const_cast<ScDPObject *>(pNewObj)->GetAutoFormatIndex() != 65535)
1413 ScViewData* pViewData = rDocShell.GetViewData();
1414 ScTabViewShell* pViewShell = pViewData->GetViewShell();
1415 pViewShell->GetDBData( TRUE, SC_DB_OLD );
1416 const ScMarkData& rMark1 = pViewData->GetMarkData();
1417 SCCOL nStartCol;
1418 SCROW nStartRow;
1419 SCTAB nStartTab;
1420 SCCOL nEndCol;
1421 SCROW nEndRow;
1422 SCTAB nEndTab;
1424 rDocShell.GetViewData()->GetSimpleArea( nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab );
1425 ScRange Outrange = pNewObj->GetOutRange();
1426 if (( (Outrange.aStart.Col() <= nStartCol) && (nStartCol <= Outrange.aEnd.Col() )&& (nStartTab == Outrange.aStart.Tab()))
1427 && ( (Outrange.aStart.Row() <= nStartRow) && (nStartRow <= Outrange.aEnd.Row() )) )
1430 if ( !rMark1.IsMarked() && !rMark1.IsMultiMarked() )
1431 pViewShell->MarkDataArea( TRUE );
1432 //FIXME: Autoformat even when clicked from a non-dp cell.
1433 pViewData->MoveNextRow();
1434 sal_uInt16 nAutoFmtIndex = pNewObj->GetAutoFormatIndex();
1435 pViewShell->AutoFormat(nAutoFmtIndex);
1436 pViewShell->AutoFormatPivotTable(const_cast<ScDPObject*>(pNewObj), nAutoFmtIndex);
1437 pViewData->MovePrevRow();
1441 if (bDone)
1442 aModificator.SetDocumentModified();
1444 if ( nErrId && !bApi )
1445 rDocShell.ErrorMessage( nErrId );
1447 return bDone;
1450 //==================================================================
1452 // Datenbank-Import...
1454 void ScDBDocFunc::UpdateImport( const String& rTarget, const String& rDBName,
1455 const String& rTableName, const String& rStatement, BOOL bNative,
1456 BYTE nType, const ::com::sun::star::uno::Reference<
1457 ::com::sun::star::sdbc::XResultSet >& xResultSet,
1458 const SbaSelectionList* pSelection )
1460 // Target ist jetzt einfach der Bereichsname
1462 ScDocument* pDoc = rDocShell.GetDocument();
1463 ScDBCollection& rDBColl = *pDoc->GetDBCollection();
1464 ScDBData* pData = NULL;
1465 ScImportParam aImportParam;
1466 BOOL bFound = FALSE;
1467 USHORT nCount = rDBColl.GetCount();
1468 for (USHORT i=0; i<nCount && !bFound; i++)
1470 pData = rDBColl[i];
1471 if (pData->GetName() == rTarget)
1472 bFound = TRUE;
1474 if (!bFound)
1476 InfoBox aInfoBox(rDocShell.GetActiveDialogParent(),
1477 ScGlobal::GetRscString( STR_TARGETNOTFOUND ) );
1478 aInfoBox.Execute();
1479 return;
1482 SCTAB nTab;
1483 SCCOL nDummyCol;
1484 SCROW nDummyRow;
1485 pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
1486 pData->GetImportParam( aImportParam );
1488 BOOL bSql = ( rStatement.Len() != 0 );
1490 aImportParam.aDBName = rDBName;
1491 aImportParam.bSql = bSql;
1492 aImportParam.aStatement = bSql ? rStatement : rTableName;
1493 aImportParam.bNative = bNative;
1494 aImportParam.nType = nType;
1495 aImportParam.bImport = TRUE;
1496 BOOL bContinue = DoImport( nTab, aImportParam, xResultSet, pSelection, TRUE );
1498 // DB-Operationen wiederholen
1500 ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
1501 if (pViewSh)
1503 ScRange aRange;
1504 pData->GetArea(aRange);
1505 pViewSh->MarkRange(aRange); // selektieren
1507 if ( bContinue ) // #41905# Fehler beim Import -> Abbruch
1509 // interne Operationen, wenn welche gespeichert
1511 if ( pData->HasQueryParam() || pData->HasSortParam() || pData->HasSubTotalParam() )
1512 pViewSh->RepeatDB();
1514 // Pivottabellen die den Bereich als Quelldaten haben
1516 rDocShell.RefreshPivotTables(aRange);