Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <sfx2/app.hxx>
21 : #include <vcl/msgbox.hxx>
22 : #include <vcl/waitobj.hxx>
23 : #include <svx/dataaccessdescriptor.hxx>
24 :
25 : #include <com/sun/star/sdb/CommandType.hpp>
26 :
27 : #include "dbdocfun.hxx"
28 : #include "sc.hrc"
29 : #include "dbdata.hxx"
30 : #include "undodat.hxx"
31 : #include "docsh.hxx"
32 : #include "docfunc.hxx"
33 : #include "globstr.hrc"
34 : #include "globalnames.hxx"
35 : #include "tabvwsh.hxx"
36 : #include "patattr.hxx"
37 : #include "rangenam.hxx"
38 : #include "olinetab.hxx"
39 : #include "dpobject.hxx"
40 : #include "dpsave.hxx"
41 : #include "dociter.hxx"
42 : #include "editable.hxx"
43 : #include "attrib.hxx"
44 : #include "drwlayer.hxx"
45 : #include "dpshttab.hxx"
46 : #include "hints.hxx"
47 : #include "queryentry.hxx"
48 : #include "markdata.hxx"
49 : #include "progress.hxx"
50 : #include <undosort.hxx>
51 : #include <inputopt.hxx>
52 :
53 : #include <set>
54 : #include <memory>
55 :
56 : using namespace ::com::sun::star;
57 :
58 4 : bool ScDBDocFunc::AddDBRange( const OUString& rName, const ScRange& rRange, bool /* bApi */ )
59 : {
60 :
61 4 : ScDocShellModificator aModificator( rDocShell );
62 :
63 4 : ScDocument& rDoc = rDocShell.GetDocument();
64 4 : ScDBCollection* pDocColl = rDoc.GetDBCollection();
65 4 : bool bUndo (rDoc.IsUndoEnabled());
66 :
67 4 : ScDBCollection* pUndoColl = NULL;
68 4 : if (bUndo)
69 4 : pUndoColl = new ScDBCollection( *pDocColl );
70 :
71 4 : ScDBData* pNew = new ScDBData( rName, rRange.aStart.Tab(),
72 8 : rRange.aStart.Col(), rRange.aStart.Row(),
73 12 : rRange.aEnd.Col(), rRange.aEnd.Row() );
74 :
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 4 : bool bCompile = !rDoc.IsImportingXML();
79 : bool bOk;
80 4 : if ( bCompile )
81 4 : rDoc.PreprocessDBDataUpdate();
82 4 : if ( rName == STR_DB_LOCAL_NONAME )
83 : {
84 1 : rDoc.SetAnonymousDBData(rRange.aStart.Tab() , pNew);
85 1 : bOk = true;
86 : }
87 : else
88 : {
89 3 : bOk = pDocColl->getNamedDBs().insert(pNew);
90 : }
91 4 : if ( bCompile )
92 4 : rDoc.CompileHybridFormula();
93 :
94 4 : if (!bOk)
95 : {
96 0 : delete pNew;
97 0 : delete pUndoColl;
98 0 : return false;
99 : }
100 :
101 4 : if (bUndo)
102 : {
103 4 : ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
104 4 : rDocShell.GetUndoManager()->AddUndoAction(
105 4 : new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
106 : }
107 :
108 4 : aModificator.SetDocumentModified();
109 4 : SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
110 4 : return true;
111 : }
112 :
113 0 : bool ScDBDocFunc::DeleteDBRange(const OUString& rName)
114 : {
115 0 : bool bDone = false;
116 0 : ScDocument& rDoc = rDocShell.GetDocument();
117 0 : ScDBCollection* pDocColl = rDoc.GetDBCollection();
118 0 : bool bUndo = rDoc.IsUndoEnabled();
119 :
120 0 : ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
121 0 : const ScDBData* p = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rName));
122 0 : if (p)
123 : {
124 0 : ScDocShellModificator aModificator( rDocShell );
125 :
126 0 : ScDBCollection* pUndoColl = NULL;
127 0 : if (bUndo)
128 0 : pUndoColl = new ScDBCollection( *pDocColl );
129 :
130 0 : rDoc.PreprocessDBDataUpdate();
131 0 : rDBs.erase(*p);
132 0 : rDoc.CompileHybridFormula();
133 :
134 0 : if (bUndo)
135 : {
136 0 : ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
137 0 : rDocShell.GetUndoManager()->AddUndoAction(
138 0 : new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
139 : }
140 :
141 0 : aModificator.SetDocumentModified();
142 0 : SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
143 0 : bDone = true;
144 : }
145 :
146 0 : return bDone;
147 : }
148 :
149 2 : bool ScDBDocFunc::RenameDBRange( const OUString& rOld, const OUString& rNew )
150 : {
151 2 : bool bDone = false;
152 2 : ScDocument& rDoc = rDocShell.GetDocument();
153 2 : ScDBCollection* pDocColl = rDoc.GetDBCollection();
154 2 : bool bUndo = rDoc.IsUndoEnabled();
155 2 : ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
156 2 : const ScDBData* pOld = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rOld));
157 2 : const ScDBData* pNew = rDBs.findByUpperName(ScGlobal::pCharClass->uppercase(rNew));
158 2 : if (pOld && !pNew)
159 : {
160 2 : ScDocShellModificator aModificator( rDocShell );
161 :
162 2 : ScDBData* pNewData = new ScDBData(rNew, *pOld);
163 :
164 2 : ScDBCollection* pUndoColl = new ScDBCollection( *pDocColl );
165 :
166 2 : rDoc.PreprocessDBDataUpdate();
167 2 : rDBs.erase(*pOld);
168 2 : bool bInserted = rDBs.insert(pNewData);
169 2 : if (!bInserted) // Fehler -> alten Zustand wiederherstellen
170 : {
171 0 : delete pNewData;
172 0 : rDoc.SetDBCollection(pUndoColl); // gehoert dann dem Dokument
173 : }
174 :
175 2 : rDoc.CompileHybridFormula();
176 :
177 2 : if (bInserted) // Einfuegen hat geklappt
178 : {
179 2 : if (bUndo)
180 : {
181 2 : ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
182 2 : rDocShell.GetUndoManager()->AddUndoAction(
183 2 : new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
184 : }
185 : else
186 0 : delete pUndoColl;
187 :
188 2 : aModificator.SetDocumentModified();
189 2 : SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
190 2 : bDone = true;
191 2 : }
192 : }
193 :
194 2 : return bDone;
195 : }
196 :
197 51 : bool ScDBDocFunc::ModifyDBData( const ScDBData& rNewData )
198 : {
199 51 : bool bDone = false;
200 51 : ScDocument& rDoc = rDocShell.GetDocument();
201 51 : ScDBCollection* pDocColl = rDoc.GetDBCollection();
202 51 : bool bUndo = rDoc.IsUndoEnabled();
203 :
204 51 : ScDBData* pData = NULL;
205 51 : if (rNewData.GetName() == STR_DB_LOCAL_NONAME)
206 : {
207 26 : ScRange aRange;
208 26 : rNewData.GetArea(aRange);
209 26 : SCTAB nTab = aRange.aStart.Tab();
210 26 : pData = rDoc.GetAnonymousDBData(nTab);
211 : }
212 : else
213 25 : pData = pDocColl->getNamedDBs().findByUpperName(rNewData.GetUpperName());
214 :
215 51 : if (pData)
216 : {
217 51 : ScDocShellModificator aModificator( rDocShell );
218 51 : ScRange aOldRange, aNewRange;
219 51 : pData->GetArea(aOldRange);
220 51 : rNewData.GetArea(aNewRange);
221 51 : bool bAreaChanged = ( aOldRange != aNewRange ); // dann muss neu compiliert werden
222 :
223 51 : ScDBCollection* pUndoColl = NULL;
224 51 : if (bUndo)
225 43 : pUndoColl = new ScDBCollection( *pDocColl );
226 :
227 51 : *pData = rNewData;
228 51 : if (bAreaChanged)
229 1 : rDoc.CompileDBFormula();
230 :
231 51 : if (bUndo)
232 : {
233 43 : ScDBCollection* pRedoColl = new ScDBCollection( *pDocColl );
234 43 : rDocShell.GetUndoManager()->AddUndoAction(
235 43 : new ScUndoDBData( &rDocShell, pUndoColl, pRedoColl ) );
236 : }
237 :
238 51 : aModificator.SetDocumentModified();
239 51 : bDone = true;
240 : }
241 :
242 51 : return bDone;
243 : }
244 :
245 1 : void ScDBDocFunc::ModifyAllDBData( const ScDBCollection& rNewColl, const std::vector<ScRange>& rDelAreaList )
246 : {
247 1 : ScDocShellModificator aModificator(rDocShell);
248 1 : ScDocument& rDoc = rDocShell.GetDocument();
249 1 : ScDBCollection* pOldColl = rDoc.GetDBCollection();
250 1 : ScDBCollection* pUndoColl = NULL;
251 1 : bool bRecord = rDoc.IsUndoEnabled();
252 :
253 1 : std::vector<ScRange>::const_iterator iter;
254 1 : for (iter = rDelAreaList.begin(); iter != rDelAreaList.end(); ++iter)
255 : {
256 : // unregistering target in SBA no longer necessary
257 0 : const ScAddress& rStart = iter->aStart;
258 0 : const ScAddress& rEnd = iter->aEnd;
259 : rDocShell.DBAreaDeleted(
260 0 : rStart.Tab(), rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row());
261 : }
262 :
263 1 : if (bRecord)
264 1 : pUndoColl = new ScDBCollection( *pOldColl );
265 :
266 : // register target in SBA no longer necessary
267 :
268 1 : rDoc.PreprocessDBDataUpdate();
269 1 : rDoc.SetDBCollection( new ScDBCollection( rNewColl ) );
270 1 : rDoc.CompileHybridFormula();
271 1 : pOldColl = NULL;
272 1 : rDocShell.PostPaint(ScRange(0, 0, 0, MAXCOL, MAXROW, MAXTAB), PAINT_GRID);
273 1 : aModificator.SetDocumentModified();
274 1 : SfxGetpApp()->Broadcast( SfxSimpleHint( SC_HINT_DBAREAS_CHANGED ) );
275 :
276 1 : if (bRecord)
277 : {
278 1 : ScDBCollection* pRedoColl = new ScDBCollection(rNewColl);
279 1 : rDocShell.GetUndoManager()->AddUndoAction(
280 1 : new ScUndoDBData(&rDocShell, pUndoColl, pRedoColl));
281 1 : }
282 1 : }
283 :
284 10 : bool ScDBDocFunc::RepeatDB( const OUString& rDBName, bool bRecord, bool bApi, bool bIsUnnamed, SCTAB aTab )
285 : {
286 : //! auch fuer ScDBFunc::RepeatDB benutzen!
287 :
288 10 : bool bDone = false;
289 10 : ScDocument& rDoc = rDocShell.GetDocument();
290 10 : if (bRecord && !rDoc.IsUndoEnabled())
291 0 : bRecord = false;
292 10 : ScDBData* pDBData = NULL;
293 10 : if (bIsUnnamed)
294 : {
295 9 : pDBData = rDoc.GetAnonymousDBData( aTab );
296 : }
297 : else
298 : {
299 1 : ScDBCollection* pColl = rDoc.GetDBCollection();
300 1 : if (pColl)
301 1 : pDBData = pColl->getNamedDBs().findByUpperName(ScGlobal::pCharClass->uppercase(rDBName));
302 : }
303 :
304 10 : if ( pDBData )
305 : {
306 10 : ScQueryParam aQueryParam;
307 10 : pDBData->GetQueryParam( aQueryParam );
308 10 : bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
309 :
310 20 : ScSortParam aSortParam;
311 10 : pDBData->GetSortParam( aSortParam );
312 10 : bool bSort = aSortParam.maKeyState[0].bDoSort;
313 :
314 10 : ScSubTotalParam aSubTotalParam;
315 10 : pDBData->GetSubTotalParam( aSubTotalParam );
316 10 : bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
317 :
318 10 : if ( bQuery || bSort || bSubTotal )
319 : {
320 10 : bool bQuerySize = false;
321 10 : ScRange aOldQuery;
322 10 : ScRange aNewQuery;
323 10 : if (bQuery && !aQueryParam.bInplace)
324 : {
325 : ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
326 0 : aQueryParam.nDestTab, true );
327 0 : if (pDest && pDest->IsDoSize())
328 : {
329 0 : pDest->GetArea( aOldQuery );
330 0 : bQuerySize = true;
331 : }
332 : }
333 :
334 : SCTAB nTab;
335 : SCCOL nStartCol;
336 : SCROW nStartRow;
337 : SCCOL nEndCol;
338 : SCROW nEndRow;
339 10 : pDBData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
340 :
341 : //! Undo nur benoetigte Daten ?
342 :
343 10 : ScDocument* pUndoDoc = NULL;
344 10 : ScOutlineTable* pUndoTab = NULL;
345 10 : ScRangeName* pUndoRange = NULL;
346 10 : ScDBCollection* pUndoDB = NULL;
347 :
348 10 : if (bRecord)
349 : {
350 10 : SCTAB nTabCount = rDoc.GetTableCount();
351 10 : pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
352 10 : ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
353 10 : if (pTable)
354 : {
355 9 : pUndoTab = new ScOutlineTable( *pTable );
356 :
357 : // column/row state
358 : SCCOLROW nOutStartCol, nOutEndCol;
359 : SCCOLROW nOutStartRow, nOutEndRow;
360 9 : pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
361 9 : pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
362 :
363 9 : pUndoDoc->InitUndo( &rDoc, nTab, nTab, true, true );
364 : rDoc.CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0,
365 : nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab,
366 9 : IDF_NONE, false, pUndoDoc );
367 : rDoc.CopyToDocument( 0, static_cast<SCROW>(nOutStartRow),
368 : nTab, MAXCOL, static_cast<SCROW>(nOutEndRow), nTab,
369 9 : IDF_NONE, false, pUndoDoc );
370 : }
371 : else
372 1 : pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, true );
373 :
374 : // Datenbereich sichern - incl. Filter-Ergebnis
375 10 : rDoc.CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, false, pUndoDoc );
376 :
377 : // alle Formeln wegen Referenzen
378 10 : rDoc.CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, false, pUndoDoc );
379 :
380 : // DB- und andere Bereiche
381 10 : ScRangeName* pDocRange = rDoc.GetRangeName();
382 10 : if (!pDocRange->empty())
383 0 : pUndoRange = new ScRangeName( *pDocRange );
384 10 : ScDBCollection* pDocDB = rDoc.GetDBCollection();
385 10 : if (!pDocDB->empty())
386 1 : pUndoDB = new ScDBCollection( *pDocDB );
387 : }
388 :
389 10 : if (bSort && bSubTotal)
390 : {
391 : // Sortieren ohne SubTotals
392 :
393 0 : aSubTotalParam.bRemoveOnly = true; // wird unten wieder zurueckgesetzt
394 0 : DoSubTotals( nTab, aSubTotalParam, NULL, false, bApi );
395 : }
396 :
397 10 : if (bSort)
398 : {
399 0 : pDBData->GetSortParam( aSortParam ); // Bereich kann sich geaendert haben
400 0 : (void)Sort( nTab, aSortParam, false, false, bApi );
401 : }
402 10 : if (bQuery)
403 : {
404 10 : pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geaendert haben
405 10 : ScRange aAdvSource;
406 10 : if (pDBData->GetAdvancedQuerySource(aAdvSource))
407 0 : Query( nTab, aQueryParam, &aAdvSource, false, bApi );
408 : else
409 10 : Query( nTab, aQueryParam, NULL, false, bApi );
410 :
411 : // bei nicht-inplace kann die Tabelle umgestellt worden sein
412 : // if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
413 : // SetTabNo( nTab );
414 : }
415 10 : if (bSubTotal)
416 : {
417 0 : pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geaendert haben
418 0 : aSubTotalParam.bRemoveOnly = false;
419 0 : DoSubTotals( nTab, aSubTotalParam, NULL, false, bApi );
420 : }
421 :
422 10 : if (bRecord)
423 : {
424 : SCTAB nDummyTab;
425 : SCCOL nDummyCol;
426 : SCROW nDummyRow;
427 : SCROW nNewEndRow;
428 10 : pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
429 :
430 10 : const ScRange* pOld = NULL;
431 10 : const ScRange* pNew = NULL;
432 10 : if (bQuerySize)
433 : {
434 : ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
435 0 : aQueryParam.nDestTab, true );
436 0 : if (pDest)
437 : {
438 0 : pDest->GetArea( aNewQuery );
439 0 : pOld = &aOldQuery;
440 0 : pNew = &aNewQuery;
441 : }
442 : }
443 :
444 10 : rDocShell.GetUndoManager()->AddUndoAction(
445 : new ScUndoRepeatDB( &rDocShell, nTab,
446 : nStartCol, nStartRow, nEndCol, nEndRow,
447 : nNewEndRow,
448 : //nCurX, nCurY,
449 : nStartCol, nStartRow,
450 : pUndoDoc, pUndoTab,
451 : pUndoRange, pUndoDB,
452 10 : pOld, pNew ) );
453 : }
454 :
455 : rDocShell.PostPaint(ScRange(0, 0, nTab, MAXCOL, MAXROW, nTab),
456 10 : PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE);
457 10 : bDone = true;
458 : }
459 0 : else if (!bApi) // "Keine Operationen auszufuehren"
460 10 : rDocShell.ErrorMessage(STR_MSSG_REPEATDB_0);
461 : }
462 :
463 10 : return bDone;
464 : }
465 :
466 29 : bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
467 : bool bRecord, bool bPaint, bool bApi )
468 : {
469 29 : ScDocShellModificator aModificator( rDocShell );
470 :
471 29 : ScDocument& rDoc = rDocShell.GetDocument();
472 29 : if (bRecord && !rDoc.IsUndoEnabled())
473 0 : bRecord = false;
474 :
475 : ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
476 29 : rSortParam.nCol2, rSortParam.nRow2 );
477 29 : if (!pDBData)
478 : {
479 : OSL_FAIL( "Sort: keine DBData" );
480 0 : return false;
481 : }
482 :
483 29 : bool bCopy = !rSortParam.bInplace;
484 29 : if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 &&
485 0 : rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab )
486 0 : bCopy = false;
487 :
488 58 : ScSortParam aLocalParam( rSortParam );
489 29 : if ( bCopy )
490 : {
491 : // Copy the data range to the destination then move the sort range to it.
492 1 : ScRange aSrcRange(rSortParam.nCol1, rSortParam.nRow1, nTab, rSortParam.nCol2, rSortParam.nRow2, nTab);
493 1 : ScAddress aDestPos(rSortParam.nDestCol,rSortParam.nDestRow,rSortParam.nDestTab);
494 :
495 1 : ScDocFunc& rDocFunc = rDocShell.GetDocFunc();
496 1 : bool bRet = rDocFunc.MoveBlock(aSrcRange, aDestPos, false, bRecord, bPaint, bApi);
497 :
498 1 : if (!bRet)
499 0 : return false;
500 :
501 1 : aLocalParam.MoveToDest();
502 1 : nTab = aLocalParam.nDestTab;
503 : }
504 :
505 : ScEditableTester aTester( &rDoc, nTab, aLocalParam.nCol1,aLocalParam.nRow1,
506 29 : aLocalParam.nCol2,aLocalParam.nRow2 );
507 29 : if (!aTester.IsEditable())
508 : {
509 0 : if (!bApi)
510 0 : rDocShell.ErrorMessage(aTester.GetMessageId());
511 0 : return false;
512 : }
513 :
514 57 : if ( aLocalParam.bIncludePattern && rDoc.HasAttrib(
515 : aLocalParam.nCol1, aLocalParam.nRow1, nTab,
516 : aLocalParam.nCol2, aLocalParam.nRow2, nTab,
517 28 : HASATTR_MERGED | HASATTR_OVERLAPPED ) )
518 : {
519 : // Merge-Attribute wuerden beim Sortieren durcheinanderkommen
520 0 : if (!bApi)
521 0 : rDocShell.ErrorMessage(STR_SORT_ERR_MERGED);
522 0 : return false;
523 : }
524 :
525 : // ausfuehren
526 :
527 58 : WaitObject aWait( ScDocShell::GetActiveDialogParent() );
528 :
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 29 : bool bShrunk = false;
533 : rDoc.ShrinkToUsedDataArea( bShrunk, nTab, aLocalParam.nCol1, aLocalParam.nRow1,
534 29 : aLocalParam.nCol2, aLocalParam.nRow2, false, aLocalParam.bByRow, !aLocalParam.bByRow);
535 :
536 29 : SCROW nStartRow = aLocalParam.nRow1;
537 29 : if (aLocalParam.bByRow && aLocalParam.bHasHeader && nStartRow < aLocalParam.nRow2)
538 16 : ++nStartRow;
539 :
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
542 : // sort.
543 : rDoc.UpdateScriptTypes(
544 : ScAddress(aLocalParam.nCol1,nStartRow,nTab),
545 : aLocalParam.nCol2-aLocalParam.nCol1+1,
546 29 : aLocalParam.nRow2-nStartRow+1);
547 :
548 : // No point adjusting row heights after the sort when all rows have the same height.
549 : bool bUniformRowHeight =
550 29 : rDoc.HasUniformRowHeight(nTab, nStartRow, aLocalParam.nRow2);
551 :
552 29 : bool bRepeatQuery = false; // bestehenden Filter wiederholen?
553 58 : ScQueryParam aQueryParam;
554 29 : pDBData->GetQueryParam( aQueryParam );
555 29 : if ( aQueryParam.GetEntry(0).bDoQuery )
556 0 : bRepeatQuery = true;
557 :
558 58 : sc::ReorderParam aUndoParam;
559 :
560 : // don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set)
561 29 : if (aLocalParam.GetSortKeyCount() && aLocalParam.maKeyState[0].bDoSort)
562 : {
563 29 : ScInputOptions aInputOption = SC_MOD()->GetInputOptions();
564 29 : bool bUpdateRefs = aInputOption.GetSortRefUpdate();
565 58 : ScProgress aProgress(&rDocShell, ScGlobal::GetRscString(STR_PROGRESS_SORTING), 0);
566 58 : rDoc.Sort(nTab, aLocalParam, bRepeatQuery, bUpdateRefs, &aProgress, &aUndoParam);
567 : }
568 :
569 29 : if (bRecord)
570 : {
571 : // Set up an undo object.
572 28 : sc::UndoSort* pUndoAction = new sc::UndoSort(&rDocShell, aUndoParam);
573 28 : rDocShell.GetUndoManager()->AddUndoAction(pUndoAction);
574 : }
575 :
576 29 : pDBData->SetSortParam(rSortParam);
577 :
578 29 : if (nStartRow <= aLocalParam.nRow2)
579 : {
580 : ScRange aDirtyRange(
581 : aLocalParam.nCol1, nStartRow, nTab,
582 29 : aLocalParam.nCol2, aLocalParam.nRow2, nTab);
583 29 : rDoc.SetDirty( aDirtyRange, true );
584 : }
585 :
586 29 : if (bPaint)
587 : {
588 27 : sal_uInt16 nPaint = PAINT_GRID;
589 27 : SCCOL nStartX = aLocalParam.nCol1;
590 27 : SCROW nStartY = aLocalParam.nRow1;
591 27 : SCCOL nEndX = aLocalParam.nCol2;
592 27 : SCROW nEndY = aLocalParam.nRow2;
593 27 : if ( bRepeatQuery )
594 : {
595 0 : nPaint |= PAINT_LEFT;
596 0 : nStartX = 0;
597 0 : nEndX = MAXCOL;
598 : }
599 27 : rDocShell.PostPaint(ScRange(nStartX, nStartY, nTab, nEndX, nEndY, nTab), nPaint);
600 : }
601 :
602 29 : if (!bUniformRowHeight && nStartRow <= aLocalParam.nRow2)
603 0 : rDocShell.AdjustRowHeight(nStartRow, aLocalParam.nRow2, nTab);
604 :
605 29 : aModificator.SetDocumentModified();
606 :
607 58 : return true;
608 : }
609 :
610 14 : bool ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam,
611 : const ScRange* pAdvSource, bool bRecord, bool bApi )
612 : {
613 14 : ScDocShellModificator aModificator( rDocShell );
614 :
615 14 : ScDocument& rDoc = rDocShell.GetDocument();
616 14 : if (bRecord && !rDoc.IsUndoEnabled())
617 0 : bRecord = false;
618 : ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rQueryParam.nCol1, rQueryParam.nRow1,
619 14 : rQueryParam.nCol2, rQueryParam.nRow2 );
620 14 : if (!pDBData)
621 : {
622 : OSL_FAIL( "Query: keine DBData" );
623 0 : return false;
624 : }
625 :
626 : // Wechsel von Inplace auf nicht-Inplace, dann erst Inplace aufheben:
627 : // (nur, wenn im Dialog "Persistent" ausgewaehlt ist)
628 :
629 14 : if ( !rQueryParam.bInplace && pDBData->HasQueryParam() && rQueryParam.bDestPers )
630 : {
631 0 : ScQueryParam aOldQuery;
632 0 : pDBData->GetQueryParam(aOldQuery);
633 0 : if (aOldQuery.bInplace)
634 : {
635 : // alte Filterung aufheben
636 :
637 0 : SCSIZE nEC = aOldQuery.GetEntryCount();
638 0 : for (SCSIZE i=0; i<nEC; i++)
639 0 : aOldQuery.GetEntry(i).bDoQuery = false;
640 0 : aOldQuery.bDuplicate = true;
641 0 : Query( nTab, aOldQuery, NULL, bRecord, bApi );
642 0 : }
643 : }
644 :
645 28 : ScQueryParam aLocalParam( rQueryParam ); // fuer Paint / Zielbereich
646 14 : bool bCopy = !rQueryParam.bInplace; // kopiert wird in Table::Query
647 14 : ScDBData* pDestData = NULL; // Bereich, in den kopiert wird
648 14 : bool bDoSize = false; // Zielgroesse anpassen (einf./loeschen)
649 14 : SCCOL nFormulaCols = 0; // nur bei bDoSize
650 14 : bool bKeepFmt = false;
651 14 : ScRange aOldDest;
652 14 : ScRange aDestTotal;
653 14 : if ( bCopy && rQueryParam.nDestCol == rQueryParam.nCol1 &&
654 0 : rQueryParam.nDestRow == rQueryParam.nRow1 && rQueryParam.nDestTab == nTab )
655 0 : bCopy = false;
656 14 : SCTAB nDestTab = nTab;
657 14 : if ( bCopy )
658 : {
659 0 : aLocalParam.MoveToDest();
660 0 : nDestTab = rQueryParam.nDestTab;
661 0 : if ( !ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
662 : {
663 0 : if (!bApi)
664 0 : rDocShell.ErrorMessage(STR_PASTE_FULL);
665 0 : return false;
666 : }
667 :
668 : ScEditableTester aTester( &rDoc, nDestTab, aLocalParam.nCol1,aLocalParam.nRow1,
669 0 : aLocalParam.nCol2,aLocalParam.nRow2);
670 0 : if (!aTester.IsEditable())
671 : {
672 0 : if (!bApi)
673 0 : rDocShell.ErrorMessage(aTester.GetMessageId());
674 0 : return false;
675 : }
676 :
677 : pDestData = rDoc.GetDBAtCursor( rQueryParam.nDestCol, rQueryParam.nDestRow,
678 0 : rQueryParam.nDestTab, true );
679 0 : if (pDestData)
680 : {
681 0 : pDestData->GetArea( aOldDest );
682 0 : aDestTotal=ScRange( rQueryParam.nDestCol,
683 : rQueryParam.nDestRow,
684 : nDestTab,
685 : rQueryParam.nDestCol + rQueryParam.nCol2 - rQueryParam.nCol1,
686 0 : rQueryParam.nDestRow + rQueryParam.nRow2 - rQueryParam.nRow1,
687 0 : nDestTab );
688 :
689 0 : bDoSize = pDestData->IsDoSize();
690 : // Test, ob Formeln aufgefuellt werden muessen (nFormulaCols):
691 0 : if ( bDoSize && aOldDest.aEnd.Col() == aDestTotal.aEnd.Col() )
692 : {
693 0 : SCCOL nTestCol = aOldDest.aEnd.Col() + 1; // neben dem Bereich
694 0 : SCROW nTestRow = rQueryParam.nDestRow +
695 0 : ( aLocalParam.bHasHeader ? 1 : 0 );
696 0 : while ( nTestCol <= MAXCOL &&
697 0 : rDoc.GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA )
698 0 : ++nTestCol, ++nFormulaCols;
699 : }
700 :
701 0 : bKeepFmt = pDestData->IsKeepFmt();
702 0 : if ( bDoSize && !rDoc.CanFitBlock( aOldDest, aDestTotal ) )
703 : {
704 0 : if (!bApi)
705 0 : rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2); // kann keine Zeilen einfuegen
706 0 : return false;
707 : }
708 : }
709 : }
710 :
711 : // ausfuehren
712 :
713 28 : WaitObject aWait( ScDocShell::GetActiveDialogParent() );
714 :
715 14 : bool bKeepSub = false; // bestehende Teilergebnisse wiederholen?
716 14 : ScSubTotalParam aSubTotalParam;
717 14 : if (rQueryParam.GetEntry(0).bDoQuery) // nicht beim Aufheben
718 : {
719 11 : pDBData->GetSubTotalParam( aSubTotalParam ); // Teilergebnisse vorhanden?
720 :
721 11 : if ( aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly )
722 0 : bKeepSub = true;
723 : }
724 :
725 14 : ScDocument* pUndoDoc = NULL;
726 14 : ScDBCollection* pUndoDB = NULL;
727 14 : const ScRange* pOld = NULL;
728 :
729 14 : if ( bRecord )
730 : {
731 4 : pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
732 4 : if (bCopy)
733 : {
734 0 : pUndoDoc->InitUndo( &rDoc, nDestTab, nDestTab, false, true );
735 : rDoc.CopyToDocument( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
736 : aLocalParam.nCol2, aLocalParam.nRow2, nDestTab,
737 0 : IDF_ALL, false, pUndoDoc );
738 : // Attribute sichern, falls beim Filtern mitkopiert
739 :
740 0 : if (pDestData)
741 : {
742 0 : rDoc.CopyToDocument( aOldDest, IDF_ALL, false, pUndoDoc );
743 0 : pOld = &aOldDest;
744 : }
745 : }
746 : else
747 : {
748 4 : pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, true );
749 : rDoc.CopyToDocument( 0, rQueryParam.nRow1, nTab, MAXCOL, rQueryParam.nRow2, nTab,
750 4 : IDF_NONE, false, pUndoDoc );
751 : }
752 :
753 4 : ScDBCollection* pDocDB = rDoc.GetDBCollection();
754 4 : if (!pDocDB->empty())
755 0 : pUndoDB = new ScDBCollection( *pDocDB );
756 :
757 4 : rDoc.BeginDrawUndo();
758 : }
759 :
760 14 : ScDocument* pAttribDoc = NULL;
761 14 : ScRange aAttribRange;
762 14 : if (pDestData) // Zielbereich loeschen
763 : {
764 0 : if ( bKeepFmt )
765 : {
766 : // kleinere der End-Spalten, Header+1 Zeile
767 0 : aAttribRange = aOldDest;
768 0 : if ( aAttribRange.aEnd.Col() > aDestTotal.aEnd.Col() )
769 0 : aAttribRange.aEnd.SetCol( aDestTotal.aEnd.Col() );
770 0 : aAttribRange.aEnd.SetRow( aAttribRange.aStart.Row() +
771 0 : ( aLocalParam.bHasHeader ? 1 : 0 ) );
772 :
773 : // auch fuer aufgefuellte Formeln
774 0 : aAttribRange.aEnd.SetCol( aAttribRange.aEnd.Col() + nFormulaCols );
775 :
776 0 : pAttribDoc = new ScDocument( SCDOCMODE_UNDO );
777 0 : pAttribDoc->InitUndo( &rDoc, nDestTab, nDestTab, false, true );
778 0 : rDoc.CopyToDocument( aAttribRange, IDF_ATTRIB, false, pAttribDoc );
779 : }
780 :
781 0 : if ( bDoSize )
782 0 : rDoc.FitBlock( aOldDest, aDestTotal );
783 : else
784 0 : rDoc.DeleteAreaTab(aOldDest, IDF_ALL); // einfach loeschen
785 : }
786 :
787 : // Filtern am Dokument ausfuehren
788 14 : SCSIZE nCount = rDoc.Query( nTab, rQueryParam, bKeepSub );
789 14 : if (bCopy)
790 : {
791 0 : aLocalParam.nRow2 = aLocalParam.nRow1 + nCount;
792 0 : if (!aLocalParam.bHasHeader && nCount > 0)
793 0 : --aLocalParam.nRow2;
794 :
795 0 : if ( bDoSize )
796 : {
797 : // auf wirklichen Ergebnis-Bereich anpassen
798 : // (das hier ist immer eine Verkleinerung)
799 :
800 : ScRange aNewDest( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
801 0 : aLocalParam.nCol2, aLocalParam.nRow2, nDestTab );
802 0 : rDoc.FitBlock( aDestTotal, aNewDest, false ); // sal_False - nicht loeschen
803 :
804 0 : if ( nFormulaCols > 0 )
805 : {
806 : // Formeln ausfuellen
807 : //! Undo (Query und Repeat) !!!
808 :
809 : ScRange aNewForm( aLocalParam.nCol2+1, aLocalParam.nRow1, nDestTab,
810 0 : aLocalParam.nCol2+nFormulaCols, aLocalParam.nRow2, nDestTab );
811 0 : ScRange aOldForm = aNewForm;
812 0 : aOldForm.aEnd.SetRow( aOldDest.aEnd.Row() );
813 0 : rDoc.FitBlock( aOldForm, aNewForm, false );
814 :
815 0 : ScMarkData aMark;
816 0 : aMark.SelectOneTable(nDestTab);
817 0 : SCROW nFStartY = aLocalParam.nRow1 + ( aLocalParam.bHasHeader ? 1 : 0 );
818 :
819 0 : sal_uLong nProgCount = nFormulaCols;
820 0 : nProgCount *= aLocalParam.nRow2 - nFStartY;
821 : ScProgress aProgress( rDoc.GetDocumentShell(),
822 0 : ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount );
823 :
824 : rDoc.Fill( aLocalParam.nCol2+1, nFStartY,
825 : aLocalParam.nCol2+nFormulaCols, nFStartY, &aProgress, aMark,
826 0 : aLocalParam.nRow2 - nFStartY,
827 0 : FILL_TO_BOTTOM, FILL_SIMPLE );
828 : }
829 : }
830 :
831 0 : if ( pAttribDoc ) // gemerkte Attribute zurueckkopieren
832 : {
833 : // Header
834 0 : if (aLocalParam.bHasHeader)
835 : {
836 0 : ScRange aHdrRange = aAttribRange;
837 0 : aHdrRange.aEnd.SetRow( aHdrRange.aStart.Row() );
838 0 : pAttribDoc->CopyToDocument( aHdrRange, IDF_ATTRIB, false, &rDoc );
839 : }
840 :
841 : // Daten
842 0 : SCCOL nAttrEndCol = aAttribRange.aEnd.Col();
843 0 : SCROW nAttrRow = aAttribRange.aStart.Row() + ( aLocalParam.bHasHeader ? 1 : 0 );
844 0 : for (SCCOL nCol = aAttribRange.aStart.Col(); nCol<=nAttrEndCol; nCol++)
845 : {
846 : const ScPatternAttr* pSrcPattern = pAttribDoc->GetPattern(
847 0 : nCol, nAttrRow, nDestTab );
848 : OSL_ENSURE(pSrcPattern,"Pattern ist 0");
849 0 : if (pSrcPattern)
850 : {
851 : rDoc.ApplyPatternAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
852 0 : nDestTab, *pSrcPattern );
853 0 : const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet();
854 0 : if (pStyle)
855 : rDoc.ApplyStyleAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
856 0 : nDestTab, *pStyle );
857 : }
858 : }
859 :
860 0 : delete pAttribDoc;
861 : }
862 : }
863 :
864 : // speichern: Inplace immer, sonst je nach Einstellung
865 : // alter Inplace-Filter ist ggf. schon aufgehoben
866 :
867 14 : bool bSave = rQueryParam.bInplace || rQueryParam.bDestPers;
868 14 : if (bSave) // merken
869 : {
870 14 : pDBData->SetQueryParam( rQueryParam );
871 14 : pDBData->SetHeader( rQueryParam.bHasHeader ); //! ???
872 14 : pDBData->SetAdvancedQuerySource( pAdvSource ); // after SetQueryParam
873 : }
874 :
875 14 : if (bCopy) // neuen DB-Bereich merken
876 : {
877 : // selektieren wird hinterher von aussen (dbfunc)
878 : // momentan ueber DB-Bereich an der Zielposition, darum muss dort
879 : // auf jeden Fall ein Bereich angelegt werden.
880 :
881 : ScDBData* pNewData;
882 0 : if (pDestData)
883 0 : pNewData = pDestData; // Bereich vorhanden -> anpassen (immer!)
884 : else // Bereich anlegen
885 : pNewData = rDocShell.GetDBData(
886 : ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
887 : aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ),
888 0 : SC_DB_MAKE, SC_DBSEL_FORCE_MARK );
889 :
890 0 : if (pNewData)
891 : {
892 : pNewData->SetArea( nDestTab, aLocalParam.nCol1, aLocalParam.nRow1,
893 0 : aLocalParam.nCol2, aLocalParam.nRow2 );
894 :
895 : // Query-Param wird am Ziel nicht mehr eingestellt, fuehrt nur zu Verwirrung
896 : // und Verwechslung mit dem Query-Param am Quellbereich (#37187#)
897 : }
898 : else
899 : {
900 : OSL_FAIL("Zielbereich nicht da");
901 : }
902 : }
903 :
904 14 : if (!bCopy)
905 : {
906 14 : rDoc.InvalidatePageBreaks(nTab);
907 14 : rDoc.UpdatePageBreaks( nTab );
908 : }
909 :
910 : // #i23299# Subtotal functions depend on cell's filtered states.
911 14 : ScRange aDirtyRange(0 , aLocalParam.nRow1, nDestTab, MAXCOL, aLocalParam.nRow2, nDestTab);
912 14 : rDoc.SetSubTotalCellsDirty(aDirtyRange);
913 :
914 14 : if ( bRecord )
915 : {
916 : // create undo action after executing, because of drawing layer undo
917 4 : rDocShell.GetUndoManager()->AddUndoAction(
918 : new ScUndoQuery( &rDocShell, nTab, rQueryParam, pUndoDoc, pUndoDB,
919 4 : pOld, bDoSize, pAdvSource ) );
920 : }
921 :
922 14 : if (bCopy)
923 : {
924 0 : SCCOL nEndX = aLocalParam.nCol2;
925 0 : SCROW nEndY = aLocalParam.nRow2;
926 0 : if (pDestData)
927 : {
928 0 : if ( aOldDest.aEnd.Col() > nEndX )
929 0 : nEndX = aOldDest.aEnd.Col();
930 0 : if ( aOldDest.aEnd.Row() > nEndY )
931 0 : nEndY = aOldDest.aEnd.Row();
932 : }
933 0 : if (bDoSize)
934 0 : nEndY = MAXROW;
935 : rDocShell.PostPaint(
936 : ScRange(aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, nEndX, nEndY, nDestTab),
937 0 : PAINT_GRID);
938 : }
939 : else
940 : rDocShell.PostPaint(
941 : ScRange(0, rQueryParam.nRow1, nTab, MAXCOL, MAXROW, nTab),
942 14 : PAINT_GRID | PAINT_LEFT);
943 14 : aModificator.SetDocumentModified();
944 :
945 28 : return true;
946 : }
947 :
948 2 : bool ScDBDocFunc::DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam,
949 : const ScSortParam* pForceNewSort, bool bRecord, bool bApi )
950 : {
951 : //! auch fuer ScDBFunc::DoSubTotals benutzen!
952 : // dann bleibt aussen:
953 : // - neuen Bereich (aus DBData) markieren
954 : // - SelectionChanged (?)
955 :
956 2 : bool bDo = !rParam.bRemoveOnly; // sal_False = nur loeschen
957 2 : bool bRet = false;
958 :
959 2 : ScDocument& rDoc = rDocShell.GetDocument();
960 2 : if (bRecord && !rDoc.IsUndoEnabled())
961 0 : bRecord = false;
962 : ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
963 2 : rParam.nCol2, rParam.nRow2 );
964 2 : if (!pDBData)
965 : {
966 : OSL_FAIL( "SubTotals: keine DBData" );
967 0 : return false;
968 : }
969 :
970 2 : ScEditableTester aTester( &rDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW );
971 2 : if (!aTester.IsEditable())
972 : {
973 0 : if (!bApi)
974 0 : rDocShell.ErrorMessage(aTester.GetMessageId());
975 0 : return false;
976 : }
977 :
978 2 : if (rDoc.HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
979 2 : rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
980 : {
981 0 : if (!bApi)
982 0 : rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen
983 0 : return false;
984 : }
985 :
986 2 : bool bOk = true;
987 2 : if (rParam.bReplace)
988 2 : if (rDoc.TestRemoveSubTotals( nTab, rParam ))
989 : {
990 0 : bOk = ( ScopedVclPtr<MessBox>::Create( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
991 : // "StarCalc" "Daten loeschen?"
992 0 : ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
993 0 : ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) )->Execute()
994 0 : == RET_YES );
995 : }
996 :
997 2 : if (bOk)
998 : {
999 2 : WaitObject aWait( ScDocShell::GetActiveDialogParent() );
1000 4 : ScDocShellModificator aModificator( rDocShell );
1001 :
1002 2 : ScSubTotalParam aNewParam( rParam ); // Bereichsende wird veraendert
1003 2 : ScDocument* pUndoDoc = NULL;
1004 2 : ScOutlineTable* pUndoTab = NULL;
1005 2 : ScRangeName* pUndoRange = NULL;
1006 2 : ScDBCollection* pUndoDB = NULL;
1007 :
1008 2 : if (bRecord) // alte Daten sichern
1009 : {
1010 2 : bool bOldFilter = bDo && rParam.bDoSort;
1011 :
1012 2 : SCTAB nTabCount = rDoc.GetTableCount();
1013 2 : pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
1014 2 : ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
1015 2 : if (pTable)
1016 : {
1017 1 : pUndoTab = new ScOutlineTable( *pTable );
1018 :
1019 : // column/row state
1020 : SCCOLROW nOutStartCol, nOutEndCol;
1021 : SCCOLROW nOutStartRow, nOutEndRow;
1022 1 : pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
1023 1 : pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
1024 :
1025 1 : pUndoDoc->InitUndo( &rDoc, nTab, nTab, true, true );
1026 1 : rDoc.CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, false, pUndoDoc );
1027 1 : rDoc.CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, false, pUndoDoc );
1028 : }
1029 : else
1030 1 : pUndoDoc->InitUndo( &rDoc, nTab, nTab, false, bOldFilter );
1031 :
1032 : // Datenbereich sichern - incl. Filter-Ergebnis
1033 : rDoc.CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab,
1034 2 : IDF_ALL, false, pUndoDoc );
1035 :
1036 : // alle Formeln wegen Referenzen
1037 : rDoc.CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
1038 2 : IDF_FORMULA, false, pUndoDoc );
1039 :
1040 : // DB- und andere Bereiche
1041 2 : ScRangeName* pDocRange = rDoc.GetRangeName();
1042 2 : if (!pDocRange->empty())
1043 0 : pUndoRange = new ScRangeName( *pDocRange );
1044 2 : ScDBCollection* pDocDB = rDoc.GetDBCollection();
1045 2 : if (!pDocDB->empty())
1046 0 : pUndoDB = new ScDBCollection( *pDocDB );
1047 : }
1048 :
1049 : // rDoc.SetOutlineTable( nTab, NULL );
1050 2 : ScOutlineTable* pOut = rDoc.GetOutlineTable( nTab );
1051 2 : if (pOut)
1052 1 : pOut->GetRowArray().RemoveAll(); // nur Zeilen-Outlines loeschen
1053 :
1054 2 : if (rParam.bReplace)
1055 2 : rDoc.RemoveSubTotals( nTab, aNewParam );
1056 2 : bool bSuccess = true;
1057 2 : if (bDo)
1058 : {
1059 : // Sortieren
1060 1 : if ( rParam.bDoSort || pForceNewSort )
1061 : {
1062 1 : pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
1063 :
1064 : // Teilergebnis-Felder vor die Sortierung setzen
1065 : // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
1066 :
1067 1 : ScSortParam aOldSort;
1068 1 : pDBData->GetSortParam( aOldSort );
1069 2 : ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
1070 2 : Sort( nTab, aSortParam, false, false, bApi );
1071 : }
1072 :
1073 1 : bSuccess = rDoc.DoSubTotals( nTab, aNewParam );
1074 1 : rDoc.SetDrawPageSize(nTab);
1075 : }
1076 : ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
1077 2 : aNewParam.nCol2, aNewParam.nRow2, nTab );
1078 2 : rDoc.SetDirty( aDirtyRange, true );
1079 :
1080 2 : if (bRecord)
1081 : {
1082 : // ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
1083 2 : rDocShell.GetUndoManager()->AddUndoAction(
1084 : new ScUndoSubTotals( &rDocShell, nTab,
1085 : rParam, aNewParam.nRow2,
1086 : pUndoDoc, pUndoTab, // pUndoDBData,
1087 2 : pUndoRange, pUndoDB ) );
1088 : }
1089 :
1090 2 : if (!bSuccess)
1091 : {
1092 : // "Kann keine Zeilen einfuegen"
1093 0 : if (!bApi)
1094 0 : rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
1095 : }
1096 :
1097 : // merken
1098 2 : pDBData->SetSubTotalParam( aNewParam );
1099 2 : pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
1100 2 : rDoc.CompileDBFormula();
1101 :
1102 : rDocShell.PostPaint(ScRange(0, 0, nTab, MAXCOL,MAXROW,nTab),
1103 2 : PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE);
1104 2 : aModificator.SetDocumentModified();
1105 :
1106 4 : bRet = bSuccess;
1107 : }
1108 2 : return bRet;
1109 : }
1110 :
1111 : namespace {
1112 :
1113 4 : bool lcl_EmptyExcept( ScDocument* pDoc, const ScRange& rRange, const ScRange& rExcept )
1114 : {
1115 4 : ScCellIterator aIter( pDoc, rRange );
1116 128 : for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
1117 : {
1118 124 : if (!aIter.isEmpty()) // real content?
1119 : {
1120 124 : if (!rExcept.In(aIter.GetPos()))
1121 0 : return false; // cell found
1122 : }
1123 : }
1124 :
1125 4 : return true; // nothing found - empty
1126 : }
1127 :
1128 53 : bool isEditable(ScDocShell& rDocShell, const ScRangeList& rRanges, bool bApi)
1129 : {
1130 53 : ScDocument& rDoc = rDocShell.GetDocument();
1131 53 : if (!rDocShell.IsEditable() || rDoc.GetChangeTrack())
1132 : {
1133 : // not recorded -> disallow
1134 0 : if (!bApi)
1135 0 : rDocShell.ErrorMessage(STR_PROTECTIONERR);
1136 :
1137 0 : return false;
1138 : }
1139 :
1140 106 : for (size_t i = 0, n = rRanges.size(); i < n; ++i)
1141 : {
1142 53 : const ScRange* p = rRanges[i];
1143 53 : ScEditableTester aTester(&rDoc, *p);
1144 53 : if (!aTester.IsEditable())
1145 : {
1146 0 : if (!bApi)
1147 0 : rDocShell.ErrorMessage(aTester.GetMessageId());
1148 :
1149 0 : return false;
1150 : }
1151 : }
1152 :
1153 53 : return true;
1154 : }
1155 :
1156 60 : void createUndoDoc(std::unique_ptr<ScDocument>& pUndoDoc, ScDocument* pDoc, const ScRange& rRange)
1157 : {
1158 60 : SCTAB nTab = rRange.aStart.Tab();
1159 60 : pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
1160 60 : pUndoDoc->InitUndo(pDoc, nTab, nTab);
1161 60 : pDoc->CopyToDocument(rRange, IDF_ALL, false, pUndoDoc.get());
1162 60 : }
1163 :
1164 29 : bool checkNewOutputRange(ScDPObject& rDPObj, ScDocShell& rDocShell, ScRange& rNewOut, bool bApi)
1165 : {
1166 29 : ScDocument& rDoc = rDocShell.GetDocument();
1167 :
1168 29 : bool bOverflow = false;
1169 29 : rNewOut = rDPObj.GetNewOutputRange(bOverflow);
1170 :
1171 : // Test for overlap with source data range.
1172 : // TODO: Check with other pivot tables as well.
1173 29 : const ScSheetSourceDesc* pSheetDesc = rDPObj.GetSheetDesc();
1174 29 : if (pSheetDesc && pSheetDesc->GetSourceRange().Intersects(rNewOut))
1175 : {
1176 : // New output range intersepts with the source data. Move it up to
1177 : // where the old range is and see if that works.
1178 0 : ScRange aOldRange = rDPObj.GetOutRange();
1179 0 : SCsROW nDiff = aOldRange.aStart.Row() - rNewOut.aStart.Row();
1180 0 : rNewOut.aStart.SetRow(aOldRange.aStart.Row());
1181 0 : rNewOut.aEnd.IncRow(nDiff);
1182 0 : if (!ValidRow(rNewOut.aStart.Row()) || !ValidRow(rNewOut.aEnd.Row()))
1183 0 : bOverflow = true;
1184 : }
1185 :
1186 29 : if (bOverflow)
1187 : {
1188 0 : if (!bApi)
1189 0 : rDocShell.ErrorMessage(STR_PIVOT_ERROR);
1190 :
1191 0 : return false;
1192 : }
1193 :
1194 29 : ScEditableTester aTester(&rDoc, rNewOut);
1195 29 : if (!aTester.IsEditable())
1196 : {
1197 : // destination area isn't editable
1198 0 : if (!bApi)
1199 0 : rDocShell.ErrorMessage(aTester.GetMessageId());
1200 :
1201 0 : return false;
1202 : }
1203 :
1204 29 : return true;
1205 : }
1206 :
1207 : }
1208 :
1209 21 : bool ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj,
1210 : bool bRecord, bool bApi, bool bAllowMove )
1211 : {
1212 21 : if (!pOldObj)
1213 : {
1214 0 : if (!pNewObj)
1215 0 : return false;
1216 :
1217 0 : return CreatePivotTable(*pNewObj, bRecord, bApi);
1218 : }
1219 :
1220 21 : if (pOldObj)
1221 : {
1222 21 : if (!pNewObj)
1223 0 : return RemovePivotTable(*pOldObj, bRecord, bApi);
1224 :
1225 21 : if (pOldObj == pNewObj)
1226 21 : return UpdatePivotTable(*pOldObj, bRecord, bApi);
1227 : }
1228 :
1229 : OSL_ASSERT(pOldObj && pNewObj && pOldObj != pNewObj);
1230 :
1231 0 : ScDocShellModificator aModificator( rDocShell );
1232 0 : WaitObject aWait( ScDocShell::GetActiveDialogParent() );
1233 :
1234 0 : ScRangeList aRanges;
1235 0 : aRanges.Append(pOldObj->GetOutRange());
1236 0 : aRanges.Append(pNewObj->GetOutRange().aStart); // at least one cell in the output position must be editable.
1237 0 : if (!isEditable(rDocShell, aRanges, bApi))
1238 0 : return false;
1239 :
1240 0 : std::unique_ptr<ScDocument> pOldUndoDoc;
1241 0 : std::unique_ptr<ScDocument> pNewUndoDoc;
1242 :
1243 0 : ScDPObject aUndoDPObj(*pOldObj); // for undo or revert on failure
1244 :
1245 0 : ScDocument& rDoc = rDocShell.GetDocument();
1246 0 : if (bRecord && !rDoc.IsUndoEnabled())
1247 0 : bRecord = false;
1248 :
1249 0 : if (bRecord)
1250 0 : createUndoDoc(pOldUndoDoc, &rDoc, pOldObj->GetOutRange());
1251 :
1252 0 : pNewObj->WriteSourceDataTo(*pOldObj); // copy source data
1253 :
1254 0 : ScDPSaveData* pData = pNewObj->GetSaveData();
1255 : OSL_ENSURE( pData, "no SaveData from living DPObject" );
1256 0 : if (pData)
1257 0 : pOldObj->SetSaveData(*pData); // copy SaveData
1258 :
1259 0 : pOldObj->SetAllowMove(bAllowMove);
1260 0 : pOldObj->ReloadGroupTableData();
1261 0 : pOldObj->SyncAllDimensionMembers();
1262 0 : pOldObj->InvalidateData(); // before getting the new output area
1263 :
1264 : // make sure the table has a name (not set by dialog)
1265 0 : if (pOldObj->GetName().isEmpty())
1266 0 : pOldObj->SetName( rDoc.GetDPCollection()->CreateNewName() );
1267 :
1268 0 : ScRange aNewOut;
1269 0 : if (!checkNewOutputRange(*pOldObj, rDocShell, aNewOut, bApi))
1270 : {
1271 0 : *pOldObj = aUndoDPObj;
1272 0 : return false;
1273 : }
1274 :
1275 : // test if new output area is empty except for old area
1276 0 : if (!bApi)
1277 : {
1278 : // OutRange of pOldObj (pDestObj) is still old area
1279 0 : if (!lcl_EmptyExcept(&rDoc, aNewOut, pOldObj->GetOutRange()))
1280 : {
1281 0 : ScopedVclPtrInstance<QueryBox> aBox( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1282 0 : ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) );
1283 0 : if (aBox->Execute() == RET_NO)
1284 : {
1285 : //! like above (not editable)
1286 0 : *pOldObj = aUndoDPObj;
1287 0 : return false;
1288 0 : }
1289 : }
1290 : }
1291 :
1292 0 : if (bRecord)
1293 0 : createUndoDoc(pNewUndoDoc, &rDoc, aNewOut);
1294 :
1295 0 : pOldObj->Output(aNewOut.aStart);
1296 0 : rDocShell.PostPaintGridAll(); //! only necessary parts
1297 :
1298 0 : if (bRecord)
1299 : {
1300 0 : rDocShell.GetUndoManager()->AddUndoAction(
1301 : new ScUndoDataPilot(
1302 0 : &rDocShell, pOldUndoDoc.release(), pNewUndoDoc.release(), &aUndoDPObj, pOldObj, bAllowMove));
1303 : }
1304 :
1305 : // notify API objects
1306 0 : rDoc.BroadcastUno( ScDataPilotModifiedHint(pOldObj->GetName()) );
1307 0 : aModificator.SetDocumentModified();
1308 :
1309 0 : return true;
1310 : }
1311 :
1312 2 : bool ScDBDocFunc::RemovePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi)
1313 : {
1314 2 : ScDocShellModificator aModificator(rDocShell);
1315 4 : WaitObject aWait(ScDocShell::GetActiveDialogParent());
1316 :
1317 2 : if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
1318 0 : return false;
1319 :
1320 4 : std::unique_ptr<ScDocument> pOldUndoDoc;
1321 4 : std::unique_ptr<ScDPObject> pUndoDPObj;
1322 :
1323 2 : if (bRecord)
1324 1 : pUndoDPObj.reset(new ScDPObject(rDPObj)); // copy old settings for undo
1325 :
1326 2 : ScDocument& rDoc = rDocShell.GetDocument();
1327 2 : if (bRecord && !rDoc.IsUndoEnabled())
1328 0 : bRecord = false;
1329 :
1330 : // delete table
1331 :
1332 2 : ScRange aRange = rDPObj.GetOutRange();
1333 2 : SCTAB nTab = aRange.aStart.Tab();
1334 :
1335 2 : if (bRecord)
1336 1 : createUndoDoc(pOldUndoDoc, &rDoc, aRange);
1337 :
1338 2 : rDoc.DeleteAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
1339 2 : aRange.aEnd.Col(), aRange.aEnd.Row(),
1340 6 : nTab, IDF_ALL );
1341 2 : rDoc.RemoveFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
1342 2 : aRange.aEnd.Col(), aRange.aEnd.Row(),
1343 6 : nTab, SC_MF_AUTO );
1344 :
1345 2 : rDoc.GetDPCollection()->FreeTable(&rDPObj); // object is deleted here
1346 :
1347 2 : rDocShell.PostPaintGridAll(); //! only necessary parts
1348 2 : rDocShell.PostPaint(aRange, PAINT_GRID);
1349 :
1350 2 : if (bRecord)
1351 : {
1352 1 : rDocShell.GetUndoManager()->AddUndoAction(
1353 : new ScUndoDataPilot(
1354 1 : &rDocShell, pOldUndoDoc.release(), NULL, pUndoDPObj.get(), NULL, false));
1355 :
1356 : // pUndoDPObj is copied
1357 : }
1358 :
1359 2 : aModificator.SetDocumentModified();
1360 4 : return true;
1361 : }
1362 :
1363 22 : bool ScDBDocFunc::CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi)
1364 : {
1365 22 : ScDocShellModificator aModificator(rDocShell);
1366 44 : WaitObject aWait(ScDocShell::GetActiveDialogParent());
1367 :
1368 : // At least one cell in the output range should be editable. Check in advance.
1369 22 : if (!isEditable(rDocShell, ScRange(rDPObj.GetOutRange().aStart), bApi))
1370 0 : return false;
1371 :
1372 44 : std::unique_ptr<ScDocument> pNewUndoDoc;
1373 :
1374 22 : ScDocument& rDoc = rDocShell.GetDocument();
1375 22 : if (bRecord && !rDoc.IsUndoEnabled())
1376 4 : bRecord = false;
1377 :
1378 : // output range must be set at pNewObj
1379 44 : std::unique_ptr<ScDPObject> pDestObj(new ScDPObject(rDPObj));
1380 :
1381 22 : ScDPObject& rDestObj = *pDestObj;
1382 :
1383 : // #i94570# When changing the output position in the dialog, a new table is created
1384 : // with the settings from the old table, including the name.
1385 : // So we have to check for duplicate names here (before inserting).
1386 22 : if (rDoc.GetDPCollection()->GetByName(rDestObj.GetName()))
1387 0 : rDestObj.SetName(OUString()); // ignore the invalid name, create a new name below
1388 :
1389 22 : if (!rDoc.GetDPCollection()->InsertNewTable(pDestObj.release()))
1390 : // Insertion into collection failed.
1391 0 : return false;
1392 :
1393 22 : rDestObj.ReloadGroupTableData();
1394 22 : rDestObj.SyncAllDimensionMembers();
1395 22 : rDestObj.InvalidateData(); // before getting the new output area
1396 :
1397 : // make sure the table has a name (not set by dialog)
1398 22 : if (rDestObj.GetName().isEmpty())
1399 1 : rDestObj.SetName(rDoc.GetDPCollection()->CreateNewName());
1400 :
1401 22 : bool bOverflow = false;
1402 22 : ScRange aNewOut = rDestObj.GetNewOutputRange(bOverflow);
1403 :
1404 22 : if (bOverflow)
1405 : {
1406 0 : if (!bApi)
1407 0 : rDocShell.ErrorMessage(STR_PIVOT_ERROR);
1408 :
1409 0 : return false;
1410 : }
1411 :
1412 : {
1413 22 : ScEditableTester aTester(&rDoc, aNewOut);
1414 22 : if (!aTester.IsEditable())
1415 : {
1416 : // destination area isn't editable
1417 0 : if (!bApi)
1418 0 : rDocShell.ErrorMessage(aTester.GetMessageId());
1419 :
1420 0 : return false;
1421 : }
1422 : }
1423 :
1424 : // test if new output area is empty except for old area
1425 22 : if (!bApi)
1426 : {
1427 : bool bEmpty = rDoc.IsBlockEmpty(
1428 0 : aNewOut.aStart.Tab(), aNewOut.aStart.Col(), aNewOut.aStart.Row(),
1429 0 : aNewOut.aEnd.Col(), aNewOut.aEnd.Row());
1430 :
1431 0 : if (!bEmpty)
1432 : {
1433 : ScopedVclPtrInstance<QueryBox> aBox(
1434 0 : ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1435 0 : ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY));
1436 :
1437 0 : if (aBox->Execute() == RET_NO)
1438 : {
1439 : //! like above (not editable)
1440 0 : return false;
1441 0 : }
1442 : }
1443 : }
1444 :
1445 22 : if (bRecord)
1446 17 : createUndoDoc(pNewUndoDoc, &rDoc, aNewOut);
1447 :
1448 22 : rDestObj.Output(aNewOut.aStart);
1449 22 : rDocShell.PostPaintGridAll(); //! only necessary parts
1450 :
1451 22 : if (bRecord)
1452 : {
1453 17 : rDocShell.GetUndoManager()->AddUndoAction(
1454 17 : new ScUndoDataPilot(&rDocShell, NULL, pNewUndoDoc.release(), NULL, &rDestObj, false));
1455 : }
1456 :
1457 : // notify API objects
1458 22 : rDoc.BroadcastUno(ScDataPilotModifiedHint(rDestObj.GetName()));
1459 22 : aModificator.SetDocumentModified();
1460 :
1461 44 : return true;
1462 : }
1463 :
1464 29 : bool ScDBDocFunc::UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi)
1465 : {
1466 29 : ScDocShellModificator aModificator( rDocShell );
1467 58 : WaitObject aWait( ScDocShell::GetActiveDialogParent() );
1468 :
1469 29 : if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
1470 0 : return false;
1471 :
1472 58 : std::unique_ptr<ScDocument> pOldUndoDoc;
1473 58 : std::unique_ptr<ScDocument> pNewUndoDoc;
1474 :
1475 58 : ScDPObject aUndoDPObj(rDPObj); // For undo or revert on failure.
1476 :
1477 29 : ScDocument& rDoc = rDocShell.GetDocument();
1478 29 : if (bRecord && !rDoc.IsUndoEnabled())
1479 0 : bRecord = false;
1480 :
1481 29 : if (bRecord)
1482 21 : createUndoDoc(pOldUndoDoc, &rDoc, rDPObj.GetOutRange());
1483 :
1484 29 : rDPObj.SetAllowMove(false);
1485 29 : rDPObj.ReloadGroupTableData();
1486 29 : if (!rDPObj.SyncAllDimensionMembers())
1487 0 : return false;
1488 :
1489 29 : rDPObj.InvalidateData(); // before getting the new output area
1490 :
1491 : // make sure the table has a name (not set by dialog)
1492 29 : if (rDPObj.GetName().isEmpty())
1493 0 : rDPObj.SetName( rDoc.GetDPCollection()->CreateNewName() );
1494 :
1495 29 : ScRange aNewOut;
1496 29 : if (!checkNewOutputRange(rDPObj, rDocShell, aNewOut, bApi))
1497 : {
1498 0 : rDPObj = aUndoDPObj;
1499 0 : return false;
1500 : }
1501 :
1502 : // test if new output area is empty except for old area
1503 29 : if (!bApi)
1504 : {
1505 4 : if (!lcl_EmptyExcept(&rDoc, aNewOut, rDPObj.GetOutRange()))
1506 : {
1507 0 : ScopedVclPtrInstance<QueryBox> aBox( ScDocShell::GetActiveDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
1508 0 : ScGlobal::GetRscString(STR_PIVOT_NOTEMPTY) );
1509 0 : if (aBox->Execute() == RET_NO)
1510 : {
1511 0 : rDPObj = aUndoDPObj;
1512 0 : return false;
1513 0 : }
1514 : }
1515 : }
1516 :
1517 29 : if (bRecord)
1518 21 : createUndoDoc(pNewUndoDoc, &rDoc, aNewOut);
1519 :
1520 29 : rDPObj.Output(aNewOut.aStart);
1521 29 : rDocShell.PostPaintGridAll(); //! only necessary parts
1522 :
1523 29 : if (bRecord)
1524 : {
1525 21 : rDocShell.GetUndoManager()->AddUndoAction(
1526 : new ScUndoDataPilot(
1527 21 : &rDocShell, pOldUndoDoc.release(), pNewUndoDoc.release(), &aUndoDPObj, &rDPObj, false));
1528 : }
1529 :
1530 : // notify API objects
1531 29 : rDoc.BroadcastUno( ScDataPilotModifiedHint(rDPObj.GetName()) );
1532 29 : aModificator.SetDocumentModified();
1533 58 : return true;
1534 : }
1535 :
1536 2 : sal_uLong ScDBDocFunc::RefreshPivotTables(ScDPObject* pDPObj, bool bApi)
1537 : {
1538 2 : ScDPCollection* pDPs = rDocShell.GetDocument().GetDPCollection();
1539 2 : if (!pDPs)
1540 0 : return 0;
1541 :
1542 2 : std::set<ScDPObject*> aRefs;
1543 2 : sal_uLong nErrId = pDPs->ReloadCache(pDPObj, aRefs);
1544 2 : if (nErrId)
1545 0 : return nErrId;
1546 :
1547 2 : std::set<ScDPObject*>::iterator it = aRefs.begin(), itEnd = aRefs.end();
1548 6 : for (; it != itEnd; ++it)
1549 : {
1550 4 : ScDPObject* pObj = *it;
1551 :
1552 : // This action is intentionally not undoable since it modifies cache.
1553 4 : UpdatePivotTable(*pObj, false, bApi);
1554 : }
1555 :
1556 2 : return 0;
1557 : }
1558 :
1559 4 : void ScDBDocFunc::RefreshPivotTableGroups(ScDPObject* pDPObj)
1560 : {
1561 4 : if (!pDPObj)
1562 0 : return;
1563 :
1564 4 : ScDPCollection* pDPs = rDocShell.GetDocument().GetDPCollection();
1565 4 : if (!pDPs)
1566 0 : return;
1567 :
1568 4 : ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1569 4 : if (!pSaveData)
1570 0 : return;
1571 :
1572 4 : std::set<ScDPObject*> aRefs;
1573 4 : if (!pDPs->ReloadGroupsInCache(pDPObj, aRefs))
1574 0 : return;
1575 :
1576 : // We allow pDimData being NULL.
1577 4 : const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
1578 4 : std::set<ScDPObject*>::iterator it = aRefs.begin(), itEnd = aRefs.end();
1579 8 : for (; it != itEnd; ++it)
1580 : {
1581 4 : ScDPObject* pObj = *it;
1582 4 : if (pObj != pDPObj)
1583 : {
1584 0 : pSaveData = pObj->GetSaveData();
1585 0 : if (pSaveData)
1586 0 : pSaveData->SetDimensionData(pDimData);
1587 : }
1588 :
1589 : // This action is intentionally not undoable since it modifies cache.
1590 4 : UpdatePivotTable(*pObj, false, false);
1591 4 : }
1592 : }
1593 :
1594 : // database import
1595 :
1596 0 : void ScDBDocFunc::UpdateImport( const OUString& rTarget, const svx::ODataAccessDescriptor& rDescriptor )
1597 : {
1598 : // rTarget is the name of a database range
1599 :
1600 0 : ScDocument& rDoc = rDocShell.GetDocument();
1601 0 : ScDBCollection& rDBColl = *rDoc.GetDBCollection();
1602 0 : const ScDBData* pData = rDBColl.getNamedDBs().findByUpperName(ScGlobal::pCharClass->uppercase(rTarget));
1603 0 : if (!pData)
1604 : {
1605 0 : ScopedVclPtrInstance<InfoBox> aInfoBox( ScDocShell::GetActiveDialogParent(),
1606 0 : ScGlobal::GetRscString( STR_TARGETNOTFOUND ) );
1607 0 : aInfoBox->Execute();
1608 0 : return;
1609 : }
1610 :
1611 : SCTAB nTab;
1612 : SCCOL nDummyCol;
1613 : SCROW nDummyRow;
1614 0 : pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
1615 :
1616 0 : ScImportParam aImportParam;
1617 0 : pData->GetImportParam( aImportParam );
1618 :
1619 0 : OUString sDBName;
1620 0 : OUString sDBTable;
1621 0 : sal_Int32 nCommandType = 0;
1622 0 : sDBName = rDescriptor.getDataSource();
1623 0 : rDescriptor[svx::daCommand] >>= sDBTable;
1624 0 : rDescriptor[svx::daCommandType] >>= nCommandType;
1625 :
1626 0 : aImportParam.aDBName = sDBName;
1627 0 : aImportParam.bSql = ( nCommandType == sdb::CommandType::COMMAND );
1628 0 : aImportParam.aStatement = sDBTable;
1629 0 : aImportParam.bNative = false;
1630 0 : aImportParam.nType = static_cast<sal_uInt8>( ( nCommandType == sdb::CommandType::QUERY ) ? ScDbQuery : ScDbTable );
1631 0 : aImportParam.bImport = true;
1632 :
1633 0 : bool bContinue = DoImport( nTab, aImportParam, &rDescriptor, true );
1634 :
1635 : // DB-Operationen wiederholen
1636 :
1637 0 : ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
1638 0 : if (pViewSh)
1639 : {
1640 0 : ScRange aRange;
1641 0 : pData->GetArea(aRange);
1642 0 : pViewSh->MarkRange(aRange); // selektieren
1643 :
1644 0 : if ( bContinue ) // Fehler beim Import -> Abbruch
1645 : {
1646 : // interne Operationen, wenn welche gespeichert
1647 :
1648 0 : if ( pData->HasQueryParam() || pData->HasSortParam() || pData->HasSubTotalParam() )
1649 0 : pViewSh->RepeatDB();
1650 :
1651 : // Pivottabellen die den Bereich als Quelldaten haben
1652 :
1653 0 : rDocShell.RefreshPivotTables(aRange);
1654 : }
1655 0 : }
1656 156 : }
1657 :
1658 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|