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 $
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 ---------------------------------------------------------------
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>
60 #include "globstr.hrc"
62 #include "undotab.hxx"
63 #include "undodat.hxx"
64 #include "dbcolect.hxx"
65 #include "rangenam.hxx"
66 #include "rangeutl.hxx"
68 #include "olinetab.hxx"
69 #include "consoli.hxx"
70 #include "olinefun.hxx"
71 #include "dpobject.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"
82 #include "userlist.hxx"
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
;
104 using ::std::hash_map
;
105 using ::std::hash_set
;
107 // STATIC DATA -----------------------------------------------------------
110 //==================================================================
116 // Outline-Gruppierung erzeugen
118 void ScDBFunc::MakeOutline( BOOL bColumns
, BOOL bRecord
)
121 if (GetViewData()->GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
123 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
124 ScOutlineDocFunc
aFunc(*pDocSh
);
125 aFunc
.MakeOutline( aRange
, bColumns
, bRecord
, FALSE
);
128 ErrorMessage(STR_NOMULTISELECT
);
131 // Outline-Gruppierung loeschen
133 void ScDBFunc::RemoveOutline( BOOL bColumns
, BOOL bRecord
)
136 if (GetViewData()->GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
138 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
139 ScOutlineDocFunc
aFunc(*pDocSh
);
140 aFunc
.RemoveOutline( aRange
, bColumns
, bRecord
, FALSE
);
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
);
163 ScOutlineArray
* pArray
;
164 ScOutlineEntry
* pEntry
;
167 BOOL bColMarked
= ( nStartRow
== 0 && nEndRow
== MAXROW
);
168 BOOL bRowMarked
= ( nStartCol
== 0 && nEndCol
== MAXCOL
);
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
) )
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
)
206 void ScDBFunc::RemoveAllOutlines( BOOL bRecord
)
208 SCTAB nTab
= GetViewData()->GetTabNo();
209 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
210 ScOutlineDocFunc
aFunc(*pDocSh
);
213 BOOL bOk
= aFunc
.RemoveAllOutlines( nTab
, bRecord
, FALSE
);
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() )
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
);
247 BOOL bOk
= aFunc
.SelectLevel( nTab
, bColumns
, nLevel
, bRecord
, bPaint
, FALSE
);
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
);
263 BOOL bOk
= aFunc
.ShowOutline( nTab
, bColumns
, nLevel
, nEntry
, bRecord
, bPaint
, FALSE
);
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
);
279 BOOL bOk
= aFunc
.HideOutline( nTab
, bColumns
, nLevel
, nEntry
, bRecord
, bPaint
, FALSE
);
286 // Menue-Status: markierten Bereich ein-/ausblenden
288 BOOL
ScDBFunc::OutlinePossible(BOOL bHide
)
290 BOOL bEnable
= FALSE
;
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
);
306 ScOutlineArray
* pArray
;
307 ScOutlineEntry
* pEntry
;
313 pArray
= pTable
->GetColArray();
314 ScSubOutlineIterator
aColIter( pArray
);
315 while ((pEntry
=aColIter
.GetNext()) != NULL
&& !bEnable
)
317 nStart
= pEntry
->GetStart();
318 nEnd
= pEntry
->GetEnd();
321 if ( nStartCol
<=static_cast<SCCOL
>(nEnd
) && nEndCol
>=static_cast<SCCOL
>(nStart
) )
322 if (!pEntry
->IsHidden())
327 if ( nStart
>=nStartCol
&& nEnd
<=nEndCol
)
328 if (pEntry
->IsHidden())
335 pArray
= pTable
->GetRowArray();
336 ScSubOutlineIterator
aRowIter( pArray
);
337 while ((pEntry
=aRowIter
.GetNext()) != NULL
)
339 nStart
= pEntry
->GetStart();
340 nEnd
= pEntry
->GetEnd();
343 if ( nStartRow
<=nEnd
&& nEndRow
>=nStart
)
344 if (!pEntry
->IsHidden())
349 if ( nStart
>=nStartRow
&& nEnd
<=nEndRow
)
350 if (pEntry
->IsHidden())
360 // markierten Bereich einblenden
362 void ScDBFunc::ShowMarkedOutlines( BOOL bRecord
)
365 if (GetViewData()->GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
367 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
368 ScOutlineDocFunc
aFunc(*pDocSh
);
370 BOOL bDone
= aFunc
.ShowMarkedOutlines( aRange
, bRecord
, FALSE
);
376 ErrorMessage(STR_NOMULTISELECT
);
379 // markierten Bereich ausblenden
381 void ScDBFunc::HideMarkedOutlines( BOOL bRecord
)
384 if (GetViewData()->GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
386 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
387 ScOutlineDocFunc
aFunc(*pDocSh
);
389 BOOL bDone
= aFunc
.HideMarkedOutlines( aRange
, bRecord
, FALSE
);
395 ErrorMessage(STR_NOMULTISELECT
);
398 // --------------------------------------------------------------------------
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())
416 ScDBData
* pDBData
= pDoc
->GetDBAtArea( nTab
, rParam
.nCol1
, rParam
.nRow1
,
417 rParam
.nCol2
, rParam
.nRow2
);
420 DBG_ERROR( "SubTotals: keine DBData" );
424 ScEditableTester
aTester( pDoc
, nTab
, 0,rParam
.nRow1
+1, MAXCOL
,MAXROW
);
425 if (!aTester
.IsEditable())
427 ErrorMessage(aTester
.GetMessageId());
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
438 WaitObject
aWait( GetViewData()->GetDialogParent() );
440 BOOL bDelete
= FALSE
;
442 if (pDoc
->TestRemoveSubTotals( nTab
, rParam
))
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()
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
);
472 pUndoTab
= new ScOutlineTable( *pTable
);
474 SCCOLROW nOutStartCol
; // Zeilen/Spaltenstatus
475 SCCOLROW nOutStartRow
;
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
);
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
);
508 pOut
->GetRowArray()->RemoveAll(); // nur Zeilen-Outlines loeschen
511 pDoc
->RemoveSubTotals( nTab
, aNewParam
);
512 BOOL bSuccess
= TRUE
;
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
);
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
) );
547 // "Kann keine Zeilen einfuegen"
548 ErrorMessage(STR_MSSG_DOSUBTOTALS_2
);
552 pDBData
->SetSubTotalParam( aNewParam
);
553 pDBData
->SetArea( nTab
, aNewParam
.nCol1
,aNewParam
.nRow1
, aNewParam
.nCol2
,aNewParam
.nRow2
);
554 pDoc
->CompileDBFormula();
558 rMark
.SetMarkArea( ScRange( aNewParam
.nCol1
,aNewParam
.nRow1
,nTab
,
559 aNewParam
.nCol2
,aNewParam
.nRow2
,nTab
) );
562 pDocSh
->PostPaint( 0,0,nTab
, MAXCOL
,MAXROW
,nTab
,
563 PAINT_GRID
| PAINT_LEFT
| PAINT_TOP
| PAINT_SIZE
);
565 aModificator
.SetDocumentModified();
575 void ScDBFunc::Consolidate( const ScConsolidateParam
& rParam
, BOOL bRecord
)
577 ScDocShell
* pDocShell
= GetViewData()->GetDocShell();
578 pDocShell
->DoConsolidate( rParam
, bRecord
);
579 SetTabNo( rParam
.nTab
, TRUE
);
586 String
lcl_MakePivotTabName( const String
& rPrefix
, SCTAB nNumber
)
588 String aName
= rPrefix
;
589 aName
+= String::CreateFromInt32( nNumber
);
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
);
605 ScDocShell
* pDocSh
= GetViewData()->GetDocShell();
606 ScDocument
* pDoc
= GetViewData()->GetDocument();
607 BOOL
bUndo(pDoc
->IsUndoEnabled());
609 ScRange aDestRange
= rDest
;
612 SCTAB nSrcTab
= GetViewData()->GetTabNo();
614 String
aName( ScGlobal::GetRscString(STR_PIVOT_TABLE
) );
617 pDoc
->GetName( nSrcTab
, aStr
);
622 SCTAB nNewTab
= nSrcTab
+1;
625 while ( !pDoc
->InsertTab( nNewTab
, lcl_MakePivotTabName( aName
, i
) ) && i
<= MAXTAB
)
628 BOOL bAppend
= ( nNewTab
+1 == pDoc
->GetTableCount() );
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();
655 const ScDPDimensionSaveData
* pDimSave
= pOldData
->GetExistingDimensionData();
656 aNewData
.SetDimensionData( pDimSave
);
658 aObj
.SetSaveData( aNewData
);
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
672 pDocSh
->PostPaintExtras();
673 SFX_APP()->Broadcast( SfxSimpleHint( SC_HINT_TABLES_CHANGED
) );
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() );
688 ScDBDocFunc
aFunc( *pDocSh
);
689 aFunc
.DataPilotUpdate( pDPObj
, NULL
, TRUE
, FALSE
);
690 CursorPosChanged(); // shells may be switched
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() );
708 ScDBDocFunc
aFunc( *pDocSh
);
709 aFunc
.DataPilotUpdate( pDPObj
, pDPObj
, TRUE
, FALSE
);
710 CursorPosChanged(); // shells may be switched
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() );
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
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
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
) )
777 rDimension
= nStartDimension
; // dimension from which the found members came
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
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
);
796 ScStrCollection aEntries
;
797 long nSelectDimension
= -1;
798 GetSelectedMemberList( aEntries
, nSelectDimension
);
800 if ( aEntries
.GetCount() > 0 )
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() );
813 const ScDPSaveNumGroupDimension
* pNumGroupDim
= pDimData
->GetNumGroupDim( aDimName
);
814 const ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDim( aDimName
);
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();
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
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();
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
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
)
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
);
895 BOOL
ScDBFunc::HasSelectionForNumGroup( ScDPNumGroupInfo
& rOldInfo
)
897 // determine if the numeric group dialog has to be shown for the current selection
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
);
909 ScStrCollection aEntries
;
910 long nSelectDimension
= -1;
911 GetSelectedMemberList( aEntries
, nSelectDimension
);
913 if ( aEntries
.GetCount() > 0 )
916 String aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
918 BOOL bInGroupDim
= FALSE
;
920 ScDPDimensionSaveData
* pDimData
=
921 const_cast<ScDPDimensionSaveData
*>( pDPObj
->GetSaveData()->GetExistingDimensionData() );
924 const ScDPSaveNumGroupDimension
* pNumGroupDim
= pDimData
->GetNumGroupDim( aDimName
);
927 // existing num group dimension
928 // -> edit settings of this dimension
930 rOldInfo
= pNumGroupDim
->GetInfo();
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
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() ) )
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
);
963 void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo
& rInfo
, sal_Int32 nParts
)
965 ScDPObject
* pDPObj
= GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
966 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
969 ScStrCollection aEntries
;
970 long nSelectDimension
= -1;
971 GetSelectedMemberList( aEntries
, nSelectDimension
);
973 if ( aEntries
.GetCount() > 0 )
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
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
1024 // create date group dimensions
1026 ScDPNumGroupInfo aEmpty
;
1028 sal_Int32 nMask
= 1;
1029 for (USHORT nBit
=0; nBit
<32; nBit
++)
1031 if ( nParts
& nMask
)
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
);
1051 ScDPSaveNumGroupDimension
aNumGroupDim( aBaseDimName
, rInfo
, nMask
);
1052 pDimData
->AddNumGroupDimension( aNumGroupDim
);
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
);
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
);
1081 ScDBDocFunc
aFunc( *GetViewData()->GetDocShell() );
1082 ScDPObject
* pNewObj
= new ScDPObject( *pDPObj
);
1083 pNewObj
->SetSaveData( aData
);
1084 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
, TRUE
, FALSE
);
1087 // unmark cell selection
1093 void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo
& rInfo
)
1095 ScDPObject
* pDPObj
= GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1096 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1099 ScStrCollection aEntries
;
1100 long nSelectDimension
= -1;
1101 GetSelectedMemberList( aEntries
, nSelectDimension
);
1103 if ( aEntries
.GetCount() > 0 )
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
);
1114 // modify existing group dimension
1115 pExisting
->SetGroupInfo( rInfo
);
1119 // create new group dimension
1120 ScDPSaveNumGroupDimension
aNumGroupDim( aDimName
, rInfo
);
1121 pDimData
->AddNumGroupDimension( aNumGroupDim
);
1125 ScDBDocFunc
aFunc( *GetViewData()->GetDocShell() );
1126 ScDPObject
* pNewObj
= new ScDPObject( *pDPObj
);
1127 pNewObj
->SetSaveData( aData
);
1128 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
, TRUE
, FALSE
);
1131 // unmark cell selection
1137 void ScDBFunc::GroupDataPilot()
1139 ScDPObject
* pDPObj
= GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1140 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1143 ScStrCollection aEntries
;
1144 long nSelectDimension
= -1;
1145 GetSelectedMemberList( aEntries
, nSelectDimension
);
1147 if ( aEntries
.GetCount() > 0 )
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();
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
);
1183 pBaseGroup
->RemoveElementsFromGroups( *pGroupDimension
); // remove all elements
1185 pGroupDimension
->RemoveFromGroups( aEntryName
);
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
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() );
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
);
1240 aGroup
.AddElementsFromGroup( *pBaseGroup
);
1242 aGroup
.AddElement( aEntryName
); // no group found -> automatic group, add the item itself
1245 aGroup
.AddElement( aEntryName
); // no group dimension, add all items directly
1248 pGroupDimension
->AddGroupItem( aGroup
);
1252 pDimData
->AddGroupDimension( *pNewGroupDim
);
1253 delete pNewGroupDim
; // AddGroupDimension copies the object
1254 // don't access pGroupDimension after here
1256 pGroupDimension
= pNewGroupDim
= NULL
;
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
);
1269 ScDBDocFunc
aFunc( *GetViewData()->GetDocShell() );
1270 ScDPObject
* pNewObj
= new ScDPObject( *pDPObj
);
1271 pNewObj
->SetSaveData( aData
);
1272 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
, TRUE
, FALSE
);
1275 // unmark cell selection
1281 void ScDBFunc::UngroupDataPilot()
1283 ScDPObject
* pDPObj
= GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1284 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1287 ScStrCollection aEntries
;
1288 long nSelectDimension
= -1;
1289 GetSelectedMemberList( aEntries
, nSelectDimension
);
1291 if ( aEntries
.GetCount() > 0 )
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();
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
);
1334 pDimData
->RemoveGroupDimension( aDimName
); // pGroupDim is deleted
1336 // also remove SaveData settings for the dimension that no longer exists
1337 aData
.RemoveDimensionByName( aDimName
);
1341 else if ( pNumGroupDim
)
1343 // remove the numerical grouping
1344 pDimData
->RemoveNumGroupDimension( aDimName
);
1345 // SaveData settings can remain unchanged - the same dimension still exists
1352 ScDBDocFunc
aFunc( *GetViewData()->GetDocShell() );
1353 ScDPObject
* pNewObj
= new ScDPObject( *pDPObj
);
1354 pNewObj
->SetSaveData( aData
);
1355 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
, TRUE
, FALSE
);
1358 // unmark cell selection
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('?'));
1382 else if (c
== sal_Unicode('\\'))
1384 // Escape a backslash character.
1388 else if (c
== sal_Unicode('?'))
1390 // A literal '?' must be escaped with a backslash ('\');
1391 aWordBuf
.append(sal_Unicode('\\'));
1398 if (aWordBuf
.getLength() > 0)
1400 OUString aWord
= aWordBuf
.makeStringAndClear();
1401 if (aWord
.equals(rMemberName
))
1402 aBuf
.append(sal_Unicode('?'));
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() );
1422 pDoc
->GetString( rPos
.Col(), rPos
.Row(), rPos
.Tab(), aOldText
);
1424 if ( aOldText
== rString
)
1426 // nothing to do: silently exit
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
);
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
);
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
);
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
);
1473 if (rString
.EqualsIgnoreCaseAscii(aDimName
))
1475 pDim
->RemoveLayoutName();
1478 else if (!pDPObj
->IsDimNameInUse(rString
))
1480 pDim
->SetLayoutName(rString
);
1484 nErrorId
= STR_INVALIDNAME
;
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
);
1499 if (rString
.EqualsIgnoreCaseAscii(pDim
->GetName()))
1501 pDim
->RemoveLayoutName();
1504 else if (!pDPObj
->IsDimNameInUse(rString
))
1506 pDim
->SetLayoutName(rString
);
1510 nErrorId
= STR_INVALIDNAME
;
1513 nErrorId
= STR_INVALIDNAME
;
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
))
1527 String aDimName
= pDPObj
->GetDimName( aPosData
.Dimension
, bIsDataLayout
);
1529 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData();
1530 ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDimAcc( aDimName
);
1533 // valid name: not empty, no existing group in this dimension
1535 if ( aNewName
.Len() && !pGroupDim
->GetNamedGroup( aNewName
) )
1537 ScDPSaveGroupItem
* pGroup
= pGroupDim
->GetNamedGroupAcc( aOldText
);
1539 pGroup
->Rename( aNewName
); // rename the existing group
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
);
1552 pSaveMember
->SetName( aNewName
);
1557 nErrorId
= STR_INVALIDNAME
;
1560 else if ((aPosData
.Flags
& MemberResultFlags::GRANDTOTAL
))
1562 aData
.SetGrandTotalName(rString
);
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
);
1574 if ((aPosData
.Flags
& MemberResultFlags::SUBTOTAL
))
1577 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName(aPosData
.MemberName
);
1583 nErrorId
= STR_INVALIDNAME
;
1587 if (aPosData
.MemberName
.equalsIgnoreAsciiCase(rString
))
1589 pDim
->RemoveLayoutName();
1592 else if (!pDPObj
->IsDimNameInUse(rString
))
1594 pDim
->SetLayoutName(rString
);
1598 nErrorId
= STR_INVALIDNAME
;
1607 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName(aDimName
);
1611 ScDPSaveMember
* pMem
= pDim
->GetExistingMemberByName(aPosData
.MemberName
);
1615 if ((aPosData
.Flags
& MemberResultFlags::SUBTOTAL
))
1617 // Change subtotal only when the table has one data dimension.
1618 if (aData
.GetDataDimensionCount() > 1)
1621 // display name for subtotal is allowed only if the subtotal type is 'Automatic'.
1622 if (pDim
->GetSubTotalsCount() != 1)
1625 if (pDim
->GetSubTotalFunc(0) != sheet::GeneralFunction_AUTO
)
1628 const OUString
* pLayoutName
= pMem
->GetLayoutName();
1631 aMemberName
= *pLayoutName
;
1633 aMemberName
= aPosData
.MemberName
;
1635 String aNew
= lcl_replaceMemberNameInSubtotal(rString
, aMemberName
);
1636 pDim
->SetSubtotalName(aNew
);
1641 // Check to make sure the member name isn't
1645 if (rString
.EqualsIgnoreCaseAscii(pMem
->GetName()))
1647 pMem
->RemoveLayoutName();
1650 else if (!pDim
->IsMemberNameInUse(rString
))
1652 pMem
->SetLayoutName(rString
);
1656 nErrorId
= STR_INVALIDNAME
;
1659 nErrorId
= STR_INVALIDNAME
;
1671 ScDBDocFunc
aFunc( *GetViewData()->GetDocShell() );
1672 ScDPObject
* pNewObj
= new ScDPObject( *pDPObj
);
1673 pNewObj
->SetSaveData( aData
);
1674 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
, TRUE
, FALSE
);
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
);
1690 pNewMember
= new ScDPSaveMember( *pOldMember
);
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());
1705 // We need to run this to get all members later.
1706 pDPObj
->BuildAllDimensionMembers();
1708 USHORT nOrientation
;
1709 long nDimIndex
= pDPObj
->GetHeaderDim(rPos
, nOrientation
);
1711 // Invalid dimension index. Bail out.
1715 ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
1719 ScDPSaveData
aNewSaveData(*pSaveData
);
1720 String aDimName
= pDPObj
->GetDimName(nDimIndex
, bDataLayout
);
1721 ScDPSaveDimension
* pSaveDim
= aNewSaveData
.GetDimensionByName(aDimName
);
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());
1739 // Sort the member list in ascending order.
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;
1749 ScUserList
* pUserList
= ScGlobal::GetUserList();
1754 sal_uInt16 n
= pUserList
->GetCount();
1755 if (!n
|| *pUserListId
>= n
)
1759 ScUserListData
* pData
= static_cast<ScUserListData
*>((*pUserList
)[*pUserListId
]);
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.
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
++;
1788 nRank
= itrSub
->second
;
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
);
1803 // All members are supposed to be present.
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
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
)
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
1857 bValid
= false; // empty (subtotal) or different field
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
);
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)
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
);
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?
1912 Unmark(); // entry was moved - no use in leaving the old cell selected
1922 BOOL
ScDBFunc::HasSelectionForDrillDown( USHORT
& rOrientation
)
1926 ScDPObject
* pDPObj
= GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1927 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1930 ScStrCollection aEntries
;
1931 long nSelectDimension
= -1;
1932 GetSelectedMemberList( aEntries
, nSelectDimension
);
1934 if ( aEntries
.GetCount() > 0 )
1937 String aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1938 if ( !bIsDataLayout
)
1940 ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
1941 ScDPSaveDimension
* pDim
= pSaveData
->GetExistingDimensionByName( aDimName
);
1944 USHORT nDimOrient
= pDim
->GetOrientation();
1945 ScDPSaveDimension
* pInner
= pSaveData
->GetInnermostDimension( nDimOrient
);
1946 if ( pDim
== pInner
)
1948 rOrientation
= nDimOrient
;
1959 void ScDBFunc::SetDataPilotDetails( BOOL bShow
, const String
* pNewDimensionName
)
1961 ScDPObject
* pDPObj
= GetViewData()->GetDocument()->GetDPAtCursor( GetViewData()->GetCurX(),
1962 GetViewData()->GetCurY(), GetViewData()->GetTabNo() );
1965 ScStrCollection aEntries
;
1966 long nSelectDimension
= -1;
1967 GetSelectedMemberList( aEntries
, nSelectDimension
);
1969 if ( aEntries
.GetCount() > 0 )
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
);
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
);
2036 ScDBDocFunc
aFunc( *GetViewData()->GetDocShell() );
2037 ScDPObject
* pNewObj
= new ScDPObject( *pDPObj
);
2038 pNewObj
->SetSaveData( aData
);
2039 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
, TRUE
, FALSE
);
2042 // unmark cell selection
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
);
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())
2064 Sequence
< Sequence
<Any
> > aTabData
= xDDSupplier
->getDrillDownData(rFilters
);
2065 sal_Int32 nRowSize
= aTabData
.getLength();
2067 // There is no data to show. Bail out.
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
];
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
)
2094 if (!(aTabData
[0][nCol
] >>= aStr
))
2097 Reference
<XPropertySet
> xPropSet(xDims
->getByName(aStr
), UNO_QUERY
);
2101 Any any
= xPropSet
->getPropertyValue( rtl::OUString::createFromAscii(SC_UNO_NUMBERFO
) );
2102 sal_Int32 nNumFmt
= 0;
2103 if (!(any
>>= nNumFmt
))
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
);
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
);
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())
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
;
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
);
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
;
2186 SCTAB nTabCount
= pDoc
->GetTableCount();
2187 pUndoDoc
= new ScDocument( SCDOCMODE_UNDO
);
2188 ScOutlineTable
* pTable
= pDoc
->GetOutlineTable( nTab
);
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
);
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
);
2232 pDBData
->GetSortParam( aSortParam
); // Bereich kann sich geaendert haben
2233 Sort( aSortParam
, FALSE
, FALSE
);
2237 pDBData
->GetQueryParam( aQueryParam
); // Bereich kann sich geaendert haben
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
);
2248 Query( aQueryParam
, NULL
, FALSE
);
2250 // bei nicht-inplace kann die Tabelle umgestellt worden sein
2251 if ( !aQueryParam
.bInplace
&& aQueryParam
.nDestTab
!= nTab
)
2256 pDBData
->GetSubTotalParam( aSubTotalParam
); // Bereich kann sich geaendert haben
2257 aSubTotalParam
.bRemoveOnly
= FALSE
;
2258 DoSubTotals( aSubTotalParam
, FALSE
);
2265 SCROW nDummyRow
, nNewEndRow
;
2266 pDBData
->GetArea( nDummyTab
, nDummyCol
,nDummyRow
, nDummyCol
,nNewEndRow
);
2268 const ScRange
* pOld
= NULL
;
2269 const ScRange
* pNew
= NULL
;
2272 ScDBData
* pDest
= pDoc
->GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
2273 aQueryParam
.nDestTab
, TRUE
);
2276 pDest
->GetArea( aNewQuery
);
2282 GetViewData()->GetDocShell()->GetUndoManager()->AddUndoAction(
2283 new ScUndoRepeatDB( GetViewData()->GetDocShell(), nTab
,
2284 nStartCol
, nStartRow
, nEndCol
, nEndRow
,
2288 pUndoRange
, pUndoDB
,
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() );
2310 pDPObj
->SetAutoFormatIndex(nIndex
);
2313 ErrorMessage(STR_PIVOT_NOTFOUND
);
2317 void ScDBFunc::AutoFormatPivotTable(ScDPObject
* pDPObj
, USHORT nIndex
)
2319 pDPObj
->SetAutoFormatIndex(nIndex
);