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"
46 #include "dbcolect.hxx"
47 #include "undodat.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"
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
;
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();
88 pDoc
->CompileDBFormula( TRUE
); // CreateFormulaString
89 BOOL bOk
= pDocColl
->Insert( pNew
);
91 pDoc
->CompileDBFormula( FALSE
); // CompileFormulaString
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
) );
112 BOOL
ScDBDocFunc::DeleteDBRange( const String
& rName
, BOOL
/* bApi */ )
115 ScDocument
* pDoc
= rDocShell
.GetDocument();
116 ScDBCollection
* pDocColl
= pDoc
->GetDBCollection();
117 BOOL
bUndo (pDoc
->IsUndoEnabled());
120 if (pDocColl
->SearchName( rName
, nPos
))
122 ScDocShellModificator
aModificator( rDocShell
);
124 ScDBCollection
* pUndoColl
= NULL
;
126 pUndoColl
= new ScDBCollection( *pDocColl
);
128 pDoc
->CompileDBFormula( TRUE
); // CreateFormulaString
129 pDocColl
->AtFree( nPos
);
130 pDoc
->CompileDBFormula( FALSE
); // CompileFormulaString
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
) );
147 BOOL
ScDBDocFunc::RenameDBRange( const String
& rOld
, const String
& rNew
, BOOL
/* bApi */ )
150 ScDocument
* pDoc
= rDocShell
.GetDocument();
151 ScDBCollection
* pDocColl
= pDoc
->GetDBCollection();
152 BOOL
bUndo (pDoc
->IsUndoEnabled());
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
173 pDoc
->SetDBCollection( pUndoColl
); // gehoert dann dem Dokument
175 pDoc
->CompileDBFormula( FALSE
); // CompileFormulaString
177 if (bInserted
) // Einfuegen hat geklappt
181 ScDBCollection
* pRedoColl
= new ScDBCollection( *pDocColl
);
182 rDocShell
.GetUndoManager()->AddUndoAction(
183 new ScUndoDBData( &rDocShell
, pUndoColl
, pRedoColl
) );
188 aModificator
.SetDocumentModified();
189 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED
) );
197 BOOL
ScDBDocFunc::ModifyDBData( const ScDBData
& rNewData
, BOOL
/* bApi */ )
200 ScDocument
* pDoc
= rDocShell
.GetDocument();
201 ScDBCollection
* pDocColl
= pDoc
->GetDBCollection();
202 BOOL
bUndo (pDoc
->IsUndoEnabled());
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
;
218 pUndoColl
= new ScDBCollection( *pDocColl
);
222 pDoc
->CompileDBFormula();
226 ScDBCollection
* pRedoColl
= new ScDBCollection( *pDocColl
);
227 rDocShell
.GetUndoManager()->AddUndoAction(
228 new ScUndoDBData( &rDocShell
, pUndoColl
, pRedoColl
) );
231 aModificator
.SetDocumentModified();
238 // -----------------------------------------------------------------
240 BOOL
ScDBDocFunc::RepeatDB( const String
& rDBName
, BOOL bRecord
, BOOL bApi
)
242 //! auch fuer ScDBFunc::RepeatDB benutzen!
245 ScDocument
* pDoc
= rDocShell
.GetDocument();
246 if (bRecord
&& !pDoc
->IsUndoEnabled())
248 ScDBCollection
* pColl
= pDoc
->GetDBCollection();
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
;
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
);
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
;
298 SCTAB nTabCount
= pDoc
->GetTableCount();
299 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
300 ScOutlineTable
* pTable
= pDoc
->GetOutlineTable( nTab
);
303 pUndoTab
= new ScOutlineTable( *pTable
);
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
);
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
);
347 pDBData
->GetSortParam( aSortParam
); // Bereich kann sich geaendert haben
348 Sort( nTab
, aSortParam
, FALSE
, FALSE
, bApi
);
352 pDBData
->GetQueryParam( aQueryParam
); // Bereich kann sich geaendert haben
354 if (pDBData
->GetAdvancedQuerySource(aAdvSource
))
355 Query( nTab
, aQueryParam
, &aAdvSource
, FALSE
, bApi
);
357 Query( nTab
, aQueryParam
, NULL
, FALSE
, bApi
);
359 // bei nicht-inplace kann die Tabelle umgestellt worden sein
360 // if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
365 pDBData
->GetSubTotalParam( aSubTotalParam
); // Bereich kann sich geaendert haben
366 aSubTotalParam
.bRemoveOnly
= FALSE
;
367 DoSubTotals( nTab
, aSubTotalParam
, NULL
, FALSE
, bApi
);
376 pDBData
->GetArea( nDummyTab
, nDummyCol
,nDummyRow
, nDummyCol
,nNewEndRow
);
378 const ScRange
* pOld
= NULL
;
379 const ScRange
* pNew
= NULL
;
382 ScDBData
* pDest
= pDoc
->GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
383 aQueryParam
.nDestTab
, TRUE
);
386 pDest
->GetArea( aNewQuery
);
392 rDocShell
.GetUndoManager()->AddUndoAction(
393 new ScUndoRepeatDB( &rDocShell
, nTab
,
394 nStartCol
, nStartRow
, nEndCol
, nEndRow
,
397 nStartCol
, nStartRow
,
403 rDocShell
.PostPaint( 0,0,nTab
, MAXCOL
,MAXROW
,nTab
,
404 PAINT_GRID
| PAINT_LEFT
| PAINT_TOP
| PAINT_SIZE
);
407 else if (!bApi
) // "Keine Operationen auszufuehren"
408 rDocShell
.ErrorMessage(STR_MSSG_REPEATDB_0
);
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())
424 SCTAB nSrcTab
= nTab
;
425 ScDrawLayer
* pDrawLayer
= pDoc
->GetDrawLayer();
427 ScDBData
* pDBData
= pDoc
->GetDBAtArea( nTab
, rSortParam
.nCol1
, rSortParam
.nRow1
,
428 rSortParam
.nCol2
, rSortParam
.nRow2
);
431 DBG_ERROR( "Sort: keine DBData" );
435 ScDBData
* pDestData
= NULL
;
437 BOOL bCopy
= !rSortParam
.bInplace
;
438 if ( bCopy
&& rSortParam
.nDestCol
== rSortParam
.nCol1
&&
439 rSortParam
.nDestRow
== rSortParam
.nRow1
&& rSortParam
.nDestTab
== nTab
)
441 ScSortParam
aLocalParam( rSortParam
);
444 aLocalParam
.MoveToDest();
445 if ( !ValidColRow( aLocalParam
.nCol2
, aLocalParam
.nRow2
) )
448 rDocShell
.ErrorMessage(STR_PASTE_FULL
);
452 nTab
= rSortParam
.nDestTab
;
453 pDestData
= pDoc
->GetDBAtCursor( rSortParam
.nDestCol
, rSortParam
.nDestRow
,
454 rSortParam
.nDestTab
, TRUE
);
456 pDestData
->GetArea(aOldDest
);
459 ScEditableTester
aTester( pDoc
, nTab
, aLocalParam
.nCol1
,aLocalParam
.nRow1
,
460 aLocalParam
.nCol2
,aLocalParam
.nRow2
);
461 if (!aTester
.IsEditable())
464 rDocShell
.ErrorMessage(aTester
.GetMessageId());
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
475 rDocShell
.ErrorMessage(STR_SORT_ERR_MERGED
);
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
)
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;
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;
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
);
531 // Zeilenhoehen immer (wegen automatischer Anpassung)
532 //! auf ScBlockUndo umstellen
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
547 pDrawLayer
->BeginCalcUndo();
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
);
569 ScSortParam aOldSortParam
;
570 pDBData
->GetSortParam( aOldSortParam
);
571 if ( aOldSortParam
.bDoSort
[0] && aOldSortParam
.bInplace
) // Inplace-Sortierung gemerkt?
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)
592 ScRange
aDestPos( aLocalParam
.nCol1
, aLocalParam
.nRow1
, nTab
,
593 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nTab
);
596 pNewData
= pDestData
; // Bereich vorhanden -> anpassen
597 else // Bereich ab Cursor/Markierung wird angelegt
598 pNewData
= rDocShell
.GetDBData(aDestPos
, SC_DB_MAKE
, TRUE
);
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
);
610 DBG_ERROR("Zielbereich nicht da");
614 ScRange
aDirtyRange( aLocalParam
.nCol1
, aLocalParam
.nRow1
, nTab
,
615 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nTab
);
616 pDoc
->SetDirty( aDirtyRange
);
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
;
627 nPaint
|= PAINT_LEFT
;
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();
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())
663 ScDBData
* pDBData
= pDoc
->GetDBAtArea( nTab
, rQueryParam
.nCol1
, rQueryParam
.nRow1
,
664 rQueryParam
.nCol2
, rQueryParam
.nRow2
);
667 DBG_ERROR( "Query: keine DBData" );
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
;
698 if ( bCopy
&& rQueryParam
.nDestCol
== rQueryParam
.nCol1
&&
699 rQueryParam
.nDestRow
== rQueryParam
.nRow1
&& rQueryParam
.nDestTab
== nTab
)
701 SCTAB nDestTab
= nTab
;
704 aLocalParam
.MoveToDest();
705 nDestTab
= rQueryParam
.nDestTab
;
706 if ( !ValidColRow( aLocalParam
.nCol2
, aLocalParam
.nRow2
) )
709 rDocShell
.ErrorMessage(STR_PASTE_FULL
);
713 ScEditableTester
aTester( pDoc
, nDestTab
, aLocalParam
.nCol1
,aLocalParam
.nRow1
,
714 aLocalParam
.nCol2
,aLocalParam
.nRow2
);
715 if (!aTester
.IsEditable())
718 rDocShell
.ErrorMessage(aTester
.GetMessageId());
722 pDestData
= pDoc
->GetDBAtCursor( rQueryParam
.nDestCol
, rQueryParam
.nDestRow
,
723 rQueryParam
.nDestTab
, TRUE
);
726 pDestData
->GetArea( aOldDest
);
727 aDestTotal
=ScRange( rQueryParam
.nDestCol
,
728 rQueryParam
.nDestRow
,
730 rQueryParam
.nDestCol
+ rQueryParam
.nCol2
- rQueryParam
.nCol1
,
731 rQueryParam
.nDestRow
+ rQueryParam
.nRow2
- rQueryParam
.nRow1
,
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
) )
750 rDocShell
.ErrorMessage(STR_MSSG_DOSUBTOTALS_2
); // kann keine Zeilen einfuegen
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
)
770 ScDocument
* pUndoDoc
= NULL
;
771 ScDBCollection
* pUndoDB
= NULL
;
772 const ScRange
* pOld
= NULL
;
776 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
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
787 pDoc
->CopyToDocument( aOldDest
, IDF_ALL
, FALSE
, pUndoDoc
);
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
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
);
827 pDoc
->FitBlock( aOldDest
, aDestTotal
);
829 pDoc
->DeleteAreaTab(aOldDest
, IDF_ALL
); // einfach loeschen
832 // Filtern am Dokument ausfuehren
833 SCSIZE nCount
= pDoc
->Query( nTab
, rQueryParam
, bKeepSub
);
836 aLocalParam
.nRow2
= aLocalParam
.nRow1
+ nCount
;
837 if (!aLocalParam
.bHasHeader
&& nCount
> 0)
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
);
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
873 if (aLocalParam
.bHasHeader
)
875 ScRange aHdrRange
= aAttribRange
;
876 aHdrRange
.aEnd
.SetRow( aHdrRange
.aStart
.Row() );
877 pAttribDoc
->CopyToDocument( aHdrRange
, IDF_ATTRIB
, FALSE
, pDoc
);
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");
889 pDoc
->ApplyPatternAreaTab( nCol
, nAttrRow
, nCol
, aLocalParam
.nRow2
,
890 nDestTab
, *pSrcPattern
);
891 const ScStyleSheet
* pStyle
= pSrcPattern
->GetStyleSheet();
893 pDoc
->ApplyStyleAreaTab( nCol
, nAttrRow
, nCol
, aLocalParam
.nRow2
,
901 // speichern: Inplace immer, sonst je nach Einstellung
902 // alter Inplace-Filter ist ggf. schon aufgehoben
904 BOOL bSave
= rQueryParam
.bInplace
|| rQueryParam
.bDestPers
;
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.
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
),
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#)
937 DBG_ERROR("Zielbereich nicht da");
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
);
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
) );
963 SCCOL nEndX
= aLocalParam
.nCol2
;
964 SCROW nEndY
= aLocalParam
.nRow2
;
967 if ( aOldDest
.aEnd
.Col() > nEndX
)
968 nEndX
= aOldDest
.aEnd
.Col();
969 if ( aOldDest
.aEnd
.Row() > nEndY
)
970 nEndY
= aOldDest
.aEnd
.Row();
974 rDocShell
.PostPaint( aLocalParam
.nCol1
, aLocalParam
.nRow1
, nDestTab
,
975 nEndX
, nEndY
, nDestTab
, PAINT_GRID
);
978 rDocShell
.PostPaint( 0, rQueryParam
.nRow1
, nTab
, MAXCOL
, MAXROW
, nTab
,
979 PAINT_GRID
| PAINT_LEFT
);
980 aModificator
.SetDocumentModified();
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
998 ScDocument
* pDoc
= rDocShell
.GetDocument();
999 if (bRecord
&& !pDoc
->IsUndoEnabled())
1001 ScDBData
* pDBData
= pDoc
->GetDBAtArea( nTab
, rParam
.nCol1
, rParam
.nRow1
,
1002 rParam
.nCol2
, rParam
.nRow2
);
1005 DBG_ERROR( "SubTotals: keine DBData" );
1009 ScEditableTester
aTester( pDoc
, nTab
, 0,rParam
.nRow1
+1, MAXCOL
,MAXROW
);
1010 if (!aTester
.IsEditable())
1013 rDocShell
.ErrorMessage(aTester
.GetMessageId());
1017 if (pDoc
->HasAttrib( rParam
.nCol1
, rParam
.nRow1
+1, nTab
,
1018 rParam
.nCol2
, rParam
.nRow2
, nTab
, HASATTR_MERGED
| HASATTR_OVERLAPPED
))
1021 rDocShell
.ErrorMessage(STR_MSSG_INSERTCELLS_0
); // nicht in zusammengefasste einfuegen
1026 BOOL bDelete
= FALSE
;
1027 if (rParam
.bReplace
)
1028 if (pDoc
->TestRemoveSubTotals( nTab
, rParam
))
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()
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
);
1059 pUndoTab
= new ScOutlineTable( *pTable
);
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
);
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
);
1094 pOut
->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen
1096 if (rParam
.bReplace
)
1097 pDoc
->RemoveSubTotals( nTab
, aNewParam
);
1098 BOOL bSuccess
= TRUE
;
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
);
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
) );
1133 // "Kann keine Zeilen einfuegen"
1135 rDocShell
.ErrorMessage(STR_MSSG_DOSUBTOTALS_2
);
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();
1152 //==================================================================
1154 BOOL
lcl_EmptyExcept( ScDocument
* pDoc
, const ScRange
& rRange
, const ScRange
& rExcept
)
1156 ScCellIterator
aIter( pDoc
, rRange
);
1157 ScBaseCell
* pCell
= aIter
.GetFirst();
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() );
1178 BOOL bUndoSelf
= FALSE
;
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())
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
;
1219 if ( pOldObj
&& !pNewObj
)
1223 ScRange aRange
= pOldObj
->GetOutRange();
1224 SCTAB nTab
= aRange
.aStart
.Tab();
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(),
1236 pDoc
->RemoveFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
1237 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(),
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
,
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
1267 pNewObj
->WriteSourceDataTo( *pOldObj
); // copy source data
1269 ScDPSaveData
* pData
= pNewObj
->GetSaveData();
1270 DBG_ASSERT( pData
, "no SaveData from living DPObject" );
1272 pOldObj
->SetSaveData( *pData
); // copy SaveData
1276 pDestObj
->SetAllowMove( bAllowMove
);
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
);
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
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() ) )
1324 // like with STR_PROTECTIONERR, use undo to reverse everything
1325 DBG_ASSERT( bRecord
, "DataPilotUpdate: can't undo" );
1327 nErrId
= STR_PIVOT_ERROR
;
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" );
1341 nErrId
= aTester
.GetMessageId();
1345 // test if new output area is empty except for old area
1349 if ( pOldObj
) // OutRange of pOldObj (pDestObj) is still old area
1350 bEmpty
= lcl_EmptyExcept( pDoc
, aNewOut
, pOldObj
->GetOutRange() );
1352 bEmpty
= pDoc
->IsBlockEmpty( aNewOut
.aStart
.Tab(),
1353 aNewOut
.aStart
.Col(), aNewOut
.aStart
.Row(),
1354 aNewOut
.aEnd
.Col(), aNewOut
.aEnd
.Row() );
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" );
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
1383 // else nothing (no old, no new)
1386 if ( bRecord
&& bDone
)
1388 SfxUndoAction
* pAction
= new ScUndoDataPilot( &rDocShell
,
1389 pOldUndoDoc
, pNewUndoDoc
, pUndoDPObj
, pDestObj
, bAllowMove
);
1391 pNewUndoDoc
= NULL
; // pointers are used in undo action
1392 // pUndoDPObj is copied
1396 // use undo action to restore original state
1397 //! prevent setting the document modified? (ScDocShellModificator)
1404 rDocShell
.GetUndoManager()->AddUndoAction( pAction
);
1407 delete pOldUndoDoc
; // if not used for undo
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();
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();
1442 aModificator
.SetDocumentModified();
1444 if ( nErrId
&& !bApi
)
1445 rDocShell
.ErrorMessage( nErrId
);
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
++)
1471 if (pData
->GetName() == rTarget
)
1476 InfoBox
aInfoBox(rDocShell
.GetActiveDialogParent(),
1477 ScGlobal::GetRscString( STR_TARGETNOTFOUND
) );
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();
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
);