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