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