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