1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
30 #include "undodat.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"
41 #include "dociter.hxx"
42 #include "editable.hxx"
44 #include "drwlayer.hxx"
45 #include "dpshttab.hxx"
47 #include "queryentry.hxx"
48 #include "markdata.hxx"
49 #include "progress.hxx"
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
;
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();
81 pDoc
->CompileDBFormula( sal_True
); // CreateFormulaString
82 if ( rName
== STR_DB_LOCAL_NONAME
)
84 pDoc
->SetAnonymousDBData(rRange
.aStart
.Tab() , pNew
);
89 bOk
= pDocColl
->getNamedDBs().insert(pNew
);
92 pDoc
->CompileDBFormula( false ); // CompileFormulaString
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
) );
113 bool ScDBDocFunc::DeleteDBRange(const OUString
& rName
)
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
));
124 ScDocShellModificator
aModificator( rDocShell
);
126 ScDBCollection
* pUndoColl
= NULL
;
128 pUndoColl
= new ScDBCollection( *pDocColl
);
130 pDoc
->CompileDBFormula( true ); // CreateFormulaString
132 pDoc
->CompileDBFormula( false ); // CompileFormulaString
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
) );
149 bool ScDBDocFunc::RenameDBRange( const OUString
& rOld
, const OUString
& rNew
)
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
));
160 ScDocShellModificator
aModificator( rDocShell
);
162 ScDBData
* pNewData
= new ScDBData(rNew
, *pOld
);
164 ScDBCollection
* pUndoColl
= new ScDBCollection( *pDocColl
);
166 pDoc
->CompileDBFormula(true); // CreateFormulaString
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
178 ScDBCollection
* pRedoColl
= new ScDBCollection( *pDocColl
);
179 rDocShell
.GetUndoManager()->AddUndoAction(
180 new ScUndoDBData( &rDocShell
, pUndoColl
, pRedoColl
) );
185 aModificator
.SetDocumentModified();
186 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED
) );
194 bool ScDBDocFunc::ModifyDBData( const ScDBData
& rNewData
)
197 ScDocument
* pDoc
= rDocShell
.GetDocument();
198 ScDBCollection
* pDocColl
= pDoc
->GetDBCollection();
199 bool bUndo
= pDoc
->IsUndoEnabled();
201 ScDBData
* pData
= NULL
;
202 if (rNewData
.GetName() == STR_DB_LOCAL_NONAME
)
205 rNewData
.GetArea(aRange
);
206 SCTAB nTab
= aRange
.aStart
.Tab();
207 pData
= pDoc
->GetAnonymousDBData(nTab
);
210 pData
= pDocColl
->getNamedDBs().findByUpperName(rNewData
.GetUpperName());
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
;
222 pUndoColl
= new ScDBCollection( *pDocColl
);
226 pDoc
->CompileDBFormula();
230 ScDBCollection
* pRedoColl
= new ScDBCollection( *pDocColl
);
231 rDocShell
.GetUndoManager()->AddUndoAction(
232 new ScUndoDBData( &rDocShell
, pUndoColl
, pRedoColl
) );
235 aModificator
.SetDocumentModified();
242 // -----------------------------------------------------------------
244 bool ScDBDocFunc::RepeatDB( const OUString
& rDBName
, bool bRecord
, bool bApi
, bool bIsUnnamed
, SCTAB aTab
)
246 //! auch fuer ScDBFunc::RepeatDB benutzen!
249 ScDocument
* pDoc
= rDocShell
.GetDocument();
250 if (bRecord
&& !pDoc
->IsUndoEnabled())
252 ScDBData
* pDBData
= NULL
;
255 pDBData
= pDoc
->GetAnonymousDBData( aTab
);
259 ScDBCollection
* pColl
= pDoc
->GetDBCollection();
261 pDBData
= pColl
->getNamedDBs().findByUpperName(ScGlobal::pCharClass
->uppercase(rDBName
));
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;
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
;
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
;
310 SCTAB nTabCount
= pDoc
->GetTableCount();
311 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
312 ScOutlineTable
* pTable
= pDoc
->GetOutlineTable( nTab
);
315 pUndoTab
= new ScOutlineTable( *pTable
);
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
);
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
);
359 pDBData
->GetSortParam( aSortParam
); // Bereich kann sich geaendert haben
360 Sort( nTab
, aSortParam
, false, false, bApi
);
364 pDBData
->GetQueryParam( aQueryParam
); // Bereich kann sich geaendert haben
366 if (pDBData
->GetAdvancedQuerySource(aAdvSource
))
367 Query( nTab
, aQueryParam
, &aAdvSource
, false, bApi
);
369 Query( nTab
, aQueryParam
, NULL
, false, bApi
);
371 // bei nicht-inplace kann die Tabelle umgestellt worden sein
372 // if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
377 pDBData
->GetSubTotalParam( aSubTotalParam
); // Bereich kann sich geaendert haben
378 aSubTotalParam
.bRemoveOnly
= false;
379 DoSubTotals( nTab
, aSubTotalParam
, NULL
, false, bApi
);
388 pDBData
->GetArea( nDummyTab
, nDummyCol
,nDummyRow
, nDummyCol
,nNewEndRow
);
390 const ScRange
* pOld
= NULL
;
391 const ScRange
* pNew
= NULL
;
394 ScDBData
* pDest
= pDoc
->GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
395 aQueryParam
.nDestTab
, sal_True
);
398 pDest
->GetArea( aNewQuery
);
404 rDocShell
.GetUndoManager()->AddUndoAction(
405 new ScUndoRepeatDB( &rDocShell
, nTab
,
406 nStartCol
, nStartRow
, nEndCol
, nEndRow
,
409 nStartCol
, nStartRow
,
415 rDocShell
.PostPaint(ScRange(0, 0, nTab
, MAXCOL
, MAXROW
, nTab
),
416 PAINT_GRID
| PAINT_LEFT
| PAINT_TOP
| PAINT_SIZE
);
419 else if (!bApi
) // "Keine Operationen auszufuehren"
420 rDocShell
.ErrorMessage(STR_MSSG_REPEATDB_0
);
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())
436 SCTAB nSrcTab
= nTab
;
437 ScDrawLayer
* pDrawLayer
= pDoc
->GetDrawLayer();
439 ScDBData
* pDBData
= pDoc
->GetDBAtArea( nTab
, rSortParam
.nCol1
, rSortParam
.nRow1
,
440 rSortParam
.nCol2
, rSortParam
.nRow2
);
443 OSL_FAIL( "Sort: keine DBData" );
447 ScDBData
* pDestData
= NULL
;
449 sal_Bool bCopy
= !rSortParam
.bInplace
;
450 if ( bCopy
&& rSortParam
.nDestCol
== rSortParam
.nCol1
&&
451 rSortParam
.nDestRow
== rSortParam
.nRow1
&& rSortParam
.nDestTab
== nTab
)
453 ScSortParam
aLocalParam( rSortParam
);
456 aLocalParam
.MoveToDest();
457 if ( !ValidColRow( aLocalParam
.nCol2
, aLocalParam
.nRow2
) )
460 rDocShell
.ErrorMessage(STR_PASTE_FULL
);
464 nTab
= rSortParam
.nDestTab
;
465 pDestData
= pDoc
->GetDBAtCursor( rSortParam
.nDestCol
, rSortParam
.nDestRow
,
466 rSortParam
.nDestTab
, sal_True
);
468 pDestData
->GetArea(aOldDest
);
471 ScEditableTester
aTester( pDoc
, nTab
, aLocalParam
.nCol1
,aLocalParam
.nRow1
,
472 aLocalParam
.nCol2
,aLocalParam
.nRow2
);
473 if (!aTester
.IsEditable())
476 rDocShell
.ErrorMessage(aTester
.GetMessageId());
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
487 rDocShell
.ErrorMessage(STR_SORT_ERR_MERGED
);
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;
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;
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
);
543 // Zeilenhoehen immer (wegen automatischer Anpassung)
544 //! auf ScBlockUndo umstellen
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
559 pDrawLayer
->BeginCalcUndo(false);
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
;
584 ScSortParam aOldSortParam
;
585 pDBData
->GetSortParam( aOldSortParam
);
586 if (aOldSortParam
.GetSortKeyCount() &&
587 aOldSortParam
.maKeyState
[0].bDoSort
&& aOldSortParam
.bInplace
)
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)
608 ScRange
aDestPos( aLocalParam
.nCol1
, aLocalParam
.nRow1
, nTab
,
609 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nTab
);
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
);
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
);
626 OSL_FAIL("Zielbereich nicht da");
630 ScRange
aDirtyRange( aLocalParam
.nCol1
, aLocalParam
.nRow1
, nTab
,
631 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nTab
);
632 pDoc
->SetDirty( aDirtyRange
);
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
;
643 nPaint
|= PAINT_LEFT
;
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();
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())
679 ScDBData
* pDBData
= pDoc
->GetDBAtArea( nTab
, rQueryParam
.nCol1
, rQueryParam
.nRow1
,
680 rQueryParam
.nCol2
, rQueryParam
.nRow2
);
683 OSL_FAIL( "Query: keine DBData" );
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;
714 if ( bCopy
&& rQueryParam
.nDestCol
== rQueryParam
.nCol1
&&
715 rQueryParam
.nDestRow
== rQueryParam
.nRow1
&& rQueryParam
.nDestTab
== nTab
)
717 SCTAB nDestTab
= nTab
;
720 aLocalParam
.MoveToDest();
721 nDestTab
= rQueryParam
.nDestTab
;
722 if ( !ValidColRow( aLocalParam
.nCol2
, aLocalParam
.nRow2
) )
725 rDocShell
.ErrorMessage(STR_PASTE_FULL
);
729 ScEditableTester
aTester( pDoc
, nDestTab
, aLocalParam
.nCol1
,aLocalParam
.nRow1
,
730 aLocalParam
.nCol2
,aLocalParam
.nRow2
);
731 if (!aTester
.IsEditable())
734 rDocShell
.ErrorMessage(aTester
.GetMessageId());
738 pDestData
= pDoc
->GetDBAtCursor( rQueryParam
.nDestCol
, rQueryParam
.nDestRow
,
739 rQueryParam
.nDestTab
, sal_True
);
742 pDestData
->GetArea( aOldDest
);
743 aDestTotal
=ScRange( rQueryParam
.nDestCol
,
744 rQueryParam
.nDestRow
,
746 rQueryParam
.nDestCol
+ rQueryParam
.nCol2
- rQueryParam
.nCol1
,
747 rQueryParam
.nDestRow
+ rQueryParam
.nRow2
- rQueryParam
.nRow1
,
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
) )
766 rDocShell
.ErrorMessage(STR_MSSG_DOSUBTOTALS_2
); // kann keine Zeilen einfuegen
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
)
786 ScDocument
* pUndoDoc
= NULL
;
787 ScDBCollection
* pUndoDB
= NULL
;
788 const ScRange
* pOld
= NULL
;
792 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
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
803 pDoc
->CopyToDocument( aOldDest
, IDF_ALL
, false, pUndoDoc
);
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
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
);
843 pDoc
->FitBlock( aOldDest
, aDestTotal
);
845 pDoc
->DeleteAreaTab(aOldDest
, IDF_ALL
); // einfach loeschen
848 // Filtern am Dokument ausfuehren
849 SCSIZE nCount
= pDoc
->Query( nTab
, rQueryParam
, bKeepSub
);
852 aLocalParam
.nRow2
= aLocalParam
.nRow1
+ nCount
;
853 if (!aLocalParam
.bHasHeader
&& nCount
> 0)
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 );
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
895 if (aLocalParam
.bHasHeader
)
897 ScRange aHdrRange
= aAttribRange
;
898 aHdrRange
.aEnd
.SetRow( aHdrRange
.aStart
.Row() );
899 pAttribDoc
->CopyToDocument( aHdrRange
, IDF_ATTRIB
, false, pDoc
);
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");
912 pDoc
->ApplyPatternAreaTab( nCol
, nAttrRow
, nCol
, aLocalParam
.nRow2
,
913 nDestTab
, *pSrcPattern
);
914 const ScStyleSheet
* pStyle
= pSrcPattern
->GetStyleSheet();
916 pDoc
->ApplyStyleAreaTab( nCol
, nAttrRow
, nCol
, aLocalParam
.nRow2
,
925 // speichern: Inplace immer, sonst je nach Einstellung
926 // alter Inplace-Filter ist ggf. schon aufgehoben
928 sal_Bool bSave
= rQueryParam
.bInplace
|| rQueryParam
.bDestPers
;
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.
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
);
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#)
961 OSL_FAIL("Zielbereich nicht da");
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
);
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
) );
986 SCCOL nEndX
= aLocalParam
.nCol2
;
987 SCROW nEndY
= aLocalParam
.nRow2
;
990 if ( aOldDest
.aEnd
.Col() > nEndX
)
991 nEndX
= aOldDest
.aEnd
.Col();
992 if ( aOldDest
.aEnd
.Row() > nEndY
)
993 nEndY
= aOldDest
.aEnd
.Row();
998 ScRange(aLocalParam
.nCol1
, aLocalParam
.nRow1
, nDestTab
, nEndX
, nEndY
, nDestTab
),
1002 rDocShell
.PostPaint(
1003 ScRange(0, rQueryParam
.nRow1
, nTab
, MAXCOL
, MAXROW
, nTab
),
1004 PAINT_GRID
| PAINT_LEFT
);
1005 aModificator
.SetDocumentModified();
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())
1026 ScDBData
* pDBData
= pDoc
->GetDBAtArea( nTab
, rParam
.nCol1
, rParam
.nRow1
,
1027 rParam
.nCol2
, rParam
.nRow2
);
1030 OSL_FAIL( "SubTotals: keine DBData" );
1034 ScEditableTester
aTester( pDoc
, nTab
, 0,rParam
.nRow1
+1, MAXCOL
,MAXROW
);
1035 if (!aTester
.IsEditable())
1038 rDocShell
.ErrorMessage(aTester
.GetMessageId());
1042 if (pDoc
->HasAttrib( rParam
.nCol1
, rParam
.nRow1
+1, nTab
,
1043 rParam
.nCol2
, rParam
.nRow2
, nTab
, HASATTR_MERGED
| HASATTR_OVERLAPPED
))
1046 rDocShell
.ErrorMessage(STR_MSSG_INSERTCELLS_0
); // nicht in zusammengefasste einfuegen
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()
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
);
1081 pUndoTab
= new ScOutlineTable( *pTable
);
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
);
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
);
1116 pOut
->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen
1118 if (rParam
.bReplace
)
1119 pDoc
->RemoveSubTotals( nTab
, aNewParam
);
1120 sal_Bool bSuccess
= sal_True
;
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 bSuccess
= pDoc
->DoSubTotals( nTab
, aNewParam
);
1138 pDoc
->SetDrawPageSize(nTab
);
1140 ScRange
aDirtyRange( aNewParam
.nCol1
, aNewParam
.nRow1
, nTab
,
1141 aNewParam
.nCol2
, aNewParam
.nRow2
, nTab
);
1142 pDoc
->SetDirty( aDirtyRange
);
1146 // ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
1147 rDocShell
.GetUndoManager()->AddUndoAction(
1148 new ScUndoSubTotals( &rDocShell
, nTab
,
1149 rParam
, aNewParam
.nRow2
,
1150 pUndoDoc
, pUndoTab
, // pUndoDBData,
1151 pUndoRange
, pUndoDB
) );
1156 // "Kann keine Zeilen einfuegen"
1158 rDocShell
.ErrorMessage(STR_MSSG_DOSUBTOTALS_2
);
1162 pDBData
->SetSubTotalParam( aNewParam
);
1163 pDBData
->SetArea( nTab
, aNewParam
.nCol1
,aNewParam
.nRow1
, aNewParam
.nCol2
,aNewParam
.nRow2
);
1164 pDoc
->CompileDBFormula();
1166 rDocShell
.PostPaint(ScRange(0, 0, nTab
, MAXCOL
,MAXROW
,nTab
),
1167 PAINT_GRID
| PAINT_LEFT
| PAINT_TOP
| PAINT_SIZE
);
1168 aModificator
.SetDocumentModified();
1177 bool lcl_EmptyExcept( ScDocument
* pDoc
, const ScRange
& rRange
, const ScRange
& rExcept
)
1179 ScCellIterator
aIter( pDoc
, rRange
);
1180 for (bool bHasCell
= aIter
.first(); bHasCell
; bHasCell
= aIter
.next())
1182 if (!aIter
.isEmpty()) // real content?
1184 if (!rExcept
.In(aIter
.GetPos()))
1185 return false; // cell found
1189 return true; // nothing found - empty
1192 bool isEditable(ScDocShell
& rDocShell
, const ScRangeList
& rRanges
, bool bApi
)
1194 ScDocument
* pDoc
= rDocShell
.GetDocument();
1195 if (!rDocShell
.IsEditable() || pDoc
->GetChangeTrack())
1197 // not recorded -> disallow
1199 rDocShell
.ErrorMessage(STR_PROTECTIONERR
);
1204 for (size_t i
= 0, n
= rRanges
.size(); i
< n
; ++i
)
1206 const ScRange
* p
= rRanges
[i
];
1207 ScEditableTester
aTester(pDoc
, *p
);
1208 if (!aTester
.IsEditable())
1211 rDocShell
.ErrorMessage(aTester
.GetMessageId());
1220 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1221 void createUndoDoc(std::auto_ptr
<ScDocument
>& pUndoDoc
, ScDocument
* pDoc
, const ScRange
& rRange
)
1223 SCTAB nTab
= rRange
.aStart
.Tab();
1224 pUndoDoc
.reset(new ScDocument(SCDOCMODE_UNDO
));
1225 pUndoDoc
->InitUndo(pDoc
, nTab
, nTab
);
1226 pDoc
->CopyToDocument(rRange
, IDF_ALL
, false, pUndoDoc
.get());
1228 SAL_WNODEPRECATED_DECLARATIONS_POP
1230 bool checkNewOutputRange(ScDPObject
& rDPObj
, ScDocShell
& rDocShell
, ScRange
& rNewOut
, bool bApi
)
1232 ScDocument
* pDoc
= rDocShell
.GetDocument();
1234 bool bOverflow
= false;
1235 rNewOut
= rDPObj
.GetNewOutputRange(bOverflow
);
1237 // Test for overlap with source data range.
1238 // TODO: Check with other pivot tables as well.
1239 const ScSheetSourceDesc
* pSheetDesc
= rDPObj
.GetSheetDesc();
1240 if (pSheetDesc
&& pSheetDesc
->GetSourceRange().Intersects(rNewOut
))
1242 // New output range intersepts with the source data. Move it up to
1243 // where the old range is and see if that works.
1244 ScRange aOldRange
= rDPObj
.GetOutRange();
1245 SCsROW nDiff
= aOldRange
.aStart
.Row() - rNewOut
.aStart
.Row();
1246 rNewOut
.aStart
.SetRow(aOldRange
.aStart
.Row());
1247 rNewOut
.aEnd
.IncRow(nDiff
);
1248 if (!ValidRow(rNewOut
.aStart
.Row()) || !ValidRow(rNewOut
.aEnd
.Row()))
1255 rDocShell
.ErrorMessage(STR_PIVOT_ERROR
);
1260 ScEditableTester
aTester(pDoc
, rNewOut
);
1261 if (!aTester
.IsEditable())
1263 // destination area isn't editable
1265 rDocShell
.ErrorMessage(aTester
.GetMessageId());
1275 bool ScDBDocFunc::DataPilotUpdate( ScDPObject
* pOldObj
, const ScDPObject
* pNewObj
,
1276 bool bRecord
, bool bApi
, bool bAllowMove
)
1283 return CreatePivotTable(*pNewObj
, bRecord
, bApi
);
1289 return RemovePivotTable(*pOldObj
, bRecord
, bApi
);
1291 if (pOldObj
== pNewObj
)
1292 return UpdatePivotTable(*pOldObj
, bRecord
, bApi
);
1295 OSL_ASSERT(pOldObj
&& pNewObj
&& pOldObj
!= pNewObj
);
1297 ScDocShellModificator
aModificator( rDocShell
);
1298 WaitObject
aWait( rDocShell
.GetActiveDialogParent() );
1300 ScRangeList aRanges
;
1301 aRanges
.Append(pOldObj
->GetOutRange());
1302 aRanges
.Append(pNewObj
->GetOutRange().aStart
); // at least one cell in the output position must be editable.
1303 if (!isEditable(rDocShell
, aRanges
, bApi
))
1306 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1307 std::auto_ptr
<ScDocument
> pOldUndoDoc
;
1308 std::auto_ptr
<ScDocument
> pNewUndoDoc
;
1309 SAL_WNODEPRECATED_DECLARATIONS_POP
1311 ScDPObject
aUndoDPObj(*pOldObj
); // for undo or revert on failure
1313 ScDocument
* pDoc
= rDocShell
.GetDocument();
1314 if (bRecord
&& !pDoc
->IsUndoEnabled())
1318 createUndoDoc(pOldUndoDoc
, pDoc
, pOldObj
->GetOutRange());
1320 pNewObj
->WriteSourceDataTo(*pOldObj
); // copy source data
1322 ScDPSaveData
* pData
= pNewObj
->GetSaveData();
1323 OSL_ENSURE( pData
, "no SaveData from living DPObject" );
1325 pOldObj
->SetSaveData(*pData
); // copy SaveData
1327 pOldObj
->SetAllowMove(bAllowMove
);
1328 pOldObj
->ReloadGroupTableData();
1329 pOldObj
->SyncAllDimensionMembers();
1330 pOldObj
->InvalidateData(); // before getting the new output area
1332 // make sure the table has a name (not set by dialog)
1333 if (pOldObj
->GetName().isEmpty())
1334 pOldObj
->SetName( pDoc
->GetDPCollection()->CreateNewName() );
1337 if (!checkNewOutputRange(*pOldObj
, rDocShell
, aNewOut
, bApi
))
1339 *pOldObj
= aUndoDPObj
;
1343 // test if new output area is empty except for old area
1346 // OutRange of pOldObj (pDestObj) is still old area
1347 if (!lcl_EmptyExcept(pDoc
, aNewOut
, pOldObj
->GetOutRange()))
1349 QueryBox
aBox( rDocShell
.GetActiveDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
1350 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY
) );
1351 if (aBox
.Execute() == RET_NO
)
1353 //! like above (not editable)
1354 *pOldObj
= aUndoDPObj
;
1361 createUndoDoc(pNewUndoDoc
, pDoc
, aNewOut
);
1363 pOldObj
->Output(aNewOut
.aStart
);
1364 rDocShell
.PostPaintGridAll(); //! only necessary parts
1368 rDocShell
.GetUndoManager()->AddUndoAction(
1369 new ScUndoDataPilot(
1370 &rDocShell
, pOldUndoDoc
.release(), pNewUndoDoc
.release(), &aUndoDPObj
, pOldObj
, bAllowMove
));
1373 // notify API objects
1374 pDoc
->BroadcastUno( ScDataPilotModifiedHint(pOldObj
->GetName()) );
1375 aModificator
.SetDocumentModified();
1380 bool ScDBDocFunc::RemovePivotTable(ScDPObject
& rDPObj
, bool bRecord
, bool bApi
)
1382 ScDocShellModificator
aModificator(rDocShell
);
1383 WaitObject
aWait(rDocShell
.GetActiveDialogParent());
1385 if (!isEditable(rDocShell
, rDPObj
.GetOutRange(), bApi
))
1388 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1389 std::auto_ptr
<ScDocument
> pOldUndoDoc
;
1390 std::auto_ptr
<ScDPObject
> pUndoDPObj
;
1391 SAL_WNODEPRECATED_DECLARATIONS_POP
1394 pUndoDPObj
.reset(new ScDPObject(rDPObj
)); // copy old settings for undo
1396 ScDocument
* pDoc
= rDocShell
.GetDocument();
1397 if (bRecord
&& !pDoc
->IsUndoEnabled())
1402 ScRange aRange
= rDPObj
.GetOutRange();
1403 SCTAB nTab
= aRange
.aStart
.Tab();
1406 createUndoDoc(pOldUndoDoc
, pDoc
, aRange
);
1408 pDoc
->DeleteAreaTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
1409 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(),
1411 pDoc
->RemoveFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
1412 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(),
1415 pDoc
->GetDPCollection()->FreeTable(&rDPObj
); // object is deleted here
1417 rDocShell
.PostPaintGridAll(); //! only necessary parts
1418 rDocShell
.PostPaint(aRange
, PAINT_GRID
);
1422 rDocShell
.GetUndoManager()->AddUndoAction(
1423 new ScUndoDataPilot(
1424 &rDocShell
, pOldUndoDoc
.release(), NULL
, pUndoDPObj
.get(), NULL
, false));
1426 // pUndoDPObj is copied
1429 aModificator
.SetDocumentModified();
1433 bool ScDBDocFunc::CreatePivotTable(const ScDPObject
& rDPObj
, bool bRecord
, bool bApi
)
1435 ScDocShellModificator
aModificator(rDocShell
);
1436 WaitObject
aWait(rDocShell
.GetActiveDialogParent());
1438 // At least one cell in the output range should be editable. Check in advance.
1439 if (!isEditable(rDocShell
, ScRange(rDPObj
.GetOutRange().aStart
), bApi
))
1442 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1443 std::auto_ptr
<ScDocument
> pNewUndoDoc
;
1444 SAL_WNODEPRECATED_DECLARATIONS_POP
1446 ScDocument
* pDoc
= rDocShell
.GetDocument();
1447 if (bRecord
&& !pDoc
->IsUndoEnabled())
1450 // output range must be set at pNewObj
1451 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1452 std::auto_ptr
<ScDPObject
> pDestObj(new ScDPObject(rDPObj
));
1453 SAL_WNODEPRECATED_DECLARATIONS_POP
1455 ScDPObject
& rDestObj
= *pDestObj
;
1457 // #i94570# When changing the output position in the dialog, a new table is created
1458 // with the settings from the old table, including the name.
1459 // So we have to check for duplicate names here (before inserting).
1460 if (pDoc
->GetDPCollection()->GetByName(rDestObj
.GetName()))
1461 rDestObj
.SetName(OUString()); // ignore the invalid name, create a new name below
1463 if (!pDoc
->GetDPCollection()->InsertNewTable(pDestObj
.release()))
1464 // Insertion into collection failed.
1467 rDestObj
.ReloadGroupTableData();
1468 rDestObj
.SyncAllDimensionMembers();
1469 rDestObj
.InvalidateData(); // before getting the new output area
1471 // make sure the table has a name (not set by dialog)
1472 if (rDestObj
.GetName().isEmpty())
1473 rDestObj
.SetName(pDoc
->GetDPCollection()->CreateNewName());
1475 bool bOverflow
= false;
1476 ScRange aNewOut
= rDestObj
.GetNewOutputRange(bOverflow
);
1481 rDocShell
.ErrorMessage(STR_PIVOT_ERROR
);
1487 ScEditableTester
aTester(pDoc
, aNewOut
);
1488 if (!aTester
.IsEditable())
1490 // destination area isn't editable
1492 rDocShell
.ErrorMessage(aTester
.GetMessageId());
1498 // test if new output area is empty except for old area
1501 bool bEmpty
= pDoc
->IsBlockEmpty(
1502 aNewOut
.aStart
.Tab(), aNewOut
.aStart
.Col(), aNewOut
.aStart
.Row(),
1503 aNewOut
.aEnd
.Col(), aNewOut
.aEnd
.Row());
1508 rDocShell
.GetActiveDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
1509 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY
));
1511 if (aBox
.Execute() == RET_NO
)
1513 //! like above (not editable)
1520 createUndoDoc(pNewUndoDoc
, pDoc
, aNewOut
);
1522 rDestObj
.Output(aNewOut
.aStart
);
1523 rDocShell
.PostPaintGridAll(); //! only necessary parts
1527 rDocShell
.GetUndoManager()->AddUndoAction(
1528 new ScUndoDataPilot(&rDocShell
, NULL
, pNewUndoDoc
.release(), NULL
, &rDestObj
, false));
1531 // notify API objects
1532 pDoc
->BroadcastUno(ScDataPilotModifiedHint(rDestObj
.GetName()));
1533 aModificator
.SetDocumentModified();
1538 bool ScDBDocFunc::UpdatePivotTable(ScDPObject
& rDPObj
, bool bRecord
, bool bApi
)
1540 ScDocShellModificator
aModificator( rDocShell
);
1541 WaitObject
aWait( rDocShell
.GetActiveDialogParent() );
1543 if (!isEditable(rDocShell
, rDPObj
.GetOutRange(), bApi
))
1546 SAL_WNODEPRECATED_DECLARATIONS_PUSH
1547 std::auto_ptr
<ScDocument
> pOldUndoDoc
;
1548 std::auto_ptr
<ScDocument
> pNewUndoDoc
;
1549 SAL_WNODEPRECATED_DECLARATIONS_POP
1551 ScDPObject
aUndoDPObj(rDPObj
); // For undo or revert on failure.
1553 ScDocument
* pDoc
= rDocShell
.GetDocument();
1554 if (bRecord
&& !pDoc
->IsUndoEnabled())
1558 createUndoDoc(pOldUndoDoc
, pDoc
, rDPObj
.GetOutRange());
1560 rDPObj
.SetAllowMove(false);
1561 rDPObj
.ReloadGroupTableData();
1562 if (!rDPObj
.SyncAllDimensionMembers())
1565 rDPObj
.InvalidateData(); // before getting the new output area
1567 // make sure the table has a name (not set by dialog)
1568 if (rDPObj
.GetName().isEmpty())
1569 rDPObj
.SetName( pDoc
->GetDPCollection()->CreateNewName() );
1572 if (!checkNewOutputRange(rDPObj
, rDocShell
, aNewOut
, bApi
))
1574 rDPObj
= aUndoDPObj
;
1578 // test if new output area is empty except for old area
1581 if (!lcl_EmptyExcept(pDoc
, aNewOut
, rDPObj
.GetOutRange()))
1583 QueryBox
aBox( rDocShell
.GetActiveDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
1584 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY
) );
1585 if (aBox
.Execute() == RET_NO
)
1587 rDPObj
= aUndoDPObj
;
1594 createUndoDoc(pNewUndoDoc
, pDoc
, aNewOut
);
1596 rDPObj
.Output(aNewOut
.aStart
);
1597 rDocShell
.PostPaintGridAll(); //! only necessary parts
1601 rDocShell
.GetUndoManager()->AddUndoAction(
1602 new ScUndoDataPilot(
1603 &rDocShell
, pOldUndoDoc
.release(), pNewUndoDoc
.release(), &aUndoDPObj
, &rDPObj
, false));
1606 // notify API objects
1607 pDoc
->BroadcastUno( ScDataPilotModifiedHint(rDPObj
.GetName()) );
1608 aModificator
.SetDocumentModified();
1612 sal_uLong
ScDBDocFunc::RefreshPivotTables(ScDPObject
* pDPObj
, bool bApi
)
1614 ScDPCollection
* pDPs
= rDocShell
.GetDocument()->GetDPCollection();
1618 std::set
<ScDPObject
*> aRefs
;
1619 sal_uLong nErrId
= pDPs
->ReloadCache(pDPObj
, aRefs
);
1623 std::set
<ScDPObject
*>::iterator it
= aRefs
.begin(), itEnd
= aRefs
.end();
1624 for (; it
!= itEnd
; ++it
)
1626 ScDPObject
* pObj
= *it
;
1628 // This action is intentionally not undoable since it modifies cache.
1629 UpdatePivotTable(*pObj
, false, bApi
);
1635 void ScDBDocFunc::RefreshPivotTableGroups(ScDPObject
* pDPObj
)
1640 ScDPCollection
* pDPs
= rDocShell
.GetDocument()->GetDPCollection();
1644 ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
1648 std::set
<ScDPObject
*> aRefs
;
1649 if (!pDPs
->ReloadGroupsInCache(pDPObj
, aRefs
))
1652 // We allow pDimData being NULL.
1653 const ScDPDimensionSaveData
* pDimData
= pSaveData
->GetExistingDimensionData();
1654 std::set
<ScDPObject
*>::iterator it
= aRefs
.begin(), itEnd
= aRefs
.end();
1655 for (; it
!= itEnd
; ++it
)
1657 ScDPObject
* pObj
= *it
;
1660 pSaveData
= pObj
->GetSaveData();
1662 pSaveData
->SetDimensionData(pDimData
);
1665 // This action is intentionally not undoable since it modifies cache.
1666 UpdatePivotTable(*pObj
, false, false);
1670 //==================================================================
1674 void ScDBDocFunc::UpdateImport( const OUString
& rTarget
, const svx::ODataAccessDescriptor
& rDescriptor
)
1676 // rTarget is the name of a database range
1678 ScDocument
* pDoc
= rDocShell
.GetDocument();
1679 ScDBCollection
& rDBColl
= *pDoc
->GetDBCollection();
1680 const ScDBData
* pData
= rDBColl
.getNamedDBs().findByUpperName(ScGlobal::pCharClass
->uppercase(rTarget
));
1683 InfoBox
aInfoBox(rDocShell
.GetActiveDialogParent(),
1684 ScGlobal::GetRscString( STR_TARGETNOTFOUND
) );
1692 pData
->GetArea( nTab
, nDummyCol
,nDummyRow
,nDummyCol
,nDummyRow
);
1694 ScImportParam aImportParam
;
1695 pData
->GetImportParam( aImportParam
);
1699 sal_Int32 nCommandType
= 0;
1700 sDBName
= rDescriptor
.getDataSource();
1701 rDescriptor
[svx::daCommand
] >>= sDBTable
;
1702 rDescriptor
[svx::daCommandType
] >>= nCommandType
;
1704 aImportParam
.aDBName
= sDBName
;
1705 aImportParam
.bSql
= ( nCommandType
== sdb::CommandType::COMMAND
);
1706 aImportParam
.aStatement
= sDBTable
;
1707 aImportParam
.bNative
= false;
1708 aImportParam
.nType
= static_cast<sal_uInt8
>( ( nCommandType
== sdb::CommandType::QUERY
) ? ScDbQuery
: ScDbTable
);
1709 aImportParam
.bImport
= true;
1711 bool bContinue
= DoImport( nTab
, aImportParam
, &rDescriptor
, true );
1713 // DB-Operationen wiederholen
1715 ScTabViewShell
* pViewSh
= rDocShell
.GetBestViewShell();
1719 pData
->GetArea(aRange
);
1720 pViewSh
->MarkRange(aRange
); // selektieren
1722 if ( bContinue
) // Fehler beim Import -> Abbruch
1724 // interne Operationen, wenn welche gespeichert
1726 if ( pData
->HasQueryParam() || pData
->HasSortParam() || pData
->HasSubTotalParam() )
1727 pViewSh
->RepeatDB();
1729 // Pivottabellen die den Bereich als Quelldaten haben
1731 rDocShell
.RefreshPivotTables(aRange
);
1739 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */