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"
50 #include <undosort.hxx>
51 #include <inputopt.hxx>
56 using namespace ::com::sun::star
;
58 bool ScDBDocFunc::AddDBRange( const OUString
& rName
, const ScRange
& rRange
, bool /* bApi */ )
61 ScDocShellModificator
aModificator( rDocShell
);
63 ScDocument
& rDoc
= rDocShell
.GetDocument();
64 ScDBCollection
* pDocColl
= rDoc
.GetDBCollection();
65 bool bUndo (rDoc
.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
= !rDoc
.IsImportingXML();
81 rDoc
.PreprocessDBDataUpdate();
82 if ( rName
== STR_DB_LOCAL_NONAME
)
84 rDoc
.SetAnonymousDBData(rRange
.aStart
.Tab() , pNew
);
89 bOk
= pDocColl
->getNamedDBs().insert(pNew
);
92 rDoc
.CompileHybridFormula();
103 ScDBCollection
* pRedoColl
= new ScDBCollection( *pDocColl
);
104 rDocShell
.GetUndoManager()->AddUndoAction(
105 new ScUndoDBData( &rDocShell
, pUndoColl
, pRedoColl
) );
108 aModificator
.SetDocumentModified();
109 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED
) );
113 bool ScDBDocFunc::DeleteDBRange(const OUString
& rName
)
116 ScDocument
& rDoc
= rDocShell
.GetDocument();
117 ScDBCollection
* pDocColl
= rDoc
.GetDBCollection();
118 bool bUndo
= rDoc
.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 rDoc
.PreprocessDBDataUpdate();
132 rDoc
.CompileHybridFormula();
136 ScDBCollection
* pRedoColl
= new ScDBCollection( *pDocColl
);
137 rDocShell
.GetUndoManager()->AddUndoAction(
138 new ScUndoDBData( &rDocShell
, pUndoColl
, pRedoColl
) );
141 aModificator
.SetDocumentModified();
142 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED
) );
149 bool ScDBDocFunc::RenameDBRange( const OUString
& rOld
, const OUString
& rNew
)
152 ScDocument
& rDoc
= rDocShell
.GetDocument();
153 ScDBCollection
* pDocColl
= rDoc
.GetDBCollection();
154 bool bUndo
= rDoc
.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 rDoc
.PreprocessDBDataUpdate();
168 bool bInserted
= rDBs
.insert(pNewData
);
169 if (!bInserted
) // Fehler -> alten Zustand wiederherstellen
172 rDoc
.SetDBCollection(pUndoColl
); // gehoert dann dem Dokument
175 rDoc
.CompileHybridFormula();
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 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED
) );
197 bool ScDBDocFunc::ModifyDBData( const ScDBData
& rNewData
)
200 ScDocument
& rDoc
= rDocShell
.GetDocument();
201 ScDBCollection
* pDocColl
= rDoc
.GetDBCollection();
202 bool bUndo
= rDoc
.IsUndoEnabled();
204 ScDBData
* pData
= NULL
;
205 if (rNewData
.GetName() == STR_DB_LOCAL_NONAME
)
208 rNewData
.GetArea(aRange
);
209 SCTAB nTab
= aRange
.aStart
.Tab();
210 pData
= rDoc
.GetAnonymousDBData(nTab
);
213 pData
= pDocColl
->getNamedDBs().findByUpperName(rNewData
.GetUpperName());
217 ScDocShellModificator
aModificator( rDocShell
);
218 ScRange aOldRange
, aNewRange
;
219 pData
->GetArea(aOldRange
);
220 rNewData
.GetArea(aNewRange
);
221 bool bAreaChanged
= ( aOldRange
!= aNewRange
); // dann muss neu compiliert werden
223 ScDBCollection
* pUndoColl
= NULL
;
225 pUndoColl
= new ScDBCollection( *pDocColl
);
229 rDoc
.CompileDBFormula();
233 ScDBCollection
* pRedoColl
= new ScDBCollection( *pDocColl
);
234 rDocShell
.GetUndoManager()->AddUndoAction(
235 new ScUndoDBData( &rDocShell
, pUndoColl
, pRedoColl
) );
238 aModificator
.SetDocumentModified();
245 void ScDBDocFunc::ModifyAllDBData( const ScDBCollection
& rNewColl
, const std::vector
<ScRange
>& rDelAreaList
)
247 ScDocShellModificator
aModificator(rDocShell
);
248 ScDocument
& rDoc
= rDocShell
.GetDocument();
249 ScDBCollection
* pOldColl
= rDoc
.GetDBCollection();
250 ScDBCollection
* pUndoColl
= NULL
;
251 bool bRecord
= rDoc
.IsUndoEnabled();
253 std::vector
<ScRange
>::const_iterator iter
;
254 for (iter
= rDelAreaList
.begin(); iter
!= rDelAreaList
.end(); ++iter
)
256 // unregistering target in SBA no longer necessary
257 const ScAddress
& rStart
= iter
->aStart
;
258 const ScAddress
& rEnd
= iter
->aEnd
;
259 rDocShell
.DBAreaDeleted(
260 rStart
.Tab(), rStart
.Col(), rStart
.Row(), rEnd
.Col(), rEnd
.Row());
264 pUndoColl
= new ScDBCollection( *pOldColl
);
266 // register target in SBA no longer necessary
268 rDoc
.PreprocessDBDataUpdate();
269 rDoc
.SetDBCollection( new ScDBCollection( rNewColl
) );
270 rDoc
.CompileHybridFormula();
272 rDocShell
.PostPaint(ScRange(0, 0, 0, MAXCOL
, MAXROW
, MAXTAB
), PAINT_GRID
);
273 aModificator
.SetDocumentModified();
274 SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED
) );
278 ScDBCollection
* pRedoColl
= new ScDBCollection(rNewColl
);
279 rDocShell
.GetUndoManager()->AddUndoAction(
280 new ScUndoDBData(&rDocShell
, pUndoColl
, pRedoColl
));
284 bool ScDBDocFunc::RepeatDB( const OUString
& rDBName
, bool bRecord
, bool bApi
, bool bIsUnnamed
, SCTAB aTab
)
286 //! auch fuer ScDBFunc::RepeatDB benutzen!
289 ScDocument
& rDoc
= rDocShell
.GetDocument();
290 if (bRecord
&& !rDoc
.IsUndoEnabled())
292 ScDBData
* pDBData
= NULL
;
295 pDBData
= rDoc
.GetAnonymousDBData( aTab
);
299 ScDBCollection
* pColl
= rDoc
.GetDBCollection();
301 pDBData
= pColl
->getNamedDBs().findByUpperName(ScGlobal::pCharClass
->uppercase(rDBName
));
306 ScQueryParam aQueryParam
;
307 pDBData
->GetQueryParam( aQueryParam
);
308 bool bQuery
= aQueryParam
.GetEntry(0).bDoQuery
;
310 ScSortParam aSortParam
;
311 pDBData
->GetSortParam( aSortParam
);
312 bool bSort
= aSortParam
.maKeyState
[0].bDoSort
;
314 ScSubTotalParam aSubTotalParam
;
315 pDBData
->GetSubTotalParam( aSubTotalParam
);
316 bool bSubTotal
= aSubTotalParam
.bGroupActive
[0] && !aSubTotalParam
.bRemoveOnly
;
318 if ( bQuery
|| bSort
|| bSubTotal
)
320 bool bQuerySize
= false;
323 if (bQuery
&& !aQueryParam
.bInplace
)
325 ScDBData
* pDest
= rDoc
.GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
326 aQueryParam
.nDestTab
, true );
327 if (pDest
&& pDest
->IsDoSize())
329 pDest
->GetArea( aOldQuery
);
339 pDBData
->GetArea( nTab
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
341 //! Undo nur benoetigte Daten ?
343 ScDocument
* pUndoDoc
= NULL
;
344 ScOutlineTable
* pUndoTab
= NULL
;
345 ScRangeName
* pUndoRange
= NULL
;
346 ScDBCollection
* pUndoDB
= NULL
;
350 SCTAB nTabCount
= rDoc
.GetTableCount();
351 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
352 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
355 pUndoTab
= new ScOutlineTable( *pTable
);
358 SCCOLROW nOutStartCol
, nOutEndCol
;
359 SCCOLROW nOutStartRow
, nOutEndRow
;
360 pTable
->GetColArray().GetRange( nOutStartCol
, nOutEndCol
);
361 pTable
->GetRowArray().GetRange( nOutStartRow
, nOutEndRow
);
363 pUndoDoc
->InitUndo( &rDoc
, nTab
, nTab
, true, true );
364 rDoc
.CopyToDocument( static_cast<SCCOL
>(nOutStartCol
), 0,
365 nTab
, static_cast<SCCOL
>(nOutEndCol
), MAXROW
, nTab
,
366 IDF_NONE
, false, pUndoDoc
);
367 rDoc
.CopyToDocument( 0, static_cast<SCROW
>(nOutStartRow
),
368 nTab
, MAXCOL
, static_cast<SCROW
>(nOutEndRow
), nTab
,
369 IDF_NONE
, false, pUndoDoc
);
372 pUndoDoc
->InitUndo( &rDoc
, nTab
, nTab
, false, true );
374 // Datenbereich sichern - incl. Filter-Ergebnis
375 rDoc
.CopyToDocument( 0,nStartRow
,nTab
, MAXCOL
,nEndRow
,nTab
, IDF_ALL
, false, pUndoDoc
);
377 // alle Formeln wegen Referenzen
378 rDoc
.CopyToDocument( 0,0,0, MAXCOL
,MAXROW
,nTabCount
-1, IDF_FORMULA
, false, pUndoDoc
);
380 // DB- und andere Bereiche
381 ScRangeName
* pDocRange
= rDoc
.GetRangeName();
382 if (!pDocRange
->empty())
383 pUndoRange
= new ScRangeName( *pDocRange
);
384 ScDBCollection
* pDocDB
= rDoc
.GetDBCollection();
385 if (!pDocDB
->empty())
386 pUndoDB
= new ScDBCollection( *pDocDB
);
389 if (bSort
&& bSubTotal
)
391 // Sortieren ohne SubTotals
393 aSubTotalParam
.bRemoveOnly
= true; // wird unten wieder zurueckgesetzt
394 DoSubTotals( nTab
, aSubTotalParam
, NULL
, false, bApi
);
399 pDBData
->GetSortParam( aSortParam
); // Bereich kann sich geaendert haben
400 (void)Sort( nTab
, aSortParam
, false, false, bApi
);
404 pDBData
->GetQueryParam( aQueryParam
); // Bereich kann sich geaendert haben
406 if (pDBData
->GetAdvancedQuerySource(aAdvSource
))
407 Query( nTab
, aQueryParam
, &aAdvSource
, false, bApi
);
409 Query( nTab
, aQueryParam
, NULL
, false, bApi
);
411 // bei nicht-inplace kann die Tabelle umgestellt worden sein
412 // if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
417 pDBData
->GetSubTotalParam( aSubTotalParam
); // Bereich kann sich geaendert haben
418 aSubTotalParam
.bRemoveOnly
= false;
419 DoSubTotals( nTab
, aSubTotalParam
, NULL
, false, bApi
);
428 pDBData
->GetArea( nDummyTab
, nDummyCol
,nDummyRow
, nDummyCol
,nNewEndRow
);
430 const ScRange
* pOld
= NULL
;
431 const ScRange
* pNew
= NULL
;
434 ScDBData
* pDest
= rDoc
.GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
435 aQueryParam
.nDestTab
, true );
438 pDest
->GetArea( aNewQuery
);
444 rDocShell
.GetUndoManager()->AddUndoAction(
445 new ScUndoRepeatDB( &rDocShell
, nTab
,
446 nStartCol
, nStartRow
, nEndCol
, nEndRow
,
449 nStartCol
, nStartRow
,
455 rDocShell
.PostPaint(ScRange(0, 0, nTab
, MAXCOL
, MAXROW
, nTab
),
456 PAINT_GRID
| PAINT_LEFT
| PAINT_TOP
| PAINT_SIZE
);
459 else if (!bApi
) // "Keine Operationen auszufuehren"
460 rDocShell
.ErrorMessage(STR_MSSG_REPEATDB_0
);
466 bool ScDBDocFunc::Sort( SCTAB nTab
, const ScSortParam
& rSortParam
,
467 bool bRecord
, bool bPaint
, bool bApi
)
469 ScDocShellModificator
aModificator( rDocShell
);
471 ScDocument
& rDoc
= rDocShell
.GetDocument();
472 if (bRecord
&& !rDoc
.IsUndoEnabled())
475 ScDBData
* pDBData
= rDoc
.GetDBAtArea( nTab
, rSortParam
.nCol1
, rSortParam
.nRow1
,
476 rSortParam
.nCol2
, rSortParam
.nRow2
);
479 OSL_FAIL( "Sort: keine DBData" );
483 bool bCopy
= !rSortParam
.bInplace
;
484 if ( bCopy
&& rSortParam
.nDestCol
== rSortParam
.nCol1
&&
485 rSortParam
.nDestRow
== rSortParam
.nRow1
&& rSortParam
.nDestTab
== nTab
)
488 ScSortParam
aLocalParam( rSortParam
);
491 // Copy the data range to the destination then move the sort range to it.
492 ScRange
aSrcRange(rSortParam
.nCol1
, rSortParam
.nRow1
, nTab
, rSortParam
.nCol2
, rSortParam
.nRow2
, nTab
);
493 ScAddress
aDestPos(rSortParam
.nDestCol
,rSortParam
.nDestRow
,rSortParam
.nDestTab
);
495 ScDocFunc
& rDocFunc
= rDocShell
.GetDocFunc();
496 bool bRet
= rDocFunc
.MoveBlock(aSrcRange
, aDestPos
, false, bRecord
, bPaint
, bApi
);
501 aLocalParam
.MoveToDest();
502 nTab
= aLocalParam
.nDestTab
;
505 ScEditableTester
aTester( &rDoc
, nTab
, aLocalParam
.nCol1
,aLocalParam
.nRow1
,
506 aLocalParam
.nCol2
,aLocalParam
.nRow2
);
507 if (!aTester
.IsEditable())
510 rDocShell
.ErrorMessage(aTester
.GetMessageId());
514 if ( aLocalParam
.bIncludePattern
&& rDoc
.HasAttrib(
515 aLocalParam
.nCol1
, aLocalParam
.nRow1
, nTab
,
516 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nTab
,
517 HASATTR_MERGED
| HASATTR_OVERLAPPED
) )
519 // Merge-Attribute wuerden beim Sortieren durcheinanderkommen
521 rDocShell
.ErrorMessage(STR_SORT_ERR_MERGED
);
527 WaitObject
aWait( ScDocShell::GetActiveDialogParent() );
529 // Adjust aLocalParam cols/rows to used data area. Keep sticky top row or
530 // column (depending on direction) in any case, not just if it has headers,
531 // so empty leading cells will be sorted to the end.
532 bool bShrunk
= false;
533 rDoc
.ShrinkToUsedDataArea( bShrunk
, nTab
, aLocalParam
.nCol1
, aLocalParam
.nRow1
,
534 aLocalParam
.nCol2
, aLocalParam
.nRow2
, false, aLocalParam
.bByRow
, !aLocalParam
.bByRow
);
536 SCROW nStartRow
= aLocalParam
.nRow1
;
537 if (aLocalParam
.bByRow
&& aLocalParam
.bHasHeader
&& nStartRow
< aLocalParam
.nRow2
)
540 // Calculate the script types for all cells in the sort range beforehand.
541 // This will speed up the row height adjustment that takes place after the
543 rDoc
.UpdateScriptTypes(
544 ScAddress(aLocalParam
.nCol1
,nStartRow
,nTab
),
545 aLocalParam
.nCol2
-aLocalParam
.nCol1
+1,
546 aLocalParam
.nRow2
-nStartRow
+1);
548 // No point adjusting row heights after the sort when all rows have the same height.
549 bool bUniformRowHeight
=
550 rDoc
.HasUniformRowHeight(nTab
, nStartRow
, aLocalParam
.nRow2
);
552 bool bRepeatQuery
= false; // bestehenden Filter wiederholen?
553 ScQueryParam aQueryParam
;
554 pDBData
->GetQueryParam( aQueryParam
);
555 if ( aQueryParam
.GetEntry(0).bDoQuery
)
558 sc::ReorderParam aUndoParam
;
560 // don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set)
561 if (aLocalParam
.GetSortKeyCount() && aLocalParam
.maKeyState
[0].bDoSort
)
563 ScInputOptions aInputOption
= SC_MOD()->GetInputOptions();
564 bool bUpdateRefs
= aInputOption
.GetSortRefUpdate();
565 ScProgress
aProgress(&rDocShell
, ScGlobal::GetRscString(STR_PROGRESS_SORTING
), 0);
566 rDoc
.Sort(nTab
, aLocalParam
, bRepeatQuery
, bUpdateRefs
, &aProgress
, &aUndoParam
);
571 // Set up an undo object.
572 sc::UndoSort
* pUndoAction
= new sc::UndoSort(&rDocShell
, aUndoParam
);
573 rDocShell
.GetUndoManager()->AddUndoAction(pUndoAction
);
576 pDBData
->SetSortParam(rSortParam
);
577 // Remember additional settings on anonymous database ranges.
578 if (pDBData
== rDoc
.GetAnonymousDBData( nTab
) || rDoc
.GetDBCollection()->getAnonDBs().has( pDBData
))
579 pDBData
->UpdateFromSortParam( rSortParam
);
581 if (nStartRow
<= aLocalParam
.nRow2
)
584 aLocalParam
.nCol1
, nStartRow
, nTab
,
585 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nTab
);
586 rDoc
.SetDirty( aDirtyRange
, true );
591 sal_uInt16 nPaint
= PAINT_GRID
;
592 SCCOL nStartX
= aLocalParam
.nCol1
;
593 SCROW nStartY
= aLocalParam
.nRow1
;
594 SCCOL nEndX
= aLocalParam
.nCol2
;
595 SCROW nEndY
= aLocalParam
.nRow2
;
598 nPaint
|= PAINT_LEFT
;
602 rDocShell
.PostPaint(ScRange(nStartX
, nStartY
, nTab
, nEndX
, nEndY
, nTab
), nPaint
);
605 if (!bUniformRowHeight
&& nStartRow
<= aLocalParam
.nRow2
)
606 rDocShell
.AdjustRowHeight(nStartRow
, aLocalParam
.nRow2
, nTab
);
608 aModificator
.SetDocumentModified();
613 bool ScDBDocFunc::Query( SCTAB nTab
, const ScQueryParam
& rQueryParam
,
614 const ScRange
* pAdvSource
, bool bRecord
, bool bApi
)
616 ScDocShellModificator
aModificator( rDocShell
);
618 ScDocument
& rDoc
= rDocShell
.GetDocument();
619 if (bRecord
&& !rDoc
.IsUndoEnabled())
621 ScDBData
* pDBData
= rDoc
.GetDBAtArea( nTab
, rQueryParam
.nCol1
, rQueryParam
.nRow1
,
622 rQueryParam
.nCol2
, rQueryParam
.nRow2
);
625 OSL_FAIL( "Query: keine DBData" );
629 // Wechsel von Inplace auf nicht-Inplace, dann erst Inplace aufheben:
630 // (nur, wenn im Dialog "Persistent" ausgewaehlt ist)
632 if ( !rQueryParam
.bInplace
&& pDBData
->HasQueryParam() && rQueryParam
.bDestPers
)
634 ScQueryParam aOldQuery
;
635 pDBData
->GetQueryParam(aOldQuery
);
636 if (aOldQuery
.bInplace
)
638 // alte Filterung aufheben
640 SCSIZE nEC
= aOldQuery
.GetEntryCount();
641 for (SCSIZE i
=0; i
<nEC
; i
++)
642 aOldQuery
.GetEntry(i
).bDoQuery
= false;
643 aOldQuery
.bDuplicate
= true;
644 Query( nTab
, aOldQuery
, NULL
, bRecord
, bApi
);
648 ScQueryParam
aLocalParam( rQueryParam
); // fuer Paint / Zielbereich
649 bool bCopy
= !rQueryParam
.bInplace
; // kopiert wird in Table::Query
650 ScDBData
* pDestData
= NULL
; // Bereich, in den kopiert wird
651 bool bDoSize
= false; // Zielgroesse anpassen (einf./loeschen)
652 SCCOL nFormulaCols
= 0; // nur bei bDoSize
653 bool bKeepFmt
= false;
656 if ( bCopy
&& rQueryParam
.nDestCol
== rQueryParam
.nCol1
&&
657 rQueryParam
.nDestRow
== rQueryParam
.nRow1
&& rQueryParam
.nDestTab
== nTab
)
659 SCTAB nDestTab
= nTab
;
662 aLocalParam
.MoveToDest();
663 nDestTab
= rQueryParam
.nDestTab
;
664 if ( !ValidColRow( aLocalParam
.nCol2
, aLocalParam
.nRow2
) )
667 rDocShell
.ErrorMessage(STR_PASTE_FULL
);
671 ScEditableTester
aTester( &rDoc
, nDestTab
, aLocalParam
.nCol1
,aLocalParam
.nRow1
,
672 aLocalParam
.nCol2
,aLocalParam
.nRow2
);
673 if (!aTester
.IsEditable())
676 rDocShell
.ErrorMessage(aTester
.GetMessageId());
680 pDestData
= rDoc
.GetDBAtCursor( rQueryParam
.nDestCol
, rQueryParam
.nDestRow
,
681 rQueryParam
.nDestTab
, true );
684 pDestData
->GetArea( aOldDest
);
685 aDestTotal
=ScRange( rQueryParam
.nDestCol
,
686 rQueryParam
.nDestRow
,
688 rQueryParam
.nDestCol
+ rQueryParam
.nCol2
- rQueryParam
.nCol1
,
689 rQueryParam
.nDestRow
+ rQueryParam
.nRow2
- rQueryParam
.nRow1
,
692 bDoSize
= pDestData
->IsDoSize();
693 // Test, ob Formeln aufgefuellt werden muessen (nFormulaCols):
694 if ( bDoSize
&& aOldDest
.aEnd
.Col() == aDestTotal
.aEnd
.Col() )
696 SCCOL nTestCol
= aOldDest
.aEnd
.Col() + 1; // neben dem Bereich
697 SCROW nTestRow
= rQueryParam
.nDestRow
+
698 ( aLocalParam
.bHasHeader
? 1 : 0 );
699 while ( nTestCol
<= MAXCOL
&&
700 rDoc
.GetCellType(ScAddress( nTestCol
, nTestRow
, nTab
)) == CELLTYPE_FORMULA
)
701 ++nTestCol
, ++nFormulaCols
;
704 bKeepFmt
= pDestData
->IsKeepFmt();
705 if ( bDoSize
&& !rDoc
.CanFitBlock( aOldDest
, aDestTotal
) )
708 rDocShell
.ErrorMessage(STR_MSSG_DOSUBTOTALS_2
); // kann keine Zeilen einfuegen
716 WaitObject
aWait( ScDocShell::GetActiveDialogParent() );
718 bool bKeepSub
= false; // bestehende Teilergebnisse wiederholen?
719 ScSubTotalParam aSubTotalParam
;
720 if (rQueryParam
.GetEntry(0).bDoQuery
) // nicht beim Aufheben
722 pDBData
->GetSubTotalParam( aSubTotalParam
); // Teilergebnisse vorhanden?
724 if ( aSubTotalParam
.bGroupActive
[0] && !aSubTotalParam
.bRemoveOnly
)
728 ScDocument
* pUndoDoc
= NULL
;
729 ScDBCollection
* pUndoDB
= NULL
;
730 const ScRange
* pOld
= NULL
;
734 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
737 pUndoDoc
->InitUndo( &rDoc
, nDestTab
, nDestTab
, false, true );
738 rDoc
.CopyToDocument( aLocalParam
.nCol1
, aLocalParam
.nRow1
, nDestTab
,
739 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nDestTab
,
740 IDF_ALL
, false, pUndoDoc
);
741 // Attribute sichern, falls beim Filtern mitkopiert
745 rDoc
.CopyToDocument( aOldDest
, IDF_ALL
, false, pUndoDoc
);
751 pUndoDoc
->InitUndo( &rDoc
, nTab
, nTab
, false, true );
752 rDoc
.CopyToDocument( 0, rQueryParam
.nRow1
, nTab
, MAXCOL
, rQueryParam
.nRow2
, nTab
,
753 IDF_NONE
, false, pUndoDoc
);
756 ScDBCollection
* pDocDB
= rDoc
.GetDBCollection();
757 if (!pDocDB
->empty())
758 pUndoDB
= new ScDBCollection( *pDocDB
);
760 rDoc
.BeginDrawUndo();
763 ScDocument
* pAttribDoc
= NULL
;
764 ScRange aAttribRange
;
765 if (pDestData
) // Zielbereich loeschen
769 // kleinere der End-Spalten, Header+1 Zeile
770 aAttribRange
= aOldDest
;
771 if ( aAttribRange
.aEnd
.Col() > aDestTotal
.aEnd
.Col() )
772 aAttribRange
.aEnd
.SetCol( aDestTotal
.aEnd
.Col() );
773 aAttribRange
.aEnd
.SetRow( aAttribRange
.aStart
.Row() +
774 ( aLocalParam
.bHasHeader
? 1 : 0 ) );
776 // auch fuer aufgefuellte Formeln
777 aAttribRange
.aEnd
.SetCol( aAttribRange
.aEnd
.Col() + nFormulaCols
);
779 pAttribDoc
= new ScDocument( SCDOCMODE_UNDO
);
780 pAttribDoc
->InitUndo( &rDoc
, nDestTab
, nDestTab
, false, true );
781 rDoc
.CopyToDocument( aAttribRange
, IDF_ATTRIB
, false, pAttribDoc
);
785 rDoc
.FitBlock( aOldDest
, aDestTotal
);
787 rDoc
.DeleteAreaTab(aOldDest
, IDF_ALL
); // einfach loeschen
790 // Filtern am Dokument ausfuehren
791 SCSIZE nCount
= rDoc
.Query( nTab
, rQueryParam
, bKeepSub
);
794 aLocalParam
.nRow2
= aLocalParam
.nRow1
+ nCount
;
795 if (!aLocalParam
.bHasHeader
&& nCount
> 0)
800 // auf wirklichen Ergebnis-Bereich anpassen
801 // (das hier ist immer eine Verkleinerung)
803 ScRange
aNewDest( aLocalParam
.nCol1
, aLocalParam
.nRow1
, nDestTab
,
804 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nDestTab
);
805 rDoc
.FitBlock( aDestTotal
, aNewDest
, false ); // sal_False - nicht loeschen
807 if ( nFormulaCols
> 0 )
809 // Formeln ausfuellen
810 //! Undo (Query und Repeat) !!!
812 ScRange
aNewForm( aLocalParam
.nCol2
+1, aLocalParam
.nRow1
, nDestTab
,
813 aLocalParam
.nCol2
+nFormulaCols
, aLocalParam
.nRow2
, nDestTab
);
814 ScRange aOldForm
= aNewForm
;
815 aOldForm
.aEnd
.SetRow( aOldDest
.aEnd
.Row() );
816 rDoc
.FitBlock( aOldForm
, aNewForm
, false );
819 aMark
.SelectOneTable(nDestTab
);
820 SCROW nFStartY
= aLocalParam
.nRow1
+ ( aLocalParam
.bHasHeader
? 1 : 0 );
822 sal_uLong nProgCount
= nFormulaCols
;
823 nProgCount
*= aLocalParam
.nRow2
- nFStartY
;
824 ScProgress
aProgress( rDoc
.GetDocumentShell(),
825 ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS
), nProgCount
);
827 rDoc
.Fill( aLocalParam
.nCol2
+1, nFStartY
,
828 aLocalParam
.nCol2
+nFormulaCols
, nFStartY
, &aProgress
, aMark
,
829 aLocalParam
.nRow2
- nFStartY
,
830 FILL_TO_BOTTOM
, FILL_SIMPLE
);
834 if ( pAttribDoc
) // gemerkte Attribute zurueckkopieren
837 if (aLocalParam
.bHasHeader
)
839 ScRange aHdrRange
= aAttribRange
;
840 aHdrRange
.aEnd
.SetRow( aHdrRange
.aStart
.Row() );
841 pAttribDoc
->CopyToDocument( aHdrRange
, IDF_ATTRIB
, false, &rDoc
);
845 SCCOL nAttrEndCol
= aAttribRange
.aEnd
.Col();
846 SCROW nAttrRow
= aAttribRange
.aStart
.Row() + ( aLocalParam
.bHasHeader
? 1 : 0 );
847 for (SCCOL nCol
= aAttribRange
.aStart
.Col(); nCol
<=nAttrEndCol
; nCol
++)
849 const ScPatternAttr
* pSrcPattern
= pAttribDoc
->GetPattern(
850 nCol
, nAttrRow
, nDestTab
);
851 OSL_ENSURE(pSrcPattern
,"Pattern ist 0");
854 rDoc
.ApplyPatternAreaTab( nCol
, nAttrRow
, nCol
, aLocalParam
.nRow2
,
855 nDestTab
, *pSrcPattern
);
856 const ScStyleSheet
* pStyle
= pSrcPattern
->GetStyleSheet();
858 rDoc
.ApplyStyleAreaTab( nCol
, nAttrRow
, nCol
, aLocalParam
.nRow2
,
867 // speichern: Inplace immer, sonst je nach Einstellung
868 // alter Inplace-Filter ist ggf. schon aufgehoben
870 bool bSave
= rQueryParam
.bInplace
|| rQueryParam
.bDestPers
;
873 pDBData
->SetQueryParam( rQueryParam
);
874 pDBData
->SetHeader( rQueryParam
.bHasHeader
); //! ???
875 pDBData
->SetAdvancedQuerySource( pAdvSource
); // after SetQueryParam
878 if (bCopy
) // neuen DB-Bereich merken
880 // selektieren wird hinterher von aussen (dbfunc)
881 // momentan ueber DB-Bereich an der Zielposition, darum muss dort
882 // auf jeden Fall ein Bereich angelegt werden.
886 pNewData
= pDestData
; // Bereich vorhanden -> anpassen (immer!)
887 else // Bereich anlegen
888 pNewData
= rDocShell
.GetDBData(
889 ScRange( aLocalParam
.nCol1
, aLocalParam
.nRow1
, nDestTab
,
890 aLocalParam
.nCol2
, aLocalParam
.nRow2
, nDestTab
),
891 SC_DB_MAKE
, SC_DBSEL_FORCE_MARK
);
895 pNewData
->SetArea( nDestTab
, aLocalParam
.nCol1
, aLocalParam
.nRow1
,
896 aLocalParam
.nCol2
, aLocalParam
.nRow2
);
898 // Query-Param wird am Ziel nicht mehr eingestellt, fuehrt nur zu Verwirrung
899 // und Verwechslung mit dem Query-Param am Quellbereich (#37187#)
903 OSL_FAIL("Zielbereich nicht da");
909 rDoc
.InvalidatePageBreaks(nTab
);
910 rDoc
.UpdatePageBreaks( nTab
);
913 // #i23299# Subtotal functions depend on cell's filtered states.
914 ScRange
aDirtyRange(0 , aLocalParam
.nRow1
, nDestTab
, MAXCOL
, aLocalParam
.nRow2
, nDestTab
);
915 rDoc
.SetSubTotalCellsDirty(aDirtyRange
);
919 // create undo action after executing, because of drawing layer undo
920 rDocShell
.GetUndoManager()->AddUndoAction(
921 new ScUndoQuery( &rDocShell
, nTab
, rQueryParam
, pUndoDoc
, pUndoDB
,
922 pOld
, bDoSize
, pAdvSource
) );
927 SCCOL nEndX
= aLocalParam
.nCol2
;
928 SCROW nEndY
= aLocalParam
.nRow2
;
931 if ( aOldDest
.aEnd
.Col() > nEndX
)
932 nEndX
= aOldDest
.aEnd
.Col();
933 if ( aOldDest
.aEnd
.Row() > nEndY
)
934 nEndY
= aOldDest
.aEnd
.Row();
939 ScRange(aLocalParam
.nCol1
, aLocalParam
.nRow1
, nDestTab
, nEndX
, nEndY
, nDestTab
),
944 ScRange(0, rQueryParam
.nRow1
, nTab
, MAXCOL
, MAXROW
, nTab
),
945 PAINT_GRID
| PAINT_LEFT
);
946 aModificator
.SetDocumentModified();
951 bool ScDBDocFunc::DoSubTotals( SCTAB nTab
, const ScSubTotalParam
& rParam
,
952 const ScSortParam
* pForceNewSort
, bool bRecord
, bool bApi
)
954 //! auch fuer ScDBFunc::DoSubTotals benutzen!
955 // dann bleibt aussen:
956 // - neuen Bereich (aus DBData) markieren
957 // - SelectionChanged (?)
959 bool bDo
= !rParam
.bRemoveOnly
; // sal_False = nur loeschen
962 ScDocument
& rDoc
= rDocShell
.GetDocument();
963 if (bRecord
&& !rDoc
.IsUndoEnabled())
965 ScDBData
* pDBData
= rDoc
.GetDBAtArea( nTab
, rParam
.nCol1
, rParam
.nRow1
,
966 rParam
.nCol2
, rParam
.nRow2
);
969 OSL_FAIL( "SubTotals: keine DBData" );
973 ScEditableTester
aTester( &rDoc
, nTab
, 0,rParam
.nRow1
+1, MAXCOL
,MAXROW
);
974 if (!aTester
.IsEditable())
977 rDocShell
.ErrorMessage(aTester
.GetMessageId());
981 if (rDoc
.HasAttrib( rParam
.nCol1
, rParam
.nRow1
+1, nTab
,
982 rParam
.nCol2
, rParam
.nRow2
, nTab
, HASATTR_MERGED
| HASATTR_OVERLAPPED
))
985 rDocShell
.ErrorMessage(STR_MSSG_INSERTCELLS_0
); // nicht in zusammengefasste einfuegen
991 if (rDoc
.TestRemoveSubTotals( nTab
, rParam
))
993 bOk
= ( ScopedVclPtr
<MessBox
>::Create( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
994 // "StarCalc" "Daten loeschen?"
995 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0
),
996 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1
) )->Execute()
1002 WaitObject
aWait( ScDocShell::GetActiveDialogParent() );
1003 ScDocShellModificator
aModificator( rDocShell
);
1005 ScSubTotalParam
aNewParam( rParam
); // Bereichsende wird veraendert
1006 ScDocument
* pUndoDoc
= NULL
;
1007 ScOutlineTable
* pUndoTab
= NULL
;
1008 ScRangeName
* pUndoRange
= NULL
;
1009 ScDBCollection
* pUndoDB
= NULL
;
1011 if (bRecord
) // alte Daten sichern
1013 bool bOldFilter
= bDo
&& rParam
.bDoSort
;
1015 SCTAB nTabCount
= rDoc
.GetTableCount();
1016 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
1017 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
1020 pUndoTab
= new ScOutlineTable( *pTable
);
1023 SCCOLROW nOutStartCol
, nOutEndCol
;
1024 SCCOLROW nOutStartRow
, nOutEndRow
;
1025 pTable
->GetColArray().GetRange( nOutStartCol
, nOutEndCol
);
1026 pTable
->GetRowArray().GetRange( nOutStartRow
, nOutEndRow
);
1028 pUndoDoc
->InitUndo( &rDoc
, nTab
, nTab
, true, true );
1029 rDoc
.CopyToDocument( static_cast<SCCOL
>(nOutStartCol
), 0, nTab
, static_cast<SCCOL
>(nOutEndCol
), MAXROW
, nTab
, IDF_NONE
, false, pUndoDoc
);
1030 rDoc
.CopyToDocument( 0, nOutStartRow
, nTab
, MAXCOL
, nOutEndRow
, nTab
, IDF_NONE
, false, pUndoDoc
);
1033 pUndoDoc
->InitUndo( &rDoc
, nTab
, nTab
, false, bOldFilter
);
1035 // Datenbereich sichern - incl. Filter-Ergebnis
1036 rDoc
.CopyToDocument( 0,rParam
.nRow1
+1,nTab
, MAXCOL
,rParam
.nRow2
,nTab
,
1037 IDF_ALL
, false, pUndoDoc
);
1039 // alle Formeln wegen Referenzen
1040 rDoc
.CopyToDocument( 0,0,0, MAXCOL
,MAXROW
,nTabCount
-1,
1041 IDF_FORMULA
, false, pUndoDoc
);
1043 // DB- und andere Bereiche
1044 ScRangeName
* pDocRange
= rDoc
.GetRangeName();
1045 if (!pDocRange
->empty())
1046 pUndoRange
= new ScRangeName( *pDocRange
);
1047 ScDBCollection
* pDocDB
= rDoc
.GetDBCollection();
1048 if (!pDocDB
->empty())
1049 pUndoDB
= new ScDBCollection( *pDocDB
);
1052 // rDoc.SetOutlineTable( nTab, NULL );
1053 ScOutlineTable
* pOut
= rDoc
.GetOutlineTable( nTab
);
1055 pOut
->GetRowArray().RemoveAll(); // nur Zeilen-Outlines loeschen
1057 if (rParam
.bReplace
)
1058 rDoc
.RemoveSubTotals( nTab
, aNewParam
);
1059 bool bSuccess
= true;
1063 if ( rParam
.bDoSort
|| pForceNewSort
)
1065 pDBData
->SetArea( nTab
, aNewParam
.nCol1
,aNewParam
.nRow1
, aNewParam
.nCol2
,aNewParam
.nRow2
);
1067 // Teilergebnis-Felder vor die Sortierung setzen
1068 // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
1070 ScSortParam aOldSort
;
1071 pDBData
->GetSortParam( aOldSort
);
1072 ScSortParam
aSortParam( aNewParam
, pForceNewSort
? *pForceNewSort
: aOldSort
);
1073 Sort( nTab
, aSortParam
, false, false, bApi
);
1076 bSuccess
= rDoc
.DoSubTotals( nTab
, aNewParam
);
1077 rDoc
.SetDrawPageSize(nTab
);
1079 ScRange
aDirtyRange( aNewParam
.nCol1
, aNewParam
.nRow1
, nTab
,
1080 aNewParam
.nCol2
, aNewParam
.nRow2
, nTab
);
1081 rDoc
.SetDirty( aDirtyRange
, true );
1085 // ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
1086 rDocShell
.GetUndoManager()->AddUndoAction(
1087 new ScUndoSubTotals( &rDocShell
, nTab
,
1088 rParam
, aNewParam
.nRow2
,
1089 pUndoDoc
, pUndoTab
, // pUndoDBData,
1090 pUndoRange
, pUndoDB
) );
1095 // "Kann keine Zeilen einfuegen"
1097 rDocShell
.ErrorMessage(STR_MSSG_DOSUBTOTALS_2
);
1101 pDBData
->SetSubTotalParam( aNewParam
);
1102 pDBData
->SetArea( nTab
, aNewParam
.nCol1
,aNewParam
.nRow1
, aNewParam
.nCol2
,aNewParam
.nRow2
);
1103 rDoc
.CompileDBFormula();
1105 rDocShell
.PostPaint(ScRange(0, 0, nTab
, MAXCOL
,MAXROW
,nTab
),
1106 PAINT_GRID
| PAINT_LEFT
| PAINT_TOP
| PAINT_SIZE
);
1107 aModificator
.SetDocumentModified();
1116 bool lcl_EmptyExcept( ScDocument
* pDoc
, const ScRange
& rRange
, const ScRange
& rExcept
)
1118 ScCellIterator
aIter( pDoc
, rRange
);
1119 for (bool bHasCell
= aIter
.first(); bHasCell
; bHasCell
= aIter
.next())
1121 if (!aIter
.isEmpty()) // real content?
1123 if (!rExcept
.In(aIter
.GetPos()))
1124 return false; // cell found
1128 return true; // nothing found - empty
1131 bool isEditable(ScDocShell
& rDocShell
, const ScRangeList
& rRanges
, bool bApi
)
1133 ScDocument
& rDoc
= rDocShell
.GetDocument();
1134 if (!rDocShell
.IsEditable() || rDoc
.GetChangeTrack())
1136 // not recorded -> disallow
1138 rDocShell
.ErrorMessage(STR_PROTECTIONERR
);
1143 for (size_t i
= 0, n
= rRanges
.size(); i
< n
; ++i
)
1145 const ScRange
* p
= rRanges
[i
];
1146 ScEditableTester
aTester(&rDoc
, *p
);
1147 if (!aTester
.IsEditable())
1150 rDocShell
.ErrorMessage(aTester
.GetMessageId());
1159 void createUndoDoc(std::unique_ptr
<ScDocument
>& pUndoDoc
, ScDocument
* pDoc
, const ScRange
& rRange
)
1161 SCTAB nTab
= rRange
.aStart
.Tab();
1162 pUndoDoc
.reset(new ScDocument(SCDOCMODE_UNDO
));
1163 pUndoDoc
->InitUndo(pDoc
, nTab
, nTab
);
1164 pDoc
->CopyToDocument(rRange
, IDF_ALL
, false, pUndoDoc
.get());
1167 bool checkNewOutputRange(ScDPObject
& rDPObj
, ScDocShell
& rDocShell
, ScRange
& rNewOut
, bool bApi
)
1169 ScDocument
& rDoc
= rDocShell
.GetDocument();
1171 bool bOverflow
= false;
1172 rNewOut
= rDPObj
.GetNewOutputRange(bOverflow
);
1174 // Test for overlap with source data range.
1175 // TODO: Check with other pivot tables as well.
1176 const ScSheetSourceDesc
* pSheetDesc
= rDPObj
.GetSheetDesc();
1177 if (pSheetDesc
&& pSheetDesc
->GetSourceRange().Intersects(rNewOut
))
1179 // New output range intersepts with the source data. Move it up to
1180 // where the old range is and see if that works.
1181 ScRange aOldRange
= rDPObj
.GetOutRange();
1182 SCsROW nDiff
= aOldRange
.aStart
.Row() - rNewOut
.aStart
.Row();
1183 rNewOut
.aStart
.SetRow(aOldRange
.aStart
.Row());
1184 rNewOut
.aEnd
.IncRow(nDiff
);
1185 if (!ValidRow(rNewOut
.aStart
.Row()) || !ValidRow(rNewOut
.aEnd
.Row()))
1192 rDocShell
.ErrorMessage(STR_PIVOT_ERROR
);
1197 ScEditableTester
aTester(&rDoc
, rNewOut
);
1198 if (!aTester
.IsEditable())
1200 // destination area isn't editable
1202 rDocShell
.ErrorMessage(aTester
.GetMessageId());
1212 bool ScDBDocFunc::DataPilotUpdate( ScDPObject
* pOldObj
, const ScDPObject
* pNewObj
,
1213 bool bRecord
, bool bApi
, bool bAllowMove
)
1220 return CreatePivotTable(*pNewObj
, bRecord
, bApi
);
1226 return RemovePivotTable(*pOldObj
, bRecord
, bApi
);
1228 if (pOldObj
== pNewObj
)
1229 return UpdatePivotTable(*pOldObj
, bRecord
, bApi
);
1232 OSL_ASSERT(pOldObj
&& pNewObj
&& pOldObj
!= pNewObj
);
1234 ScDocShellModificator
aModificator( rDocShell
);
1235 WaitObject
aWait( ScDocShell::GetActiveDialogParent() );
1237 ScRangeList aRanges
;
1238 aRanges
.Append(pOldObj
->GetOutRange());
1239 aRanges
.Append(pNewObj
->GetOutRange().aStart
); // at least one cell in the output position must be editable.
1240 if (!isEditable(rDocShell
, aRanges
, bApi
))
1243 std::unique_ptr
<ScDocument
> pOldUndoDoc
;
1244 std::unique_ptr
<ScDocument
> pNewUndoDoc
;
1246 ScDPObject
aUndoDPObj(*pOldObj
); // for undo or revert on failure
1248 ScDocument
& rDoc
= rDocShell
.GetDocument();
1249 if (bRecord
&& !rDoc
.IsUndoEnabled())
1253 createUndoDoc(pOldUndoDoc
, &rDoc
, pOldObj
->GetOutRange());
1255 pNewObj
->WriteSourceDataTo(*pOldObj
); // copy source data
1257 ScDPSaveData
* pData
= pNewObj
->GetSaveData();
1258 OSL_ENSURE( pData
, "no SaveData from living DPObject" );
1260 pOldObj
->SetSaveData(*pData
); // copy SaveData
1262 pOldObj
->SetAllowMove(bAllowMove
);
1263 pOldObj
->ReloadGroupTableData();
1264 pOldObj
->SyncAllDimensionMembers();
1265 pOldObj
->InvalidateData(); // before getting the new output area
1267 // make sure the table has a name (not set by dialog)
1268 if (pOldObj
->GetName().isEmpty())
1269 pOldObj
->SetName( rDoc
.GetDPCollection()->CreateNewName() );
1272 if (!checkNewOutputRange(*pOldObj
, rDocShell
, aNewOut
, bApi
))
1274 *pOldObj
= aUndoDPObj
;
1278 // test if new output area is empty except for old area
1281 // OutRange of pOldObj (pDestObj) is still old area
1282 if (!lcl_EmptyExcept(&rDoc
, aNewOut
, pOldObj
->GetOutRange()))
1284 ScopedVclPtrInstance
<QueryBox
> aBox( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
1285 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY
) );
1286 if (aBox
->Execute() == RET_NO
)
1288 //! like above (not editable)
1289 *pOldObj
= aUndoDPObj
;
1296 createUndoDoc(pNewUndoDoc
, &rDoc
, aNewOut
);
1298 pOldObj
->Output(aNewOut
.aStart
);
1299 rDocShell
.PostPaintGridAll(); //! only necessary parts
1303 rDocShell
.GetUndoManager()->AddUndoAction(
1304 new ScUndoDataPilot(
1305 &rDocShell
, pOldUndoDoc
.release(), pNewUndoDoc
.release(), &aUndoDPObj
, pOldObj
, bAllowMove
));
1308 // notify API objects
1309 rDoc
.BroadcastUno( ScDataPilotModifiedHint(pOldObj
->GetName()) );
1310 aModificator
.SetDocumentModified();
1315 bool ScDBDocFunc::RemovePivotTable(ScDPObject
& rDPObj
, bool bRecord
, bool bApi
)
1317 ScDocShellModificator
aModificator(rDocShell
);
1318 WaitObject
aWait(ScDocShell::GetActiveDialogParent());
1320 if (!isEditable(rDocShell
, rDPObj
.GetOutRange(), bApi
))
1323 std::unique_ptr
<ScDocument
> pOldUndoDoc
;
1324 std::unique_ptr
<ScDPObject
> pUndoDPObj
;
1327 pUndoDPObj
.reset(new ScDPObject(rDPObj
)); // copy old settings for undo
1329 ScDocument
& rDoc
= rDocShell
.GetDocument();
1330 if (bRecord
&& !rDoc
.IsUndoEnabled())
1335 ScRange aRange
= rDPObj
.GetOutRange();
1336 SCTAB nTab
= aRange
.aStart
.Tab();
1339 createUndoDoc(pOldUndoDoc
, &rDoc
, aRange
);
1341 rDoc
.DeleteAreaTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
1342 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(),
1344 rDoc
.RemoveFlagsTab( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
1345 aRange
.aEnd
.Col(), aRange
.aEnd
.Row(),
1348 rDoc
.GetDPCollection()->FreeTable(&rDPObj
); // object is deleted here
1350 rDocShell
.PostPaintGridAll(); //! only necessary parts
1351 rDocShell
.PostPaint(aRange
, PAINT_GRID
);
1355 rDocShell
.GetUndoManager()->AddUndoAction(
1356 new ScUndoDataPilot(
1357 &rDocShell
, pOldUndoDoc
.release(), NULL
, pUndoDPObj
.get(), NULL
, false));
1359 // pUndoDPObj is copied
1362 aModificator
.SetDocumentModified();
1366 bool ScDBDocFunc::CreatePivotTable(const ScDPObject
& rDPObj
, bool bRecord
, bool bApi
)
1368 ScDocShellModificator
aModificator(rDocShell
);
1369 WaitObject
aWait(ScDocShell::GetActiveDialogParent());
1371 // At least one cell in the output range should be editable. Check in advance.
1372 if (!isEditable(rDocShell
, ScRange(rDPObj
.GetOutRange().aStart
), bApi
))
1375 std::unique_ptr
<ScDocument
> pNewUndoDoc
;
1377 ScDocument
& rDoc
= rDocShell
.GetDocument();
1378 if (bRecord
&& !rDoc
.IsUndoEnabled())
1381 // output range must be set at pNewObj
1382 std::unique_ptr
<ScDPObject
> pDestObj(new ScDPObject(rDPObj
));
1384 ScDPObject
& rDestObj
= *pDestObj
;
1386 // #i94570# When changing the output position in the dialog, a new table is created
1387 // with the settings from the old table, including the name.
1388 // So we have to check for duplicate names here (before inserting).
1389 if (rDoc
.GetDPCollection()->GetByName(rDestObj
.GetName()))
1390 rDestObj
.SetName(OUString()); // ignore the invalid name, create a new name below
1392 if (!rDoc
.GetDPCollection()->InsertNewTable(pDestObj
.release()))
1393 // Insertion into collection failed.
1396 rDestObj
.ReloadGroupTableData();
1397 rDestObj
.SyncAllDimensionMembers();
1398 rDestObj
.InvalidateData(); // before getting the new output area
1400 // make sure the table has a name (not set by dialog)
1401 if (rDestObj
.GetName().isEmpty())
1402 rDestObj
.SetName(rDoc
.GetDPCollection()->CreateNewName());
1404 bool bOverflow
= false;
1405 ScRange aNewOut
= rDestObj
.GetNewOutputRange(bOverflow
);
1410 rDocShell
.ErrorMessage(STR_PIVOT_ERROR
);
1416 ScEditableTester
aTester(&rDoc
, aNewOut
);
1417 if (!aTester
.IsEditable())
1419 // destination area isn't editable
1421 rDocShell
.ErrorMessage(aTester
.GetMessageId());
1427 // test if new output area is empty except for old area
1430 bool bEmpty
= rDoc
.IsBlockEmpty(
1431 aNewOut
.aStart
.Tab(), aNewOut
.aStart
.Col(), aNewOut
.aStart
.Row(),
1432 aNewOut
.aEnd
.Col(), aNewOut
.aEnd
.Row());
1436 ScopedVclPtrInstance
<QueryBox
> aBox(
1437 ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
1438 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY
));
1440 if (aBox
->Execute() == RET_NO
)
1442 //! like above (not editable)
1449 createUndoDoc(pNewUndoDoc
, &rDoc
, aNewOut
);
1451 rDestObj
.Output(aNewOut
.aStart
);
1452 rDocShell
.PostPaintGridAll(); //! only necessary parts
1456 rDocShell
.GetUndoManager()->AddUndoAction(
1457 new ScUndoDataPilot(&rDocShell
, NULL
, pNewUndoDoc
.release(), NULL
, &rDestObj
, false));
1460 // notify API objects
1461 rDoc
.BroadcastUno(ScDataPilotModifiedHint(rDestObj
.GetName()));
1462 aModificator
.SetDocumentModified();
1467 bool ScDBDocFunc::UpdatePivotTable(ScDPObject
& rDPObj
, bool bRecord
, bool bApi
)
1469 ScDocShellModificator
aModificator( rDocShell
);
1470 WaitObject
aWait( ScDocShell::GetActiveDialogParent() );
1472 if (!isEditable(rDocShell
, rDPObj
.GetOutRange(), bApi
))
1475 std::unique_ptr
<ScDocument
> pOldUndoDoc
;
1476 std::unique_ptr
<ScDocument
> pNewUndoDoc
;
1478 ScDPObject
aUndoDPObj(rDPObj
); // For undo or revert on failure.
1480 ScDocument
& rDoc
= rDocShell
.GetDocument();
1481 if (bRecord
&& !rDoc
.IsUndoEnabled())
1485 createUndoDoc(pOldUndoDoc
, &rDoc
, rDPObj
.GetOutRange());
1487 rDPObj
.SetAllowMove(false);
1488 rDPObj
.ReloadGroupTableData();
1489 if (!rDPObj
.SyncAllDimensionMembers())
1492 rDPObj
.InvalidateData(); // before getting the new output area
1494 // make sure the table has a name (not set by dialog)
1495 if (rDPObj
.GetName().isEmpty())
1496 rDPObj
.SetName( rDoc
.GetDPCollection()->CreateNewName() );
1499 if (!checkNewOutputRange(rDPObj
, rDocShell
, aNewOut
, bApi
))
1501 rDPObj
= aUndoDPObj
;
1505 // test if new output area is empty except for old area
1508 if (!lcl_EmptyExcept(&rDoc
, aNewOut
, rDPObj
.GetOutRange()))
1510 ScopedVclPtrInstance
<QueryBox
> aBox( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO
| WB_DEF_YES
),
1511 ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY
) );
1512 if (aBox
->Execute() == RET_NO
)
1514 rDPObj
= aUndoDPObj
;
1521 createUndoDoc(pNewUndoDoc
, &rDoc
, aNewOut
);
1523 rDPObj
.Output(aNewOut
.aStart
);
1524 rDocShell
.PostPaintGridAll(); //! only necessary parts
1528 rDocShell
.GetUndoManager()->AddUndoAction(
1529 new ScUndoDataPilot(
1530 &rDocShell
, pOldUndoDoc
.release(), pNewUndoDoc
.release(), &aUndoDPObj
, &rDPObj
, false));
1533 // notify API objects
1534 rDoc
.BroadcastUno( ScDataPilotModifiedHint(rDPObj
.GetName()) );
1535 aModificator
.SetDocumentModified();
1539 sal_uLong
ScDBDocFunc::RefreshPivotTables(ScDPObject
* pDPObj
, bool bApi
)
1541 ScDPCollection
* pDPs
= rDocShell
.GetDocument().GetDPCollection();
1545 std::set
<ScDPObject
*> aRefs
;
1546 sal_uLong nErrId
= pDPs
->ReloadCache(pDPObj
, aRefs
);
1550 std::set
<ScDPObject
*>::iterator it
= aRefs
.begin(), itEnd
= aRefs
.end();
1551 for (; it
!= itEnd
; ++it
)
1553 ScDPObject
* pObj
= *it
;
1555 // This action is intentionally not undoable since it modifies cache.
1556 UpdatePivotTable(*pObj
, false, bApi
);
1562 void ScDBDocFunc::RefreshPivotTableGroups(ScDPObject
* pDPObj
)
1567 ScDPCollection
* pDPs
= rDocShell
.GetDocument().GetDPCollection();
1571 ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
1575 std::set
<ScDPObject
*> aRefs
;
1576 if (!pDPs
->ReloadGroupsInCache(pDPObj
, aRefs
))
1579 // We allow pDimData being NULL.
1580 const ScDPDimensionSaveData
* pDimData
= pSaveData
->GetExistingDimensionData();
1581 std::set
<ScDPObject
*>::iterator it
= aRefs
.begin(), itEnd
= aRefs
.end();
1582 for (; it
!= itEnd
; ++it
)
1584 ScDPObject
* pObj
= *it
;
1587 pSaveData
= pObj
->GetSaveData();
1589 pSaveData
->SetDimensionData(pDimData
);
1592 // This action is intentionally not undoable since it modifies cache.
1593 UpdatePivotTable(*pObj
, false, false);
1599 void ScDBDocFunc::UpdateImport( const OUString
& rTarget
, const svx::ODataAccessDescriptor
& rDescriptor
)
1601 // rTarget is the name of a database range
1603 ScDocument
& rDoc
= rDocShell
.GetDocument();
1604 ScDBCollection
& rDBColl
= *rDoc
.GetDBCollection();
1605 const ScDBData
* pData
= rDBColl
.getNamedDBs().findByUpperName(ScGlobal::pCharClass
->uppercase(rTarget
));
1608 ScopedVclPtrInstance
<InfoBox
> aInfoBox( ScDocShell::GetActiveDialogParent(),
1609 ScGlobal::GetRscString( STR_TARGETNOTFOUND
) );
1610 aInfoBox
->Execute();
1617 pData
->GetArea( nTab
, nDummyCol
,nDummyRow
,nDummyCol
,nDummyRow
);
1619 ScImportParam aImportParam
;
1620 pData
->GetImportParam( aImportParam
);
1624 sal_Int32 nCommandType
= 0;
1625 sDBName
= rDescriptor
.getDataSource();
1626 rDescriptor
[svx::daCommand
] >>= sDBTable
;
1627 rDescriptor
[svx::daCommandType
] >>= nCommandType
;
1629 aImportParam
.aDBName
= sDBName
;
1630 aImportParam
.bSql
= ( nCommandType
== sdb::CommandType::COMMAND
);
1631 aImportParam
.aStatement
= sDBTable
;
1632 aImportParam
.bNative
= false;
1633 aImportParam
.nType
= static_cast<sal_uInt8
>( ( nCommandType
== sdb::CommandType::QUERY
) ? ScDbQuery
: ScDbTable
);
1634 aImportParam
.bImport
= true;
1636 bool bContinue
= DoImport( nTab
, aImportParam
, &rDescriptor
, true );
1638 // DB-Operationen wiederholen
1640 ScTabViewShell
* pViewSh
= rDocShell
.GetBestViewShell();
1644 pData
->GetArea(aRange
);
1645 pViewSh
->MarkRange(aRange
); // selektieren
1647 if ( bContinue
) // Fehler beim Import -> Abbruch
1649 // interne Operationen, wenn welche gespeichert
1651 if ( pData
->HasQueryParam() || pData
->HasSortParam() || pData
->HasSubTotalParam() )
1652 pViewSh
->RepeatDB();
1654 // Pivottabellen die den Bereich als Quelldaten haben
1656 rDocShell
.RefreshPivotTables(aRange
);
1661 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */