merge the formfield patch from ooo-build
[ooovba.git] / sc / source / ui / view / dbfunc3.cxx
blob1e5ff2cb00edc6e57cb34c9f827de3be4cb5e68d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dbfunc3.cxx,v $
10 * $Revision: 1.20 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 // INCLUDE ---------------------------------------------------------------
38 #include "dbfunc.hxx"
39 #include "scitems.hxx"
40 #include <sfx2/bindings.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/msgbox.hxx>
43 #include <vcl/sound.hxx>
44 #include <vcl/waitobj.hxx>
45 #include <svtools/zforlist.hxx>
46 #include <sfx2/app.hxx>
47 #include <com/sun/star/beans/XPropertySet.hpp>
48 #include <com/sun/star/container/XNameAccess.hpp>
49 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
50 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
51 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
52 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
53 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
54 #include <com/sun/star/sheet/GeneralFunction.hpp>
55 #include <com/sun/star/sheet/MemberResultFlags.hpp>
56 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
57 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
59 #include "global.hxx"
60 #include "globstr.hrc"
61 #include "sc.hrc"
62 #include "undotab.hxx"
63 #include "undodat.hxx"
64 #include "dbcolect.hxx"
65 #include "rangenam.hxx"
66 #include "rangeutl.hxx"
67 #include "docsh.hxx"
68 #include "olinetab.hxx"
69 #include "consoli.hxx"
70 #include "olinefun.hxx"
71 #include "dpobject.hxx"
72 #include "dpsave.hxx"
73 #include "dpdimsave.hxx"
74 #include "dbdocfun.hxx"
75 #include "dpoutput.hxx"
76 #include "dptabsrc.hxx"
77 #include "editable.hxx"
78 #include "docpool.hxx"
79 #include "patattr.hxx"
80 #include "unonames.hxx"
81 #include "cell.hxx"
82 #include "userlist.hxx"
84 #include <hash_set>
85 #include <hash_map>
86 #include <memory>
87 #include <list>
88 #include <vector>
90 using namespace com::sun::star;
91 using ::com::sun::star::uno::Any;
92 using ::com::sun::star::uno::Sequence;
93 using ::com::sun::star::uno::Reference;
94 using ::com::sun::star::uno::UNO_QUERY;
95 using ::com::sun::star::beans::XPropertySet;
96 using ::com::sun::star::container::XNameAccess;
97 using ::com::sun::star::sheet::XDimensionsSupplier;
98 using ::rtl::OUString;
99 using ::rtl::OUStringHash;
100 using ::rtl::OUStringBuffer;
101 using ::std::auto_ptr;
102 using ::std::list;
103 using ::std::vector;
104 using ::std::hash_map;
105 using ::std::hash_set;
107 // STATIC DATA -----------------------------------------------------------
110 //==================================================================
113 // Outliner
116 // Outline-Gruppierung erzeugen
118 void ScDBFunc::MakeOutline( BOOL bColumns, BOOL bRecord )
120 ScRange aRange;
121 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
123 ScDocShell* pDocSh = GetViewData()->GetDocShell();
124 ScOutlineDocFunc aFunc(*pDocSh);
125 aFunc.MakeOutline( aRange, bColumns, bRecord, FALSE );
127 else
128 ErrorMessage(STR_NOMULTISELECT);
131 // Outline-Gruppierung loeschen
133 void ScDBFunc::RemoveOutline( BOOL bColumns, BOOL bRecord )
135 ScRange aRange;
136 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
138 ScDocShell* pDocSh = GetViewData()->GetDocShell();
139 ScOutlineDocFunc aFunc(*pDocSh);
140 aFunc.RemoveOutline( aRange, bColumns, bRecord, FALSE );
142 else
143 ErrorMessage(STR_NOMULTISELECT);
146 // Menue-Status: Outlines loeschen
148 void ScDBFunc::TestRemoveOutline( BOOL& rCol, BOOL& rRow )
150 BOOL bColFound = FALSE;
151 BOOL bRowFound = FALSE;
153 SCCOL nStartCol, nEndCol;
154 SCROW nStartRow, nEndRow;
155 SCTAB nStartTab, nEndTab;
156 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
158 SCTAB nTab = nStartTab;
159 ScDocument* pDoc = GetViewData()->GetDocument();
160 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
161 if (pTable)
163 ScOutlineArray* pArray;
164 ScOutlineEntry* pEntry;
165 SCCOLROW nStart;
166 SCCOLROW nEnd;
167 BOOL bColMarked = ( nStartRow == 0 && nEndRow == MAXROW );
168 BOOL bRowMarked = ( nStartCol == 0 && nEndCol == MAXCOL );
170 // Spalten
172 if ( !bRowMarked || bColMarked ) // nicht wenn ganze Zeilen markiert
174 pArray = pTable->GetColArray();
175 ScSubOutlineIterator aColIter( pArray );
176 while ((pEntry=aColIter.GetNext()) != NULL && !bColFound)
178 nStart = pEntry->GetStart();
179 nEnd = pEntry->GetEnd();
180 if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
181 bColFound = TRUE;
185 // Zeilen
187 if ( !bColMarked || bRowMarked ) // nicht wenn ganze Spalten markiert
189 pArray = pTable->GetRowArray();
190 ScSubOutlineIterator aRowIter( pArray );
191 while ((pEntry=aRowIter.GetNext()) != NULL && !bRowFound)
193 nStart = pEntry->GetStart();
194 nEnd = pEntry->GetEnd();
195 if ( nStartRow<=nEnd && nEndRow>=nStart )
196 bRowFound = TRUE;
202 rCol = bColFound;
203 rRow = bRowFound;
206 void ScDBFunc::RemoveAllOutlines( BOOL bRecord )
208 SCTAB nTab = GetViewData()->GetTabNo();
209 ScDocShell* pDocSh = GetViewData()->GetDocShell();
210 ScOutlineDocFunc aFunc(*pDocSh);
212 HideCursor();
213 BOOL bOk = aFunc.RemoveAllOutlines( nTab, bRecord, FALSE );
214 ShowCursor();
216 if (bOk)
217 UpdateScrollBars();
220 // Auto-Outlines
222 void ScDBFunc::AutoOutline( BOOL bRecord )
224 SCTAB nTab = GetViewData()->GetTabNo();
225 ScRange aRange( 0,0,nTab, MAXCOL,MAXROW,nTab ); // ganze Tabelle, wenn nichts markiert
226 ScMarkData& rMark = GetViewData()->GetMarkData();
227 if ( rMark.IsMarked() || rMark.IsMultiMarked() )
229 rMark.MarkToMulti();
230 rMark.GetMultiMarkArea( aRange );
233 ScDocShell* pDocSh = GetViewData()->GetDocShell();
234 ScOutlineDocFunc aFunc(*pDocSh);
235 aFunc.AutoOutline( aRange, bRecord, FALSE );
238 // Outline-Ebene auswaehlen
240 void ScDBFunc::SelectLevel( BOOL bColumns, USHORT nLevel, BOOL bRecord, BOOL bPaint )
242 SCTAB nTab = GetViewData()->GetTabNo();
243 ScDocShell* pDocSh = GetViewData()->GetDocShell();
244 ScOutlineDocFunc aFunc(*pDocSh);
246 HideCursor();
247 BOOL bOk = aFunc.SelectLevel( nTab, bColumns, nLevel, bRecord, bPaint, FALSE );
248 ShowCursor();
250 if (bOk)
251 UpdateScrollBars();
254 // einzelne Outline-Gruppe einblenden
256 void ScDBFunc::ShowOutline( BOOL bColumns, USHORT nLevel, USHORT nEntry, BOOL bRecord, BOOL bPaint )
258 SCTAB nTab = GetViewData()->GetTabNo();
259 ScDocShell* pDocSh = GetViewData()->GetDocShell();
260 ScOutlineDocFunc aFunc(*pDocSh);
262 HideCursor();
263 BOOL bOk = aFunc.ShowOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint, FALSE );
264 ShowCursor();
266 if ( bOk && bPaint )
267 UpdateScrollBars();
270 // einzelne Outline-Gruppe ausblenden
272 void ScDBFunc::HideOutline( BOOL bColumns, USHORT nLevel, USHORT nEntry, BOOL bRecord, BOOL bPaint )
274 SCTAB nTab = GetViewData()->GetTabNo();
275 ScDocShell* pDocSh = GetViewData()->GetDocShell();
276 ScOutlineDocFunc aFunc(*pDocSh);
278 HideCursor();
279 BOOL bOk = aFunc.HideOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint, FALSE );
280 ShowCursor();
282 if ( bOk && bPaint )
283 UpdateScrollBars();
286 // Menue-Status: markierten Bereich ein-/ausblenden
288 BOOL ScDBFunc::OutlinePossible(BOOL bHide)
290 BOOL bEnable = FALSE;
292 SCCOL nStartCol;
293 SCROW nStartRow;
294 SCTAB nStartTab;
295 SCCOL nEndCol;
296 SCROW nEndRow;
297 SCTAB nEndTab;
299 if (GetViewData()->GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
301 ScDocument* pDoc = GetViewData()->GetDocument();
302 SCTAB nTab = GetViewData()->GetTabNo();
303 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
304 if (pTable)
306 ScOutlineArray* pArray;
307 ScOutlineEntry* pEntry;
308 SCCOLROW nStart;
309 SCCOLROW nEnd;
311 // Spalten
313 pArray = pTable->GetColArray();
314 ScSubOutlineIterator aColIter( pArray );
315 while ((pEntry=aColIter.GetNext()) != NULL && !bEnable)
317 nStart = pEntry->GetStart();
318 nEnd = pEntry->GetEnd();
319 if ( bHide )
321 if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
322 if (!pEntry->IsHidden())
323 bEnable = TRUE;
325 else
327 if ( nStart>=nStartCol && nEnd<=nEndCol )
328 if (pEntry->IsHidden())
329 bEnable = TRUE;
333 // Zeilen
335 pArray = pTable->GetRowArray();
336 ScSubOutlineIterator aRowIter( pArray );
337 while ((pEntry=aRowIter.GetNext()) != NULL)
339 nStart = pEntry->GetStart();
340 nEnd = pEntry->GetEnd();
341 if ( bHide )
343 if ( nStartRow<=nEnd && nEndRow>=nStart )
344 if (!pEntry->IsHidden())
345 bEnable = TRUE;
347 else
349 if ( nStart>=nStartRow && nEnd<=nEndRow )
350 if (pEntry->IsHidden())
351 bEnable = TRUE;
357 return bEnable;
360 // markierten Bereich einblenden
362 void ScDBFunc::ShowMarkedOutlines( BOOL bRecord )
364 ScRange aRange;
365 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
367 ScDocShell* pDocSh = GetViewData()->GetDocShell();
368 ScOutlineDocFunc aFunc(*pDocSh);
369 HideCursor();
370 BOOL bDone = aFunc.ShowMarkedOutlines( aRange, bRecord, FALSE );
371 ShowCursor();
372 if (bDone)
373 UpdateScrollBars();
375 else
376 ErrorMessage(STR_NOMULTISELECT);
379 // markierten Bereich ausblenden
381 void ScDBFunc::HideMarkedOutlines( BOOL bRecord )
383 ScRange aRange;
384 if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE)
386 ScDocShell* pDocSh = GetViewData()->GetDocShell();
387 ScOutlineDocFunc aFunc(*pDocSh);
388 HideCursor();
389 BOOL bDone = aFunc.HideMarkedOutlines( aRange, bRecord, FALSE );
390 ShowCursor();
391 if (bDone)
392 UpdateScrollBars();
394 else
395 ErrorMessage(STR_NOMULTISELECT);
398 // --------------------------------------------------------------------------
401 // Teilergebnisse
404 void ScDBFunc::DoSubTotals( const ScSubTotalParam& rParam, BOOL bRecord,
405 const ScSortParam* pForceNewSort )
407 BOOL bDo = !rParam.bRemoveOnly; // FALSE = nur loeschen
409 ScDocShell* pDocSh = GetViewData()->GetDocShell();
410 ScDocument* pDoc = pDocSh->GetDocument();
411 ScMarkData& rMark = GetViewData()->GetMarkData();
412 SCTAB nTab = GetViewData()->GetTabNo();
413 if (bRecord && !pDoc->IsUndoEnabled())
414 bRecord = FALSE;
416 ScDBData* pDBData = pDoc->GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
417 rParam.nCol2, rParam.nRow2 );
418 if (!pDBData)
420 DBG_ERROR( "SubTotals: keine DBData" );
421 return;
424 ScEditableTester aTester( pDoc, nTab, 0,rParam.nRow1+1, MAXCOL,MAXROW );
425 if (!aTester.IsEditable())
427 ErrorMessage(aTester.GetMessageId());
428 return;
431 if (pDoc->HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
432 rParam.nCol2, rParam.nRow2, nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ))
434 ErrorMessage(STR_MSSG_INSERTCELLS_0); // nicht in zusammengefasste einfuegen
435 return;
438 WaitObject aWait( GetViewData()->GetDialogParent() );
439 BOOL bOk = TRUE;
440 BOOL bDelete = FALSE;
441 if (rParam.bReplace)
442 if (pDoc->TestRemoveSubTotals( nTab, rParam ))
444 bDelete = TRUE;
445 bOk = ( MessBox( GetViewData()->GetDialogParent(), WinBits(WB_YES_NO | WB_DEF_YES),
446 // "StarCalc" "Daten loeschen?"
447 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ),
448 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_1 ) ).Execute()
449 == RET_YES );
452 if (bOk)
454 ScDocShellModificator aModificator( *pDocSh );
456 ScSubTotalParam aNewParam( rParam ); // Bereichsende wird veraendert
457 ScDocument* pUndoDoc = NULL;
458 ScOutlineTable* pUndoTab = NULL;
459 ScRangeName* pUndoRange = NULL;
460 ScDBCollection* pUndoDB = NULL;
461 SCTAB nTabCount = 0; // fuer Referenz-Undo
463 if (bRecord) // alte Daten sichern
465 BOOL bOldFilter = bDo && rParam.bDoSort;
467 nTabCount = pDoc->GetTableCount();
468 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
469 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
470 if (pTable)
472 pUndoTab = new ScOutlineTable( *pTable );
474 SCCOLROW nOutStartCol; // Zeilen/Spaltenstatus
475 SCCOLROW nOutStartRow;
476 SCCOLROW nOutEndCol;
477 SCCOLROW nOutEndRow;
478 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
479 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
481 pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE );
482 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc );
483 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, FALSE, pUndoDoc );
485 else
486 pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, bOldFilter );
488 // Datenbereich sichern - incl. Filter-Ergebnis
489 pDoc->CopyToDocument( 0,rParam.nRow1+1,nTab, MAXCOL,rParam.nRow2,nTab,
490 IDF_ALL, FALSE, pUndoDoc );
492 // alle Formeln wegen Referenzen
493 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1,
494 IDF_FORMULA, FALSE, pUndoDoc );
496 // DB- und andere Bereiche
497 ScRangeName* pDocRange = pDoc->GetRangeName();
498 if (pDocRange->GetCount())
499 pUndoRange = new ScRangeName( *pDocRange );
500 ScDBCollection* pDocDB = pDoc->GetDBCollection();
501 if (pDocDB->GetCount())
502 pUndoDB = new ScDBCollection( *pDocDB );
505 // pDoc->SetOutlineTable( nTab, NULL );
506 ScOutlineTable* pOut = pDoc->GetOutlineTable( nTab );
507 if (pOut)
508 pOut->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen
510 if (rParam.bReplace)
511 pDoc->RemoveSubTotals( nTab, aNewParam );
512 BOOL bSuccess = TRUE;
513 if (bDo)
515 // Sortieren
516 if ( rParam.bDoSort || pForceNewSort )
518 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
520 // Teilergebnis-Felder vor die Sortierung setzen
521 // (doppelte werden weggelassen, kann darum auch wieder aufgerufen werden)
523 ScSortParam aOldSort;
524 pDBData->GetSortParam( aOldSort );
525 ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
526 Sort( aSortParam, FALSE, FALSE );
529 bSuccess = pDoc->DoSubTotals( nTab, aNewParam );
531 ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
532 aNewParam.nCol2, aNewParam.nRow2, nTab );
533 pDoc->SetDirty( aDirtyRange );
535 if (bRecord)
537 // ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
538 pDocSh->GetUndoManager()->AddUndoAction(
539 new ScUndoSubTotals( pDocSh, nTab,
540 rParam, aNewParam.nRow2,
541 pUndoDoc, pUndoTab, // pUndoDBData,
542 pUndoRange, pUndoDB ) );
545 if (!bSuccess)
547 // "Kann keine Zeilen einfuegen"
548 ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
551 // merken
552 pDBData->SetSubTotalParam( aNewParam );
553 pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
554 pDoc->CompileDBFormula();
556 DoneBlockMode();
557 InitOwnBlockMode();
558 rMark.SetMarkArea( ScRange( aNewParam.nCol1,aNewParam.nRow1,nTab,
559 aNewParam.nCol2,aNewParam.nRow2,nTab ) );
560 MarkDataChanged();
562 pDocSh->PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
563 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE );
565 aModificator.SetDocumentModified();
567 SelectionChanged();
572 // Consolidate
575 void ScDBFunc::Consolidate( const ScConsolidateParam& rParam, BOOL bRecord )
577 ScDocShell* pDocShell = GetViewData()->GetDocShell();
578 pDocShell->DoConsolidate( rParam, bRecord );
579 SetTabNo( rParam.nTab, TRUE );
583 // Pivot
586 String lcl_MakePivotTabName( const String& rPrefix, SCTAB nNumber )
588 String aName = rPrefix;
589 aName += String::CreateFromInt32( nNumber );
590 return aName;
593 bool ScDBFunc::MakePivotTable( const ScDPSaveData& rData, const ScRange& rDest, BOOL bNewTable,
594 const ScDPObject& rSource, BOOL bApi )
596 // #70096# error message if no fields are set
597 // this must be removed when drag&drop of fields from a toolbox is available
599 if ( rData.IsEmpty() && !bApi )
601 ErrorMessage(STR_PIVOT_NODATA);
602 return false;
605 ScDocShell* pDocSh = GetViewData()->GetDocShell();
606 ScDocument* pDoc = GetViewData()->GetDocument();
607 BOOL bUndo(pDoc->IsUndoEnabled());
609 ScRange aDestRange = rDest;
610 if ( bNewTable )
612 SCTAB nSrcTab = GetViewData()->GetTabNo();
614 String aName( ScGlobal::GetRscString(STR_PIVOT_TABLE) );
615 String aStr;
617 pDoc->GetName( nSrcTab, aStr );
618 aName += '_';
619 aName += aStr;
620 aName += '_';
622 SCTAB nNewTab = nSrcTab+1;
624 SCTAB i=1;
625 while ( !pDoc->InsertTab( nNewTab, lcl_MakePivotTabName( aName, i ) ) && i <= MAXTAB )
626 i++;
628 BOOL bAppend = ( nNewTab+1 == pDoc->GetTableCount() );
629 if (bUndo)
631 pDocSh->GetUndoManager()->AddUndoAction(
632 new ScUndoInsertTab( pDocSh, nNewTab, bAppend, lcl_MakePivotTabName( aName, i ) ));
635 GetViewData()->InsertTab( nNewTab );
636 SetTabNo( nNewTab, TRUE );
638 aDestRange = ScRange( 0, 0, nNewTab );
641 ScDPObject* pDPObj = pDoc->GetDPAtCursor(
642 aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aStart.Tab() );
644 ScDPObject aObj( rSource );
645 aObj.SetOutRange( aDestRange );
646 if ( pDPObj && !rData.GetExistingDimensionData() )
648 // copy dimension data from old object - lost in the dialog
649 //! change the dialog to keep the dimension data
651 ScDPSaveData aNewData( rData );
652 const ScDPSaveData* pOldData = pDPObj->GetSaveData();
653 if ( pOldData )
655 const ScDPDimensionSaveData* pDimSave = pOldData->GetExistingDimensionData();
656 aNewData.SetDimensionData( pDimSave );
658 aObj.SetSaveData( aNewData );
660 else
661 aObj.SetSaveData( rData );
663 BOOL bAllowMove = ( pDPObj != NULL ); // allow re-positioning when editing existing table
665 ScDBDocFunc aFunc( *pDocSh );
666 bool bSuccess = aFunc.DataPilotUpdate( pDPObj, &aObj, TRUE, FALSE, bAllowMove );
668 CursorPosChanged(); // shells may be switched
670 if ( bNewTable )
672 pDocSh->PostPaintExtras();
673 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED ) );
676 return bSuccess;
679 void ScDBFunc::DeletePivotTable()
681 ScDocShell* pDocSh = GetViewData()->GetDocShell();
682 ScDocument* pDoc = pDocSh->GetDocument();
683 ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(),
684 GetViewData()->GetCurY(),
685 GetViewData()->GetTabNo() );
686 if ( pDPObj )
688 ScDBDocFunc aFunc( *pDocSh );
689 aFunc.DataPilotUpdate( pDPObj, NULL, TRUE, FALSE );
690 CursorPosChanged(); // shells may be switched
692 else
693 ErrorMessage(STR_PIVOT_NOTFOUND);
696 void ScDBFunc::RecalcPivotTable()
698 ScDocShell* pDocSh = GetViewData()->GetDocShell();
699 ScDocument* pDoc = GetViewData()->GetDocument();
701 // old pivot not used any more
703 ScDPObject* pDPObj = pDoc->GetDPAtCursor( GetViewData()->GetCurX(),
704 GetViewData()->GetCurY(),
705 GetViewData()->GetTabNo() );
706 if ( pDPObj )
708 ScDBDocFunc aFunc( *pDocSh );
709 aFunc.DataPilotUpdate( pDPObj, pDPObj, TRUE, FALSE );
710 CursorPosChanged(); // shells may be switched
712 else
713 ErrorMessage(STR_PIVOT_NOTFOUND);
716 void ScDBFunc::GetSelectedMemberList( ScStrCollection& rEntries, long& rDimension )
718 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
719 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
720 if ( !pDPObj )
721 return;
723 long nStartDimension = -1;
724 long nStartHierarchy = -1;
725 long nStartLevel = -1;
727 ScRangeListRef xRanges;
728 GetViewData()->GetMultiArea( xRanges ); // incl. cursor if nothing is selected
729 ULONG nRangeCount = xRanges->Count();
730 BOOL bContinue = TRUE;
732 for (ULONG nRangePos=0; nRangePos<nRangeCount && bContinue; nRangePos++)
734 ScRange aRange = *xRanges->GetObject(nRangePos);
735 SCCOL nStartCol = aRange.aStart.Col();
736 SCROW nStartRow = aRange.aStart.Row();
737 SCCOL nEndCol = aRange.aEnd.Col();
738 SCROW nEndRow = aRange.aEnd.Row();
739 SCTAB nTab = aRange.aStart.Tab();
741 for (SCROW nRow=nStartRow; nRow<=nEndRow && bContinue; nRow++)
742 for (SCCOL nCol=nStartCol; nCol<=nEndCol && bContinue; nCol++)
744 sheet::DataPilotTableHeaderData aData;
745 pDPObj->GetHeaderPositionData(ScAddress(nCol, nRow, nTab), aData);
746 if ( aData.Dimension < 0 )
747 bContinue = FALSE; // not part of any dimension
748 else
750 if ( nStartDimension < 0 ) // first member?
752 nStartDimension = aData.Dimension;
753 nStartHierarchy = aData.Hierarchy;
754 nStartLevel = aData.Level;
756 if ( aData.Dimension != nStartDimension ||
757 aData.Hierarchy != nStartHierarchy ||
758 aData.Level != nStartLevel )
760 bContinue = FALSE; // cannot mix dimensions
763 if ( bContinue )
765 // accept any part of a member description, also subtotals,
766 // but don't stop if empty parts are contained
767 if ( aData.Flags & sheet::MemberResultFlags::HASMEMBER )
769 StrData* pNew = new StrData( aData.MemberName );
770 if ( !rEntries.Insert( pNew ) )
771 delete pNew;
777 rDimension = nStartDimension; // dimension from which the found members came
778 if (!bContinue)
779 rEntries.FreeAll(); // remove all if not valid
782 BOOL ScDBFunc::HasSelectionForDateGroup( ScDPNumGroupInfo& rOldInfo, sal_Int32& rParts )
784 // determine if the date group dialog has to be shown for the current selection
786 BOOL bFound = FALSE;
788 SCCOL nCurX = GetViewData()->GetCurX();
789 SCROW nCurY = GetViewData()->GetCurY();
790 SCTAB nTab = GetViewData()->GetTabNo();
791 ScDocument* pDoc = GetViewData()->GetDocument();
793 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nCurX, nCurY, nTab );
794 if ( pDPObj )
796 ScStrCollection aEntries;
797 long nSelectDimension = -1;
798 GetSelectedMemberList( aEntries, nSelectDimension );
800 if ( aEntries.GetCount() > 0 )
802 BOOL bIsDataLayout;
803 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
804 String aBaseDimName( aDimName );
806 BOOL bInGroupDim = FALSE;
807 BOOL bFoundParts = FALSE;
809 ScDPDimensionSaveData* pDimData =
810 const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
811 if ( pDimData )
813 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
814 const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( aDimName );
815 if ( pNumGroupDim )
817 // existing num group dimension
819 if ( pNumGroupDim->GetDatePart() != 0 )
821 // dimension has date info -> edit settings of this dimension
822 // (parts are collected below)
824 rOldInfo = pNumGroupDim->GetDateInfo();
825 bFound = TRUE;
827 else if ( pNumGroupDim->GetInfo().DateValues )
829 // Numerical grouping with DateValues flag is used for grouping
830 // of days with a "Number of days" value.
832 rOldInfo = pNumGroupDim->GetInfo();
833 rParts = com::sun::star::sheet::DataPilotFieldGroupBy::DAYS; // not found in CollectDateParts
834 bFoundParts = TRUE;
835 bFound = TRUE;
837 bInGroupDim = TRUE;
839 else if ( pGroupDim )
841 // existing additional group dimension
843 if ( pGroupDim->GetDatePart() != 0 )
845 // dimension has date info -> edit settings of this dimension
846 // (parts are collected below)
848 rOldInfo = pGroupDim->GetDateInfo();
849 aBaseDimName = pGroupDim->GetSourceDimName();
850 bFound = TRUE;
852 bInGroupDim = TRUE;
855 if ( bFound && !bFoundParts )
857 // collect date parts from all group dimensions
858 rParts = pDimData->CollectDateParts( aBaseDimName );
860 if ( !bFound && !bInGroupDim )
862 // create new date group dimensions if the selection is a single cell
863 // in a normal dimension with date content
865 ScRange aSelRange;
866 if ( (GetViewData()->GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
867 aSelRange.aStart == aSelRange.aEnd )
869 SCCOL nSelCol = aSelRange.aStart.Col();
870 SCROW nSelRow = aSelRange.aStart.Row();
871 SCTAB nSelTab = aSelRange.aStart.Tab();
872 if ( pDoc->HasValueData( nSelCol, nSelRow, nSelTab ) )
874 ULONG nIndex = static_cast<const SfxUInt32Item*>(pDoc->GetAttr(
875 nSelCol, nSelRow, nSelTab, ATTR_VALUE_FORMAT))->GetValue();
876 short nType = pDoc->GetFormatTable()->GetType(nIndex);
877 if ( nType == NUMBERFORMAT_DATE || nType == NUMBERFORMAT_TIME || nType == NUMBERFORMAT_DATETIME )
879 bFound = TRUE;
880 // use currently selected value for automatic limits
881 if( rOldInfo.AutoStart )
882 rOldInfo.Start = pDoc->GetValue( aSelRange.aStart );
883 if( rOldInfo.AutoEnd )
884 rOldInfo.End = pDoc->GetValue( aSelRange.aStart );
892 return bFound;
895 BOOL ScDBFunc::HasSelectionForNumGroup( ScDPNumGroupInfo& rOldInfo )
897 // determine if the numeric group dialog has to be shown for the current selection
899 BOOL bFound = FALSE;
901 SCCOL nCurX = GetViewData()->GetCurX();
902 SCROW nCurY = GetViewData()->GetCurY();
903 SCTAB nTab = GetViewData()->GetTabNo();
904 ScDocument* pDoc = GetViewData()->GetDocument();
906 ScDPObject* pDPObj = pDoc->GetDPAtCursor( nCurX, nCurY, nTab );
907 if ( pDPObj )
909 ScStrCollection aEntries;
910 long nSelectDimension = -1;
911 GetSelectedMemberList( aEntries, nSelectDimension );
913 if ( aEntries.GetCount() > 0 )
915 BOOL bIsDataLayout;
916 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
918 BOOL bInGroupDim = FALSE;
920 ScDPDimensionSaveData* pDimData =
921 const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
922 if ( pDimData )
924 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
925 if ( pNumGroupDim )
927 // existing num group dimension
928 // -> edit settings of this dimension
930 rOldInfo = pNumGroupDim->GetInfo();
931 bFound = TRUE;
933 else if ( pDimData->GetNamedGroupDim( aDimName ) )
934 bInGroupDim = TRUE; // in a group dimension
936 if ( !bFound && !bInGroupDim )
938 // create a new num group dimension if the selection is a single cell
939 // in a normal dimension with numeric content
941 ScRange aSelRange;
942 if ( (GetViewData()->GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
943 aSelRange.aStart == aSelRange.aEnd )
945 if ( pDoc->HasValueData( aSelRange.aStart.Col(), aSelRange.aStart.Row(),
946 aSelRange.aStart.Tab() ) )
948 bFound = TRUE;
949 // use currently selected value for automatic limits
950 if( rOldInfo.AutoStart )
951 rOldInfo.Start = pDoc->GetValue( aSelRange.aStart );
952 if( rOldInfo.AutoEnd )
953 rOldInfo.End = pDoc->GetValue( aSelRange.aStart );
960 return bFound;
963 void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo& rInfo, sal_Int32 nParts )
965 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
966 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
967 if ( pDPObj )
969 ScStrCollection aEntries;
970 long nSelectDimension = -1;
971 GetSelectedMemberList( aEntries, nSelectDimension );
973 if ( aEntries.GetCount() > 0 )
975 BOOL bIsDataLayout;
976 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
978 ScDPSaveData aData( *pDPObj->GetSaveData() );
979 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
981 // find original base
982 String aBaseDimName = aDimName;
983 if( const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName ) )
984 aBaseDimName = pBaseGroupDim->GetSourceDimName();
986 // remove all existing parts (the grouping is built completely new)
988 /* Remove numeric group dimension (exists once at most). No need
989 to delete anything in save data (grouping was done inplace in
990 an existing base dimension). */
991 pDimData->RemoveNumGroupDimension( aBaseDimName );
993 /* Remove named group dimension(s). Collect deleted dimension
994 names which may be reused while recreating the groups.
995 Dimensions have to be removed from dimension save data and from
996 save data too. */
997 std::vector< String > aDeletedNames;
998 const ScDPSaveGroupDimension* pExistingGroup = pDimData->GetGroupDimForBase( aBaseDimName );
999 while ( pExistingGroup )
1001 String aGroupDimName = pExistingGroup->GetGroupDimName();
1002 pDimData->RemoveGroupDimension( aGroupDimName ); // pExistingGroup is deleted
1004 // also remove SaveData settings for the dimension that no longer exists
1005 aData.RemoveDimensionByName( aGroupDimName );
1007 /* The name can be used for the new group dimensions, although
1008 it is still in use with the DataPilotSource. */
1009 aDeletedNames.push_back( aGroupDimName );
1011 // see if there are more group dimensions
1012 pExistingGroup = pDimData->GetGroupDimForBase( aBaseDimName );
1014 if ( pExistingGroup && pExistingGroup->GetGroupDimName() == aGroupDimName )
1016 // still get the same group dimension?
1017 DBG_ERROR("couldn't remove group dimension");
1018 pExistingGroup = NULL; // avoid endless loop
1022 if ( nParts )
1024 // create date group dimensions
1026 ScDPNumGroupInfo aEmpty;
1027 bool bFirst = true;
1028 sal_Int32 nMask = 1;
1029 for (USHORT nBit=0; nBit<32; nBit++)
1031 if ( nParts & nMask )
1033 if ( bFirst )
1035 // innermost part: create NumGroupDimension (replacing original values)
1036 // Dimension name is left unchanged
1038 if ( (nParts == sheet::DataPilotFieldGroupBy::DAYS) && (rInfo.Step >= 1.0) )
1040 // only days, and a step value specified: use numerical grouping
1041 // with DateValues flag, not date grouping
1043 ScDPNumGroupInfo aNumInfo( rInfo );
1044 aNumInfo.DateValues = sal_True;
1046 ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, aNumInfo );
1047 pDimData->AddNumGroupDimension( aNumGroupDim );
1049 else
1051 ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, rInfo, nMask );
1052 pDimData->AddNumGroupDimension( aNumGroupDim );
1055 bFirst = false;
1057 else
1059 // additional parts: create GroupDimension (shown as additional dimensions)
1060 String aGroupDimName = pDimData->CreateDateGroupDimName( nMask, *pDPObj, true, &aDeletedNames );
1061 ScDPSaveGroupDimension aGroupDim( aBaseDimName, aGroupDimName );
1062 aGroupDim.SetDateInfo( rInfo, nMask );
1063 pDimData->AddGroupDimension( aGroupDim );
1065 // set orientation
1066 ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
1067 if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
1069 ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aBaseDimName );
1070 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
1071 long nPosition = 0; //! before (immediate) base
1072 aData.SetPosition( pSaveDimension, nPosition );
1076 nMask *= 2;
1080 // apply changes
1081 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1082 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1083 pNewObj->SetSaveData( aData );
1084 aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE );
1085 delete pNewObj;
1087 // unmark cell selection
1088 Unmark();
1093 void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo& rInfo )
1095 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1096 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1097 if ( pDPObj )
1099 ScStrCollection aEntries;
1100 long nSelectDimension = -1;
1101 GetSelectedMemberList( aEntries, nSelectDimension );
1103 if ( aEntries.GetCount() > 0 )
1105 BOOL bIsDataLayout;
1106 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1108 ScDPSaveData aData( *pDPObj->GetSaveData() );
1109 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1111 ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( aDimName );
1112 if ( pExisting )
1114 // modify existing group dimension
1115 pExisting->SetGroupInfo( rInfo );
1117 else
1119 // create new group dimension
1120 ScDPSaveNumGroupDimension aNumGroupDim( aDimName, rInfo );
1121 pDimData->AddNumGroupDimension( aNumGroupDim );
1124 // apply changes
1125 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1126 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1127 pNewObj->SetSaveData( aData );
1128 aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE );
1129 delete pNewObj;
1131 // unmark cell selection
1132 Unmark();
1137 void ScDBFunc::GroupDataPilot()
1139 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1140 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1141 if ( pDPObj )
1143 ScStrCollection aEntries;
1144 long nSelectDimension = -1;
1145 GetSelectedMemberList( aEntries, nSelectDimension );
1147 if ( aEntries.GetCount() > 0 )
1149 BOOL bIsDataLayout;
1150 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1152 ScDPSaveData aData( *pDPObj->GetSaveData() );
1153 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1155 // find original base
1156 String aBaseDimName( aDimName );
1157 const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
1158 if ( pBaseGroupDim )
1160 // any entry's SourceDimName is the original base
1161 aBaseDimName = pBaseGroupDim->GetSourceDimName();
1164 // find existing group dimension
1165 // (using the selected dim, can be intermediate group dim)
1166 ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
1168 // remove the selected items from their groups
1169 // (empty groups are removed, too)
1170 USHORT nEntryCount = aEntries.GetCount();
1171 USHORT nEntry;
1172 if ( pGroupDimension )
1174 for (nEntry=0; nEntry<nEntryCount; nEntry++)
1176 String aEntryName = aEntries[nEntry]->GetString();
1177 if ( pBaseGroupDim )
1179 // for each selected (intermediate) group, remove all its items
1180 // (same logic as for adding, below)
1181 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
1182 if ( pBaseGroup )
1183 pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements
1184 else
1185 pGroupDimension->RemoveFromGroups( aEntryName );
1187 else
1188 pGroupDimension->RemoveFromGroups( aEntryName );
1192 ScDPSaveGroupDimension* pNewGroupDim = NULL;
1193 if ( !pGroupDimension )
1195 // create a new group dimension
1196 String aGroupDimName = pDimData->CreateGroupDimName( aBaseDimName, *pDPObj, false, NULL );
1197 pNewGroupDim = new ScDPSaveGroupDimension( aBaseDimName, aGroupDimName );
1199 pGroupDimension = pNewGroupDim; // make changes to the new dim if none existed
1201 if ( pBaseGroupDim )
1203 // If it's a higher-order group dimension, pre-allocate groups for all
1204 // non-selected original groups, so the individual base members aren't
1205 // used for automatic groups (this would make the original groups hard
1206 // to find).
1207 //! Also do this when removing groups?
1208 //! Handle this case dynamically with automatic groups?
1210 long nGroupCount = pBaseGroupDim->GetGroupCount();
1211 for ( long nGroup = 0; nGroup < nGroupCount; nGroup++ )
1213 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
1215 StrData aStrData( pBaseGroup->GetGroupName() );
1216 USHORT nCollIndex;
1217 if ( !aEntries.Search( &aStrData, nCollIndex ) ) //! ignore case?
1219 // add an additional group for each item that is not in the selection
1220 ScDPSaveGroupItem aGroup( pBaseGroup->GetGroupName() );
1221 aGroup.AddElementsFromGroup( *pBaseGroup );
1222 pGroupDimension->AddGroupItem( aGroup );
1227 String aGroupDimName = pGroupDimension->GetGroupDimName();
1229 //! localized prefix string
1230 String aGroupName = pGroupDimension->CreateGroupName( String::CreateFromAscii("Group") );
1231 ScDPSaveGroupItem aGroup( aGroupName );
1232 for (nEntry=0; nEntry<nEntryCount; nEntry++)
1234 String aEntryName = aEntries[nEntry]->GetString();
1235 if ( pBaseGroupDim )
1237 // for each selected (intermediate) group, add all its items
1238 const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
1239 if ( pBaseGroup )
1240 aGroup.AddElementsFromGroup( *pBaseGroup );
1241 else
1242 aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself
1244 else
1245 aGroup.AddElement( aEntryName ); // no group dimension, add all items directly
1248 pGroupDimension->AddGroupItem( aGroup );
1250 if ( pNewGroupDim )
1252 pDimData->AddGroupDimension( *pNewGroupDim );
1253 delete pNewGroupDim; // AddGroupDimension copies the object
1254 // don't access pGroupDimension after here
1256 pGroupDimension = pNewGroupDim = NULL;
1258 // set orientation
1259 ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
1260 if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
1262 ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aDimName );
1263 pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
1264 long nPosition = 0; //! before (immediate) base
1265 aData.SetPosition( pSaveDimension, nPosition );
1268 // apply changes
1269 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1270 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1271 pNewObj->SetSaveData( aData );
1272 aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE );
1273 delete pNewObj;
1275 // unmark cell selection
1276 Unmark();
1281 void ScDBFunc::UngroupDataPilot()
1283 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1284 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1285 if ( pDPObj )
1287 ScStrCollection aEntries;
1288 long nSelectDimension = -1;
1289 GetSelectedMemberList( aEntries, nSelectDimension );
1291 if ( aEntries.GetCount() > 0 )
1293 BOOL bIsDataLayout;
1294 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1296 ScDPSaveData aData( *pDPObj->GetSaveData() );
1297 ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1298 //! test first if DimensionData exists?
1300 BOOL bApply = FALSE;
1302 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
1303 const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
1304 if ( ( pGroupDim && pGroupDim->GetDatePart() != 0 ) ||
1305 ( pNumGroupDim && pNumGroupDim->GetDatePart() != 0 ) )
1307 // Date grouping: need to remove all affected group dimensions.
1308 // This is done using DateGroupDataPilot with nParts=0.
1310 DateGroupDataPilot( ScDPNumGroupInfo(), 0 );
1311 // bApply remains FALSE
1312 // dimension pointers become invalid
1314 else if ( pGroupDim )
1316 USHORT nEntryCount = aEntries.GetCount();
1317 for (USHORT nEntry=0; nEntry<nEntryCount; nEntry++)
1319 String aEntryName = aEntries[nEntry]->GetString();
1320 pGroupDim->RemoveGroup( aEntryName );
1322 // remove group dimension if empty
1323 bool bEmptyDim = pGroupDim->IsEmpty();
1324 if ( !bEmptyDim )
1326 // If all remaining groups in the dimension aren't shown, remove
1327 // the dimension too, as if it was completely empty.
1328 ScStrCollection aVisibleEntries;
1329 pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
1330 bEmptyDim = pGroupDim->HasOnlyHidden( aVisibleEntries );
1332 if ( bEmptyDim )
1334 pDimData->RemoveGroupDimension( aDimName ); // pGroupDim is deleted
1336 // also remove SaveData settings for the dimension that no longer exists
1337 aData.RemoveDimensionByName( aDimName );
1339 bApply = TRUE;
1341 else if ( pNumGroupDim )
1343 // remove the numerical grouping
1344 pDimData->RemoveNumGroupDimension( aDimName );
1345 // SaveData settings can remain unchanged - the same dimension still exists
1346 bApply = TRUE;
1349 if ( bApply )
1351 // apply changes
1352 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1353 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1354 pNewObj->SetSaveData( aData );
1355 aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE );
1356 delete pNewObj;
1358 // unmark cell selection
1359 Unmark();
1365 static OUString lcl_replaceMemberNameInSubtotal(const OUString& rSubtotal, const OUString& rMemberName)
1367 sal_Int32 n = rSubtotal.getLength();
1368 const sal_Unicode* p = rSubtotal.getStr();
1369 OUStringBuffer aBuf, aWordBuf;
1370 for (sal_Int32 i = 0; i < n; ++i)
1372 sal_Unicode c = p[i];
1373 if (c == sal_Unicode(' '))
1375 OUString aWord = aWordBuf.makeStringAndClear();
1376 if (aWord.equals(rMemberName))
1377 aBuf.append(sal_Unicode('?'));
1378 else
1379 aBuf.append(aWord);
1380 aBuf.append(c);
1382 else if (c == sal_Unicode('\\'))
1384 // Escape a backslash character.
1385 aWordBuf.append(c);
1386 aWordBuf.append(c);
1388 else if (c == sal_Unicode('?'))
1390 // A literal '?' must be escaped with a backslash ('\');
1391 aWordBuf.append(sal_Unicode('\\'));
1392 aWordBuf.append(c);
1394 else
1395 aWordBuf.append(c);
1398 if (aWordBuf.getLength() > 0)
1400 OUString aWord = aWordBuf.makeStringAndClear();
1401 if (aWord.equals(rMemberName))
1402 aBuf.append(sal_Unicode('?'));
1403 else
1404 aBuf.append(aWord);
1407 return aBuf.makeStringAndClear();
1410 void ScDBFunc::DataPilotInput( const ScAddress& rPos, const String& rString )
1412 using namespace ::com::sun::star::sheet;
1414 String aNewName( rString );
1416 ScDocument* pDoc = GetViewData()->GetDocument();
1417 ScDPObject* pDPObj = pDoc->GetDPAtCursor( rPos.Col(), rPos.Row(), rPos.Tab() );
1418 if (!pDPObj)
1419 return;
1421 String aOldText;
1422 pDoc->GetString( rPos.Col(), rPos.Row(), rPos.Tab(), aOldText );
1424 if ( aOldText == rString )
1426 // nothing to do: silently exit
1427 return;
1430 USHORT nErrorId = 0;
1432 pDPObj->BuildAllDimensionMembers();
1433 ScDPSaveData aData( *pDPObj->GetSaveData() );
1434 BOOL bChange = FALSE;
1436 USHORT nOrient = DataPilotFieldOrientation_HIDDEN;
1437 long nField = pDPObj->GetHeaderDim( rPos, nOrient );
1438 if ( nField >= 0 )
1440 // changing a field title
1441 if ( aData.GetExistingDimensionData() )
1443 // only group dimensions can be renamed
1445 ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1446 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aOldText );
1447 if ( pGroupDim )
1449 // valid name: not empty, no existing dimension (group or other)
1450 if ( rString.Len() && !pDPObj->IsDimNameInUse(rString) )
1452 pGroupDim->Rename( aNewName );
1454 // also rename in SaveData to preserve the field settings
1455 ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aOldText );
1456 pSaveDim->SetName( aNewName );
1458 bChange = TRUE;
1460 else
1461 nErrorId = STR_INVALIDNAME;
1464 else if (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW)
1466 BOOL bDataLayout = false;
1467 String aDimName = pDPObj->GetDimName(nField, bDataLayout);
1468 ScDPSaveDimension* pDim = bDataLayout ? aData.GetDataLayoutDimension() : aData.GetDimensionByName(aDimName);
1469 if (pDim)
1471 if (rString.Len())
1473 if (rString.EqualsIgnoreCaseAscii(aDimName))
1475 pDim->RemoveLayoutName();
1476 bChange = true;
1478 else if (!pDPObj->IsDimNameInUse(rString))
1480 pDim->SetLayoutName(rString);
1481 bChange = true;
1483 else
1484 nErrorId = STR_INVALIDNAME;
1486 else
1487 nErrorId = STR_INVALIDNAME;
1491 else if (pDPObj->IsDataDescriptionCell(rPos))
1493 // There is only one data dimension.
1494 ScDPSaveDimension* pDim = aData.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA);
1495 if (pDim)
1497 if (rString.Len())
1499 if (rString.EqualsIgnoreCaseAscii(pDim->GetName()))
1501 pDim->RemoveLayoutName();
1502 bChange = true;
1504 else if (!pDPObj->IsDimNameInUse(rString))
1506 pDim->SetLayoutName(rString);
1507 bChange = true;
1509 else
1510 nErrorId = STR_INVALIDNAME;
1512 else
1513 nErrorId = STR_INVALIDNAME;
1516 else
1518 // This is not a field header.
1519 sheet::DataPilotTableHeaderData aPosData;
1520 pDPObj->GetHeaderPositionData(rPos, aPosData);
1522 if ( (aPosData.Flags & MemberResultFlags::HASMEMBER) && aOldText.Len() )
1524 if ( aData.GetExistingDimensionData() && !(aPosData.Flags & MemberResultFlags::SUBTOTAL))
1526 BOOL bIsDataLayout;
1527 String aDimName = pDPObj->GetDimName( aPosData.Dimension, bIsDataLayout );
1529 ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1530 ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
1531 if ( pGroupDim )
1533 // valid name: not empty, no existing group in this dimension
1534 //! ignore case?
1535 if ( aNewName.Len() && !pGroupDim->GetNamedGroup( aNewName ) )
1537 ScDPSaveGroupItem* pGroup = pGroupDim->GetNamedGroupAcc( aOldText );
1538 if ( pGroup )
1539 pGroup->Rename( aNewName ); // rename the existing group
1540 else
1542 // create a new group to replace the automatic group
1543 ScDPSaveGroupItem aGroup( aNewName );
1544 aGroup.AddElement( aOldText );
1545 pGroupDim->AddGroupItem( aGroup );
1548 // in both cases also adjust savedata, to preserve member settings (show details)
1549 ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aDimName );
1550 ScDPSaveMember* pSaveMember = pSaveDim->GetExistingMemberByName( aOldText );
1551 if ( pSaveMember )
1552 pSaveMember->SetName( aNewName );
1554 bChange = TRUE;
1556 else
1557 nErrorId = STR_INVALIDNAME;
1560 else if ((aPosData.Flags & MemberResultFlags::GRANDTOTAL))
1562 aData.SetGrandTotalName(rString);
1563 bChange = true;
1565 else if (aPosData.Dimension >= 0 && aPosData.MemberName.getLength() > 0)
1567 BOOL bDataLayout = false;
1568 String aDimName = pDPObj->GetDimName(static_cast<long>(aPosData.Dimension), bDataLayout);
1569 if (bDataLayout)
1571 // data dimension
1574 if ((aPosData.Flags & MemberResultFlags::SUBTOTAL))
1575 break;
1577 ScDPSaveDimension* pDim = aData.GetDimensionByName(aPosData.MemberName);
1578 if (!pDim)
1579 break;
1581 if (!rString.Len())
1583 nErrorId = STR_INVALIDNAME;
1584 break;
1587 if (aPosData.MemberName.equalsIgnoreAsciiCase(rString))
1589 pDim->RemoveLayoutName();
1590 bChange = true;
1592 else if (!pDPObj->IsDimNameInUse(rString))
1594 pDim->SetLayoutName(rString);
1595 bChange = true;
1597 else
1598 nErrorId = STR_INVALIDNAME;
1600 while (false);
1602 else
1604 // field member
1607 ScDPSaveDimension* pDim = aData.GetDimensionByName(aDimName);
1608 if (!pDim)
1609 break;
1611 ScDPSaveMember* pMem = pDim->GetExistingMemberByName(aPosData.MemberName);
1612 if (!pMem)
1613 break;
1615 if ((aPosData.Flags & MemberResultFlags::SUBTOTAL))
1617 // Change subtotal only when the table has one data dimension.
1618 if (aData.GetDataDimensionCount() > 1)
1619 break;
1621 // display name for subtotal is allowed only if the subtotal type is 'Automatic'.
1622 if (pDim->GetSubTotalsCount() != 1)
1623 break;
1625 if (pDim->GetSubTotalFunc(0) != sheet::GeneralFunction_AUTO)
1626 break;
1628 const OUString* pLayoutName = pMem->GetLayoutName();
1629 String aMemberName;
1630 if (pLayoutName)
1631 aMemberName = *pLayoutName;
1632 else
1633 aMemberName = aPosData.MemberName;
1635 String aNew = lcl_replaceMemberNameInSubtotal(rString, aMemberName);
1636 pDim->SetSubtotalName(aNew);
1637 bChange = true;
1639 else
1641 // Check to make sure the member name isn't
1642 // already used.
1643 if (rString.Len())
1645 if (rString.EqualsIgnoreCaseAscii(pMem->GetName()))
1647 pMem->RemoveLayoutName();
1648 bChange = true;
1650 else if (!pDim->IsMemberNameInUse(rString))
1652 pMem->SetLayoutName(rString);
1653 bChange = true;
1655 else
1656 nErrorId = STR_INVALIDNAME;
1658 else
1659 nErrorId = STR_INVALIDNAME;
1662 while (false);
1668 if ( bChange )
1670 // apply changes
1671 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1672 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1673 pNewObj->SetSaveData( aData );
1674 aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE );
1675 delete pNewObj;
1677 else
1679 if ( !nErrorId )
1680 nErrorId = STR_ERR_DATAPILOT_INPUT;
1681 ErrorMessage( nErrorId );
1685 void lcl_MoveToEnd( ScDPSaveDimension& rDim, const String& rItemName )
1687 ScDPSaveMember* pNewMember = NULL;
1688 const ScDPSaveMember* pOldMember = rDim.GetExistingMemberByName( rItemName );
1689 if ( pOldMember )
1690 pNewMember = new ScDPSaveMember( *pOldMember );
1691 else
1692 pNewMember = new ScDPSaveMember( rItemName );
1693 rDim.AddMember( pNewMember );
1694 // AddMember takes ownership of the new pointer,
1695 // puts it to the end of the list even if it was in the list before.
1698 bool ScDBFunc::DataPilotSort( const ScAddress& rPos, bool bAscending, sal_uInt16* pUserListId )
1700 ScDocument* pDoc = GetViewData()->GetDocument();
1701 ScDPObject* pDPObj = pDoc->GetDPAtCursor(rPos.Col(), rPos.Row(), rPos.Tab());
1702 if (!pDPObj)
1703 return false;
1705 // We need to run this to get all members later.
1706 pDPObj->BuildAllDimensionMembers();
1708 USHORT nOrientation;
1709 long nDimIndex = pDPObj->GetHeaderDim(rPos, nOrientation);
1710 if (nDimIndex < 0)
1711 // Invalid dimension index. Bail out.
1712 return false;
1714 BOOL bDataLayout;
1715 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1716 if (!pSaveData)
1717 return false;
1719 ScDPSaveData aNewSaveData(*pSaveData);
1720 String aDimName = pDPObj->GetDimName(nDimIndex, bDataLayout);
1721 ScDPSaveDimension* pSaveDim = aNewSaveData.GetDimensionByName(aDimName);
1722 if (!pSaveDim)
1723 return false;
1725 typedef ScDPSaveDimension::MemberList MemList;
1726 const MemList& rDimMembers = pSaveDim->GetMembers();
1727 list<OUString> aMembers;
1728 hash_set<OUString, ::rtl::OUStringHash> aMemberSet;
1729 size_t nMemberCount = 0;
1730 for (MemList::const_iterator itr = rDimMembers.begin(), itrEnd = rDimMembers.end();
1731 itr != itrEnd; ++itr)
1733 ScDPSaveMember* pMem = *itr;
1734 aMembers.push_back(pMem->GetName());
1735 aMemberSet.insert(pMem->GetName());
1736 ++nMemberCount;
1739 // Sort the member list in ascending order.
1740 aMembers.sort();
1742 // Collect and rank those custom sort strings that also exist in the member name list.
1744 typedef hash_map<OUString, sal_uInt16, OUStringHash> UserSortMap;
1745 UserSortMap aSubStrs;
1746 sal_uInt16 nSubCount = 0;
1747 if (pUserListId)
1749 ScUserList* pUserList = ScGlobal::GetUserList();
1750 if (!pUserList)
1751 return false;
1754 sal_uInt16 n = pUserList->GetCount();
1755 if (!n || *pUserListId >= n)
1756 return false;
1759 ScUserListData* pData = static_cast<ScUserListData*>((*pUserList)[*pUserListId]);
1760 if (pData)
1762 sal_uInt16 n = pData->GetSubCount();
1763 for (sal_uInt16 i = 0; i < n; ++i)
1765 OUString aSub = pData->GetSubStr(i);
1766 if (!aMemberSet.count(aSub))
1767 // This string doesn't exist in the member name set. Don't add this.
1768 continue;
1770 aSubStrs.insert(UserSortMap::value_type(aSub, nSubCount++));
1775 // Rank all members.
1777 vector<OUString> aRankedNames(nMemberCount);
1778 sal_uInt16 nCurStrId = 0;
1779 for (list<OUString>::const_iterator itr = aMembers.begin(), itrEnd = aMembers.end();
1780 itr != itrEnd; ++itr)
1782 OUString aName = *itr;
1783 sal_uInt16 nRank = 0;
1784 UserSortMap::const_iterator itrSub = aSubStrs.find(aName);
1785 if (itrSub == aSubStrs.end())
1786 nRank = nSubCount + nCurStrId++;
1787 else
1788 nRank = itrSub->second;
1790 if (!bAscending)
1791 nRank = nMemberCount - nRank - 1;
1793 aRankedNames[nRank] = aName;
1796 // Re-order ScDPSaveMember instances with the new ranks.
1798 for (vector<OUString>::const_iterator itr = aRankedNames.begin(), itrEnd = aRankedNames.end();
1799 itr != itrEnd; ++itr)
1801 const ScDPSaveMember* pOldMem = pSaveDim->GetExistingMemberByName(*itr);
1802 if (!pOldMem)
1803 // All members are supposed to be present.
1804 continue;
1806 ScDPSaveMember* pNewMem = new ScDPSaveMember(*pOldMem);
1807 pSaveDim->AddMember(pNewMem);
1810 // Set the sorting mode to manual for now. We may introduce a new sorting
1811 // mode later on.
1813 sheet::DataPilotFieldSortInfo aSortInfo;
1814 aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
1815 pSaveDim->SetSortInfo(&aSortInfo);
1817 // Update the datapilot with the newly sorted field members.
1819 auto_ptr<ScDPObject> pNewObj(new ScDPObject(*pDPObj));
1820 pNewObj->SetSaveData(aNewSaveData);
1821 ScDBDocFunc aFunc(*GetViewData()->GetDocShell());
1823 return aFunc.DataPilotUpdate(pDPObj, pNewObj.get(), true, false);
1826 BOOL ScDBFunc::DataPilotMove( const ScRange& rSource, const ScAddress& rDest )
1828 BOOL bRet = FALSE;
1829 ScDocument* pDoc = GetViewData()->GetDocument();
1830 ScDPObject* pDPObj = pDoc->GetDPAtCursor( rSource.aStart.Col(), rSource.aStart.Row(), rSource.aStart.Tab() );
1831 if ( pDPObj && pDPObj == pDoc->GetDPAtCursor( rDest.Col(), rDest.Row(), rDest.Tab() ) )
1833 sheet::DataPilotTableHeaderData aDestData;
1834 pDPObj->GetHeaderPositionData( rDest, aDestData );
1835 bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
1837 // look through the source range
1838 std::hash_set< rtl::OUString, rtl::OUStringHash, std::equal_to<rtl::OUString> > aMembersSet; // for lookup
1839 std::vector< rtl::OUString > aMembersVector; // members in original order, for inserting
1840 aMembersVector.reserve( std::max( static_cast<SCSIZE>( rSource.aEnd.Col() - rSource.aStart.Col() + 1 ),
1841 static_cast<SCSIZE>( rSource.aEnd.Row() - rSource.aStart.Row() + 1 ) ) );
1842 for (SCROW nRow = rSource.aStart.Row(); bValid && nRow <= rSource.aEnd.Row(); ++nRow )
1843 for (SCCOL nCol = rSource.aStart.Col(); bValid && nCol <= rSource.aEnd.Col(); ++nCol )
1845 sheet::DataPilotTableHeaderData aSourceData;
1846 pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, rSource.aStart.Tab() ), aSourceData );
1847 if ( aSourceData.Dimension == aDestData.Dimension && aSourceData.MemberName.getLength() )
1849 if ( aMembersSet.find( aSourceData.MemberName ) == aMembersSet.end() )
1851 aMembersSet.insert( aSourceData.MemberName );
1852 aMembersVector.push_back( aSourceData.MemberName );
1854 // duplicates are ignored
1856 else
1857 bValid = false; // empty (subtotal) or different field
1860 if ( bValid )
1862 BOOL bIsDataLayout;
1863 String aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
1864 if ( !bIsDataLayout )
1866 ScDPSaveData aData( *pDPObj->GetSaveData() );
1867 ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
1869 // get all member names in source order
1870 uno::Sequence<rtl::OUString> aMemberNames;
1871 pDPObj->GetMemberNames( aDestData.Dimension, aMemberNames );
1873 bool bInserted = false;
1875 sal_Int32 nMemberCount = aMemberNames.getLength();
1876 for (sal_Int32 nMemberPos=0; nMemberPos<nMemberCount; ++nMemberPos)
1878 String aMemberStr( aMemberNames[nMemberPos] );
1880 if ( !bInserted && aMemberNames[nMemberPos] == aDestData.MemberName )
1882 // insert dragged items before this item
1883 for ( std::vector<rtl::OUString>::const_iterator aIter = aMembersVector.begin();
1884 aIter != aMembersVector.end(); ++aIter )
1885 lcl_MoveToEnd( *pDim, *aIter );
1886 bInserted = true;
1889 if ( aMembersSet.find( aMemberStr ) == aMembersSet.end() ) // skip dragged items
1890 lcl_MoveToEnd( *pDim, aMemberStr );
1892 // insert dragged item at end if dest wasn't found (for example, empty)
1893 if ( !bInserted )
1894 for ( std::vector<rtl::OUString>::const_iterator aIter = aMembersVector.begin();
1895 aIter != aMembersVector.end(); ++aIter )
1896 lcl_MoveToEnd( *pDim, *aIter );
1898 // Items that were in SaveData, but not in the source, end up at the start of the list.
1900 // set flag for manual sorting
1901 sheet::DataPilotFieldSortInfo aSortInfo;
1902 aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
1903 pDim->SetSortInfo( &aSortInfo );
1905 // apply changes
1906 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
1907 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
1908 pNewObj->SetSaveData( aData );
1909 aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE ); //! bApi for drag&drop?
1910 delete pNewObj;
1912 Unmark(); // entry was moved - no use in leaving the old cell selected
1914 bRet = TRUE;
1919 return bRet;
1922 BOOL ScDBFunc::HasSelectionForDrillDown( USHORT& rOrientation )
1924 BOOL bRet = FALSE;
1926 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1927 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1928 if ( pDPObj )
1930 ScStrCollection aEntries;
1931 long nSelectDimension = -1;
1932 GetSelectedMemberList( aEntries, nSelectDimension );
1934 if ( aEntries.GetCount() > 0 )
1936 BOOL bIsDataLayout;
1937 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1938 if ( !bIsDataLayout )
1940 ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1941 ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName( aDimName );
1942 if ( pDim )
1944 USHORT nDimOrient = pDim->GetOrientation();
1945 ScDPSaveDimension* pInner = pSaveData->GetInnermostDimension( nDimOrient );
1946 if ( pDim == pInner )
1948 rOrientation = nDimOrient;
1949 bRet = TRUE;
1956 return bRet;
1959 void ScDBFunc::SetDataPilotDetails( BOOL bShow, const String* pNewDimensionName )
1961 ScDPObject* pDPObj = GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1962 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1963 if ( pDPObj )
1965 ScStrCollection aEntries;
1966 long nSelectDimension = -1;
1967 GetSelectedMemberList( aEntries, nSelectDimension );
1969 if ( aEntries.GetCount() > 0 )
1971 BOOL bIsDataLayout;
1972 String aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1973 if ( !bIsDataLayout )
1975 ScDPSaveData aData( *pDPObj->GetSaveData() );
1976 ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
1978 if ( bShow && pNewDimensionName )
1980 // add the new dimension with the same orientation, at the end
1982 ScDPSaveDimension* pNewDim = aData.GetDimensionByName( *pNewDimensionName );
1983 ScDPSaveDimension* pDuplicated = NULL;
1984 if ( pNewDim->GetOrientation() == sheet::DataPilotFieldOrientation_DATA )
1986 // Need to duplicate the dimension, create column/row in addition to data:
1987 // The duplicated dimension inherits the existing settings, pNewDim is modified below.
1988 pDuplicated = aData.DuplicateDimension( *pNewDimensionName );
1991 USHORT nOrientation = pDim->GetOrientation();
1992 pNewDim->SetOrientation( nOrientation );
1994 long nPosition = LONG_MAX;
1995 aData.SetPosition( pNewDim, nPosition );
1997 ScDPSaveDimension* pDataLayout = aData.GetDataLayoutDimension();
1998 if ( pDataLayout->GetOrientation() == nOrientation &&
1999 aData.GetDataDimensionCount() <= 1 )
2001 // If there is only one data dimension, the data layout dimension
2002 // must still be the last one in its orientation.
2003 aData.SetPosition( pDataLayout, nPosition );
2006 if ( pDuplicated )
2008 // The duplicated (data) dimension needs to be behind the original dimension
2009 aData.SetPosition( pDuplicated, nPosition );
2012 // Hide details for all visible members (selected are changed below).
2013 //! Use all members from source level instead (including non-visible)?
2015 ScStrCollection aVisibleEntries;
2016 pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
2018 USHORT nVisCount = aVisibleEntries.GetCount();
2019 for (USHORT nVisPos=0; nVisPos<nVisCount; nVisPos++)
2021 String aVisName = aVisibleEntries[nVisPos]->GetString();
2022 ScDPSaveMember* pMember = pDim->GetMemberByName( aVisName );
2023 pMember->SetShowDetails( FALSE );
2027 USHORT nEntryCount = aEntries.GetCount();
2028 for (USHORT nEntry=0; nEntry<nEntryCount; nEntry++)
2030 String aEntryName = aEntries[nEntry]->GetString();
2031 ScDPSaveMember* pMember = pDim->GetMemberByName( aEntryName );
2032 pMember->SetShowDetails( bShow );
2035 // apply changes
2036 ScDBDocFunc aFunc( *GetViewData()->GetDocShell() );
2037 ScDPObject* pNewObj = new ScDPObject( *pDPObj );
2038 pNewObj->SetSaveData( aData );
2039 aFunc.DataPilotUpdate( pDPObj, pNewObj, TRUE, FALSE );
2040 delete pNewObj;
2042 // unmark cell selection
2043 Unmark();
2049 void ScDBFunc::ShowDataPilotSourceData( ScDPObject& rDPObj, const Sequence<sheet::DataPilotFieldFilter>& rFilters )
2051 ScDocument* pDoc = GetViewData()->GetDocument();
2052 if (pDoc->GetDocumentShell()->IsReadOnly())
2054 ErrorMessage(STR_READONLYERR);
2055 return;
2058 Reference<sheet::XDimensionsSupplier> xDimSupplier = rDPObj.GetSource();
2059 Reference<container::XNameAccess> xDims = xDimSupplier->getDimensions();
2060 Reference<sheet::XDrillDownDataSupplier> xDDSupplier(xDimSupplier, UNO_QUERY);
2061 if (!xDDSupplier.is())
2062 return;
2064 Sequence< Sequence<Any> > aTabData = xDDSupplier->getDrillDownData(rFilters);
2065 sal_Int32 nRowSize = aTabData.getLength();
2066 if (nRowSize <= 1)
2067 // There is no data to show. Bail out.
2068 return;
2070 sal_Int32 nColSize = aTabData[0].getLength();
2072 SCTAB nNewTab = GetViewData()->GetTabNo();
2074 auto_ptr<ScDocument> pInsDoc(new ScDocument(SCDOCMODE_CLIP));
2075 pInsDoc->ResetClip( pDoc, nNewTab );
2076 for (SCROW nRow = 0; nRow < nRowSize; ++nRow)
2078 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
2080 const Any& rAny = aTabData[nRow][nCol];
2081 rtl::OUString aStr;
2082 double fVal;
2083 if (rAny >>= aStr)
2084 pInsDoc->PutCell( ScAddress(nCol, nRow, nNewTab), new ScStringCell(String(aStr)) );
2085 else if (rAny >>= fVal)
2086 pInsDoc->SetValue(nCol, nRow, nNewTab, fVal);
2090 // set number format (important for dates)
2091 for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
2093 rtl::OUString aStr;
2094 if (!(aTabData[0][nCol] >>= aStr))
2095 continue;
2097 Reference<XPropertySet> xPropSet(xDims->getByName(aStr), UNO_QUERY);
2098 if (!xPropSet.is())
2099 continue;
2101 Any any = xPropSet->getPropertyValue( rtl::OUString::createFromAscii(SC_UNO_NUMBERFO) );
2102 sal_Int32 nNumFmt = 0;
2103 if (!(any >>= nNumFmt))
2104 continue;
2106 ScPatternAttr aPattern( pInsDoc->GetPool() );
2107 aPattern.GetItemSet().Put( SfxUInt32Item(ATTR_VALUE_FORMAT, static_cast<UINT32>(nNumFmt)) );
2108 pInsDoc->ApplyPatternAreaTab(nCol, 1, nCol, nRowSize-1, nNewTab, aPattern);
2111 SCCOL nEndCol = 0;
2112 SCROW nEndRow = 0;
2113 pInsDoc->GetCellArea( nNewTab, nEndCol, nEndRow );
2114 pInsDoc->SetClipArea( ScRange( 0, 0, nNewTab, nEndCol, nEndRow, nNewTab ) );
2116 SfxUndoManager* pMgr = GetViewData()->GetDocShell()->GetUndoManager();
2117 String aUndo = ScGlobal::GetRscString( STR_UNDO_DOOUTLINE );
2118 pMgr->EnterListAction( aUndo, aUndo );
2120 String aNewTabName;
2121 pDoc->CreateValidTabName(aNewTabName);
2122 if ( InsertTable(aNewTabName, nNewTab) )
2123 PasteFromClip( IDF_ALL, pInsDoc.get() );
2125 pMgr->LeaveListAction();
2129 // DB-Operationen (Sortieren, Filtern, Teilergebnisse) wiederholen
2132 void ScDBFunc::RepeatDB( BOOL bRecord )
2134 SCCOL nCurX = GetViewData()->GetCurX();
2135 SCROW nCurY = GetViewData()->GetCurY();
2136 SCTAB nTab = GetViewData()->GetTabNo();
2137 ScDocument* pDoc = GetViewData()->GetDocument();
2138 ScDBData* pDBData = GetDBData();
2139 if (bRecord && !pDoc->IsUndoEnabled())
2140 bRecord = FALSE;
2142 ScQueryParam aQueryParam;
2143 pDBData->GetQueryParam( aQueryParam );
2144 BOOL bQuery = aQueryParam.GetEntry(0).bDoQuery;
2146 ScSortParam aSortParam;
2147 pDBData->GetSortParam( aSortParam );
2148 BOOL bSort = aSortParam.bDoSort[0];
2150 ScSubTotalParam aSubTotalParam;
2151 pDBData->GetSubTotalParam( aSubTotalParam );
2152 BOOL bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
2154 if ( bQuery || bSort || bSubTotal )
2156 BOOL bQuerySize = FALSE;
2157 ScRange aOldQuery;
2158 ScRange aNewQuery;
2159 if (bQuery && !aQueryParam.bInplace)
2161 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
2162 aQueryParam.nDestTab, TRUE );
2163 if (pDest && pDest->IsDoSize())
2165 pDest->GetArea( aOldQuery );
2166 bQuerySize = TRUE;
2170 SCTAB nDummy;
2171 SCCOL nStartCol;
2172 SCROW nStartRow;
2173 SCCOL nEndCol;
2174 SCROW nEndRow;
2175 pDBData->GetArea( nDummy, nStartCol, nStartRow, nEndCol, nEndRow );
2177 //! Undo nur benoetigte Daten ?
2179 ScDocument* pUndoDoc = NULL;
2180 ScOutlineTable* pUndoTab = NULL;
2181 ScRangeName* pUndoRange = NULL;
2182 ScDBCollection* pUndoDB = NULL;
2184 if (bRecord)
2186 SCTAB nTabCount = pDoc->GetTableCount();
2187 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
2188 ScOutlineTable* pTable = pDoc->GetOutlineTable( nTab );
2189 if (pTable)
2191 pUndoTab = new ScOutlineTable( *pTable );
2193 SCCOLROW nOutStartCol; // Zeilen/Spaltenstatus
2194 SCCOLROW nOutStartRow;
2195 SCCOLROW nOutEndCol;
2196 SCCOLROW nOutEndRow;
2197 pTable->GetColArray()->GetRange( nOutStartCol, nOutEndCol );
2198 pTable->GetRowArray()->GetRange( nOutStartRow, nOutEndRow );
2200 pUndoDoc->InitUndo( pDoc, nTab, nTab, TRUE, TRUE );
2201 pDoc->CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), MAXROW, nTab, IDF_NONE, FALSE, pUndoDoc );
2202 pDoc->CopyToDocument( 0, nOutStartRow, nTab, MAXCOL, nOutEndRow, nTab, IDF_NONE, FALSE, pUndoDoc );
2204 else
2205 pUndoDoc->InitUndo( pDoc, nTab, nTab, FALSE, TRUE );
2207 // Datenbereich sichern - incl. Filter-Ergebnis
2208 pDoc->CopyToDocument( 0,nStartRow,nTab, MAXCOL,nEndRow,nTab, IDF_ALL, FALSE, pUndoDoc );
2210 // alle Formeln wegen Referenzen
2211 pDoc->CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTabCount-1, IDF_FORMULA, FALSE, pUndoDoc );
2213 // DB- und andere Bereiche
2214 ScRangeName* pDocRange = pDoc->GetRangeName();
2215 if (pDocRange->GetCount())
2216 pUndoRange = new ScRangeName( *pDocRange );
2217 ScDBCollection* pDocDB = pDoc->GetDBCollection();
2218 if (pDocDB->GetCount())
2219 pUndoDB = new ScDBCollection( *pDocDB );
2222 if (bSort && bSubTotal)
2224 // Sortieren ohne SubTotals
2226 aSubTotalParam.bRemoveOnly = TRUE; // wird unten wieder zurueckgesetzt
2227 DoSubTotals( aSubTotalParam, FALSE );
2230 if (bSort)
2232 pDBData->GetSortParam( aSortParam ); // Bereich kann sich geaendert haben
2233 Sort( aSortParam, FALSE, FALSE);
2235 if (bQuery)
2237 pDBData->GetQueryParam( aQueryParam ); // Bereich kann sich geaendert haben
2238 ScRange aAdvSource;
2239 if (pDBData->GetAdvancedQuerySource(aAdvSource))
2241 pDoc->CreateQueryParam(
2242 aAdvSource.aStart.Col(), aAdvSource.aStart.Row(),
2243 aAdvSource.aEnd.Col(), aAdvSource.aEnd.Row(),
2244 aAdvSource.aStart.Tab(), aQueryParam );
2245 Query( aQueryParam, &aAdvSource, FALSE );
2247 else
2248 Query( aQueryParam, NULL, FALSE );
2250 // bei nicht-inplace kann die Tabelle umgestellt worden sein
2251 if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
2252 SetTabNo( nTab );
2254 if (bSubTotal)
2256 pDBData->GetSubTotalParam( aSubTotalParam ); // Bereich kann sich geaendert haben
2257 aSubTotalParam.bRemoveOnly = FALSE;
2258 DoSubTotals( aSubTotalParam, FALSE );
2261 if (bRecord)
2263 SCTAB nDummyTab;
2264 SCCOL nDummyCol;
2265 SCROW nDummyRow, nNewEndRow;
2266 pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
2268 const ScRange* pOld = NULL;
2269 const ScRange* pNew = NULL;
2270 if (bQuerySize)
2272 ScDBData* pDest = pDoc->GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
2273 aQueryParam.nDestTab, TRUE );
2274 if (pDest)
2276 pDest->GetArea( aNewQuery );
2277 pOld = &aOldQuery;
2278 pNew = &aNewQuery;
2282 GetViewData()->GetDocShell()->GetUndoManager()->AddUndoAction(
2283 new ScUndoRepeatDB( GetViewData()->GetDocShell(), nTab,
2284 nStartCol, nStartRow, nEndCol, nEndRow,
2285 nNewEndRow,
2286 nCurX, nCurY,
2287 pUndoDoc, pUndoTab,
2288 pUndoRange, pUndoDB,
2289 pOld, pNew ) );
2292 GetViewData()->GetDocShell()->PostPaint( 0,0,nTab, MAXCOL,MAXROW,nTab,
2293 PAINT_GRID | PAINT_LEFT | PAINT_TOP | PAINT_SIZE );
2295 else // "Keine Operationen auszufuehren"
2296 ErrorMessage(STR_MSSG_REPEATDB_0);
2299 void ScDBFunc::AutoFormatPivotTable(USHORT nIndex)
2301 ScDocument* pDoc = GetViewData()->GetDocument();
2303 // old pivot not used any more
2305 ScDPObject* pDPObj = pDoc->GetDPAtCursor(
2306 GetViewData()->GetCurX(), GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
2308 if ( pDPObj )
2310 pDPObj->SetAutoFormatIndex(nIndex);
2312 else
2313 ErrorMessage(STR_PIVOT_NOTFOUND);
2317 void ScDBFunc::AutoFormatPivotTable(ScDPObject* pDPObj, USHORT nIndex)
2319 pDPObj->SetAutoFormatIndex(nIndex);