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