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