bump product version to 4.1.6.2
[LibreOffice.git] / sc / source / ui / view / dbfunc3.cxx
blob96a08ce284f558bfeed92491592503c4af2a290a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "dbfunc.hxx"
21 #include "scitems.hxx"
22 #include <sfx2/bindings.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/msgbox.hxx>
25 #include <vcl/waitobj.hxx>
26 #include <svl/zforlist.hxx>
27 #include <sfx2/app.hxx>
28 #include <com/sun/star/beans/XPropertySet.hpp>
29 #include <com/sun/star/container/XNameAccess.hpp>
30 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
31 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
32 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
33 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
34 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
35 #include <com/sun/star/sheet/GeneralFunction.hpp>
36 #include <com/sun/star/sheet/MemberResultFlags.hpp>
37 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
38 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
40 #include "global.hxx"
41 #include "globstr.hrc"
42 #include "sc.hrc"
43 #include "undotab.hxx"
44 #include "undodat.hxx"
45 #include "dbdata.hxx"
46 #include "rangenam.hxx"
47 #include "rangeutl.hxx"
48 #include "docsh.hxx"
49 #include "olinetab.hxx"
50 #include "consoli.hxx"
51 #include "olinefun.hxx"
52 #include "dpobject.hxx"
53 #include "dpsave.hxx"
54 #include "dpdimsave.hxx"
55 #include "dbdocfun.hxx"
56 #include "dpoutput.hxx"
57 #include "dptabsrc.hxx"
58 #include "dpshttab.hxx"
59 #include "dpsdbtab.hxx"
60 #include "editable.hxx"
61 #include "docpool.hxx"
62 #include "patattr.hxx"
63 #include "unonames.hxx"
64 #include "formulacell.hxx"
65 #include "userlist.hxx"
66 #include "queryentry.hxx"
67 #include "markdata.hxx"
68 #include "stringutil.hxx"
70 #include <boost/unordered_set.hpp>
71 #include <boost/unordered_map.hpp>
72 #include <memory>
73 #include <list>
74 #include <vector>
76 using namespace com::sun::star;
77 using ::com::sun::star::uno::Any;
78 using ::com::sun::star::uno::Sequence;
79 using ::com::sun::star::uno::Reference;
80 using ::com::sun::star::uno::UNO_QUERY;
81 using ::com::sun::star::beans::XPropertySet;
82 using ::com::sun::star::container::XNameAccess;
83 using ::com::sun::star::sheet::XDimensionsSupplier;
84 using ::std::auto_ptr;
85 using ::std::list;
86 using ::std::vector;
88 // STATIC DATA -----------------------------------------------------------
91 //==================================================================
94 // Outliner
97 // Outline-Gruppierung erzeugen
99 void ScDBFunc::MakeOutline( sal_Bool bColumns, sal_Bool bRecord )
101 ScRange aRange;
102 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
104 ScDocShell* pDocSh = GetViewData()->GetDocShell();
105 ScOutlineDocFunc aFunc(*pDocSh);
106 aFunc.MakeOutline( aRange, bColumns, bRecord, false );
108 else
109 ErrorMessage(STR_NOMULTISELECT);
112 // Outline-Gruppierung loeschen
114 void ScDBFunc::RemoveOutline( sal_Bool bColumns, sal_Bool bRecord )
116 ScRange aRange;
117 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
119 ScDocShell* pDocSh = GetViewData()->GetDocShell();
120 ScOutlineDocFunc aFunc(*pDocSh);
121 aFunc.RemoveOutline( aRange, bColumns, bRecord, false );
123 else
124 ErrorMessage(STR_NOMULTISELECT);
127 // Menue-Status: Outlines loeschen
129 void ScDBFunc::TestRemoveOutline( sal_Bool& rCol, sal_Bool& rRow )
131 sal_Bool bColFound = false;
132 sal_Bool bRowFound = false;
134 SCCOL nStartCol, nEndCol;
135 SCROW nStartRow, nEndRow;
136 SCTAB nStartTab, nEndTab;
137 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
139 SCTAB nTab = nStartTab;
140 ScDocument* pDoc = GetViewData()->GetDocument();
141 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
142 if (pTable)
144 ScOutlineArray* pArray;
145 ScOutlineEntry* pEntry;
146 SCCOLROW nStart;
147 SCCOLROW nEnd;
148 sal_Bool bColMarked = ( nStartRow == 0 && nEndRow == MAXROW );
149 sal_Bool bRowMarked = ( nStartCol == 0 && nEndCol == MAXCOL );
151 // Spalten
153 if ( !bRowMarked || bColMarked ) // nicht wenn ganze Zeilen markiert
155 pArray = pTable->GetColArray();
156 ScSubOutlineIterator aColIter( pArray );
157 while ((pEntry=aColIter.GetNext()) != NULL && !bColFound)
159 nStart = pEntry->GetStart();
160 nEnd = pEntry->GetEnd();
161 if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
162 bColFound = sal_True;
166 // Zeilen
168 if ( !bColMarked || bRowMarked ) // nicht wenn ganze Spalten markiert
170 pArray = pTable->GetRowArray();
171 ScSubOutlineIterator aRowIter( pArray );
172 while ((pEntry=aRowIter.GetNext()) != NULL && !bRowFound)
174 nStart = pEntry->GetStart();
175 nEnd = pEntry->GetEnd();
176 if ( nStartRow<=nEnd && nEndRow>=nStart )
177 bRowFound = sal_True;
183 rCol = bColFound;
184 rRow = bRowFound;
187 void ScDBFunc::RemoveAllOutlines( sal_Bool bRecord )
189 SCTAB nTab = GetViewData()->GetTabNo();
190 ScDocShell* pDocSh = GetViewData()->GetDocShell();
191 ScOutlineDocFunc aFunc(*pDocSh);
193 sal_Bool bOk = aFunc.RemoveAllOutlines( nTab, bRecord, false );
195 if (bOk)
196 UpdateScrollBars();
199 // Auto-Outlines
201 void ScDBFunc::AutoOutline( sal_Bool bRecord )
203 SCTAB nTab = GetViewData()->GetTabNo();
204 ScRange aRange( 0,0,nTab, MAXCOL,MAXROW,nTab ); // ganze Tabelle, wenn nichts markiert
205 ScMarkData& rMark = GetViewData()->GetMarkData();
206 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
208 rMark.MarkToMulti();
209 rMark.GetMultiMarkArea( aRange );
212 ScDocShell* pDocSh = GetViewData()->GetDocShell();
213 ScOutlineDocFunc aFunc(*pDocSh);
214 aFunc.AutoOutline( aRange, bRecord, false );
217 // Outline-Ebene auswaehlen
219 void ScDBFunc::SelectLevel( sal_Bool bColumns, sal_uInt16 nLevel, sal_Bool bRecord, sal_Bool bPaint )
221 SCTAB nTab = GetViewData()->GetTabNo();
222 ScDocShell* pDocSh = GetViewData()->GetDocShell();
223 ScOutlineDocFunc aFunc(*pDocSh);
225 sal_Bool bOk = aFunc.SelectLevel( nTab, bColumns, nLevel, bRecord, bPaint, false );
227 if (bOk)
228 UpdateScrollBars();
231 // einzelne Outline-Gruppe einblenden
233 void ScDBFunc::ShowOutline( sal_Bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bRecord, sal_Bool bPaint )
235 SCTAB nTab = GetViewData()->GetTabNo();
236 ScDocShell* pDocSh = GetViewData()->GetDocShell();
237 ScOutlineDocFunc aFunc(*pDocSh);
239 sal_Bool bOk = aFunc.ShowOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint, false );
241 if ( bOk && bPaint )
242 UpdateScrollBars();
245 // einzelne Outline-Gruppe ausblenden
247 void ScDBFunc::HideOutline( sal_Bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, sal_Bool bRecord, sal_Bool bPaint )
249 SCTAB nTab = GetViewData()->GetTabNo();
250 ScDocShell* pDocSh = GetViewData()->GetDocShell();
251 ScOutlineDocFunc aFunc(*pDocSh);
253 sal_Bool bOk = aFunc.HideOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint, false );
255 if ( bOk && bPaint )
256 UpdateScrollBars();
259 // Menue-Status: markierten Bereich ein-/ausblenden
261 sal_Bool ScDBFunc::OutlinePossible(sal_Bool bHide)
263 sal_Bool bEnable = false;
265 SCCOL nStartCol;
266 SCROW nStartRow;
267 SCTAB nStartTab;
268 SCCOL nEndCol;
269 SCROW nEndRow;
270 SCTAB nEndTab;
272 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
274 ScDocument* pDoc = GetViewData()->GetDocument();
275 SCTAB nTab = GetViewData()->GetTabNo();
276 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
277 if (pTable)
279 ScOutlineArray* pArray;
280 ScOutlineEntry* pEntry;
281 SCCOLROW nStart;
282 SCCOLROW nEnd;
284 // Spalten
286 pArray = pTable->GetColArray();
287 ScSubOutlineIterator aColIter( pArray );
288 while ((pEntry=aColIter.GetNext()) != NULL && !bEnable)
290 nStart = pEntry->GetStart();
291 nEnd = pEntry->GetEnd();
292 if ( bHide )
294 if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
295 if (!pEntry->IsHidden())
296 bEnable = sal_True;
298 else
300 if ( nStart>=nStartCol && nEnd<=nEndCol )
301 if (pEntry->IsHidden())
302 bEnable = sal_True;
306 // Zeilen
308 pArray = pTable->GetRowArray();
309 ScSubOutlineIterator aRowIter( pArray );
310 while ((pEntry=aRowIter.GetNext()) != NULL)
312 nStart = pEntry->GetStart();
313 nEnd = pEntry->GetEnd();
314 if ( bHide )
316 if ( nStartRow<=nEnd && nEndRow>=nStart )
317 if (!pEntry->IsHidden())
318 bEnable = sal_True;
320 else
322 if ( nStart>=nStartRow && nEnd<=nEndRow )
323 if (pEntry->IsHidden())
324 bEnable = sal_True;
330 return bEnable;
333 // markierten Bereich einblenden
335 void ScDBFunc::ShowMarkedOutlines( sal_Bool bRecord )
337 ScRange aRange;
338 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
340 ScDocShell* pDocSh = GetViewData()->GetDocShell();
341 ScOutlineDocFunc aFunc(*pDocSh);
342 sal_Bool bDone = aFunc.ShowMarkedOutlines( aRange, bRecord );
343 if (bDone)
344 UpdateScrollBars();
346 else
347 ErrorMessage(STR_NOMULTISELECT);
350 // markierten Bereich ausblenden
352 void ScDBFunc::HideMarkedOutlines( sal_Bool bRecord )
354 ScRange aRange;
355 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
357 ScDocShell* pDocSh = GetViewData()->GetDocShell();
358 ScOutlineDocFunc aFunc(*pDocSh);
359 sal_Bool bDone = aFunc.HideMarkedOutlines( aRange, bRecord, false );
360 if (bDone)
361 UpdateScrollBars();
363 else
364 ErrorMessage(STR_NOMULTISELECT);
367 // --------------------------------------------------------------------------
370 // Teilergebnisse
373 void ScDBFunc::DoSubTotals( const ScSubTotalParam& rParam, sal_Bool bRecord,
374 const ScSortParam* pForceNewSort )
376 sal_Bool bDo = !rParam.bRemoveOnly; // sal_False = nur loeschen
378 ScDocShell* pDocSh = GetViewData()->GetDocShell();
379 ScDocument* pDoc = pDocSh->GetDocument();
380 ScMarkData& rMark = GetViewData()->GetMarkData();
381 SCTAB nTab = GetViewData()->GetTabNo();
382 if (bRecord && !pDoc->IsUndoEnabled())
383 bRecord = false;
385 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
386 rParam.nCol2, rParam.nRow2 );
387 if (!pDBData)
389 OSL_FAIL( "SubTotals: keine DBData" );
390 return;
393 ScEditableTester aTester( pDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW );
394 if (!aTester.IsEditable())
396 ErrorMessage(aTester.GetMessageId());
397 return;
400 if (pDoc->HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
401 rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
403 ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen
404 return;
407 WaitObject aWait( GetViewData()->GetDialogParent() );
408 sal_Bool bOk = true;
409 if (rParam.bReplace)
410 if (pDoc->TestRemoveSubTotals( nTab, rParam ))
412 bOk = ( MessBox( GetViewData()->GetDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
413 // "StarCalc" "Daten loeschen?"
414 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
415 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) ).Execute()
416 == RET_YES );
419 if (bOk)
421 ScDocShellModificator aModificator( *pDocSh );
423 ScSubTotalParam aNewParam( rParam ); // Bereichsende wird veraendert
424 ScDocument* pUndoDoc = NULL;
425 ScOutlineTable* pUndoTab = NULL;
426 ScRangeName* pUndoRange = NULL;
427 ScDBCollection* pUndoDB = NULL;
429 if (bRecord) // alte Daten sichern
431 sal_Bool bOldFilter = bDo && rParam.bDoSort;
432 SCTAB nTabCount = pDoc->GetTableCount();
433 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
434 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
435 if (pTable)
437 pUndoTab = new ScOutlineTable( *pTable );
439 SCCOLROW nOutStartCol; // Zeilen/Spaltenstatus
440 SCCOLROW nOutStartRow;
441 SCCOLROW nOutEndCol;
442 SCCOLROW nOutEndRow;
443 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
444 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
446 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True );
447 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, false, pUndoDoc );
448 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, false, pUndoDoc );
450 else
451 pUndoDoc->InitUndo( pDoc, nTab, nTab, false, bOldFilter );
453 // Datenbereich sichern - incl. Filter-Ergebnis
454 pDoc->CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab,
455 IDF_ALL, false, pUndoDoc );
457 // alle Formeln wegen Referenzen
458 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
459 IDF_FORMULA, false, pUndoDoc );
461 // DB- und andere Bereiche
462 ScRangeName* pDocRange = pDoc->GetRangeName();
463 if (!pDocRange->empty())
464 pUndoRange = new ScRangeName( *pDocRange );
465 ScDBCollection* pDocDB = pDoc->GetDBCollection();
466 if (!pDocDB->empty())
467 pUndoDB = new ScDBCollection( *pDocDB );
470 ScOutlineTable* pOut = pDoc->GetOutlineTable( nTab );
471 if (pOut)
473 // Remove all existing outlines in the specified range.
474 ScOutlineArray* pRowArray = pOut->GetRowArray();
475 sal_uInt16 nDepth = pRowArray->GetDepth();
476 for (sal_uInt16 i = 0; i < nDepth; ++i)
478 bool bSize;
479 pRowArray->Remove(aNewParam.nRow1, aNewParam.nRow2, bSize);
483 if (rParam.bReplace)
484 pDoc->RemoveSubTotals( nTab, aNewParam );
485 sal_Bool bSuccess = sal_True;
486 if (bDo)
488 // Sortieren
489 if ( rParam.bDoSort || pForceNewSort )
491 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
493 // Teilergebnis-Felder vor die Sortierung setzen
494 // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
496 ScSortParam aOldSort;
497 pDBData->GetSortParam( aOldSort );
498 ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
499 Sort( aSortParam, false, false );
502 bSuccess = pDoc->DoSubTotals( nTab, aNewParam );
504 ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
505 aNewParam.nCol2, aNewParam.nRow2, nTab );
506 pDoc->SetDirty( aDirtyRange );
508 if (bRecord)
510 pDocSh->GetUndoManager()->AddUndoAction(
511 new ScUndoSubTotals( pDocSh, nTab,
512 rParam, aNewParam.nRow2,
513 pUndoDoc, pUndoTab, // pUndoDBData,
514 pUndoRange, pUndoDB ) );
517 if (!bSuccess)
519 // "Kann keine Zeilen einfuegen"
520 ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
523 // merken
524 pDBData->SetSubTotalParam( aNewParam );
525 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
526 pDoc->CompileDBFormula();
528 DoneBlockMode();
529 InitOwnBlockMode();
530 rMark.SetMarkArea( ScRange( aNewParam.nCol1,aNewParam.nRow1,nTab,
531 aNewParam.nCol2,aNewParam.nRow2,nTab ) );
532 MarkDataChanged();
534 pDocSh->PostPaint(ScRange(0, 0, nTab, MAXCOL, MAXROW, nTab),
535 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE);
537 aModificator.SetDocumentModified();
539 SelectionChanged();
544 // Consolidate
547 void ScDBFunc::Consolidate( const ScConsolidateParam& rParam, sal_Bool bRecord )
549 ScDocShell* pDocShell = GetViewData()->GetDocShell();
550 pDocShell->DoConsolidate( rParam, bRecord );
551 SetTabNo( rParam.nTab, sal_True );
555 // Pivot
558 static OUString lcl_MakePivotTabName( const String& rPrefix, SCTAB nNumber )
560 OUString aName = rPrefix + OUString::number( nNumber );
561 return aName;
564 bool ScDBFunc::MakePivotTable(
565 const ScDPSaveData& rData, const ScRange& rDest, bool bNewTable,
566 const ScDPObject& rSource, bool bApi )
568 // error message if no fields are set
569 // this must be removed when drag&drop of fields from a toolbox is available
571 if ( rData.IsEmpty() && !bApi )
573 ErrorMessage(STR_PIVOT_NODATA);
574 return false;
577 ScDocShell* pDocSh = GetViewData()->GetDocShell();
578 ScDocument* pDoc = GetViewData()->GetDocument();
579 bool bUndo = pDoc->IsUndoEnabled();
581 ScRange aDestRange = rDest;
582 if ( bNewTable )
584 SCTAB nSrcTab = GetViewData()->GetTabNo();
586 String aName( ScGlobal::GetRscString(STR_PIVOT_TABLE) );
587 OUString aStr;
589 pDoc->GetName( nSrcTab, aStr );
590 aName += '_';
591 aName += String(aStr);
592 aName += '_';
594 SCTAB nNewTab = nSrcTab+1;
596 SCTAB i=1;
597 while ( !pDoc->InsertTab( nNewTab, lcl_MakePivotTabName( aName, i ) ) && i <= MAXTAB )
598 i++;
600 bool bAppend = ( nNewTab+1 == pDoc->GetTableCount() );
601 if (bUndo)
603 pDocSh->GetUndoManager()->AddUndoAction(
604 new ScUndoInsertTab( pDocSh, nNewTab, bAppend, lcl_MakePivotTabName( aName, i ) ));
607 GetViewData()->InsertTab( nNewTab );
608 SetTabNo(nNewTab, true);
610 aDestRange = ScRange( 0, 0, nNewTab );
613 ScDPObject* pDPObj = pDoc->GetDPAtCursor(
614 aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aStart.Tab() );
616 ScDPObject aObj( rSource );
617 aObj.SetOutRange( aDestRange );
618 if ( pDPObj && !rData.GetExistingDimensionData() )
620 // copy dimension data from old object - lost in the dialog
621 //! change the dialog to keep the dimension data
623 ScDPSaveData aNewData( rData );
624 const ScDPSaveData* pOldData = pDPObj->GetSaveData();
625 if ( pOldData )
627 const ScDPDimensionSaveData* pDimSave = pOldData->GetExistingDimensionData();
628 aNewData.SetDimensionData( pDimSave );
630 aObj.SetSaveData( aNewData );
632 else
633 aObj.SetSaveData( rData );
635 bool bAllowMove = (pDPObj != NULL); // allow re-positioning when editing existing table
637 ScDBDocFunc aFunc( *pDocSh );
638 bool bSuccess = aFunc.DataPilotUpdate(pDPObj, &aObj, true, false, bAllowMove);
640 CursorPosChanged(); // shells may be switched
642 if ( bNewTable )
644 pDocSh->PostPaintExtras();
645 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
648 return bSuccess;
651 void ScDBFunc::DeletePivotTable()
653 ScDocShell* pDocSh = GetViewData()->GetDocShell();
654 ScDocument* pDoc = pDocSh->GetDocument();
655 ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(),
656 GetViewData()->GetCurY(),
657 GetViewData()->GetTabNo() );
658 if ( pDPObj )
660 ScDBDocFunc aFunc( *pDocSh );
661 aFunc.RemovePivotTable(*pDPObj, true, false);
662 CursorPosChanged(); // shells may be switched
664 else
665 ErrorMessage(STR_PIVOT_NOTFOUND);
668 void ScDBFunc::RecalcPivotTable()
670 ScDocShell* pDocSh = GetViewData()->GetDocShell();
671 ScDocument* pDoc = GetViewData()->GetDocument();
673 ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(),
674 GetViewData()->GetCurY(),
675 GetViewData()->GetTabNo() );
676 if (pDPObj)
678 // Remove existing data cache for the data that this datapilot uses,
679 // to force re-build data cache.
680 ScDBDocFunc aFunc(*pDocSh);
681 aFunc.RefreshPivotTables(pDPObj, false);
683 CursorPosChanged(); // shells may be switched
685 else
686 ErrorMessage(STR_PIVOT_NOTFOUND);
689 void ScDBFunc::GetSelectedMemberList(ScDPUniqueStringSet& rEntries, long& rDimension)
691 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
692 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
693 if ( !pDPObj )
694 return;
696 long nStartDimension = -1;
697 long nStartHierarchy = -1;
698 long nStartLevel = -1;
700 ScRangeListRef xRanges;
701 GetViewData()->GetMultiArea( xRanges ); // incl. cursor if nothing is selected
702 size_t nRangeCount = xRanges->size();
703 sal_Bool bContinue = true;
705 for (size_t nRangePos=0; nRangePos < nRangeCount && bContinue; nRangePos++)
707 ScRange aRange = *(*xRanges)[nRangePos];
708 SCCOL nStartCol = aRange.aStart.Col();
709 SCROW nStartRow = aRange.aStart.Row();
710 SCCOL nEndCol = aRange.aEnd.Col();
711 SCROW nEndRow = aRange.aEnd.Row();
712 SCTAB nTab = aRange.aStart.Tab();
714 for (SCROW nRow=nStartRow; nRow<=nEndRow && bContinue; nRow++)
715 for (SCCOL nCol=nStartCol; nCol<=nEndCol && bContinue; nCol++)
717 sheet::DataPilotTableHeaderData aData;
718 pDPObj->GetHeaderPositionData(ScAddress(nCol, nRow, nTab), aData);
719 if ( aData.Dimension < 0 )
720 bContinue = false; // not part of any dimension
721 else
723 if ( nStartDimension < 0 ) // first member?
725 nStartDimension = aData.Dimension;
726 nStartHierarchy = aData.Hierarchy;
727 nStartLevel = aData.Level;
729 if ( aData.Dimension != nStartDimension ||
730 aData.Hierarchy != nStartHierarchy ||
731 aData.Level != nStartLevel )
733 bContinue = false; // cannot mix dimensions
736 if ( bContinue )
738 // accept any part of a member description, also subtotals,
739 // but don't stop if empty parts are contained
740 if ( aData.Flags & sheet::MemberResultFlags::HASMEMBER )
741 rEntries.insert(aData.MemberName);
746 rDimension = nStartDimension; // dimension from which the found members came
747 if (!bContinue)
748 rEntries.clear(); // remove all if not valid
751 bool ScDBFunc::HasSelectionForDateGroup( ScDPNumGroupInfo& rOldInfo, sal_Int32& rParts )
753 // determine if the date group dialog has to be shown for the current selection
755 bool bFound = false;
757 SCCOL nCurX = GetViewData()->GetCurX();
758 SCROW nCurY = GetViewData()->GetCurY();
759 SCTAB nTab = GetViewData()->GetTabNo();
760 ScDocument* pDoc = GetViewData()->GetDocument();
762 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nCurX, nCurY, nTab );
763 if ( pDPObj )
765 ScDPUniqueStringSet aEntries;
766 long nSelectDimension = -1;
767 GetSelectedMemberList( aEntries, nSelectDimension );
769 if (!aEntries.empty())
771 bool bIsDataLayout;
772 OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
773 String aBaseDimName( aDimName );
775 sal_Bool bInGroupDim = false;
776 sal_Bool bFoundParts = false;
778 ScDPDimensionSaveData* pDimData =
779 const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
780 if ( pDimData )
782 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
783 const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( aDimName );
784 if ( pNumGroupDim )
786 // existing num group dimension
788 if ( pNumGroupDim->GetDatePart() != 0 )
790 // dimension has date info -> edit settings of this dimension
791 // (parts are collected below)
793 rOldInfo = pNumGroupDim->GetDateInfo();
794 bFound = sal_True;
796 else if ( pNumGroupDim->GetInfo().mbDateValues )
798 // Numerical grouping with DateValues flag is used for grouping
799 // of days with a "Number of days" value.
801 rOldInfo = pNumGroupDim->GetInfo();
802 rParts = com::sun::star::sheet::DataPilotFieldGroupBy::DAYS; // not found in CollectDateParts
803 bFoundParts = sal_True;
804 bFound = sal_True;
806 bInGroupDim = sal_True;
808 else if ( pGroupDim )
810 // existing additional group dimension
812 if ( pGroupDim->GetDatePart() != 0 )
814 // dimension has date info -> edit settings of this dimension
815 // (parts are collected below)
817 rOldInfo = pGroupDim->GetDateInfo();
818 aBaseDimName = pGroupDim->GetSourceDimName();
819 bFound = sal_True;
821 bInGroupDim = sal_True;
824 if ( bFound && !bFoundParts )
826 // collect date parts from all group dimensions
827 rParts = pDimData->CollectDateParts( aBaseDimName );
829 if ( !bFound && !bInGroupDim )
831 // create new date group dimensions if the selection is a single cell
832 // in a normal dimension with date content
834 ScRange aSelRange;
835 if ( (GetViewData()->GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
836 aSelRange.aStart == aSelRange.aEnd )
838 SCCOL nSelCol = aSelRange.aStart.Col();
839 SCROW nSelRow = aSelRange.aStart.Row();
840 SCTAB nSelTab = aSelRange.aStart.Tab();
841 if ( pDoc->HasValueData( nSelCol, nSelRow, nSelTab ) )
843 sal_uLong nIndex = static_cast<const SfxUInt32Item*>(pDoc->GetAttr(
844 nSelCol, nSelRow, nSelTab, ATTR_VALUE_FORMAT))->GetValue();
845 short nType = pDoc->GetFormatTable()->GetType(nIndex);
846 if ( nType == NUMBERFORMAT_DATE || nType == NUMBERFORMAT_TIME || nType == NUMBERFORMAT_DATETIME )
848 bFound = sal_True;
849 // use currently selected value for automatic limits
850 if( rOldInfo.mbAutoStart )
851 rOldInfo.mfStart = pDoc->GetValue( aSelRange.aStart );
852 if( rOldInfo.mbAutoEnd )
853 rOldInfo.mfEnd = pDoc->GetValue( aSelRange.aStart );
861 return bFound;
864 bool ScDBFunc::HasSelectionForNumGroup( ScDPNumGroupInfo& rOldInfo )
866 // determine if the numeric group dialog has to be shown for the current selection
868 bool bFound = false;
870 SCCOL nCurX = GetViewData()->GetCurX();
871 SCROW nCurY = GetViewData()->GetCurY();
872 SCTAB nTab = GetViewData()->GetTabNo();
873 ScDocument* pDoc = GetViewData()->GetDocument();
875 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nCurX, nCurY, nTab );
876 if ( pDPObj )
878 ScDPUniqueStringSet aEntries;
879 long nSelectDimension = -1;
880 GetSelectedMemberList( aEntries, nSelectDimension );
882 if (!aEntries.empty())
884 bool bIsDataLayout;
885 OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
887 sal_Bool bInGroupDim = false;
889 ScDPDimensionSaveData* pDimData =
890 const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
891 if ( pDimData )
893 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
894 if ( pNumGroupDim )
896 // existing num group dimension
897 // -> edit settings of this dimension
899 rOldInfo = pNumGroupDim->GetInfo();
900 bFound = sal_True;
902 else if ( pDimData->GetNamedGroupDim( aDimName ) )
903 bInGroupDim = sal_True; // in a group dimension
905 if ( !bFound && !bInGroupDim )
907 // create a new num group dimension if the selection is a single cell
908 // in a normal dimension with numeric content
910 ScRange aSelRange;
911 if ( (GetViewData()->GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
912 aSelRange.aStart == aSelRange.aEnd )
914 if ( pDoc->HasValueData( aSelRange.aStart.Col(), aSelRange.aStart.Row(),
915 aSelRange.aStart.Tab() ) )
917 bFound = sal_True;
918 // use currently selected value for automatic limits
919 if( rOldInfo.mbAutoStart )
920 rOldInfo.mfStart = pDoc->GetValue( aSelRange.aStart );
921 if( rOldInfo.mbAutoEnd )
922 rOldInfo.mfEnd = pDoc->GetValue( aSelRange.aStart );
929 return bFound;
932 void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo& rInfo, sal_Int32 nParts )
934 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
935 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
936 if (!pDPObj)
937 return;
939 ScDPUniqueStringSet aEntries;
940 long nSelectDimension = -1;
941 GetSelectedMemberList( aEntries, nSelectDimension );
943 if (aEntries.empty())
944 return;
946 std::vector<OUString> aDeletedNames;
947 bool bIsDataLayout;
948 OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
950 ScDPSaveData aData( *pDPObj->GetSaveData() );
951 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
953 // find the source dimension name.
954 OUString aBaseDimName = aDimName;
955 if( const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName ) )
956 aBaseDimName = pBaseGroupDim->GetSourceDimName();
958 // Remove all group dimensions associated with this source dimension. For
959 // date grouping, we need to remove all existing groups for the affected
960 // source dimension and build new one(s) from scratch. Keep the deleted
961 // names so that they can be reused during re-construction.
962 aData.RemoveAllGroupDimensions(aBaseDimName, &aDeletedNames);
964 if ( nParts )
966 // create date group dimensions
968 ScDPNumGroupInfo aEmpty;
969 bool bFirst = true;
970 sal_Int32 nMask = 1;
971 for (sal_uInt16 nBit=0; nBit<32; nBit++)
973 if ( nParts & nMask )
975 if ( bFirst )
977 // innermost part: create NumGroupDimension (replacing original values)
978 // Dimension name is left unchanged
980 if ( (nParts == sheet::DataPilotFieldGroupBy::DAYS) && (rInfo.mfStep >= 1.0) )
982 // only days, and a step value specified: use numerical grouping
983 // with DateValues flag, not date grouping
985 ScDPNumGroupInfo aNumInfo( rInfo );
986 aNumInfo.mbDateValues = true;
988 ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, aNumInfo );
989 pDimData->AddNumGroupDimension( aNumGroupDim );
991 else
993 ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, rInfo, nMask );
994 pDimData->AddNumGroupDimension( aNumGroupDim );
997 bFirst = false;
999 else
1001 // additional parts: create GroupDimension (shown as additional dimensions)
1002 OUString aGroupDimName =
1003 pDimData->CreateDateGroupDimName(nMask, *pDPObj, true, &aDeletedNames);
1004 ScDPSaveGroupDimension aGroupDim( aBaseDimName, aGroupDimName );
1005 aGroupDim.SetDateInfo( rInfo, nMask );
1006 pDimData->AddGroupDimension( aGroupDim );
1008 // set orientation
1009 ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
1010 if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
1012 ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aBaseDimName );
1013 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
1014 long nPosition = 0; //! before (immediate) base
1015 aData.SetPosition( pSaveDimension, nPosition );
1019 nMask *= 2;
1023 // apply changes
1024 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1025 pDPObj->SetSaveData( aData );
1026 aFunc.RefreshPivotTableGroups(pDPObj);
1028 // unmark cell selection
1029 Unmark();
1032 void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo& rInfo )
1034 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1035 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1036 if (!pDPObj)
1037 return;
1039 ScDPUniqueStringSet aEntries;
1040 long nSelectDimension = -1;
1041 GetSelectedMemberList( aEntries, nSelectDimension );
1043 if (aEntries.empty())
1044 return;
1046 bool bIsDataLayout;
1047 OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1049 ScDPSaveData aData( *pDPObj->GetSaveData() );
1050 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1052 ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( aDimName );
1053 if ( pExisting )
1055 // modify existing group dimension
1056 pExisting->SetGroupInfo( rInfo );
1058 else
1060 // create new group dimension
1061 ScDPSaveNumGroupDimension aNumGroupDim( aDimName, rInfo );
1062 pDimData->AddNumGroupDimension( aNumGroupDim );
1065 // apply changes
1066 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1067 pDPObj->SetSaveData( aData );
1068 aFunc.RefreshPivotTableGroups(pDPObj);
1070 // unmark cell selection
1071 Unmark();
1074 void ScDBFunc::GroupDataPilot()
1076 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1077 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1078 if (!pDPObj)
1079 return;
1081 ScDPUniqueStringSet aEntries;
1082 long nSelectDimension = -1;
1083 GetSelectedMemberList( aEntries, nSelectDimension );
1085 if (aEntries.empty())
1086 return;
1088 bool bIsDataLayout;
1089 OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1091 ScDPSaveData aData( *pDPObj->GetSaveData() );
1092 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1094 // find original base
1095 OUString aBaseDimName = aDimName;
1096 const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
1097 if ( pBaseGroupDim )
1099 // any entry's SourceDimName is the original base
1100 aBaseDimName = pBaseGroupDim->GetSourceDimName();
1103 // find existing group dimension
1104 // (using the selected dim, can be intermediate group dim)
1105 ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
1107 // remove the selected items from their groups
1108 // (empty groups are removed, too)
1109 if ( pGroupDimension )
1111 ScDPUniqueStringSet::const_iterator it = aEntries.begin(), itEnd = aEntries.end();
1112 for (; it != itEnd; ++it)
1114 const OUString& aEntryName = *it;
1115 if ( pBaseGroupDim )
1117 // for each selected (intermediate) group, remove all its items
1118 // (same logic as for adding, below)
1119 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
1120 if ( pBaseGroup )
1121 pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements
1122 else
1123 pGroupDimension->RemoveFromGroups( aEntryName );
1125 else
1126 pGroupDimension->RemoveFromGroups( aEntryName );
1130 ScDPSaveGroupDimension* pNewGroupDim = NULL;
1131 if ( !pGroupDimension )
1133 // create a new group dimension
1134 OUString aGroupDimName =
1135 pDimData->CreateGroupDimName(aBaseDimName, *pDPObj, false, NULL);
1136 pNewGroupDim = new ScDPSaveGroupDimension( aBaseDimName, aGroupDimName );
1138 pGroupDimension = pNewGroupDim; // make changes to the new dim if none existed
1140 if ( pBaseGroupDim )
1142 // If it's a higher-order group dimension, pre-allocate groups for all
1143 // non-selected original groups, so the individual base members aren't
1144 // used for automatic groups (this would make the original groups hard
1145 // to find).
1146 //! Also do this when removing groups?
1147 //! Handle this case dynamically with automatic groups?
1149 long nGroupCount = pBaseGroupDim->GetGroupCount();
1150 for ( long nGroup = 0; nGroup < nGroupCount; nGroup++ )
1152 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
1154 if (!aEntries.count(pBaseGroup->GetGroupName()))
1156 // add an additional group for each item that is not in the selection
1157 ScDPSaveGroupItem aGroup( pBaseGroup->GetGroupName() );
1158 aGroup.AddElementsFromGroup( *pBaseGroup );
1159 pGroupDimension->AddGroupItem( aGroup );
1164 OUString aGroupDimName = pGroupDimension->GetGroupDimName();
1166 OUString aGroupName = pGroupDimension->CreateGroupName(ScGlobal::GetRscString(STR_PIVOT_GROUP));
1167 ScDPSaveGroupItem aGroup( aGroupName );
1168 ScDPUniqueStringSet::const_iterator it = aEntries.begin(), itEnd = aEntries.end();
1169 for (; it != itEnd; ++it)
1171 const OUString& aEntryName = *it;
1172 if ( pBaseGroupDim )
1174 // for each selected (intermediate) group, add all its items
1175 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
1176 if ( pBaseGroup )
1177 aGroup.AddElementsFromGroup( *pBaseGroup );
1178 else
1179 aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself
1181 else
1182 aGroup.AddElement( aEntryName ); // no group dimension, add all items directly
1185 pGroupDimension->AddGroupItem( aGroup );
1187 if ( pNewGroupDim )
1189 pDimData->AddGroupDimension( *pNewGroupDim );
1190 delete pNewGroupDim; // AddGroupDimension copies the object
1191 // don't access pGroupDimension after here
1193 pGroupDimension = pNewGroupDim = NULL;
1195 // set orientation
1196 ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
1197 if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
1199 ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aDimName );
1200 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
1201 long nPosition = 0; //! before (immediate) base
1202 aData.SetPosition( pSaveDimension, nPosition );
1205 // apply changes
1206 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1207 pDPObj->SetSaveData( aData );
1208 aFunc.RefreshPivotTableGroups(pDPObj);
1210 // unmark cell selection
1211 Unmark();
1214 void ScDBFunc::UngroupDataPilot()
1216 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1217 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1218 if (!pDPObj)
1219 return;
1221 ScDPUniqueStringSet aEntries;
1222 long nSelectDimension = -1;
1223 GetSelectedMemberList( aEntries, nSelectDimension );
1225 if (aEntries.empty())
1226 return;
1228 bool bIsDataLayout;
1229 OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1231 ScDPSaveData aData( *pDPObj->GetSaveData() );
1232 if (!aData.GetExistingDimensionData())
1233 // There is nothing to ungroup.
1234 return;
1236 ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1238 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
1239 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
1240 if ( ( pGroupDim && pGroupDim->GetDatePart() != 0 ) ||
1241 ( pNumGroupDim && pNumGroupDim->GetDatePart() != 0 ) )
1243 // Date grouping: need to remove all affected group dimensions.
1244 // This is done using DateGroupDataPilot with nParts=0.
1246 DateGroupDataPilot( ScDPNumGroupInfo(), 0 );
1247 return;
1250 if ( pGroupDim )
1252 ScDPUniqueStringSet::const_iterator it = aEntries.begin(), itEnd = aEntries.end();
1253 for (; it != itEnd; ++it)
1254 pGroupDim->RemoveGroup(*it);
1256 // remove group dimension if empty
1257 bool bEmptyDim = pGroupDim->IsEmpty();
1258 if ( !bEmptyDim )
1260 // If all remaining groups in the dimension aren't shown, remove
1261 // the dimension too, as if it was completely empty.
1262 ScDPUniqueStringSet aVisibleEntries;
1263 pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
1264 bEmptyDim = pGroupDim->HasOnlyHidden( aVisibleEntries );
1266 if ( bEmptyDim )
1268 pDimData->RemoveGroupDimension( aDimName ); // pGroupDim is deleted
1270 // also remove SaveData settings for the dimension that no longer exists
1271 aData.RemoveDimensionByName( aDimName );
1274 else if ( pNumGroupDim )
1276 // remove the numerical grouping
1277 pDimData->RemoveNumGroupDimension( aDimName );
1278 // SaveData settings can remain unchanged - the same dimension still exists
1281 // apply changes
1282 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1283 pDPObj->SetSaveData( aData );
1284 aFunc.RefreshPivotTableGroups(pDPObj);
1286 // unmark cell selection
1287 Unmark();
1290 static OUString lcl_replaceMemberNameInSubtotal(const OUString& rSubtotal, const OUString& rMemberName)
1292 sal_Int32 n = rSubtotal.getLength();
1293 const sal_Unicode* p = rSubtotal.getStr();
1294 OUStringBuffer aBuf, aWordBuf;
1295 for (sal_Int32 i = 0; i < n; ++i)
1297 sal_Unicode c = p[i];
1298 if (c == sal_Unicode(' '))
1300 OUString aWord = aWordBuf.makeStringAndClear();
1301 if (aWord.equals(rMemberName))
1302 aBuf.append(sal_Unicode('?'));
1303 else
1304 aBuf.append(aWord);
1305 aBuf.append(c);
1307 else if (c == sal_Unicode('\\'))
1309 // Escape a backslash character.
1310 aWordBuf.append(c);
1311 aWordBuf.append(c);
1313 else if (c == sal_Unicode('?'))
1315 // A literal '?' must be escaped with a backslash ('\');
1316 aWordBuf.append(sal_Unicode('\\'));
1317 aWordBuf.append(c);
1319 else
1320 aWordBuf.append(c);
1323 if (aWordBuf.getLength() > 0)
1325 OUString aWord = aWordBuf.makeStringAndClear();
1326 if (aWord.equals(rMemberName))
1327 aBuf.append(sal_Unicode('?'));
1328 else
1329 aBuf.append(aWord);
1332 return aBuf.makeStringAndClear();
1335 void ScDBFunc::DataPilotInput( const ScAddress& rPos, const OUString& rString )
1337 using namespace ::com::sun::star::sheet;
1339 ScDocument* pDoc = GetViewData()->GetDocument();
1340 ScDPObject* pDPObj = pDoc->GetDPAtCursor( rPos.Col(), rPos.Row(), rPos.Tab() );
1341 if (!pDPObj)
1342 return;
1344 OUString aOldText = pDoc->GetString(rPos.Col(), rPos.Row(), rPos.Tab());
1346 if ( aOldText == rString )
1348 // nothing to do: silently exit
1349 return;
1352 sal_uInt16 nErrorId = 0;
1354 pDPObj->BuildAllDimensionMembers();
1355 ScDPSaveData aData( *pDPObj->GetSaveData() );
1356 bool bChange = false;
1358 sal_uInt16 nOrient = DataPilotFieldOrientation_HIDDEN;
1359 long nField = pDPObj->GetHeaderDim( rPos, nOrient );
1360 if ( nField >= 0 )
1362 // changing a field title
1363 if ( aData.GetExistingDimensionData() )
1365 // only group dimensions can be renamed
1367 ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1368 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aOldText );
1369 if ( pGroupDim )
1371 // valid name: not empty, no existing dimension (group or other)
1372 if (!rString.isEmpty() && !pDPObj->IsDimNameInUse(rString))
1374 pGroupDim->Rename( rString );
1376 // also rename in SaveData to preserve the field settings
1377 ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aOldText );
1378 pSaveDim->SetName( rString );
1380 bChange = true;
1382 else
1383 nErrorId = STR_INVALIDNAME;
1386 else if (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW)
1388 bool bDataLayout = false;
1389 OUString aDimName = pDPObj->GetDimName(nField, bDataLayout);
1390 ScDPSaveDimension* pDim = bDataLayout ? aData.GetDataLayoutDimension() : aData.GetDimensionByName(aDimName);
1391 if (pDim)
1393 if (!rString.isEmpty())
1395 if (rString.equalsIgnoreAsciiCase(aDimName))
1397 pDim->RemoveLayoutName();
1398 bChange = true;
1400 else if (!pDPObj->IsDimNameInUse(rString))
1402 pDim->SetLayoutName(rString);
1403 bChange = true;
1405 else
1406 nErrorId = STR_INVALIDNAME;
1408 else
1409 nErrorId = STR_INVALIDNAME;
1413 else if (pDPObj->IsDataDescriptionCell(rPos))
1415 // There is only one data dimension.
1416 ScDPSaveDimension* pDim = aData.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA);
1417 if (pDim)
1419 if (!rString.isEmpty())
1421 if (pDim->GetName().equalsIgnoreAsciiCase(rString))
1423 pDim->RemoveLayoutName();
1424 bChange = true;
1426 else if (!pDPObj->IsDimNameInUse(rString))
1428 pDim->SetLayoutName(rString);
1429 bChange = true;
1431 else
1432 nErrorId = STR_INVALIDNAME;
1434 else
1435 nErrorId = STR_INVALIDNAME;
1438 else
1440 // This is not a field header.
1441 sheet::DataPilotTableHeaderData aPosData;
1442 pDPObj->GetHeaderPositionData(rPos, aPosData);
1444 if ((aPosData.Flags & MemberResultFlags::HASMEMBER) && !aOldText.isEmpty())
1446 if ( aData.GetExistingDimensionData() && !(aPosData.Flags & MemberResultFlags::SUBTOTAL))
1448 bool bIsDataLayout;
1449 OUString aDimName = pDPObj->GetDimName( aPosData.Dimension, bIsDataLayout );
1451 ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1452 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
1453 if ( pGroupDim )
1455 // valid name: not empty, no existing group in this dimension
1456 //! ignore case?
1457 if (!rString.isEmpty() && !pGroupDim->GetNamedGroup(rString))
1459 ScDPSaveGroupItem* pGroup = pGroupDim->GetNamedGroupAcc( aOldText );
1460 if ( pGroup )
1461 pGroup->Rename( rString ); // rename the existing group
1462 else
1464 // create a new group to replace the automatic group
1465 ScDPSaveGroupItem aGroup( rString );
1466 aGroup.AddElement( aOldText );
1467 pGroupDim->AddGroupItem( aGroup );
1470 // in both cases also adjust savedata, to preserve member settings (show details)
1471 ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aDimName );
1472 ScDPSaveMember* pSaveMember = pSaveDim->GetExistingMemberByName( aOldText );
1473 if ( pSaveMember )
1474 pSaveMember->SetName( rString );
1476 bChange = true;
1478 else
1479 nErrorId = STR_INVALIDNAME;
1482 else if ((aPosData.Flags & MemberResultFlags::GRANDTOTAL))
1484 aData.SetGrandTotalName(rString);
1485 bChange = true;
1487 else if (aPosData.Dimension >= 0 && !aPosData.MemberName.isEmpty())
1489 bool bDataLayout = false;
1490 OUString aDimName = pDPObj->GetDimName(static_cast<long>(aPosData.Dimension), bDataLayout);
1491 if (bDataLayout)
1493 // data dimension
1496 if ((aPosData.Flags & MemberResultFlags::SUBTOTAL))
1497 break;
1499 ScDPSaveDimension* pDim = aData.GetDimensionByName(aPosData.MemberName);
1500 if (!pDim)
1501 break;
1503 if (rString.isEmpty())
1505 nErrorId = STR_INVALIDNAME;
1506 break;
1509 if (aPosData.MemberName.equalsIgnoreAsciiCase(rString))
1511 pDim->RemoveLayoutName();
1512 bChange = true;
1514 else if (!pDPObj->IsDimNameInUse(rString))
1516 pDim->SetLayoutName(rString);
1517 bChange = true;
1519 else
1520 nErrorId = STR_INVALIDNAME;
1522 while (false);
1524 else
1526 // field member
1529 ScDPSaveDimension* pDim = aData.GetDimensionByName(aDimName);
1530 if (!pDim)
1531 break;
1533 ScDPSaveMember* pMem = pDim->GetExistingMemberByName(aPosData.MemberName);
1534 if (!pMem)
1535 break;
1537 if ((aPosData.Flags & MemberResultFlags::SUBTOTAL))
1539 // Change subtotal only when the table has one data dimension.
1540 if (aData.GetDataDimensionCount() > 1)
1541 break;
1543 // display name for subtotal is allowed only if the subtotal type is 'Automatic'.
1544 if (pDim->GetSubTotalsCount() != 1)
1545 break;
1547 if (pDim->GetSubTotalFunc(0) != sheet::GeneralFunction_AUTO)
1548 break;
1550 const OUString* pLayoutName = pMem->GetLayoutName();
1551 String aMemberName;
1552 if (pLayoutName)
1553 aMemberName = *pLayoutName;
1554 else
1555 aMemberName = aPosData.MemberName;
1557 String aNew = lcl_replaceMemberNameInSubtotal(rString, aMemberName);
1558 pDim->SetSubtotalName(aNew);
1559 bChange = true;
1561 else
1563 // Check to make sure the member name isn't
1564 // already used.
1565 if (!rString.isEmpty())
1567 if (rString.equalsIgnoreAsciiCase(pMem->GetName()))
1569 pMem->RemoveLayoutName();
1570 bChange = true;
1572 else if (!pDim->IsMemberNameInUse(rString))
1574 pMem->SetLayoutName(rString);
1575 bChange = true;
1577 else
1578 nErrorId = STR_INVALIDNAME;
1580 else
1581 nErrorId = STR_INVALIDNAME;
1584 while (false);
1590 if ( bChange )
1592 // apply changes
1593 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1594 pDPObj->SetSaveData( aData );
1595 aFunc.UpdatePivotTable(*pDPObj, true, false);
1597 else
1599 if ( !nErrorId )
1600 nErrorId = STR_ERR_DATAPILOT_INPUT;
1601 ErrorMessage( nErrorId );
1605 static void lcl_MoveToEnd( ScDPSaveDimension& rDim, const String& rItemName )
1607 ScDPSaveMember* pNewMember = NULL;
1608 const ScDPSaveMember* pOldMember = rDim.GetExistingMemberByName( rItemName );
1609 if ( pOldMember )
1610 pNewMember = new ScDPSaveMember( *pOldMember );
1611 else
1612 pNewMember = new ScDPSaveMember( rItemName );
1613 rDim.AddMember( pNewMember );
1614 // AddMember takes ownership of the new pointer,
1615 // puts it to the end of the list even if it was in the list before.
1618 struct ScOUStringCollate
1620 CollatorWrapper* mpCollator;
1622 ScOUStringCollate(CollatorWrapper* pColl) : mpCollator(pColl) {}
1624 bool operator()(const OUString& rStr1, const OUString& rStr2) const
1626 return ( mpCollator->compareString(rStr1, rStr2) < 0 );
1630 bool ScDBFunc::DataPilotSort( const ScAddress& rPos, bool bAscending, sal_uInt16* pUserListId )
1632 ScDocument* pDoc = GetViewData()->GetDocument();
1633 ScDPObject* pDPObj = pDoc->GetDPAtCursor(rPos.Col(), rPos.Row(), rPos.Tab());
1634 if (!pDPObj)
1635 return false;
1637 // We need to run this to get all members later.
1638 if ( pUserListId )
1639 pDPObj->BuildAllDimensionMembers();
1641 sal_uInt16 nOrientation;
1642 long nDimIndex = pDPObj->GetHeaderDim(rPos, nOrientation);
1643 if (nDimIndex < 0)
1644 // Invalid dimension index. Bail out.
1645 return false;
1647 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1648 if (!pSaveData)
1649 return false;
1651 ScDPSaveData aNewSaveData(*pSaveData);
1652 bool bDataLayout;
1653 OUString aDimName = pDPObj->GetDimName(nDimIndex, bDataLayout);
1654 ScDPSaveDimension* pSaveDim = aNewSaveData.GetDimensionByName(aDimName);
1655 if (!pSaveDim)
1656 return false;
1658 // manual evaluation of sort order is only needed if a user list id is given
1659 if ( pUserListId )
1661 typedef ScDPSaveDimension::MemberList MemList;
1662 const MemList& rDimMembers = pSaveDim->GetMembers();
1663 list<OUString> aMembers;
1664 boost::unordered_set<OUString, OUStringHash> aMemberSet;
1665 size_t nMemberCount = 0;
1666 for (MemList::const_iterator itr = rDimMembers.begin(), itrEnd = rDimMembers.end();
1667 itr != itrEnd; ++itr)
1669 ScDPSaveMember* pMem = *itr;
1670 aMembers.push_back(pMem->GetName());
1671 aMemberSet.insert(pMem->GetName());
1672 ++nMemberCount;
1675 // Sort the member list in ascending order.
1676 ScOUStringCollate aCollate( ScGlobal::GetCollator() );
1677 aMembers.sort(aCollate);
1679 // Collect and rank those custom sort strings that also exist in the member name list.
1681 typedef boost::unordered_map<OUString, sal_uInt16, OUStringHash> UserSortMap;
1682 UserSortMap aSubStrs;
1683 sal_uInt16 nSubCount = 0;
1684 if (pUserListId)
1686 ScUserList* pUserList = ScGlobal::GetUserList();
1687 if (!pUserList)
1688 return false;
1691 size_t n = pUserList->size();
1692 if (!n || *pUserListId >= static_cast<sal_uInt16>(n))
1693 return false;
1696 const ScUserListData* pData = (*pUserList)[*pUserListId];
1697 if (pData)
1699 sal_uInt16 n = pData->GetSubCount();
1700 for (sal_uInt16 i = 0; i < n; ++i)
1702 OUString aSub = pData->GetSubStr(i);
1703 if (!aMemberSet.count(aSub))
1704 // This string doesn't exist in the member name set. Don't add this.
1705 continue;
1707 aSubStrs.insert(UserSortMap::value_type(aSub, nSubCount++));
1712 // Rank all members.
1714 vector<OUString> aRankedNames(nMemberCount);
1715 sal_uInt16 nCurStrId = 0;
1716 for (list<OUString>::const_iterator itr = aMembers.begin(), itrEnd = aMembers.end();
1717 itr != itrEnd; ++itr)
1719 OUString aName = *itr;
1720 sal_uInt16 nRank = 0;
1721 UserSortMap::const_iterator itrSub = aSubStrs.find(aName);
1722 if (itrSub == aSubStrs.end())
1723 nRank = nSubCount + nCurStrId++;
1724 else
1725 nRank = itrSub->second;
1727 if (!bAscending)
1728 nRank = static_cast< sal_uInt16 >( nMemberCount - nRank - 1 );
1730 aRankedNames[nRank] = aName;
1733 // Re-order ScDPSaveMember instances with the new ranks.
1735 for (vector<OUString>::const_iterator itr = aRankedNames.begin(), itrEnd = aRankedNames.end();
1736 itr != itrEnd; ++itr)
1738 const ScDPSaveMember* pOldMem = pSaveDim->GetExistingMemberByName(*itr);
1739 if (!pOldMem)
1740 // All members are supposed to be present.
1741 continue;
1743 ScDPSaveMember* pNewMem = new ScDPSaveMember(*pOldMem);
1744 pSaveDim->AddMember(pNewMem);
1747 // Set the sorting mode to manual for now. We may introduce a new sorting
1748 // mode later on.
1750 sheet::DataPilotFieldSortInfo aSortInfo;
1751 aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
1752 pSaveDim->SetSortInfo(&aSortInfo);
1754 else
1756 // without user list id, just apply sorting mode
1758 sheet::DataPilotFieldSortInfo aSortInfo;
1759 aSortInfo.Mode = sheet::DataPilotFieldSortMode::NAME;
1760 aSortInfo.IsAscending = bAscending;
1761 pSaveDim->SetSortInfo(&aSortInfo);
1764 // Update the datapilot with the newly sorted field members.
1766 auto_ptr<ScDPObject> pNewObj(new ScDPObject(*pDPObj));
1767 pNewObj->SetSaveData(aNewSaveData);
1768 ScDBDocFunc aFunc(*GetViewData()->GetDocShell());
1770 return aFunc.DataPilotUpdate(pDPObj, pNewObj.get(), true, false);
1773 sal_Bool ScDBFunc::DataPilotMove( const ScRange& rSource, const ScAddress& rDest )
1775 sal_Bool bRet = false;
1776 ScDocument* pDoc = GetViewData()->GetDocument();
1777 ScDPObject* pDPObj = pDoc->GetDPAtCursor( rSource.aStart.Col(), rSource.aStart.Row(), rSource.aStart.Tab() );
1778 if ( pDPObj && pDPObj == pDoc->GetDPAtCursor( rDest.Col(), rDest.Row(), rDest.Tab() ) )
1780 sheet::DataPilotTableHeaderData aDestData;
1781 pDPObj->GetHeaderPositionData( rDest, aDestData );
1782 bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
1784 // look through the source range
1785 boost::unordered_set< OUString, OUStringHash, std::equal_to<OUString> > aMembersSet; // for lookup
1786 std::vector< OUString > aMembersVector; // members in original order, for inserting
1787 aMembersVector.reserve( std::max( static_cast<SCSIZE>( rSource.aEnd.Col() - rSource.aStart.Col() + 1 ),
1788 static_cast<SCSIZE>( rSource.aEnd.Row() - rSource.aStart.Row() + 1 ) ) );
1789 for (SCROW nRow = rSource.aStart.Row(); bValid && nRow <= rSource.aEnd.Row(); ++nRow )
1790 for (SCCOL nCol = rSource.aStart.Col(); bValid && nCol <= rSource.aEnd.Col(); ++nCol )
1792 sheet::DataPilotTableHeaderData aSourceData;
1793 pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, rSource.aStart.Tab() ), aSourceData );
1794 if ( aSourceData.Dimension == aDestData.Dimension && !aSourceData.MemberName.isEmpty() )
1796 if ( aMembersSet.find( aSourceData.MemberName ) == aMembersSet.end() )
1798 aMembersSet.insert( aSourceData.MemberName );
1799 aMembersVector.push_back( aSourceData.MemberName );
1801 // duplicates are ignored
1803 else
1804 bValid = false; // empty (subtotal) or different field
1807 if ( bValid )
1809 bool bIsDataLayout;
1810 OUString aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
1811 if ( !bIsDataLayout )
1813 ScDPSaveData aData( *pDPObj->GetSaveData() );
1814 ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
1816 // get all member names in source order
1817 uno::Sequence<OUString> aMemberNames;
1818 pDPObj->GetMemberNames( aDestData.Dimension, aMemberNames );
1820 bool bInserted = false;
1822 sal_Int32 nMemberCount = aMemberNames.getLength();
1823 for (sal_Int32 nMemberPos=0; nMemberPos<nMemberCount; ++nMemberPos)
1825 String aMemberStr( aMemberNames[nMemberPos] );
1827 if ( !bInserted && aMemberNames[nMemberPos] == aDestData.MemberName )
1829 // insert dragged items before this item
1830 for ( std::vector<OUString>::const_iterator aIter = aMembersVector.begin();
1831 aIter != aMembersVector.end(); ++aIter )
1832 lcl_MoveToEnd( *pDim, *aIter );
1833 bInserted = true;
1836 if ( aMembersSet.find( aMemberStr ) == aMembersSet.end() ) // skip dragged items
1837 lcl_MoveToEnd( *pDim, aMemberStr );
1839 // insert dragged item at end if dest wasn't found (for example, empty)
1840 if ( !bInserted )
1841 for ( std::vector<OUString>::const_iterator aIter = aMembersVector.begin();
1842 aIter != aMembersVector.end(); ++aIter )
1843 lcl_MoveToEnd( *pDim, *aIter );
1845 // Items that were in SaveData, but not in the source, end up at the start of the list.
1847 // set flag for manual sorting
1848 sheet::DataPilotFieldSortInfo aSortInfo;
1849 aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
1850 pDim->SetSortInfo( &aSortInfo );
1852 // apply changes
1853 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1854 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1855 pNewObj->SetSaveData( aData );
1856 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, false ); //! bApi for drag&drop?
1857 delete pNewObj;
1859 Unmark(); // entry was moved - no use in leaving the old cell selected
1861 bRet = sal_True;
1866 return bRet;
1869 bool ScDBFunc::HasSelectionForDrillDown( sal_uInt16& rOrientation )
1871 bool bRet = false;
1873 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1874 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1875 if ( pDPObj )
1877 ScDPUniqueStringSet aEntries;
1878 long nSelectDimension = -1;
1879 GetSelectedMemberList( aEntries, nSelectDimension );
1881 if (!aEntries.empty())
1883 bool bIsDataLayout;
1884 OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1885 if ( !bIsDataLayout )
1887 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1888 ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName( aDimName );
1889 if ( pDim )
1891 sal_uInt16 nDimOrient = pDim->GetOrientation();
1892 ScDPSaveDimension* pInner = pSaveData->GetInnermostDimension( nDimOrient );
1893 if ( pDim == pInner )
1895 rOrientation = nDimOrient;
1896 bRet = true;
1903 return bRet;
1906 void ScDBFunc::SetDataPilotDetails(bool bShow, const OUString* pNewDimensionName)
1908 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1909 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1910 if ( pDPObj )
1912 ScDPUniqueStringSet aEntries;
1913 long nSelectDimension = -1;
1914 GetSelectedMemberList( aEntries, nSelectDimension );
1916 if (!aEntries.empty())
1918 bool bIsDataLayout;
1919 OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1920 if ( !bIsDataLayout )
1922 ScDPSaveData aData( *pDPObj->GetSaveData() );
1923 ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
1925 if ( bShow && pNewDimensionName )
1927 // add the new dimension with the same orientation, at the end
1929 ScDPSaveDimension* pNewDim = aData.GetDimensionByName( *pNewDimensionName );
1930 ScDPSaveDimension* pDuplicated = NULL;
1931 if ( pNewDim->GetOrientation() == sheet::DataPilotFieldOrientation_DATA )
1933 // Need to duplicate the dimension, create column/row in addition to data:
1934 // The duplicated dimension inherits the existing settings, pNewDim is modified below.
1935 pDuplicated = aData.DuplicateDimension( *pNewDimensionName );
1938 sal_uInt16 nOrientation = pDim->GetOrientation();
1939 pNewDim->SetOrientation( nOrientation );
1941 long nPosition = LONG_MAX;
1942 aData.SetPosition( pNewDim, nPosition );
1944 ScDPSaveDimension* pDataLayout = aData.GetDataLayoutDimension();
1945 if ( pDataLayout->GetOrientation() == nOrientation &&
1946 aData.GetDataDimensionCount() <= 1 )
1948 // If there is only one data dimension, the data layout dimension
1949 // must still be the last one in its orientation.
1950 aData.SetPosition( pDataLayout, nPosition );
1953 if ( pDuplicated )
1955 // The duplicated (data) dimension needs to be behind the original dimension
1956 aData.SetPosition( pDuplicated, nPosition );
1959 // Hide details for all visible members (selected are changed below).
1960 //! Use all members from source level instead (including non-visible)?
1962 ScDPUniqueStringSet aVisibleEntries;
1963 pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
1965 ScDPUniqueStringSet::const_iterator it = aVisibleEntries.begin(), itEnd = aVisibleEntries.end();
1966 for (; it != itEnd; ++it)
1968 const OUString& aVisName = *it;
1969 ScDPSaveMember* pMember = pDim->GetMemberByName( aVisName );
1970 pMember->SetShowDetails( false );
1974 ScDPUniqueStringSet::const_iterator it = aEntries.begin(), itEnd = aEntries.end();
1975 for (; it != itEnd; ++it)
1977 ScDPSaveMember* pMember = pDim->GetMemberByName(*it);
1978 pMember->SetShowDetails( bShow );
1981 // apply changes
1982 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1983 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1984 pNewObj->SetSaveData( aData );
1985 aFunc.DataPilotUpdate( pDPObj, pNewObj, sal_True, false );
1986 delete pNewObj;
1988 // unmark cell selection
1989 Unmark();
1995 void ScDBFunc::ShowDataPilotSourceData( ScDPObject& rDPObj, const Sequence<sheet::DataPilotFieldFilter>& rFilters )
1997 ScDocument* pDoc = GetViewData()->GetDocument();
1998 if (pDoc->GetDocumentShell()->IsReadOnly())
2000 ErrorMessage(STR_READONLYERR);
2001 return;
2004 Reference<sheet::XDimensionsSupplier> xDimSupplier = rDPObj.GetSource();
2005 Reference<container::XNameAccess> xDims = xDimSupplier->getDimensions();
2006 Reference<sheet::XDrillDownDataSupplier> xDDSupplier(xDimSupplier, UNO_QUERY);
2007 if (!xDDSupplier.is())
2008 return;
2010 Sequence< Sequence<Any> > aTabData = xDDSupplier->getDrillDownData(rFilters);
2011 sal_Int32 nRowSize = aTabData.getLength();
2012 if (nRowSize <= 1)
2013 // There is no data to show. Bail out.
2014 return;
2016 sal_Int32 nColSize = aTabData[0].getLength();
2018 SCTAB nNewTab = GetViewData()->GetTabNo();
2020 auto_ptr<ScDocument> pInsDoc(new ScDocument(SCDOCMODE_CLIP));
2021 pInsDoc->ResetClip( pDoc, nNewTab );
2022 for (SCROW nRow = 0; nRow < nRowSize; ++nRow)
2024 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
2026 const Any& rAny = aTabData[nRow][nCol];
2027 OUString aStr;
2028 double fVal;
2029 if (rAny >>= aStr)
2031 ScSetStringParam aParam;
2032 aParam.setTextInput();
2033 pInsDoc->SetString(ScAddress(nCol,nRow,nNewTab), aStr);
2035 else if (rAny >>= fVal)
2036 pInsDoc->SetValue(nCol, nRow, nNewTab, fVal);
2040 // set number format (important for dates)
2041 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
2043 OUString aStr;
2044 if (!(aTabData[0][nCol] >>= aStr))
2045 continue;
2047 Reference<XPropertySet> xPropSet(xDims->getByName(aStr), UNO_QUERY);
2048 if (!xPropSet.is())
2049 continue;
2051 Any any = xPropSet->getPropertyValue( OUString(SC_UNO_DP_NUMBERFO) );
2052 sal_Int32 nNumFmt = 0;
2053 if (!(any >>= nNumFmt))
2054 continue;
2056 ScPatternAttr aPattern( pInsDoc->GetPool() );
2057 aPattern.GetItemSet().Put( SfxUInt32Item(ATTR_VALUE_FORMAT, static_cast<sal_uInt32>(nNumFmt)) );
2058 pInsDoc->ApplyPatternAreaTab(nCol, 1, nCol, nRowSize-1, nNewTab, aPattern);
2061 SCCOL nEndCol = 0;
2062 SCROW nEndRow = 0;
2063 pInsDoc->GetCellArea( nNewTab, nEndCol, nEndRow );
2064 pInsDoc->SetClipArea( ScRange( 0, 0, nNewTab, nEndCol, nEndRow, nNewTab ) );
2066 ::svl::IUndoManager* pMgr = GetViewData()->GetDocShell()->GetUndoManager();
2067 String aUndo = ScGlobal::GetRscString( STR_UNDO_DOOUTLINE );
2068 pMgr->EnterListAction( aUndo, aUndo );
2070 OUString aNewTabName;
2071 pDoc->CreateValidTabName(aNewTabName);
2072 if ( InsertTable(aNewTabName, nNewTab) )
2073 PasteFromClip( IDF_ALL, pInsDoc.get() );
2075 pMgr->LeaveListAction();
2079 // DB-Operationen (Sortieren, Filtern, Teilergebnisse) wiederholen
2082 void ScDBFunc::RepeatDB( sal_Bool bRecord )
2084 SCCOL nCurX = GetViewData()->GetCurX();
2085 SCROW nCurY = GetViewData()->GetCurY();
2086 SCTAB nTab = GetViewData()->GetTabNo();
2087 ScDocument* pDoc = GetViewData()->GetDocument();
2088 ScDBData* pDBData = GetDBData();
2089 if (bRecord && !pDoc->IsUndoEnabled())
2090 bRecord = false;
2092 ScQueryParam aQueryParam;
2093 pDBData->GetQueryParam( aQueryParam );
2094 sal_Bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
2096 ScSortParam aSortParam;
2097 pDBData->GetSortParam( aSortParam );
2098 sal_Bool bSort = aSortParam.maKeyState[0].bDoSort;
2100 ScSubTotalParam aSubTotalParam;
2101 pDBData->GetSubTotalParam( aSubTotalParam );
2102 sal_Bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
2104 if ( bQuery || bSort || bSubTotal )
2106 sal_Bool bQuerySize = false;
2107 ScRange aOldQuery;
2108 ScRange aNewQuery;
2109 if (bQuery && !aQueryParam.bInplace)
2111 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
2112 aQueryParam.nDestTab, sal_True );
2113 if (pDest && pDest->IsDoSize())
2115 pDest->GetArea( aOldQuery );
2116 bQuerySize = sal_True;
2120 SCTAB nDummy;
2121 SCCOL nStartCol;
2122 SCROW nStartRow;
2123 SCCOL nEndCol;
2124 SCROW nEndRow;
2125 pDBData->GetArea( nDummy, nStartCol, nStartRow, nEndCol, nEndRow );
2127 //! Undo nur benoetigte Daten ?
2129 ScDocument* pUndoDoc = NULL;
2130 ScOutlineTable* pUndoTab = NULL;
2131 ScRangeName* pUndoRange = NULL;
2132 ScDBCollection* pUndoDB = NULL;
2134 if (bRecord)
2136 SCTAB nTabCount = pDoc->GetTableCount();
2137 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2138 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
2139 if (pTable)
2141 pUndoTab = new ScOutlineTable( *pTable );
2143 SCCOLROW nOutStartCol; // Zeilen/Spaltenstatus
2144 SCCOLROW nOutStartRow;
2145 SCCOLROW nOutEndCol;
2146 SCCOLROW nOutEndRow;
2147 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
2148 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
2150 pUndoDoc->InitUndo( pDoc, nTab, nTab, sal_True, sal_True );
2151 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, false, pUndoDoc );
2152 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, false, pUndoDoc );
2154 else
2155 pUndoDoc->InitUndo( pDoc, nTab, nTab, false, sal_True );
2157 // Datenbereich sichern - incl. Filter-Ergebnis
2158 pDoc->CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, false, pUndoDoc );
2160 // alle Formeln wegen Referenzen
2161 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, false, pUndoDoc );
2163 // DB- und andere Bereiche
2164 ScRangeName* pDocRange = pDoc->GetRangeName();
2165 if (!pDocRange->empty())
2166 pUndoRange = new ScRangeName( *pDocRange );
2167 ScDBCollection* pDocDB = pDoc->GetDBCollection();
2168 if (!pDocDB->empty())
2169 pUndoDB = new ScDBCollection( *pDocDB );
2172 if (bSort && bSubTotal)
2174 // Sortieren ohne SubTotals
2176 aSubTotalParam.bRemoveOnly = sal_True; // wird unten wieder zurueckgesetzt
2177 DoSubTotals( aSubTotalParam, false );
2180 if (bSort)
2182 pDBData->GetSortParam( aSortParam ); // Bereich kann sich geaendert haben
2183 Sort( aSortParam, false, false);
2185 if (bQuery)
2187 pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geaendert haben
2188 ScRange aAdvSource;
2189 if (pDBData->GetAdvancedQuerySource(aAdvSource))
2191 pDoc->CreateQueryParam(
2192 aAdvSource.aStart.Col(), aAdvSource.aStart.Row(),
2193 aAdvSource.aEnd.Col(), aAdvSource.aEnd.Row(),
2194 aAdvSource.aStart.Tab(), aQueryParam );
2195 Query( aQueryParam, &aAdvSource, false );
2197 else
2198 Query( aQueryParam, NULL, false );
2200 // bei nicht-inplace kann die Tabelle umgestellt worden sein
2201 if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
2202 SetTabNo( nTab );
2204 if (bSubTotal)
2206 pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geaendert haben
2207 aSubTotalParam.bRemoveOnly = false;
2208 DoSubTotals( aSubTotalParam, false );
2211 if (bRecord)
2213 SCTAB nDummyTab;
2214 SCCOL nDummyCol;
2215 SCROW nDummyRow, nNewEndRow;
2216 pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
2218 const ScRange* pOld = NULL;
2219 const ScRange* pNew = NULL;
2220 if (bQuerySize)
2222 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
2223 aQueryParam.nDestTab, sal_True );
2224 if (pDest)
2226 pDest->GetArea( aNewQuery );
2227 pOld = &aOldQuery;
2228 pNew = &aNewQuery;
2232 GetViewData()->GetDocShell()->GetUndoManager()->AddUndoAction(
2233 new ScUndoRepeatDB( GetViewData()->GetDocShell(), nTab,
2234 nStartCol, nStartRow, nEndCol, nEndRow,
2235 nNewEndRow,
2236 nCurX, nCurY,
2237 pUndoDoc, pUndoTab,
2238 pUndoRange, pUndoDB,
2239 pOld, pNew ) );
2242 GetViewData()->GetDocShell()->PostPaint(
2243 ScRange(0, 0, nTab, MAXCOL, MAXROW, nTab),
2244 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE);
2246 else // "Keine Operationen auszufuehren"
2247 ErrorMessage(STR_MSSG_REPEATDB_0);
2250 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */