1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_sc.hxx"
24
25 // INCLUDE ---------------------------------------------------------------
26
27 #include "dbfunc.hxx"
28 #include "scitems.hxx"
29 #include <sfx2/bindings.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/msgbox.hxx>
32 #include <vcl/waitobj.hxx>
33 #include <svl/zforlist.hxx>
34 #include <sfx2/app.hxx>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/container/XNameAccess.hpp>
37 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
38 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
39 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
40 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
41 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
42 #include <com/sun/star/sheet/GeneralFunction.hpp>
43 #include <com/sun/star/sheet/MemberResultFlags.hpp>
44 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
45 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
46
47 #include "global.hxx"
48 #include "globstr.hrc"
49 #include "sc.hrc"
50 #include "undotab.hxx"
51 #include "undodat.hxx"
52 #include "dbcolect.hxx"
53 #include "rangenam.hxx"
54 #include "rangeutl.hxx"
55 #include "docsh.hxx"
56 #include "olinetab.hxx"
57 #include "consoli.hxx"
58 #include "olinefun.hxx"
59 #include "dpobject.hxx"
60 #include "dpsave.hxx"
61 #include "dpdimsave.hxx"
62 #include "dbdocfun.hxx"
63 #include "dpoutput.hxx"
64 #include "dptabsrc.hxx"
65 #include "editable.hxx"
66 #include "docpool.hxx"
67 #include "patattr.hxx"
68 #include "unonames.hxx"
69 #include "cell.hxx"
70 #include "userlist.hxx"
71
72 #include <hash_set>
73 #include <hash_map>
74 #include <memory>
75 #include <list>
76 #include <vector>
77
78 using namespace com::sun::star;
79 using ::com::sun::star::uno::Any;
80 using ::com::sun::star::uno::Sequence;
81 using ::com::sun::star::uno::Reference;
82 using ::com::sun::star::uno::UNO_QUERY;
83 using ::com::sun::star::beans::XPropertySet;
84 using ::com::sun::star::container::XNameAccess;
85 using ::com::sun::star::sheet::XDimensionsSupplier;
86 using ::rtl::OUString;
87 using ::rtl::OUStringHash;
88 using ::rtl::OUStringBuffer;
89 using ::std::auto_ptr;
90 using ::std::list;
91 using ::std::vector;
92 using ::std::hash_map;
93 using ::std::hash_set;
94
95 // STATIC DATA -----------------------------------------------------------
96
97 //==================================================================
98
99 //
100 // Outliner
101 //
102
103 // Outline-Gruppierung erzeugen
104
MakeOutline(sal_Bool bColumns,sal_Bool bRecord)105 void ScDBFunc::MakeOutline( sal_Bool bColumns, sal_Bool bRecord )
106 {
107 ScRange aRange;
108 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
109 {
110 ScDocShell* pDocSh = GetViewData()->GetDocShell();
111 ScOutlineDocFunc aFunc(*pDocSh);
112 aFunc.MakeOutline( aRange, bColumns, bRecord, sal_False );
113 }
114 else
115 ErrorMessage(STR_NOMULTISELECT);
116 }
117
118 // Outline-Gruppierung löschen
119
RemoveOutline(sal_Bool bColumns,sal_Bool bRecord)120 void ScDBFunc::RemoveOutline( sal_Bool bColumns, sal_Bool bRecord )
121 {
122 ScRange aRange;
123 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
124 {
125 ScDocShell* pDocSh = GetViewData()->GetDocShell();
126 ScOutlineDocFunc aFunc(*pDocSh);
127 aFunc.RemoveOutline( aRange, bColumns, bRecord, sal_False );
128 }
129 else
130 ErrorMessage(STR_NOMULTISELECT);
131 }
132
133 // Menue-Status: Outlines löschen
134
TestRemoveOutline(sal_Bool & rCol,sal_Bool & rRow)135 void ScDBFunc::TestRemoveOutline( sal_Bool& rCol, sal_Bool& rRow )
136 {
137 sal_Bool bColFound = sal_False;
138 sal_Bool bRowFound = sal_False;
139
140 SCCOL nStartCol, nEndCol;
141 SCROW nStartRow, nEndRow;
142 SCTAB nStartTab, nEndTab;
143 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
144 {
145 SCTAB nTab = nStartTab;
146 ScDocument* pDoc = GetViewData()->GetDocument();
147 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
148 if (pTable)
149 {
150 ScOutlineArray* pArray;
151 ScOutlineEntry* pEntry;
152 SCCOLROW nStart;
153 SCCOLROW nEnd;
154 sal_Bool bColMarked = ( nStartRow == 0 && nEndRow == MAXROW );
155 sal_Bool bRowMarked = ( nStartCol == 0 && nEndCol == MAXCOL );
156
157 // Spalten
158
159 if ( !bRowMarked || bColMarked ) // nicht wenn ganze Zeilen markiert
160 {
161 pArray = pTable->GetColArray();
162 ScSubOutlineIterator aColIter( pArray );
163 while ((pEntry=aColIter.GetNext()) != NULL && !bColFound)
164 {
165 nStart = pEntry->GetStart();
166 nEnd = pEntry->GetEnd();
167 if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
168 bColFound = sal_True;
169 }
170 }
171
172 // Zeilen
173
174 if ( !bColMarked || bRowMarked ) // nicht wenn ganze Spalten markiert
175 {
176 pArray = pTable->GetRowArray();
177 ScSubOutlineIterator aRowIter( pArray );
178 while ((pEntry=aRowIter.GetNext()) != NULL && !bRowFound)
179 {
180 nStart = pEntry->GetStart();
181 nEnd = pEntry->GetEnd();
182 if ( nStartRow<=nEnd && nEndRow>=nStart )
183 bRowFound = sal_True;
184 }
185 }
186 }
187 }
188
189 rCol = bColFound;
190 rRow = bRowFound;
191 }
192
RemoveAllOutlines(sal_Bool bRecord)193 void ScDBFunc::RemoveAllOutlines( sal_Bool bRecord )
194 {
195 SCTAB nTab = GetViewData()->GetTabNo();
196 ScDocShell* pDocSh = GetViewData()->GetDocShell();
197 ScOutlineDocFunc aFunc(*pDocSh);
198
199 HideCursor();
200 sal_Bool bOk = aFunc.RemoveAllOutlines( nTab, bRecord, sal_False );
201 ShowCursor();
202
203 if (bOk)
204 UpdateScrollBars();
205 }
206
207 // Auto-Outlines
208
AutoOutline(sal_Bool bRecord)209 void ScDBFunc::AutoOutline( sal_Bool bRecord )
210 {
211 SCTAB nTab = GetViewData()->GetTabNo();
212 ScRange aRange( 0,0,nTab, MAXCOL,MAXROW,nTab ); // ganze Tabelle, wenn nichts markiert
213 ScMarkData& rMark = GetViewData()->GetMarkData();
214 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
215 {
216 rMark.MarkToMulti();
217 rMark.GetMultiMarkArea( aRange );
218 }
219
220 ScDocShell* pDocSh = GetViewData()->GetDocShell();
221 ScOutlineDocFunc aFunc(*pDocSh);
222 aFunc.AutoOutline( aRange, bRecord, sal_False );
223 }
224
225 // Outline-Ebene auswählen
226
SelectLevel(sal_Bool bColumns,sal_uInt16 nLevel,sal_Bool bRecord,sal_Bool bPaint)227 void ScDBFunc::SelectLevel( sal_Bool bColumns, sal_uInt16 nLevel, sal_Bool bRecord, sal_Bool bPaint )
228 {
229 SCTAB nTab = GetViewData()->GetTabNo();
230 ScDocShell* pDocSh = GetViewData()->GetDocShell();
231 ScOutlineDocFunc aFunc(*pDocSh);
232
233 HideCursor();
234 sal_Bool bOk = aFunc.SelectLevel( nTab, bColumns, nLevel, bRecord, bPaint, sal_False );
235 ShowCursor();
236
237 if (bOk)
238 UpdateScrollBars();
239 }
240
241 // einzelne Outline-Gruppe einblenden
242
ShowOutline(sal_Bool bColumns,sal_uInt16 nLevel,sal_uInt16 nEntry,sal_Bool bRecord,sal_Bool bPaint)243 void ScDBFunc::ShowOutline( sal_Bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bRecord, sal_Bool bPaint )
244 {
245 SCTAB nTab = GetViewData()->GetTabNo();
246 ScDocShell* pDocSh = GetViewData()->GetDocShell();
247 ScOutlineDocFunc aFunc(*pDocSh);
248
249 HideCursor();
250 sal_Bool bOk = aFunc.ShowOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint, sal_False );
251 ShowCursor();
252
253 if ( bOk && bPaint )
254 UpdateScrollBars();
255 }
256
257 // einzelne Outline-Gruppe ausblenden
258
HideOutline(sal_Bool bColumns,sal_uInt16 nLevel,sal_uInt16 nEntry,sal_Bool bRecord,sal_Bool bPaint)259 void ScDBFunc::HideOutline( sal_Bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bRecord, sal_Bool bPaint )
260 {
261 SCTAB nTab = GetViewData()->GetTabNo();
262 ScDocShell* pDocSh = GetViewData()->GetDocShell();
263 ScOutlineDocFunc aFunc(*pDocSh);
264
265 HideCursor();
266 sal_Bool bOk = aFunc.HideOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint, sal_False );
267 ShowCursor();
268
269 if ( bOk && bPaint )
270 UpdateScrollBars();
271 }
272
273 // Menü-Status: markierten Bereich ein-/ausblenden
274
OutlinePossible(sal_Bool bHide)275 sal_Bool ScDBFunc::OutlinePossible(sal_Bool bHide)
276 {
277 sal_Bool bEnable = sal_False;
278
279 SCCOL nStartCol;
280 SCROW nStartRow;
281 SCTAB nStartTab;
282 SCCOL nEndCol;
283 SCROW nEndRow;
284 SCTAB nEndTab;
285
286 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
287 {
288 ScDocument* pDoc = GetViewData()->GetDocument();
289 SCTAB nTab = GetViewData()->GetTabNo();
290 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
291 if (pTable)
292 {
293 ScOutlineArray* pArray;
294 ScOutlineEntry* pEntry;
295 SCCOLROW nStart;
296 SCCOLROW nEnd;
297
298 // Columns
299
300 pArray = pTable->GetColArray();
301 ScSubOutlineIterator aColIter( pArray );
302 while ((pEntry=aColIter.GetNext()) != NULL && !bEnable)
303 {
304 nStart = pEntry->GetStart();
305 nEnd = pEntry->GetEnd();
306 if ( bHide )
307 {
308 if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
309 if (!pEntry->IsHidden())
310 bEnable = sal_True;
311 }
312 else
313 {
314 if ( nStart>=nStartCol && nEnd<=nEndCol )
315 if (pEntry->IsHidden())
316 bEnable = sal_True;
317 }
318 }
319
320 // Rows
321
322 pArray = pTable->GetRowArray();
323 ScSubOutlineIterator aRowIter( pArray );
324 while ((pEntry=aRowIter.GetNext()) != NULL)
325 {
326 nStart = pEntry->GetStart();
327 nEnd = pEntry->GetEnd();
328 if ( bHide )
329 {
330 if ( nStartRow<=nEnd && nEndRow>=nStart )
331 if (!pEntry->IsHidden())
332 bEnable = sal_True;
333 }
334 else
335 {
336 if ( nStart>=nStartRow && nEnd<=nEndRow )
337 if (pEntry->IsHidden())
338 bEnable = sal_True;
339 }
340 }
341 }
342 }
343
344 return bEnable;
345 }
346
347 // markierten Bereich einblenden
348
ShowMarkedOutlines(sal_Bool bRecord)349 void ScDBFunc::ShowMarkedOutlines( sal_Bool bRecord )
350 {
351 ScRange aRange;
352 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
353 {
354 ScDocShell* pDocSh = GetViewData()->GetDocShell();
355 ScOutlineDocFunc aFunc(*pDocSh);
356 HideCursor();
357 sal_Bool bDone = aFunc.ShowMarkedOutlines( aRange, bRecord, sal_False );
358 ShowCursor();
359 if (bDone)
360 UpdateScrollBars();
361 }
362 else
363 ErrorMessage(STR_NOMULTISELECT);
364 }
365
366 // markierten Bereich ausblenden
367
HideMarkedOutlines(sal_Bool bRecord)368 void ScDBFunc::HideMarkedOutlines( sal_Bool bRecord )
369 {
370 ScRange aRange;
371 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
372 {
373 ScDocShell* pDocSh = GetViewData()->GetDocShell();
374 ScOutlineDocFunc aFunc(*pDocSh);
375 HideCursor();
376 sal_Bool bDone = aFunc.HideMarkedOutlines( aRange, bRecord, sal_False );
377 ShowCursor();
378 if (bDone)
379 UpdateScrollBars();
380 }
381 else
382 ErrorMessage(STR_NOMULTISELECT);
383 }
384
385 // --------------------------------------------------------------------------
386
387 //
388 // Teilergebnisse
389 //
390
DoSubTotals(const ScSubTotalParam & rParam,sal_Bool bRecord,const ScSortParam * pForceNewSort)391 void ScDBFunc::DoSubTotals( const ScSubTotalParam& rParam, sal_Bool bRecord,
392 const ScSortParam* pForceNewSort )
393 {
394 sal_Bool bDo = !rParam.bRemoveOnly; // sal_False = nur löschen
395
396 ScDocShell* pDocSh = GetViewData()->GetDocShell();
397 ScDocument* pDoc = pDocSh->GetDocument();
398 ScMarkData& rMark = GetViewData()->GetMarkData();
399 SCTAB nTab = GetViewData()->GetTabNo();
400 if (bRecord && !pDoc->IsUndoEnabled())
401 bRecord = sal_False;
402
403 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
404 rParam.nCol2, rParam.nRow2 );
405 if (!pDBData)
406 {
407 DBG_ERROR( "SubTotals: no DBData" );
408 return;
409 }
410
411 ScEditableTester aTester( pDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW );
412 if (!aTester.IsEditable())
413 {
414 ErrorMessage(aTester.GetMessageId());
415 return;
416 }
417
418 if (pDoc->HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
419 rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
420 {
421 ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfügen
422 return;
423 }
424
425 WaitObject aWait( GetViewData()->GetDialogParent() );
426 sal_Bool bOk = sal_True;
427 sal_Bool bDelete = sal_False;
428 if (rParam.bReplace)
429 if (pDoc->TestRemoveSubTotals( nTab, rParam ))
430 {
431 bDelete = sal_True;
432 bOk = ( MessBox( GetViewData()->GetDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
433 // "Calc" "Daten löschen?"
434 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
435 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) ).Execute()
436 == RET_YES );
437 }
438
439 if (bOk)
440 {
441 ScDocShellModificator aModificator( *pDocSh );
442
443 ScSubTotalParam aNewParam( rParam ); // Bereichsende wird verändert
444 ScDocument* pUndoDoc = NULL;
445 ScOutlineTable* pUndoTab = NULL;
446 ScRangeName* pUndoRange = NULL;
447 ScDBCollection* pUndoDB = NULL;
448 SCTAB nTabCount = 0; // für Referenz-Undo
449
450 if (bRecord) // alte Daten sichern
451 {
452 sal_Bool bOldFilter = bDo && rParam.bDoSort;
453
454 nTabCount = pDoc->GetTableCount();
455 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
456 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
457 if (pTable)
458 {
459 pUndoTab = new ScOutlineTable( *pTable );
460
461 SCCOLROW nOutStartCol; // Zeilen/Spaltenstatus
462 SCCOLROW nOutStartRow;
463 SCCOLROW nOutEndCol;
464 SCCOLROW nOutEndRow;
465 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
466 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
467
468 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True );
469 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, sal_False, pUndoDoc );
470 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, sal_False, pUndoDoc );
471 }
472 else
473 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_False, bOldFilter );
474
475 // Datenbereich sichern - incl. Filter-Ergebnis
476 pDoc->CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab,
477 IDF_ALL, sal_False, pUndoDoc );
478
479 // alle Formeln wegen Referenzen
480 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
481 IDF_FORMULA, sal_False, pUndoDoc );
482
483 // DB- und andere Bereiche
484 ScRangeName* pDocRange = pDoc->GetRangeName();
485 if (pDocRange->GetCount())
486 pUndoRange = new ScRangeName( *pDocRange );
487 ScDBCollection* pDocDB = pDoc->GetDBCollection();
488 if (pDocDB->GetCount())
489 pUndoDB = new ScDBCollection( *pDocDB );
490 }
491
492 // pDoc->SetOutlineTable( nTab, NULL );
493 ScOutlineTable* pOut = pDoc->GetOutlineTable( nTab );
494 if (pOut)
495 pOut->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines löschen
496
497 if (rParam.bReplace)
498 pDoc->RemoveSubTotals( nTab, aNewParam );
499 sal_Bool bSuccess = sal_True;
500 if (bDo)
501 {
502 // Sortieren
503 if ( rParam.bDoSort || pForceNewSort )
504 {
505 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
506
507 // Teilergebnis-Felder vor die Sortierung setzen
508 // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
509
510 ScSortParam aOldSort;
511 pDBData->GetSortParam( aOldSort );
512 ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
513 Sort( aSortParam, sal_False, sal_False );
514 }
515
516 bSuccess = pDoc->DoSubTotals( nTab, aNewParam );
517 }
518 ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
519 aNewParam.nCol2, aNewParam.nRow2, nTab );
520 pDoc->SetDirty( aDirtyRange );
521
522 if (bRecord)
523 {
524 // ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
525 pDocSh->GetUndoManager()->AddUndoAction(
526 new ScUndoSubTotals( pDocSh, nTab,
527 rParam, aNewParam.nRow2,
528 pUndoDoc, pUndoTab, // pUndoDBData,
529 pUndoRange, pUndoDB ) );
530 }
531
532 if (!bSuccess)
533 {
534 // "Kann keine Zeilen einfügen"
535 ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
536 }
537
538 // merken
539 pDBData->SetSubTotalParam( aNewParam );
540 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
541 pDoc->CompileDBFormula();
542
543 DoneBlockMode();
544 InitOwnBlockMode();
545 rMark.SetMarkArea( ScRange( aNewParam.nCol1,aNewParam.nRow1,nTab,
546 aNewParam.nCol2,aNewParam.nRow2,nTab ) );
547 MarkDataChanged();
548
549 pDocSh->PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
550 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE );
551
552 aModificator.SetDocumentModified();
553
554 SelectionChanged();
555 }
556 }
557
558 //
559 // Consolidate
560 //
561
Consolidate(const ScConsolidateParam & rParam,sal_Bool bRecord)562 void ScDBFunc::Consolidate( const ScConsolidateParam& rParam, sal_Bool bRecord )
563 {
564 ScDocShell* pDocShell = GetViewData()->GetDocShell();
565 pDocShell->DoConsolidate( rParam, bRecord );
566 SetTabNo( rParam.nTab, sal_True );
567 }
568
569 //
570 // Pivot
571 //
572
lcl_MakePivotTabName(const String & rPrefix,SCTAB nNumber)573 String lcl_MakePivotTabName( const String& rPrefix, SCTAB nNumber )
574 {
575 String aName = rPrefix;
576 aName += String::CreateFromInt32( nNumber );
577 return aName;
578 }
579
MakePivotTable(const ScDPSaveData & rData,const ScRange & rDest,sal_Bool bNewTable,const ScDPObject & rSource,sal_Bool bApi)580 bool ScDBFunc::MakePivotTable( const ScDPSaveData& rData, const ScRange& rDest, sal_Bool bNewTable,
581 const ScDPObject& rSource, sal_Bool bApi )
582 {
583 // #70096# error message if no fields are set
584 // this must be removed when drag&drop of fields from a toolbox is available
585
586 if ( rData.IsEmpty() && !bApi )
587 {
588 ErrorMessage(STR_PIVOT_NODATA);
589 return false;
590 }
591
592 ScDocShell* pDocSh = GetViewData()->GetDocShell();
593 ScDocument* pDoc = GetViewData()->GetDocument();
594 sal_Bool bUndo(pDoc->IsUndoEnabled());
595
596 ScRange aDestRange = rDest;
597 if ( bNewTable )
598 {
599 SCTAB nSrcTab = GetViewData()->GetTabNo();
600
601 String aName( ScGlobal::GetRscString(STR_PIVOT_TABLE) );
602 String aStr;
603
604 pDoc->GetName( nSrcTab, aStr );
605 aName += '_';
606 aName += aStr;
607 aName += '_';
608
609 SCTAB nNewTab = nSrcTab+1;
610
611 const bool bDrawUndo = ( bUndo && !pDoc->IsDrawRecording() );
612
613 if( bDrawUndo )
614 pDoc->BeginDrawUndo();
615
616 SCTAB i=1;
617 while ( !pDoc->InsertTab( nNewTab, lcl_MakePivotTabName( aName, i ) ) && i <= MAXTAB )
618 i++;
619
620 sal_Bool bAppend = ( nNewTab+1 == pDoc->GetTableCount() );
621 if (bUndo)
622 {
623 pDocSh->GetUndoManager()->AddUndoAction(
624 new ScUndoInsertTab( pDocSh, nNewTab, bAppend, lcl_MakePivotTabName( aName, i ) ));
625 }
626
627 GetViewData()->InsertTab( nNewTab );
628 SetTabNo( nNewTab, sal_True );
629
630 aDestRange = ScRange( 0, 0, nNewTab );
631
632 if( bDrawUndo )
633 pDoc->EndDrawUndo();
634 }
635
636 ScDPObject* pDPObj = pDoc->GetDPAtCursor(
637 aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aStart.Tab() );
638
639 ScDPObject aObj( rSource );
640 aObj.SetOutRange( aDestRange );
641 if ( pDPObj && !rData.GetExistingDimensionData() )
642 {
643 // copy dimension data from old object - lost in the dialog
644 //! change the dialog to keep the dimension data
645
646 ScDPSaveData aNewData( rData );
647 const ScDPSaveData* pOldData = pDPObj->GetSaveData();
648 if ( pOldData )
649 {
650 const ScDPDimensionSaveData* pDimSave = pOldData->GetExistingDimensionData();
651 aNewData.SetDimensionData( pDimSave );
652 }
653 aObj.SetSaveData( aNewData );
654 }
655 else
656 aObj.SetSaveData( rData );
657
658 sal_Bool bAllowMove = ( pDPObj != NULL ); // allow re-positioning when editing existing table
659
660 ScDBDocFunc aFunc( *pDocSh );
661 bool bSuccess = aFunc.DataPilotUpdate( pDPObj, &aObj, sal_True, sal_False, bAllowMove );
662
663 CursorPosChanged(); // shells may be switched
664
665 if ( bNewTable )
666 {
667 pDocSh->PostPaintExtras();
668 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
669 }
670
671 return bSuccess;
672 }
673
DeletePivotTable()674 void ScDBFunc::DeletePivotTable()
675 {
676 ScDocShell* pDocSh = GetViewData()->GetDocShell();
677 ScDocument* pDoc = pDocSh->GetDocument();
678 ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(),
679 GetViewData()->GetCurY(),
680 GetViewData()->GetTabNo() );
681 if ( pDPObj )
682 {
683 ScDBDocFunc aFunc( *pDocSh );
684 aFunc.DataPilotUpdate( pDPObj, NULL, sal_True, sal_False );
685 CursorPosChanged(); // shells may be switched
686 }
687 else
688 ErrorMessage(STR_PIVOT_NOTFOUND);
689 }
RefreshDPObject(ScDPObject * pDPObj,ScDocument * pDoc,ScDocShell * pDocSh,sal_Bool bRecord,sal_Bool bApi)690 sal_uLong RefreshDPObject( ScDPObject *pDPObj, ScDocument *pDoc, ScDocShell *pDocSh, sal_Bool bRecord, sal_Bool bApi )
691 {
692 if( !pDPObj )
693 return STR_PIVOT_NOTFOUND;
694
695 if ( pDocSh && !pDoc )
696 pDoc = pDocSh->GetDocument();
697
698 if( !pDoc )
699 return static_cast<sal_uLong>(-1);
700
701 if( !pDocSh && ( pDocSh = PTR_CAST( ScDocShell, pDoc->GetDocumentShell() ) ) == NULL )
702 return static_cast<sal_uLong>(-1);
703
704 if( sal_uLong nErrId = pDPObj->RefreshCache() )
705 return nErrId;
706 else if ( nErrId == 0 )
707 {
708 // Refresh all dpobjects
709 ScDPCollection* pDPCollection = pDoc->GetDPCollection();
710 sal_uInt16 nCount = pDPCollection->GetCount();
711 for (sal_uInt16 i=0; i<nCount; i++)
712 {
713 if ( (*pDPCollection)[i]->GetCacheId() == pDPObj->GetCacheId() )
714 {
715 ScDBDocFunc aFunc( * pDocSh );
716 if ( !aFunc.DataPilotUpdate( (*pDPCollection)[i], (*pDPCollection)[i], bRecord, bApi ) )
717 break;
718 }
719 }
720
721 return nErrId;
722 }
723
724 return 0U;
725 }
726
RecalcPivotTable()727 sal_uLong ScDBFunc::RecalcPivotTable()
728 {
729 ScDocShell* pDocSh = GetViewData()->GetDocShell();
730 ScDocument* pDoc = GetViewData()->GetDocument();
731
732 // old pivot not used any more
733
734 ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(),
735 GetViewData()->GetCurY(),
736 GetViewData()->GetTabNo() );
737 if ( pDPObj )
738 {
739 // Wang Xu Ming -- 2009-6-17
740 // DataPilot Migration
741 //ScDBDocFunc aFunc( *pDocSh );
742 //aFunc.DataPilotUpdate( pDPObj, pDPObj, sal_True, sal_False );
743 //CursorPosChanged(); // shells may be switched
744 sal_uLong nErrId = RefreshDPObject( pDPObj, pDoc, pDocSh, sal_True, sal_False );//pDPObj->RefreshCache();
745 if ( nErrId == 0 )
746 {
747 // There is no undo for the refresh of the cache table, but the undo history for cell changes
748 // remains valid and should be preserved, so the history isn't cleared here.
749 //GetViewData()->GetDocShell()->GetUndoManager()->Clear();
750 }
751 else if (nErrId <= USHRT_MAX)
752 ErrorMessage(static_cast<sal_uInt16>(nErrId));
753 return nErrId;
754 // End Comments
755 }
756 else
757 ErrorMessage(STR_PIVOT_NOTFOUND);
758 return STR_PIVOT_NOTFOUND;
759 }
760
GetSelectedMemberList(ScStrCollection & rEntries,long & rDimension)761 void ScDBFunc::GetSelectedMemberList( ScStrCollection& rEntries, long& rDimension )
762 {
763 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
764 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
765 if ( !pDPObj )
766 return;
767
768 long nStartDimension = -1;
769 long nStartHierarchy = -1;
770 long nStartLevel = -1;
771
772 ScRangeListRef xRanges;
773 GetViewData()->GetMultiArea( xRanges ); // incl. cursor if nothing is selected
774 sal_uLong nRangeCount = xRanges->Count();
775 sal_Bool bContinue = sal_True;
776
777 for (sal_uLong nRangePos=0; nRangePos<nRangeCount && bContinue; nRangePos++)
778 {
779 ScRange aRange = *xRanges->GetObject(nRangePos);
780 SCCOL nStartCol = aRange.aStart.Col();
781 SCROW nStartRow = aRange.aStart.Row();
782 SCCOL nEndCol = aRange.aEnd.Col();
783 SCROW nEndRow = aRange.aEnd.Row();
784 SCTAB nTab = aRange.aStart.Tab();
785
786 for (SCROW nRow=nStartRow; nRow<=nEndRow && bContinue; nRow++)
787 for (SCCOL nCol=nStartCol; nCol<=nEndCol && bContinue; nCol++)
788 {
789 sheet::DataPilotTableHeaderData aData;
790 pDPObj->GetHeaderPositionData(ScAddress(nCol, nRow, nTab), aData);
791 if ( aData.Dimension < 0 )
792 bContinue = sal_False; // not part of any dimension
793 else
794 {
795 if ( nStartDimension < 0 ) // first member?
796 {
797 nStartDimension = aData.Dimension;
798 nStartHierarchy = aData.Hierarchy;
799 nStartLevel = aData.Level;
800 }
801 if ( aData.Dimension != nStartDimension ||
802 aData.Hierarchy != nStartHierarchy ||
803 aData.Level != nStartLevel )
804 {
805 bContinue = sal_False; // cannot mix dimensions
806 }
807 }
808 if ( bContinue )
809 {
810 // accept any part of a member description, also subtotals,
811 // but don't stop if empty parts are contained
812 if ( aData.Flags & sheet::MemberResultFlags::HASMEMBER )
813 {
814 StrData* pNew = new StrData( aData.MemberName );
815 if ( !rEntries.Insert( pNew ) )
816 delete pNew;
817 }
818 }
819 }
820 }
821
822 rDimension = nStartDimension; // dimension from which the found members came
823 if (!bContinue)
824 rEntries.FreeAll(); // remove all if not valid
825 }
826
HasSelectionForDateGroup(ScDPNumGroupInfo & rOldInfo,sal_Int32 & rParts)827 sal_Bool ScDBFunc::HasSelectionForDateGroup( ScDPNumGroupInfo& rOldInfo, sal_Int32& rParts )
828 {
829 // determine if the date group dialog has to be shown for the current selection
830
831 sal_Bool bFound = sal_False;
832
833 SCCOL nCurX = GetViewData()->GetCurX();
834 SCROW nCurY = GetViewData()->GetCurY();
835 SCTAB nTab = GetViewData()->GetTabNo();
836 ScDocument* pDoc = GetViewData()->GetDocument();
837
838 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nCurX, nCurY, nTab );
839 if ( pDPObj )
840 {
841 ScStrCollection aEntries;
842 long nSelectDimension = -1;
843 GetSelectedMemberList( aEntries, nSelectDimension );
844
845 if ( aEntries.GetCount() > 0 )
846 {
847 sal_Bool bIsDataLayout;
848 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
849 String aBaseDimName( aDimName );
850
851 sal_Bool bInGroupDim = sal_False;
852 sal_Bool bFoundParts = sal_False;
853
854 ScDPDimensionSaveData* pDimData =
855 const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
856 if ( pDimData )
857 {
858 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
859 const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( aDimName );
860 if ( pNumGroupDim )
861 {
862 // existing num group dimension
863
864 if ( pNumGroupDim->GetDatePart() != 0 )
865 {
866 // dimension has date info -> edit settings of this dimension
867 // (parts are collected below)
868
869 rOldInfo = pNumGroupDim->GetDateInfo();
870 bFound = sal_True;
871 }
872 else if ( pNumGroupDim->GetInfo().DateValues )
873 {
874 // Numerical grouping with DateValues flag is used for grouping
875 // of days with a "Number of days" value.
876
877 rOldInfo = pNumGroupDim->GetInfo();
878 rParts = com::sun::star::sheet::DataPilotFieldGroupBy::DAYS; // not found in CollectDateParts
879 bFoundParts = sal_True;
880 bFound = sal_True;
881 }
882 bInGroupDim = sal_True;
883 }
884 else if ( pGroupDim )
885 {
886 // existing additional group dimension
887
888 if ( pGroupDim->GetDatePart() != 0 )
889 {
890 // dimension has date info -> edit settings of this dimension
891 // (parts are collected below)
892
893 rOldInfo = pGroupDim->GetDateInfo();
894 aBaseDimName = pGroupDim->GetSourceDimName();
895 bFound = sal_True;
896 }
897 bInGroupDim = sal_True;
898 }
899 }
900 if ( bFound && !bFoundParts )
901 {
902 // collect date parts from all group dimensions
903 rParts = pDimData->CollectDateParts( aBaseDimName );
904 }
905 if ( !bFound && !bInGroupDim )
906 {
907 // create new date group dimensions if the selection is a single cell
908 // in a normal dimension with date content
909
910 ScRange aSelRange;
911 if ( (GetViewData()->GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
912 aSelRange.aStart == aSelRange.aEnd )
913 {
914 SCCOL nSelCol = aSelRange.aStart.Col();
915 SCROW nSelRow = aSelRange.aStart.Row();
916 SCTAB nSelTab = aSelRange.aStart.Tab();
917 if ( pDoc->HasValueData( nSelCol, nSelRow, nSelTab ) )
918 {
919 sal_uLong nIndex = static_cast<const SfxUInt32Item*>(pDoc->GetAttr(
920 nSelCol, nSelRow, nSelTab, ATTR_VALUE_FORMAT))->GetValue();
921 short nType = pDoc->GetFormatTable()->GetType(nIndex);
922 if ( nType == NUMBERFORMAT_DATE || nType == NUMBERFORMAT_TIME || nType == NUMBERFORMAT_DATETIME )
923 {
924 bFound = sal_True;
925 // use currently selected value for automatic limits
926 if( rOldInfo.AutoStart )
927 rOldInfo.Start = pDoc->GetValue( aSelRange.aStart );
928 if( rOldInfo.AutoEnd )
929 rOldInfo.End = pDoc->GetValue( aSelRange.aStart );
930 }
931 }
932 }
933 }
934 }
935 }
936
937 return bFound;
938 }
939
HasSelectionForNumGroup(ScDPNumGroupInfo & rOldInfo)940 sal_Bool ScDBFunc::HasSelectionForNumGroup( ScDPNumGroupInfo& rOldInfo )
941 {
942 // determine if the numeric group dialog has to be shown for the current selection
943
944 sal_Bool bFound = sal_False;
945
946 SCCOL nCurX = GetViewData()->GetCurX();
947 SCROW nCurY = GetViewData()->GetCurY();
948 SCTAB nTab = GetViewData()->GetTabNo();
949 ScDocument* pDoc = GetViewData()->GetDocument();
950
951 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nCurX, nCurY, nTab );
952 if ( pDPObj )
953 {
954 ScStrCollection aEntries;
955 long nSelectDimension = -1;
956 GetSelectedMemberList( aEntries, nSelectDimension );
957
958 if ( aEntries.GetCount() > 0 )
959 {
960 sal_Bool bIsDataLayout;
961 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
962
963 sal_Bool bInGroupDim = sal_False;
964
965 ScDPDimensionSaveData* pDimData =
966 const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
967 if ( pDimData )
968 {
969 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
970 if ( pNumGroupDim )
971 {
972 // existing num group dimension
973 // -> edit settings of this dimension
974
975 rOldInfo = pNumGroupDim->GetInfo();
976 bFound = sal_True;
977 }
978 else if ( pDimData->GetNamedGroupDim( aDimName ) )
979 bInGroupDim = sal_True; // in a group dimension
980 }
981 if ( !bFound && !bInGroupDim )
982 {
983 // create a new num group dimension if the selection is a single cell
984 // in a normal dimension with numeric content
985
986 ScRange aSelRange;
987 if ( (GetViewData()->GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
988 aSelRange.aStart == aSelRange.aEnd )
989 {
990 if ( pDoc->HasValueData( aSelRange.aStart.Col(), aSelRange.aStart.Row(),
991 aSelRange.aStart.Tab() ) )
992 {
993 bFound = sal_True;
994 // use currently selected value for automatic limits
995 if( rOldInfo.AutoStart )
996 rOldInfo.Start = pDoc->GetValue( aSelRange.aStart );
997 if( rOldInfo.AutoEnd )
998 rOldInfo.End = pDoc->GetValue( aSelRange.aStart );
999 }
1000 }
1001 }
1002 }
1003 }
1004
1005 return bFound;
1006 }
1007
DateGroupDataPilot(const ScDPNumGroupInfo & rInfo,sal_Int32 nParts)1008 void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo& rInfo, sal_Int32 nParts )
1009 {
1010 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1011 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1012 if ( pDPObj )
1013 {
1014 ScStrCollection aEntries;
1015 long nSelectDimension = -1;
1016 GetSelectedMemberList( aEntries, nSelectDimension );
1017
1018 if ( aEntries.GetCount() > 0 )
1019 {
1020 sal_Bool bIsDataLayout;
1021 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1022
1023 ScDPSaveData aData( *pDPObj->GetSaveData() );
1024 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1025
1026 // find original base
1027 String aBaseDimName = aDimName;
1028 if( const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName ) )
1029 aBaseDimName = pBaseGroupDim->GetSourceDimName();
1030
1031 // remove all existing parts (the grouping is built completely new)
1032
1033 /* Remove numeric group dimension (exists once at most). No need
1034 to delete anything in save data (grouping was done inplace in
1035 an existing base dimension). */
1036 pDimData->RemoveNumGroupDimension( aBaseDimName );
1037
1038 /* Remove named group dimension(s). Collect deleted dimension
1039 names which may be reused while recreating the groups.
1040 Dimensions have to be removed from dimension save data and from
1041 save data too. */
1042 std::vector< String > aDeletedNames;
1043 const ScDPSaveGroupDimension* pExistingGroup = pDimData->GetGroupDimForBase( aBaseDimName );
1044 while ( pExistingGroup )
1045 {
1046 String aGroupDimName = pExistingGroup->GetGroupDimName();
1047 pDimData->RemoveGroupDimension( aGroupDimName ); // pExistingGroup is deleted
1048
1049 // also remove SaveData settings for the dimension that no longer exists
1050 aData.RemoveDimensionByName( aGroupDimName );
1051
1052 /* The name can be used for the new group dimensions, although
1053 it is still in use with the DataPilotSource. */
1054 aDeletedNames.push_back( aGroupDimName );
1055
1056 // see if there are more group dimensions
1057 pExistingGroup = pDimData->GetGroupDimForBase( aBaseDimName );
1058
1059 if ( pExistingGroup && pExistingGroup->GetGroupDimName() == aGroupDimName )
1060 {
1061 // still get the same group dimension?
1062 DBG_ERROR("couldn't remove group dimension");
1063 pExistingGroup = NULL; // avoid endless loop
1064 }
1065 }
1066
1067 if ( nParts )
1068 {
1069 // create date group dimensions
1070
1071 ScDPNumGroupInfo aEmpty;
1072 bool bFirst = true;
1073 sal_Int32 nMask = 1;
1074 for (sal_uInt16 nBit=0; nBit<32; nBit++)
1075 {
1076 if ( nParts & nMask )
1077 {
1078 if ( bFirst )
1079 {
1080 // innermost part: create NumGroupDimension (replacing original values)
1081 // Dimension name is left unchanged
1082
1083 if ( (nParts == sheet::DataPilotFieldGroupBy::DAYS) && (rInfo.Step >= 1.0) )
1084 {
1085 // only days, and a step value specified: use numerical grouping
1086 // with DateValues flag, not date grouping
1087
1088 ScDPNumGroupInfo aNumInfo( rInfo );
1089 aNumInfo.DateValues = sal_True;
1090
1091 ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, aNumInfo );
1092 pDimData->AddNumGroupDimension( aNumGroupDim );
1093 }
1094 else
1095 {
1096 ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, rInfo, nMask );
1097 pDimData->AddNumGroupDimension( aNumGroupDim );
1098 }
1099
1100 bFirst = false;
1101 }
1102 else
1103 {
1104 // additional parts: create GroupDimension (shown as additional dimensions)
1105 String aGroupDimName = pDimData->CreateDateGroupDimName( nMask, *pDPObj, true, &aDeletedNames );
1106 ScDPSaveGroupDimension aGroupDim( aBaseDimName, aGroupDimName );
1107 aGroupDim.SetDateInfo( rInfo, nMask );
1108 pDimData->AddGroupDimension( aGroupDim );
1109
1110 // set orientation
1111 ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
1112 if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
1113 {
1114 ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aBaseDimName );
1115 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
1116 long nPosition = 0; //! before (immediate) base
1117 aData.SetPosition( pSaveDimension, nPosition );
1118 }
1119 }
1120 }
1121 nMask *= 2;
1122 }
1123 }
1124
1125 // apply changes
1126 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1127 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1128 pNewObj->SetSaveData( aData );
1129 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False );
1130 delete pNewObj;
1131
1132 // unmark cell selection
1133 Unmark();
1134 }
1135 }
1136 }
1137
NumGroupDataPilot(const ScDPNumGroupInfo & rInfo)1138 void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo& rInfo )
1139 {
1140 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1141 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1142 if ( pDPObj )
1143 {
1144 ScStrCollection aEntries;
1145 long nSelectDimension = -1;
1146 GetSelectedMemberList( aEntries, nSelectDimension );
1147
1148 if ( aEntries.GetCount() > 0 )
1149 {
1150 sal_Bool bIsDataLayout;
1151 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1152
1153 ScDPSaveData aData( *pDPObj->GetSaveData() );
1154 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1155
1156 ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( aDimName );
1157 if ( pExisting )
1158 {
1159 // modify existing group dimension
1160 pExisting->SetGroupInfo( rInfo );
1161 }
1162 else
1163 {
1164 // create new group dimension
1165 ScDPSaveNumGroupDimension aNumGroupDim( aDimName, rInfo );
1166 pDimData->AddNumGroupDimension( aNumGroupDim );
1167 }
1168
1169 // apply changes
1170 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1171 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1172 pNewObj->SetSaveData( aData );
1173 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False );
1174 delete pNewObj;
1175
1176 // unmark cell selection
1177 Unmark();
1178 }
1179 }
1180 }
1181
GroupDataPilot()1182 void ScDBFunc::GroupDataPilot()
1183 {
1184 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1185 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1186 if ( pDPObj )
1187 {
1188 ScStrCollection aEntries;
1189 long nSelectDimension = -1;
1190 GetSelectedMemberList( aEntries, nSelectDimension );
1191
1192 if ( aEntries.GetCount() > 0 )
1193 {
1194 sal_Bool bIsDataLayout;
1195 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1196
1197 ScDPSaveData aData( *pDPObj->GetSaveData() );
1198 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1199
1200 // find original base
1201 String aBaseDimName( aDimName );
1202 const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
1203 if ( pBaseGroupDim )
1204 {
1205 // any entry's SourceDimName is the original base
1206 aBaseDimName = pBaseGroupDim->GetSourceDimName();
1207 }
1208
1209 // find existing group dimension
1210 // (using the selected dim, can be intermediate group dim)
1211 ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
1212
1213 // remove the selected items from their groups
1214 // (empty groups are removed, too)
1215 sal_uInt16 nEntryCount = aEntries.GetCount();
1216 sal_uInt16 nEntry;
1217 if ( pGroupDimension )
1218 {
1219 for (nEntry=0; nEntry<nEntryCount; nEntry++)
1220 {
1221 String aEntryName = aEntries[nEntry]->GetString();
1222 if ( pBaseGroupDim )
1223 {
1224 // for each selected (intermediate) group, remove all its items
1225 // (same logic as for adding, below)
1226 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
1227 if ( pBaseGroup )
1228 pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements
1229 else
1230 pGroupDimension->RemoveFromGroups( aEntryName );
1231 }
1232 else
1233 pGroupDimension->RemoveFromGroups( aEntryName );
1234 }
1235 }
1236
1237 ScDPSaveGroupDimension* pNewGroupDim = NULL;
1238 if ( !pGroupDimension )
1239 {
1240 // create a new group dimension
1241 String aGroupDimName = pDimData->CreateGroupDimName( aBaseDimName, *pDPObj, false, NULL );
1242 pNewGroupDim = new ScDPSaveGroupDimension( aBaseDimName, aGroupDimName );
1243
1244 pGroupDimension = pNewGroupDim; // make changes to the new dim if none existed
1245
1246 if ( pBaseGroupDim )
1247 {
1248 // If it's a higher-order group dimension, pre-allocate groups for all
1249 // non-selected original groups, so the individual base members aren't
1250 // used for automatic groups (this would make the original groups hard
1251 // to find).
1252 //! Also do this when removing groups?
1253 //! Handle this case dynamically with automatic groups?
1254
1255 long nGroupCount = pBaseGroupDim->GetGroupCount();
1256 for ( long nGroup = 0; nGroup < nGroupCount; nGroup++ )
1257 {
1258 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
1259
1260 StrData aStrData( pBaseGroup->GetGroupName() );
1261 sal_uInt16 nCollIndex;
1262 if ( !aEntries.Search( &aStrData, nCollIndex ) ) //! ignore case?
1263 {
1264 // add an additional group for each item that is not in the selection
1265 ScDPSaveGroupItem aGroup( pBaseGroup->GetGroupName() );
1266 aGroup.AddElementsFromGroup( *pBaseGroup );
1267 pGroupDimension->AddGroupItem( aGroup );
1268 }
1269 }
1270 }
1271 }
1272 String aGroupDimName = pGroupDimension->GetGroupDimName();
1273
1274 //! localized prefix string
1275 String aGroupName = pGroupDimension->CreateGroupName( String::CreateFromAscii("Group") );
1276 ScDPSaveGroupItem aGroup( aGroupName );
1277 for (nEntry=0; nEntry<nEntryCount; nEntry++)
1278 {
1279 String aEntryName = aEntries[nEntry]->GetString();
1280 if ( pBaseGroupDim )
1281 {
1282 // for each selected (intermediate) group, add all its items
1283 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
1284 if ( pBaseGroup )
1285 aGroup.AddElementsFromGroup( *pBaseGroup );
1286 else
1287 aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself
1288 }
1289 else
1290 aGroup.AddElement( aEntryName ); // no group dimension, add all items directly
1291 }
1292
1293 pGroupDimension->AddGroupItem( aGroup );
1294
1295 if ( pNewGroupDim )
1296 {
1297 pDimData->AddGroupDimension( *pNewGroupDim );
1298 delete pNewGroupDim; // AddGroupDimension copies the object
1299 // don't access pGroupDimension after here
1300 }
1301 pGroupDimension = pNewGroupDim = NULL;
1302
1303 // set orientation
1304 ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
1305 if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
1306 {
1307 ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aDimName );
1308 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
1309 long nPosition = 0; //! before (immediate) base
1310 aData.SetPosition( pSaveDimension, nPosition );
1311 }
1312
1313 // apply changes
1314 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1315 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1316 pNewObj->SetSaveData( aData );
1317 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False );
1318 delete pNewObj;
1319
1320 // unmark cell selection
1321 Unmark();
1322 }
1323 }
1324 }
1325
UngroupDataPilot()1326 void ScDBFunc::UngroupDataPilot()
1327 {
1328 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1329 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1330 if ( pDPObj )
1331 {
1332 ScStrCollection aEntries;
1333 long nSelectDimension = -1;
1334 GetSelectedMemberList( aEntries, nSelectDimension );
1335
1336 if ( aEntries.GetCount() > 0 )
1337 {
1338 sal_Bool bIsDataLayout;
1339 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1340
1341 ScDPSaveData aData( *pDPObj->GetSaveData() );
1342 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1343 //! test first if DimensionData exists?
1344
1345 sal_Bool bApply = sal_False;
1346
1347 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
1348 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
1349 if ( ( pGroupDim && pGroupDim->GetDatePart() != 0 ) ||
1350 ( pNumGroupDim && pNumGroupDim->GetDatePart() != 0 ) )
1351 {
1352 // Date grouping: need to remove all affected group dimensions.
1353 // This is done using DateGroupDataPilot with nParts=0.
1354
1355 DateGroupDataPilot( ScDPNumGroupInfo(), 0 );
1356 // bApply remains FALSE
1357 // dimension pointers become invalid
1358 }
1359 else if ( pGroupDim )
1360 {
1361 sal_uInt16 nEntryCount = aEntries.GetCount();
1362 for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
1363 {
1364 String aEntryName = aEntries[nEntry]->GetString();
1365 pGroupDim->RemoveGroup( aEntryName );
1366 }
1367 // remove group dimension if empty
1368 bool bEmptyDim = pGroupDim->IsEmpty();
1369 if ( !bEmptyDim )
1370 {
1371 // If all remaining groups in the dimension aren't shown, remove
1372 // the dimension too, as if it was completely empty.
1373 ScStrCollection aVisibleEntries;
1374 pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
1375 bEmptyDim = pGroupDim->HasOnlyHidden( aVisibleEntries );
1376 }
1377 if ( bEmptyDim )
1378 {
1379 pDimData->RemoveGroupDimension( aDimName ); // pGroupDim is deleted
1380
1381 // also remove SaveData settings for the dimension that no longer exists
1382 aData.RemoveDimensionByName( aDimName );
1383 }
1384 bApply = sal_True;
1385 }
1386 else if ( pNumGroupDim )
1387 {
1388 // remove the numerical grouping
1389 pDimData->RemoveNumGroupDimension( aDimName );
1390 // SaveData settings can remain unchanged - the same dimension still exists
1391 bApply = sal_True;
1392 }
1393
1394 if ( bApply )
1395 {
1396 // apply changes
1397 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1398 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1399 pNewObj->SetSaveData( aData );
1400 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False );
1401 delete pNewObj;
1402
1403 // unmark cell selection
1404 Unmark();
1405 }
1406 }
1407 }
1408 }
1409
lcl_replaceMemberNameInSubtotal(const OUString & rSubtotal,const OUString & rMemberName)1410 static OUString lcl_replaceMemberNameInSubtotal(const OUString& rSubtotal, const OUString& rMemberName)
1411 {
1412 sal_Int32 n = rSubtotal.getLength();
1413 const sal_Unicode* p = rSubtotal.getStr();
1414 OUStringBuffer aBuf, aWordBuf;
1415 for (sal_Int32 i = 0; i < n; ++i)
1416 {
1417 sal_Unicode c = p[i];
1418 if (c == sal_Unicode(' '))
1419 {
1420 OUString aWord = aWordBuf.makeStringAndClear();
1421 if (aWord.equals(rMemberName))
1422 aBuf.append(sal_Unicode('?'));
1423 else
1424 aBuf.append(aWord);
1425 aBuf.append(c);
1426 }
1427 else if (c == sal_Unicode('\\'))
1428 {
1429 // Escape a backslash character.
1430 aWordBuf.append(c);
1431 aWordBuf.append(c);
1432 }
1433 else if (c == sal_Unicode('?'))
1434 {
1435 // A literal '?' must be escaped with a backslash ('\');
1436 aWordBuf.append(sal_Unicode('\\'));
1437 aWordBuf.append(c);
1438 }
1439 else
1440 aWordBuf.append(c);
1441 }
1442
1443 if (aWordBuf.getLength() > 0)
1444 {
1445 OUString aWord = aWordBuf.makeStringAndClear();
1446 if (aWord.equals(rMemberName))
1447 aBuf.append(sal_Unicode('?'));
1448 else
1449 aBuf.append(aWord);
1450 }
1451
1452 return aBuf.makeStringAndClear();
1453 }
1454
DataPilotInput(const ScAddress & rPos,const String & rString)1455 void ScDBFunc::DataPilotInput( const ScAddress& rPos, const String& rString )
1456 {
1457 using namespace ::com::sun::star::sheet;
1458
1459 String aNewName( rString );
1460
1461 ScDocument* pDoc = GetViewData()->GetDocument();
1462 ScDPObject* pDPObj = pDoc->GetDPAtCursor( rPos.Col(), rPos.Row(), rPos.Tab() );
1463 if (!pDPObj)
1464 return;
1465
1466 String aOldText;
1467 pDoc->GetString( rPos.Col(), rPos.Row(), rPos.Tab(), aOldText );
1468
1469 if ( aOldText == rString )
1470 {
1471 // nothing to do: silently exit
1472 return;
1473 }
1474
1475 sal_uInt16 nErrorId = 0;
1476
1477 pDPObj->BuildAllDimensionMembers();
1478 ScDPSaveData aData( *pDPObj->GetSaveData() );
1479 sal_Bool bChange = sal_False;
1480
1481 sal_uInt16 nOrient = DataPilotFieldOrientation_HIDDEN;
1482 long nField = pDPObj->GetHeaderDim( rPos, nOrient );
1483 if ( nField >= 0 )
1484 {
1485 // changing a field title
1486 if ( aData.GetExistingDimensionData() )
1487 {
1488 // only group dimensions can be renamed
1489
1490 ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1491 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aOldText );
1492 if ( pGroupDim )
1493 {
1494 // valid name: not empty, no existing dimension (group or other)
1495 if ( rString.Len() && !pDPObj->IsDimNameInUse(rString) )
1496 {
1497 pGroupDim->Rename( aNewName );
1498
1499 // also rename in SaveData to preserve the field settings
1500 ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aOldText );
1501 pSaveDim->SetName( aNewName );
1502
1503 bChange = sal_True;
1504 }
1505 else
1506 nErrorId = STR_INVALIDNAME;
1507 }
1508 }
1509 else if (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW)
1510 {
1511 sal_Bool bDataLayout = false;
1512 String aDimName = pDPObj->GetDimName(nField, bDataLayout);
1513 ScDPSaveDimension* pDim = bDataLayout ? aData.GetDataLayoutDimension() : aData.GetDimensionByName(aDimName);
1514 if (pDim)
1515 {
1516 if (rString.Len())
1517 {
1518 if (rString.EqualsIgnoreCaseAscii(aDimName))
1519 {
1520 pDim->RemoveLayoutName();
1521 bChange = true;
1522 }
1523 else if (!pDPObj->IsDimNameInUse(rString))
1524 {
1525 pDim->SetLayoutName(rString);
1526 bChange = true;
1527 }
1528 else
1529 nErrorId = STR_INVALIDNAME;
1530 }
1531 else
1532 nErrorId = STR_INVALIDNAME;
1533 }
1534 }
1535 }
1536 else if (pDPObj->IsDataDescriptionCell(rPos))
1537 {
1538 // There is only one data dimension.
1539 ScDPSaveDimension* pDim = aData.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA);
1540 if (pDim)
1541 {
1542 if (rString.Len())
1543 {
1544 if (rString.EqualsIgnoreCaseAscii(pDim->GetName()))
1545 {
1546 pDim->RemoveLayoutName();
1547 bChange = true;
1548 }
1549 else if (!pDPObj->IsDimNameInUse(rString))
1550 {
1551 pDim->SetLayoutName(rString);
1552 bChange = true;
1553 }
1554 else
1555 nErrorId = STR_INVALIDNAME;
1556 }
1557 else
1558 nErrorId = STR_INVALIDNAME;
1559 }
1560 }
1561 else
1562 {
1563 // This is not a field header.
1564 sheet::DataPilotTableHeaderData aPosData;
1565 pDPObj->GetHeaderPositionData(rPos, aPosData);
1566
1567 if ( (aPosData.Flags & MemberResultFlags::HASMEMBER) && aOldText.Len() )
1568 {
1569 if ( aData.GetExistingDimensionData() && !(aPosData.Flags & MemberResultFlags::SUBTOTAL))
1570 {
1571 sal_Bool bIsDataLayout;
1572 String aDimName = pDPObj->GetDimName( aPosData.Dimension, bIsDataLayout );
1573
1574 ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1575 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
1576 if ( pGroupDim )
1577 {
1578 // valid name: not empty, no existing group in this dimension
1579 //! ignore case?
1580 if ( aNewName.Len() && !pGroupDim->GetNamedGroup( aNewName ) )
1581 {
1582 ScDPSaveGroupItem* pGroup = pGroupDim->GetNamedGroupAcc( aOldText );
1583 if ( pGroup )
1584 pGroup->Rename( aNewName ); // rename the existing group
1585 else
1586 {
1587 // create a new group to replace the automatic group
1588 ScDPSaveGroupItem aGroup( aNewName );
1589 aGroup.AddElement( aOldText );
1590 pGroupDim->AddGroupItem( aGroup );
1591 }
1592
1593 // in both cases also adjust savedata, to preserve member settings (show details)
1594 ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aDimName );
1595 ScDPSaveMember* pSaveMember = pSaveDim->GetExistingMemberByName( aOldText );
1596 if ( pSaveMember )
1597 pSaveMember->SetName( aNewName );
1598
1599 bChange = sal_True;
1600 }
1601 else
1602 nErrorId = STR_INVALIDNAME;
1603 }
1604 }
1605 else if ((aPosData.Flags & MemberResultFlags::GRANDTOTAL))
1606 {
1607 aData.SetGrandTotalName(rString);
1608 bChange = true;
1609 }
1610 else if (aPosData.Dimension >= 0 && aPosData.MemberName.getLength() > 0)
1611 {
1612 sal_Bool bDataLayout = false;
1613 String aDimName = pDPObj->GetDimName(static_cast<long>(aPosData.Dimension), bDataLayout);
1614 if (bDataLayout)
1615 {
1616 // data dimension
1617 do
1618 {
1619 if ((aPosData.Flags & MemberResultFlags::SUBTOTAL))
1620 break;
1621
1622 ScDPSaveDimension* pDim = aData.GetDimensionByName(aPosData.MemberName);
1623 if (!pDim)
1624 break;
1625
1626 if (!rString.Len())
1627 {
1628 nErrorId = STR_INVALIDNAME;
1629 break;
1630 }
1631
1632 if (aPosData.MemberName.equalsIgnoreAsciiCase(rString))
1633 {
1634 pDim->RemoveLayoutName();
1635 bChange = true;
1636 }
1637 else if (!pDPObj->IsDimNameInUse(rString))
1638 {
1639 pDim->SetLayoutName(rString);
1640 bChange = true;
1641 }
1642 else
1643 nErrorId = STR_INVALIDNAME;
1644 }
1645 while (false);
1646 }
1647 else
1648 {
1649 // field member
1650 do
1651 {
1652 ScDPSaveDimension* pDim = aData.GetDimensionByName(aDimName);
1653 if (!pDim)
1654 break;
1655
1656 ScDPSaveMember* pMem = pDim->GetExistingMemberByName(aPosData.MemberName);
1657 if (!pMem)
1658 break;
1659
1660 if ((aPosData.Flags & MemberResultFlags::SUBTOTAL))
1661 {
1662 // Change subtotal only when the table has one data dimension.
1663 if (aData.GetDataDimensionCount() > 1)
1664 break;
1665
1666 // display name for subtotal is allowed only if the subtotal type is 'Automatic'.
1667 if (pDim->GetSubTotalsCount() != 1)
1668 break;
1669
1670 if (pDim->GetSubTotalFunc(0) != sheet::GeneralFunction_AUTO)
1671 break;
1672
1673 const OUString* pLayoutName = pMem->GetLayoutName();
1674 String aMemberName;
1675 if (pLayoutName)
1676 aMemberName = *pLayoutName;
1677 else
1678 aMemberName = aPosData.MemberName;
1679
1680 String aNew = lcl_replaceMemberNameInSubtotal(rString, aMemberName);
1681 pDim->SetSubtotalName(aNew);
1682 bChange = true;
1683 }
1684 else
1685 {
1686 // Check to make sure the member name isn't
1687 // already used.
1688 if (rString.Len())
1689 {
1690 if (rString.EqualsIgnoreCaseAscii(pMem->GetName()))
1691 {
1692 pMem->RemoveLayoutName();
1693 bChange = true;
1694 }
1695 else if (!pDim->IsMemberNameInUse(rString))
1696 {
1697 pMem->SetLayoutName(rString);
1698 bChange = true;
1699 }
1700 else
1701 nErrorId = STR_INVALIDNAME;
1702 }
1703 else
1704 nErrorId = STR_INVALIDNAME;
1705 }
1706 }
1707 while (false);
1708 }
1709 }
1710 }
1711 }
1712
1713 if ( bChange )
1714 {
1715 // apply changes
1716 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1717 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1718 pNewObj->SetSaveData( aData );
1719 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False );
1720 delete pNewObj;
1721 }
1722 else
1723 {
1724 if ( !nErrorId )
1725 nErrorId = STR_ERR_DATAPILOT_INPUT;
1726 ErrorMessage( nErrorId );
1727 }
1728 }
1729
lcl_MoveToEnd(ScDPSaveDimension & rDim,const String & rItemName)1730 void lcl_MoveToEnd( ScDPSaveDimension& rDim, const String& rItemName )
1731 {
1732 ScDPSaveMember* pNewMember = NULL;
1733 const ScDPSaveMember* pOldMember = rDim.GetExistingMemberByName( rItemName );
1734 if ( pOldMember )
1735 pNewMember = new ScDPSaveMember( *pOldMember );
1736 else
1737 pNewMember = new ScDPSaveMember( rItemName );
1738 rDim.AddMember( pNewMember );
1739 // AddMember takes ownership of the new pointer,
1740 // puts it to the end of the list even if it was in the list before.
1741 }
1742
1743 struct ScOUStringCollate
1744 {
1745 CollatorWrapper* mpCollator;
1746
ScOUStringCollateScOUStringCollate1747 ScOUStringCollate(CollatorWrapper* pColl) : mpCollator(pColl) {}
1748
operator ()ScOUStringCollate1749 bool operator()(const rtl::OUString& rStr1, const rtl::OUString& rStr2) const
1750 {
1751 return ( mpCollator->compareString(rStr1, rStr2) < 0 );
1752 }
1753 };
1754
DataPilotSort(const ScAddress & rPos,bool bAscending,sal_uInt16 * pUserListId)1755 bool ScDBFunc::DataPilotSort( const ScAddress& rPos, bool bAscending, sal_uInt16* pUserListId )
1756 {
1757 ScDocument* pDoc = GetViewData()->GetDocument();
1758 ScDPObject* pDPObj = pDoc->GetDPAtCursor(rPos.Col(), rPos.Row(), rPos.Tab());
1759 if (!pDPObj)
1760 return false;
1761
1762 // We need to run this to get all members later.
1763 if ( pUserListId )
1764 pDPObj->BuildAllDimensionMembers();
1765
1766 sal_uInt16 nOrientation;
1767 long nDimIndex = pDPObj->GetHeaderDim(rPos, nOrientation);
1768 if (nDimIndex < 0)
1769 // Invalid dimension index. Bail out.
1770 return false;
1771
1772 sal_Bool bDataLayout;
1773 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1774 if (!pSaveData)
1775 return false;
1776
1777 ScDPSaveData aNewSaveData(*pSaveData);
1778 String aDimName = pDPObj->GetDimName(nDimIndex, bDataLayout);
1779 ScDPSaveDimension* pSaveDim = aNewSaveData.GetDimensionByName(aDimName);
1780 if (!pSaveDim)
1781 return false;
1782
1783 // manual evaluation of sort order is only needed if a user list id is given
1784 if ( pUserListId )
1785 {
1786 typedef ScDPSaveDimension::MemberList MemList;
1787 const MemList& rDimMembers = pSaveDim->GetMembers();
1788 list<OUString> aMembers;
1789 hash_set<OUString, ::rtl::OUStringHash> aMemberSet;
1790 size_t nMemberCount = 0;
1791 for (MemList::const_iterator itr = rDimMembers.begin(), itrEnd = rDimMembers.end();
1792 itr != itrEnd; ++itr)
1793 {
1794 ScDPSaveMember* pMem = *itr;
1795 aMembers.push_back(pMem->GetName());
1796 aMemberSet.insert(pMem->GetName());
1797 ++nMemberCount;
1798 }
1799
1800 // Sort the member list in ascending order.
1801 ScOUStringCollate aCollate( ScGlobal::GetCollator() );
1802 aMembers.sort(aCollate);
1803
1804 // Collect and rank those custom sort strings that also exist in the member name list.
1805
1806 typedef hash_map<OUString, sal_uInt16, OUStringHash> UserSortMap;
1807 UserSortMap aSubStrs;
1808 sal_uInt16 nSubCount = 0;
1809 if (pUserListId)
1810 {
1811 ScUserList* pUserList = ScGlobal::GetUserList();
1812 if (!pUserList)
1813 return false;
1814
1815 {
1816 sal_uInt16 n = pUserList->GetCount();
1817 if (!n || *pUserListId >= n)
1818 return false;
1819 }
1820
1821 ScUserListData* pData = static_cast<ScUserListData*>((*pUserList)[*pUserListId]);
1822 if (pData)
1823 {
1824 sal_uInt16 n = pData->GetSubCount();
1825 for (sal_uInt16 i = 0; i < n; ++i)
1826 {
1827 OUString aSub = pData->GetSubStr(i);
1828 if (!aMemberSet.count(aSub))
1829 // This string doesn't exist in the member name set. Don't add this.
1830 continue;
1831
1832 aSubStrs.insert(UserSortMap::value_type(aSub, nSubCount++));
1833 }
1834 }
1835 }
1836
1837 // Rank all members.
1838
1839 vector<OUString> aRankedNames(nMemberCount);
1840 sal_uInt16 nCurStrId = 0;
1841 for (list<OUString>::const_iterator itr = aMembers.begin(), itrEnd = aMembers.end();
1842 itr != itrEnd; ++itr)
1843 {
1844 OUString aName = *itr;
1845 sal_uInt16 nRank = 0;
1846 UserSortMap::const_iterator itrSub = aSubStrs.find(aName);
1847 if (itrSub == aSubStrs.end())
1848 nRank = nSubCount + nCurStrId++;
1849 else
1850 nRank = itrSub->second;
1851
1852 if (!bAscending)
1853 nRank = static_cast< sal_uInt16 >( nMemberCount - nRank - 1 );
1854
1855 aRankedNames[nRank] = aName;
1856 }
1857
1858 // Re-order ScDPSaveMember instances with the new ranks.
1859
1860 for (vector<OUString>::const_iterator itr = aRankedNames.begin(), itrEnd = aRankedNames.end();
1861 itr != itrEnd; ++itr)
1862 {
1863 const ScDPSaveMember* pOldMem = pSaveDim->GetExistingMemberByName(*itr);
1864 if (!pOldMem)
1865 // All members are supposed to be present.
1866 continue;
1867
1868 ScDPSaveMember* pNewMem = new ScDPSaveMember(*pOldMem);
1869 pSaveDim->AddMember(pNewMem);
1870 }
1871
1872 // Set the sorting mode to manual for now. We may introduce a new sorting
1873 // mode later on.
1874
1875 sheet::DataPilotFieldSortInfo aSortInfo;
1876 aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
1877 pSaveDim->SetSortInfo(&aSortInfo);
1878 }
1879 else
1880 {
1881 // without user list id, just apply sorting mode
1882
1883 sheet::DataPilotFieldSortInfo aSortInfo;
1884 aSortInfo.Mode = sheet::DataPilotFieldSortMode::NAME;
1885 aSortInfo.IsAscending = bAscending;
1886 pSaveDim->SetSortInfo(&aSortInfo);
1887 }
1888
1889 // Update the datapilot with the newly sorted field members.
1890
1891 auto_ptr<ScDPObject> pNewObj(new ScDPObject(*pDPObj));
1892 pNewObj->SetSaveData(aNewSaveData);
1893 ScDBDocFunc aFunc(*GetViewData()->GetDocShell());
1894
1895 return aFunc.DataPilotUpdate(pDPObj, pNewObj.get(), true, false);
1896 }
1897
DataPilotMove(const ScRange & rSource,const ScAddress & rDest)1898 sal_Bool ScDBFunc::DataPilotMove( const ScRange& rSource, const ScAddress& rDest )
1899 {
1900 sal_Bool bRet = sal_False;
1901 ScDocument* pDoc = GetViewData()->GetDocument();
1902 ScDPObject* pDPObj = pDoc->GetDPAtCursor( rSource.aStart.Col(), rSource.aStart.Row(), rSource.aStart.Tab() );
1903 if ( pDPObj && pDPObj == pDoc->GetDPAtCursor( rDest.Col(), rDest.Row(), rDest.Tab() ) )
1904 {
1905 sheet::DataPilotTableHeaderData aDestData;
1906 pDPObj->GetHeaderPositionData( rDest, aDestData );
1907 bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
1908
1909 // look through the source range
1910 std::hash_set< rtl::OUString, rtl::OUStringHash, std::equal_to<rtl::OUString> > aMembersSet; // for lookup
1911 std::vector< rtl::OUString > aMembersVector; // members in original order, for inserting
1912 aMembersVector.reserve( std::max( static_cast<SCSIZE>( rSource.aEnd.Col() - rSource.aStart.Col() + 1 ),
1913 static_cast<SCSIZE>( rSource.aEnd.Row() - rSource.aStart.Row() + 1 ) ) );
1914 for (SCROW nRow = rSource.aStart.Row(); bValid && nRow <= rSource.aEnd.Row(); ++nRow )
1915 for (SCCOL nCol = rSource.aStart.Col(); bValid && nCol <= rSource.aEnd.Col(); ++nCol )
1916 {
1917 sheet::DataPilotTableHeaderData aSourceData;
1918 pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, rSource.aStart.Tab() ), aSourceData );
1919 if ( aSourceData.Dimension == aDestData.Dimension && aSourceData.MemberName.getLength() )
1920 {
1921 if ( aMembersSet.find( aSourceData.MemberName ) == aMembersSet.end() )
1922 {
1923 aMembersSet.insert( aSourceData.MemberName );
1924 aMembersVector.push_back( aSourceData.MemberName );
1925 }
1926 // duplicates are ignored
1927 }
1928 else
1929 bValid = false; // empty (subtotal) or different field
1930 }
1931
1932 if ( bValid )
1933 {
1934 sal_Bool bIsDataLayout;
1935 String aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
1936 if ( !bIsDataLayout )
1937 {
1938 ScDPSaveData aData( *pDPObj->GetSaveData() );
1939 ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
1940
1941 // get all member names in source order
1942 uno::Sequence<rtl::OUString> aMemberNames;
1943 pDPObj->GetMemberNames( aDestData.Dimension, aMemberNames );
1944
1945 bool bInserted = false;
1946
1947 sal_Int32 nMemberCount = aMemberNames.getLength();
1948 for (sal_Int32 nMemberPos=0; nMemberPos<nMemberCount; ++nMemberPos)
1949 {
1950 String aMemberStr( aMemberNames[nMemberPos] );
1951
1952 if ( !bInserted && aMemberNames[nMemberPos] == aDestData.MemberName )
1953 {
1954 // insert dragged items before this item
1955 for ( std::vector<rtl::OUString>::const_iterator aIter = aMembersVector.begin();
1956 aIter != aMembersVector.end(); ++aIter )
1957 lcl_MoveToEnd( *pDim, *aIter );
1958 bInserted = true;
1959 }
1960
1961 if ( aMembersSet.find( aMemberStr ) == aMembersSet.end() ) // skip dragged items
1962 lcl_MoveToEnd( *pDim, aMemberStr );
1963 }
1964 // insert dragged item at end if dest wasn't found (for example, empty)
1965 if ( !bInserted )
1966 for ( std::vector<rtl::OUString>::const_iterator aIter = aMembersVector.begin();
1967 aIter != aMembersVector.end(); ++aIter )
1968 lcl_MoveToEnd( *pDim, *aIter );
1969
1970 // Items that were in SaveData, but not in the source, end up at the start of the list.
1971
1972 // set flag for manual sorting
1973 sheet::DataPilotFieldSortInfo aSortInfo;
1974 aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
1975 pDim->SetSortInfo( &aSortInfo );
1976
1977 // apply changes
1978 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1979 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1980 pNewObj->SetSaveData( aData );
1981 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False ); //! bApi for drag&drop?
1982 delete pNewObj;
1983
1984 Unmark(); // entry was moved - no use in leaving the old cell selected
1985
1986 bRet = sal_True;
1987 }
1988 }
1989 }
1990
1991 return bRet;
1992 }
1993
HasSelectionForDrillDown(sal_uInt16 & rOrientation)1994 sal_Bool ScDBFunc::HasSelectionForDrillDown( sal_uInt16& rOrientation )
1995 {
1996 sal_Bool bRet = sal_False;
1997
1998 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1999 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
2000 if ( pDPObj )
2001 {
2002 ScStrCollection aEntries;
2003 long nSelectDimension = -1;
2004 GetSelectedMemberList( aEntries, nSelectDimension );
2005
2006 if ( aEntries.GetCount() > 0 )
2007 {
2008 sal_Bool bIsDataLayout;
2009 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
2010 if ( !bIsDataLayout )
2011 {
2012 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
2013 ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName( aDimName );
2014 if ( pDim )
2015 {
2016 sal_uInt16 nDimOrient = pDim->GetOrientation();
2017 ScDPSaveDimension* pInner = pSaveData->GetInnermostDimension( nDimOrient );
2018 if ( pDim == pInner )
2019 {
2020 rOrientation = nDimOrient;
2021 bRet = sal_True;
2022 }
2023 }
2024 }
2025 }
2026 }
2027
2028 return bRet;
2029 }
2030
SetDataPilotDetails(sal_Bool bShow,const String * pNewDimensionName)2031 void ScDBFunc::SetDataPilotDetails( sal_Bool bShow, const String* pNewDimensionName )
2032 {
2033 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
2034 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
2035 if ( pDPObj )
2036 {
2037 ScStrCollection aEntries;
2038 long nSelectDimension = -1;
2039 GetSelectedMemberList( aEntries, nSelectDimension );
2040
2041 if ( aEntries.GetCount() > 0 )
2042 {
2043 sal_Bool bIsDataLayout;
2044 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
2045 if ( !bIsDataLayout )
2046 {
2047 ScDPSaveData aData( *pDPObj->GetSaveData() );
2048 ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
2049
2050 if ( bShow && pNewDimensionName )
2051 {
2052 // add the new dimension with the same orientation, at the end
2053
2054 ScDPSaveDimension* pNewDim = aData.GetDimensionByName( *pNewDimensionName );
2055 ScDPSaveDimension* pDuplicated = NULL;
2056 if ( pNewDim->GetOrientation() == sheet::DataPilotFieldOrientation_DATA )
2057 {
2058 // Need to duplicate the dimension, create column/row in addition to data:
2059 // The duplicated dimension inherits the existing settings, pNewDim is modified below.
2060 pDuplicated = aData.DuplicateDimension( *pNewDimensionName );
2061 }
2062
2063 sal_uInt16 nOrientation = pDim->GetOrientation();
2064 pNewDim->SetOrientation( nOrientation );
2065
2066 long nPosition = LONG_MAX;
2067 aData.SetPosition( pNewDim, nPosition );
2068
2069 ScDPSaveDimension* pDataLayout = aData.GetDataLayoutDimension();
2070 if ( pDataLayout->GetOrientation() == nOrientation &&
2071 aData.GetDataDimensionCount() <= 1 )
2072 {
2073 // If there is only one data dimension, the data layout dimension
2074 // must still be the last one in its orientation.
2075 aData.SetPosition( pDataLayout, nPosition );
2076 }
2077
2078 if ( pDuplicated )
2079 {
2080 // The duplicated (data) dimension needs to be behind the original dimension
2081 aData.SetPosition( pDuplicated, nPosition );
2082 }
2083
2084 // Hide details for all visible members (selected are changed below).
2085 //! Use all members from source level instead (including non-visible)?
2086
2087 ScStrCollection aVisibleEntries;
2088 pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
2089
2090 sal_uInt16 nVisCount = aVisibleEntries.GetCount();
2091 for (sal_uInt16 nVisPos=0; nVisPos<nVisCount; nVisPos++)
2092 {
2093 String aVisName = aVisibleEntries[nVisPos]->GetString();
2094 ScDPSaveMember* pMember = pDim->GetMemberByName( aVisName );
2095 pMember->SetShowDetails( sal_False );
2096 }
2097 }
2098
2099 sal_uInt16 nEntryCount = aEntries.GetCount();
2100 for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
2101 {
2102 String aEntryName = aEntries[nEntry]->GetString();
2103 ScDPSaveMember* pMember = pDim->GetMemberByName( aEntryName );
2104 pMember->SetShowDetails( bShow );
2105 }
2106
2107 // apply changes
2108 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
2109 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
2110 pNewObj->SetSaveData( aData );
2111 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, sal_False );
2112 delete pNewObj;
2113
2114 // unmark cell selection
2115 Unmark();
2116 }
2117 }
2118 }
2119 }
2120
ShowDataPilotSourceData(ScDPObject & rDPObj,const Sequence<sheet::DataPilotFieldFilter> & rFilters)2121 void ScDBFunc::ShowDataPilotSourceData( ScDPObject& rDPObj, const Sequence<sheet::DataPilotFieldFilter>& rFilters )
2122 {
2123 ScDocument* pDoc = GetViewData()->GetDocument();
2124 if (pDoc->GetDocumentShell()->IsReadOnly())
2125 {
2126 ErrorMessage(STR_READONLYERR);
2127 return;
2128 }
2129
2130 Reference<sheet::XDimensionsSupplier> xDimSupplier = rDPObj.GetSource();
2131 Reference<container::XNameAccess> xDims = xDimSupplier->getDimensions();
2132 Reference<sheet::XDrillDownDataSupplier> xDDSupplier(xDimSupplier, UNO_QUERY);
2133 if (!xDDSupplier.is())
2134 return;
2135
2136 Sequence< Sequence<Any> > aTabData = xDDSupplier->getDrillDownData(rFilters);
2137 sal_Int32 nRowSize = aTabData.getLength();
2138 if (nRowSize <= 1)
2139 // There is no data to show. Bail out.
2140 return;
2141
2142 sal_Int32 nColSize = aTabData[0].getLength();
2143
2144 SCTAB nNewTab = GetViewData()->GetTabNo();
2145
2146 auto_ptr<ScDocument> pInsDoc(new ScDocument(SCDOCMODE_CLIP));
2147 pInsDoc->ResetClip( pDoc, nNewTab );
2148 for (SCROW nRow = 0; nRow < nRowSize; ++nRow)
2149 {
2150 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
2151 {
2152 const Any& rAny = aTabData[nRow][nCol];
2153 rtl::OUString aStr;
2154 double fVal;
2155 if (rAny >>= aStr)
2156 pInsDoc->PutCell( ScAddress(nCol, nRow, nNewTab), new ScStringCell(String(aStr)) );
2157 else if (rAny >>= fVal)
2158 pInsDoc->SetValue(nCol, nRow, nNewTab, fVal);
2159 }
2160 }
2161
2162 // set number format (important for dates)
2163 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
2164 {
2165 rtl::OUString aStr;
2166 if (!(aTabData[0][nCol] >>= aStr))
2167 continue;
2168
2169 Reference<XPropertySet> xPropSet(xDims->getByName(aStr), UNO_QUERY);
2170 if (!xPropSet.is())
2171 continue;
2172
2173 Any any = xPropSet->getPropertyValue( rtl::OUString::createFromAscii(SC_UNO_NUMBERFO) );
2174 sal_Int32 nNumFmt = 0;
2175 if (!(any >>= nNumFmt))
2176 continue;
2177
2178 ScPatternAttr aPattern( pInsDoc->GetPool() );
2179 aPattern.GetItemSet().Put( SfxUInt32Item(ATTR_VALUE_FORMAT, static_cast<sal_uInt32>(nNumFmt)) );
2180 pInsDoc->ApplyPatternAreaTab(nCol, 1, nCol, nRowSize-1, nNewTab, aPattern);
2181 }
2182
2183 SCCOL nEndCol = 0;
2184 SCROW nEndRow = 0;
2185 pInsDoc->GetCellArea( nNewTab, nEndCol, nEndRow );
2186 pInsDoc->SetClipArea( ScRange( 0, 0, nNewTab, nEndCol, nEndRow, nNewTab ) );
2187
2188 ::svl::IUndoManager* pMgr = GetViewData()->GetDocShell()->GetUndoManager();
2189 String aUndo = ScGlobal::GetRscString( STR_UNDO_DOOUTLINE );
2190 pMgr->EnterListAction( aUndo, aUndo );
2191
2192 String aNewTabName;
2193 pDoc->CreateValidTabName(aNewTabName);
2194 if ( InsertTable(aNewTabName, nNewTab) )
2195 PasteFromClip( IDF_ALL, pInsDoc.get() );
2196
2197 pMgr->LeaveListAction();
2198 }
2199
2200 //
2201 // DB-Operationen (Sortieren, Filtern, Teilergebnisse) wiederholen
2202 //
2203
RepeatDB(sal_Bool bRecord)2204 void ScDBFunc::RepeatDB( sal_Bool bRecord )
2205 {
2206 SCCOL nCurX = GetViewData()->GetCurX();
2207 SCROW nCurY = GetViewData()->GetCurY();
2208 SCTAB nTab = GetViewData()->GetTabNo();
2209 ScDocument* pDoc = GetViewData()->GetDocument();
2210 ScDBData* pDBData = GetDBData();
2211 if (bRecord && !pDoc->IsUndoEnabled())
2212 bRecord = sal_False;
2213
2214 ScQueryParam aQueryParam;
2215 pDBData->GetQueryParam( aQueryParam );
2216 sal_Bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
2217
2218 ScSortParam aSortParam;
2219 pDBData->GetSortParam( aSortParam );
2220 sal_Bool bSort = aSortParam.bDoSort[0];
2221
2222 ScSubTotalParam aSubTotalParam;
2223 pDBData->GetSubTotalParam( aSubTotalParam );
2224 sal_Bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
2225
2226 if ( bQuery || bSort || bSubTotal )
2227 {
2228 sal_Bool bQuerySize = sal_False;
2229 ScRange aOldQuery;
2230 ScRange aNewQuery;
2231 if (bQuery && !aQueryParam.bInplace)
2232 {
2233 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
2234 aQueryParam.nDestTab, sal_True );
2235 if (pDest && pDest->IsDoSize())
2236 {
2237 pDest->GetArea( aOldQuery );
2238 bQuerySize = sal_True;
2239 }
2240 }
2241
2242 SCTAB nDummy;
2243 SCCOL nStartCol;
2244 SCROW nStartRow;
2245 SCCOL nEndCol;
2246 SCROW nEndRow;
2247 pDBData->GetArea( nDummy, nStartCol, nStartRow, nEndCol, nEndRow );
2248
2249 //! Undo nur benötigte Daten ?
2250
2251 ScDocument* pUndoDoc = NULL;
2252 ScOutlineTable* pUndoTab = NULL;
2253 ScRangeName* pUndoRange = NULL;
2254 ScDBCollection* pUndoDB = NULL;
2255
2256 if (bRecord)
2257 {
2258 SCTAB nTabCount = pDoc->GetTableCount();
2259 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2260 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
2261 if (pTable)
2262 {
2263 pUndoTab = new ScOutlineTable( *pTable );
2264
2265 SCCOLROW nOutStartCol; // Zeilen/Spaltenstatus
2266 SCCOLROW nOutStartRow;
2267 SCCOLROW nOutEndCol;
2268 SCCOLROW nOutEndRow;
2269 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
2270 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
2271
2272 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True );
2273 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, sal_False, pUndoDoc );
2274 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, sal_False, pUndoDoc );
2275 }
2276 else
2277 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_False, sal_True );
2278
2279 // Datenbereich sichern - incl. Filter-Ergebnis
2280 pDoc->CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, sal_False, pUndoDoc );
2281
2282 // alle Formeln wegen Referenzen
2283 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, sal_False, pUndoDoc );
2284
2285 // DB- und andere Bereiche
2286 ScRangeName* pDocRange = pDoc->GetRangeName();
2287 if (pDocRange->GetCount())
2288 pUndoRange = new ScRangeName( *pDocRange );
2289 ScDBCollection* pDocDB = pDoc->GetDBCollection();
2290 if (pDocDB->GetCount())
2291 pUndoDB = new ScDBCollection( *pDocDB );
2292 }
2293
2294 if (bSort && bSubTotal)
2295 {
2296 // Sortieren ohne SubTotals
2297
2298 aSubTotalParam.bRemoveOnly = sal_True; // wird unten wieder zurückgesetzt
2299 DoSubTotals( aSubTotalParam, sal_False );
2300 }
2301
2302 if (bSort)
2303 {
2304 pDBData->GetSortParam( aSortParam ); // Bereich kann sich geändert haben
2305 Sort( aSortParam, sal_False, sal_False);
2306 }
2307 if (bQuery)
2308 {
2309 pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geändert haben
2310 ScRange aAdvSource;
2311 if (pDBData->GetAdvancedQuerySource(aAdvSource))
2312 {
2313 pDoc->CreateQueryParam(
2314 aAdvSource.aStart.Col(), aAdvSource.aStart.Row(),
2315 aAdvSource.aEnd.Col(), aAdvSource.aEnd.Row(),
2316 aAdvSource.aStart.Tab(), aQueryParam );
2317 Query( aQueryParam, &aAdvSource, sal_False );
2318 }
2319 else
2320 Query( aQueryParam, NULL, sal_False );
2321
2322 // bei nicht-inplace kann die Tabelle umgestellt worden sein
2323 if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
2324 SetTabNo( nTab );
2325 }
2326 if (bSubTotal)
2327 {
2328 pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geändert haben
2329 aSubTotalParam.bRemoveOnly = sal_False;
2330 DoSubTotals( aSubTotalParam, sal_False );
2331 }
2332
2333 if (bRecord)
2334 {
2335 SCTAB nDummyTab;
2336 SCCOL nDummyCol;
2337 SCROW nDummyRow, nNewEndRow;
2338 pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
2339
2340 const ScRange* pOld = NULL;
2341 const ScRange* pNew = NULL;
2342 if (bQuerySize)
2343 {
2344 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
2345 aQueryParam.nDestTab, sal_True );
2346 if (pDest)
2347 {
2348 pDest->GetArea( aNewQuery );
2349 pOld = &aOldQuery;
2350 pNew = &aNewQuery;
2351 }
2352 }
2353
2354 GetViewData()->GetDocShell()->GetUndoManager()->AddUndoAction(
2355 new ScUndoRepeatDB( GetViewData()->GetDocShell(), nTab,
2356 nStartCol, nStartRow, nEndCol, nEndRow,
2357 nNewEndRow,
2358 nCurX, nCurY,
2359 pUndoDoc, pUndoTab,
2360 pUndoRange, pUndoDB,
2361 pOld, pNew ) );
2362 }
2363
2364 GetViewData()->GetDocShell()->PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
2365 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE );
2366 }
2367 else // "Keine Operationen auszuführen"
2368 ErrorMessage(STR_MSSG_REPEATDB_0);
2369 }
2370
2371 /* vim: set noet sw=4 ts=4: */
2372