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 <vcl/svapp.hxx>
23 #include <vcl/weld.hxx>
24 #include <svl/numformat.hxx>
25 #include <svl/zforlist.hxx>
26 #include <sfx2/app.hxx>
27 #include <unotools/collatorwrapper.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/MemberResultFlags.hpp>
36 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
37 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
40 #include <scresid.hxx>
41 #include <globstr.hrc>
42 #include <undotab.hxx>
43 #include <undodat.hxx>
45 #include <rangenam.hxx>
47 #include <olinetab.hxx>
48 #include <olinefun.hxx>
49 #include <dpobject.hxx>
51 #include <dpdimsave.hxx>
52 #include <dbdocfun.hxx>
53 #include <dpoutput.hxx>
54 #include <editable.hxx>
55 #include <patattr.hxx>
56 #include <unonames.hxx>
57 #include <userlist.hxx>
58 #include <queryentry.hxx>
59 #include <markdata.hxx>
60 #include <tabvwsh.hxx>
61 #include <generalfunction.hxx>
62 #include <sortparam.hxx>
64 #include <comphelper/lok.hxx>
65 #include <osl/diagnose.h>
68 #include <string_view>
69 #include <unordered_set>
70 #include <unordered_map>
74 using namespace com::sun::star
;
75 using ::com::sun::star::uno::Any
;
76 using ::com::sun::star::uno::Sequence
;
77 using ::com::sun::star::uno::Reference
;
78 using ::com::sun::star::uno::UNO_QUERY
;
79 using ::com::sun::star::beans::XPropertySet
;
80 using ::com::sun::star::container::XNameAccess
;
81 using ::com::sun::star::sheet::XDimensionsSupplier
;
86 // create outline grouping
88 void ScDBFunc::MakeOutline( bool bColumns
, bool bRecord
)
91 if (GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
93 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
94 ScOutlineDocFunc
aFunc(*pDocSh
);
95 aFunc
.MakeOutline( aRange
, bColumns
, bRecord
, false );
97 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), bColumns
? COLUMN_HEADER
: ROW_HEADER
, GetViewData().GetTabNo());
98 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
99 bColumns
, !bColumns
, false /* bSizes*/,
100 false /* bHidden */, false /* bFiltered */,
101 true /* bGroups */, GetViewData().GetTabNo());
104 ErrorMessage(STR_NOMULTISELECT
);
107 // delete outline grouping
109 void ScDBFunc::RemoveOutline( bool bColumns
, bool bRecord
)
112 if (GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
114 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
115 ScOutlineDocFunc
aFunc(*pDocSh
);
116 aFunc
.RemoveOutline( aRange
, bColumns
, bRecord
, false );
118 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), bColumns
? COLUMN_HEADER
: ROW_HEADER
, GetViewData().GetTabNo());
119 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
120 bColumns
, !bColumns
, false /* bSizes*/,
121 true /* bHidden */, true /* bFiltered */,
122 true /* bGroups */, GetViewData().GetTabNo());
125 ErrorMessage(STR_NOMULTISELECT
);
128 // menu status: delete outlines
130 void ScDBFunc::TestRemoveOutline( bool& rCol
, bool& rRow
)
132 bool bColFound
= false;
133 bool bRowFound
= false;
135 SCCOL nStartCol
, nEndCol
;
136 SCROW nStartRow
, nEndRow
;
137 SCTAB nStartTab
, nEndTab
;
138 if (GetViewData().GetSimpleArea(nStartCol
,nStartRow
,nStartTab
,nEndCol
,nEndRow
,nEndTab
) == SC_MARK_SIMPLE
)
140 SCTAB nTab
= nStartTab
;
141 ScDocument
& rDoc
= GetViewData().GetDocument();
142 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
145 ScOutlineEntry
* pEntry
;
148 bool bColMarked
= ( nStartRow
== 0 && nEndRow
== rDoc
.MaxRow() );
149 bool bRowMarked
= ( nStartCol
== 0 && nEndCol
== rDoc
.MaxCol() );
153 if ( !bRowMarked
|| bColMarked
) // not when entire rows are marked
155 ScOutlineArray
& rArray
= pTable
->GetColArray();
156 ScSubOutlineIterator
aColIter( &rArray
);
159 pEntry
=aColIter
.GetNext();
162 nStart
= pEntry
->GetStart();
163 nEnd
= pEntry
->GetEnd();
164 if ( nStartCol
<=static_cast<SCCOL
>(nEnd
) && nEndCol
>=static_cast<SCCOL
>(nStart
) )
171 if ( !bColMarked
|| bRowMarked
) // not when entire columns are marked
173 ScOutlineArray
& rArray
= pTable
->GetRowArray();
174 ScSubOutlineIterator
aRowIter( &rArray
);
177 pEntry
=aRowIter
.GetNext();
180 nStart
= pEntry
->GetStart();
181 nEnd
= pEntry
->GetEnd();
182 if ( nStartRow
<=nEnd
&& nEndRow
>=nStart
)
193 void ScDBFunc::RemoveAllOutlines( bool bRecord
)
195 SCTAB nTab
= GetViewData().GetTabNo();
196 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
197 ScOutlineDocFunc
aFunc(*pDocSh
);
199 bool bOk
= aFunc
.RemoveAllOutlines( nTab
, bRecord
);
203 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
204 true /* bColumns */, true /* bRows */, false /* bSizes*/,
205 true /* bHidden */, true /* bFiltered */,
206 true /* bGroups */, nTab
);
207 UpdateScrollBars(BOTH_HEADERS
);
213 void ScDBFunc::AutoOutline( )
215 ScDocument
& rDoc
= GetViewData().GetDocument();
216 SCTAB nTab
= GetViewData().GetTabNo();
217 ScRange
aRange( 0,0,nTab
, rDoc
.MaxCol(),rDoc
.MaxRow(),nTab
); // the complete sheet, if nothing is marked
218 ScMarkData
& rMark
= GetViewData().GetMarkData();
219 if ( rMark
.IsMarked() || rMark
.IsMultiMarked() )
222 aRange
= rMark
.GetMultiMarkArea();
225 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
226 ScOutlineDocFunc
aFunc(*pDocSh
);
227 aFunc
.AutoOutline( aRange
, true );
230 // select outline level
232 void ScDBFunc::SelectLevel( bool bColumns
, sal_uInt16 nLevel
, bool bRecord
)
234 SCTAB nTab
= GetViewData().GetTabNo();
235 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
236 ScOutlineDocFunc
aFunc(*pDocSh
);
238 bool bOk
= aFunc
.SelectLevel( nTab
, bColumns
, nLevel
, bRecord
, true/*bPaint*/ );
242 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
243 bColumns
, !bColumns
, false /* bSizes*/,
244 true /* bHidden */, true /* bFiltered */,
245 true /* bGroups */, nTab
);
246 UpdateScrollBars(bColumns
? COLUMN_HEADER
: ROW_HEADER
);
250 // show individual outline groups
252 void ScDBFunc::SetOutlineState( bool bColumns
, sal_uInt16 nLevel
, sal_uInt16 nEntry
, bool bHidden
)
254 const sal_uInt16 nHeadEntry
= static_cast< sal_uInt16
>( -1 );
255 if ( nEntry
== nHeadEntry
)
256 SelectLevel( bColumns
, sal::static_int_cast
<sal_uInt16
>(nLevel
) );
260 ShowOutline( bColumns
, sal::static_int_cast
<sal_uInt16
>(nLevel
), sal::static_int_cast
<sal_uInt16
>(nEntry
) );
262 HideOutline( bColumns
, sal::static_int_cast
<sal_uInt16
>(nLevel
), sal::static_int_cast
<sal_uInt16
>(nEntry
) );
266 void ScDBFunc::ShowOutline( bool bColumns
, sal_uInt16 nLevel
, sal_uInt16 nEntry
, bool bRecord
, bool bPaint
)
268 SCTAB nTab
= GetViewData().GetTabNo();
269 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
270 ScOutlineDocFunc
aFunc(*pDocSh
);
272 aFunc
.ShowOutline( nTab
, bColumns
, nLevel
, nEntry
, bRecord
, bPaint
);
276 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
277 bColumns
, !bColumns
, false /* bSizes*/,
278 true /* bHidden */, true /* bFiltered */,
279 true /* bGroups */, nTab
);
280 UpdateScrollBars(bColumns
? COLUMN_HEADER
: ROW_HEADER
);
284 // hide individual outline groups
286 void ScDBFunc::HideOutline( bool bColumns
, sal_uInt16 nLevel
, sal_uInt16 nEntry
, bool bRecord
, bool bPaint
)
288 SCTAB nTab
= GetViewData().GetTabNo();
289 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
290 ScOutlineDocFunc
aFunc(*pDocSh
);
292 bool bOk
= aFunc
.HideOutline( nTab
, bColumns
, nLevel
, nEntry
, bRecord
, bPaint
);
296 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
297 bColumns
, !bColumns
, false /* bSizes*/,
298 true /* bHidden */, true /* bFiltered */,
299 true /* bGroups */, nTab
);
300 UpdateScrollBars(bColumns
? COLUMN_HEADER
: ROW_HEADER
);
304 // menu status: show/hide marked range
306 bool ScDBFunc::OutlinePossible(bool bHide
)
308 bool bEnable
= false;
317 if (GetViewData().GetSimpleArea(nStartCol
,nStartRow
,nStartTab
,nEndCol
,nEndRow
,nEndTab
) == SC_MARK_SIMPLE
)
319 ScDocument
& rDoc
= GetViewData().GetDocument();
320 SCTAB nTab
= GetViewData().GetTabNo();
321 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
329 ScOutlineArray
& rColArray
= pTable
->GetColArray();
330 ScSubOutlineIterator
aColIter( &rColArray
);
333 ScOutlineEntry
* pEntry
= aColIter
.GetNext();
336 nStart
= pEntry
->GetStart();
337 nEnd
= pEntry
->GetEnd();
340 if ( nStartCol
<=static_cast<SCCOL
>(nEnd
) && nEndCol
>=static_cast<SCCOL
>(nStart
) )
341 if (!pEntry
->IsHidden())
346 if ( nStart
>=nStartCol
&& nEnd
<=nEndCol
)
347 if (pEntry
->IsHidden())
354 ScOutlineArray
& rRowArray
= pTable
->GetRowArray();
355 ScSubOutlineIterator
aRowIter( &rRowArray
);
358 ScOutlineEntry
* pEntry
= aRowIter
.GetNext();
361 nStart
= pEntry
->GetStart();
362 nEnd
= pEntry
->GetEnd();
365 if ( nStartRow
<=nEnd
&& nEndRow
>=nStart
)
366 if (!pEntry
->IsHidden())
371 if ( nStart
>=nStartRow
&& nEnd
<=nEndRow
)
372 if (pEntry
->IsHidden())
384 void ScDBFunc::ShowMarkedOutlines( bool bRecord
)
387 if (GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
389 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
390 ScOutlineDocFunc
aFunc(*pDocSh
);
391 bool bDone
= aFunc
.ShowMarkedOutlines( aRange
, bRecord
);
394 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
395 GetViewData().GetViewShell(), true, true,
396 false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
397 true /* bGroups */, GetViewData().GetTabNo());
402 ErrorMessage(STR_NOMULTISELECT
);
407 void ScDBFunc::HideMarkedOutlines( bool bRecord
)
410 if (GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
412 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
413 ScOutlineDocFunc
aFunc(*pDocSh
);
414 bool bDone
= aFunc
.HideMarkedOutlines( aRange
, bRecord
);
417 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
418 GetViewData().GetViewShell(), true, true,
419 false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
420 true /* bGroups */, GetViewData().GetTabNo());
425 ErrorMessage(STR_NOMULTISELECT
);
430 void ScDBFunc::DoSubTotals( const ScSubTotalParam
& rParam
, bool bRecord
,
431 const ScSortParam
* pForceNewSort
)
433 bool bDo
= !rParam
.bRemoveOnly
; // sal_False = only delete
435 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
436 ScDocument
& rDoc
= pDocSh
->GetDocument();
437 ScMarkData
& rMark
= GetViewData().GetMarkData();
438 SCTAB nTab
= GetViewData().GetTabNo();
439 if (bRecord
&& !rDoc
.IsUndoEnabled())
442 ScDBData
* pDBData
= rDoc
.GetDBAtArea( nTab
, rParam
.nCol1
, rParam
.nRow1
,
443 rParam
.nCol2
, rParam
.nRow2
);
446 OSL_FAIL( "SubTotals: no DBData" );
450 ScEditableTester
aTester( rDoc
, nTab
, 0,rParam
.nRow1
+1, rDoc
.MaxCol(),rDoc
.MaxRow() );
451 if (!aTester
.IsEditable())
453 ErrorMessage(aTester
.GetMessageId());
457 if (rDoc
.HasAttrib( rParam
.nCol1
, rParam
.nRow1
+1, nTab
,
458 rParam
.nCol2
, rParam
.nRow2
, nTab
, HasAttrFlags::Merged
| HasAttrFlags::Overlapped
))
460 ErrorMessage(STR_MSSG_INSERTCELLS_0
); // do not insert into merged
464 weld::WaitObject
aWait(GetViewData().GetDialogParent());
468 if (rDoc
.TestRemoveSubTotals( nTab
, rParam
))
470 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
471 VclMessageType::Question
, VclButtonsType::YesNo
,
472 ScResId(STR_MSSG_DOSUBTOTALS_1
))); // "delete data?"
473 xBox
->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0
)); // "StarCalc"
474 xBox
->set_default_response(RET_YES
);
475 bOk
= xBox
->run() == RET_YES
;
482 ScDocShellModificator
aModificator( *pDocSh
);
484 ScSubTotalParam
aNewParam( rParam
); // change end of range
485 ScDocumentUniquePtr pUndoDoc
;
486 std::unique_ptr
<ScOutlineTable
> pUndoTab
;
487 std::unique_ptr
<ScRangeName
> pUndoRange
;
488 std::unique_ptr
<ScDBCollection
> pUndoDB
;
490 if (bRecord
) // record old data
492 bool bOldFilter
= bDo
&& rParam
.bDoSort
;
493 SCTAB nTabCount
= rDoc
.GetTableCount();
494 pUndoDoc
.reset(new ScDocument( SCDOCMODE_UNDO
));
495 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
498 pUndoTab
.reset(new ScOutlineTable( *pTable
));
500 SCCOLROW nOutStartCol
; // row/column status
501 SCCOLROW nOutStartRow
;
504 pTable
->GetColArray().GetRange( nOutStartCol
, nOutEndCol
);
505 pTable
->GetRowArray().GetRange( nOutStartRow
, nOutEndRow
);
507 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, true, true );
508 rDoc
.CopyToDocument( static_cast<SCCOL
>(nOutStartCol
), 0, nTab
, static_cast<SCCOL
>(nOutEndCol
), rDoc
.MaxRow(), nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
509 rDoc
.CopyToDocument( 0, nOutStartRow
, nTab
, rDoc
.MaxCol(), nOutEndRow
, nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
512 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, false, bOldFilter
);
514 // record data range - including filter results
515 rDoc
.CopyToDocument( 0,rParam
.nRow1
+1,nTab
, rDoc
.MaxCol(),rParam
.nRow2
,nTab
,
516 InsertDeleteFlags::ALL
, false, *pUndoDoc
);
518 // all formulas for reference
519 rDoc
.CopyToDocument( 0,0,0, rDoc
.MaxCol(),rDoc
.MaxRow(),nTabCount
-1,
520 InsertDeleteFlags::FORMULA
, false, *pUndoDoc
);
522 // database and other ranges
523 ScRangeName
* pDocRange
= rDoc
.GetRangeName();
524 if (!pDocRange
->empty())
525 pUndoRange
.reset(new ScRangeName( *pDocRange
));
526 ScDBCollection
* pDocDB
= rDoc
.GetDBCollection();
527 if (!pDocDB
->empty())
528 pUndoDB
.reset(new ScDBCollection( *pDocDB
));
531 ScOutlineTable
* pOut
= rDoc
.GetOutlineTable( nTab
);
534 // Remove all existing outlines in the specified range.
535 ScOutlineArray
& rRowArray
= pOut
->GetRowArray();
536 sal_uInt16 nDepth
= rRowArray
.GetDepth();
537 for (sal_uInt16 i
= 0; i
< nDepth
; ++i
)
540 rRowArray
.Remove(aNewParam
.nRow1
, aNewParam
.nRow2
, bSize
);
545 rDoc
.RemoveSubTotals( nTab
, aNewParam
);
546 bool bSuccess
= true;
550 if ( rParam
.bDoSort
|| pForceNewSort
)
552 pDBData
->SetArea( nTab
, aNewParam
.nCol1
,aNewParam
.nRow1
, aNewParam
.nCol2
,aNewParam
.nRow2
);
554 // set subtotal fields before sorting
555 // (duplicate values are dropped, so that they can be called again)
557 ScSortParam aOldSort
;
558 pDBData
->GetSortParam( aOldSort
);
559 ScSortParam
aSortParam( aNewParam
, pForceNewSort
? *pForceNewSort
: aOldSort
);
560 Sort( aSortParam
, false, false );
563 bSuccess
= rDoc
.DoSubTotals( nTab
, aNewParam
);
565 ScRange
aDirtyRange( aNewParam
.nCol1
, aNewParam
.nRow1
, nTab
,
566 aNewParam
.nCol2
, aNewParam
.nRow2
, nTab
);
567 rDoc
.SetDirty( aDirtyRange
, true );
571 pDocSh
->GetUndoManager()->AddUndoAction(
572 std::make_unique
<ScUndoSubTotals
>( pDocSh
, nTab
,
573 rParam
, aNewParam
.nRow2
,
574 std::move(pUndoDoc
), std::move(pUndoTab
), // pUndoDBData,
575 std::move(pUndoRange
), std::move(pUndoDB
) ) );
580 // "Can not insert any rows"
581 ErrorMessage(STR_MSSG_DOSUBTOTALS_2
);
585 pDBData
->SetSubTotalParam( aNewParam
);
586 pDBData
->SetArea( nTab
, aNewParam
.nCol1
,aNewParam
.nRow1
, aNewParam
.nCol2
,aNewParam
.nRow2
);
587 rDoc
.CompileDBFormula();
589 const ScRange
aMarkRange( aNewParam
.nCol1
, aNewParam
.nRow1
, nTab
, aNewParam
.nCol2
, aNewParam
.nRow2
, nTab
);
591 InitOwnBlockMode( aMarkRange
);
592 rMark
.SetMarkArea( aMarkRange
);
595 pDocSh
->PostPaint(ScRange(0, 0, nTab
, rDoc
.MaxCol(), rDoc
.MaxRow(), nTab
),
596 PaintPartFlags::Grid
| PaintPartFlags::Left
| PaintPartFlags::Top
| PaintPartFlags::Size
);
598 aModificator
.SetDocumentModified();
605 void ScDBFunc::Consolidate( const ScConsolidateParam
& rParam
)
607 ScDocShell
* pDocShell
= GetViewData().GetDocShell();
608 pDocShell
->DoConsolidate( rParam
);
609 SetTabNo( rParam
.nTab
, true );
614 static OUString
lcl_MakePivotTabName( std::u16string_view rPrefix
, SCTAB nNumber
)
616 OUString aName
= rPrefix
+ OUString::number( nNumber
);
620 bool ScDBFunc::MakePivotTable(
621 const ScDPSaveData
& rData
, const ScRange
& rDest
, bool bNewTable
,
622 const ScDPObject
& rSource
)
624 // error message if no fields are set
625 // this must be removed when drag&drop of fields from a toolbox is available
627 if ( rData
.IsEmpty() )
629 ErrorMessage(STR_PIVOT_NODATA
);
633 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
634 ScDocument
& rDoc
= GetViewData().GetDocument();
635 bool bUndo
= rDoc
.IsUndoEnabled();
637 ScRange aDestRange
= rDest
;
640 SCTAB nSrcTab
= GetViewData().GetTabNo();
642 OUString
aName( ScResId(STR_PIVOT_TABLE
) );
645 rDoc
.GetName( nSrcTab
, aStr
);
646 aName
+= "_" + aStr
+ "_";
648 SCTAB nNewTab
= nSrcTab
+1;
651 while ( !rDoc
.InsertTab( nNewTab
, lcl_MakePivotTabName( aName
, i
) ) && i
<= MAXTAB
)
654 bool bAppend
= ( nNewTab
+1 == rDoc
.GetTableCount() );
657 pDocSh
->GetUndoManager()->AddUndoAction(
658 std::make_unique
<ScUndoInsertTab
>( pDocSh
, nNewTab
, bAppend
, lcl_MakePivotTabName( aName
, i
) ));
661 GetViewData().InsertTab( nNewTab
);
662 SetTabNo(nNewTab
, true);
664 aDestRange
= ScRange( 0, 0, nNewTab
);
667 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor(
668 aDestRange
.aStart
.Col(), aDestRange
.aStart
.Row(), aDestRange
.aStart
.Tab() );
670 ScDPObject
aObj( rSource
);
671 aObj
.SetOutRange( aDestRange
);
672 if ( pDPObj
&& !rData
.GetExistingDimensionData() )
674 // copy dimension data from old object - lost in the dialog
675 //! change the dialog to keep the dimension data
677 ScDPSaveData
aNewData( rData
);
678 const ScDPSaveData
* pOldData
= pDPObj
->GetSaveData();
681 const ScDPDimensionSaveData
* pDimSave
= pOldData
->GetExistingDimensionData();
682 aNewData
.SetDimensionData( pDimSave
);
684 aObj
.SetSaveData( aNewData
);
687 aObj
.SetSaveData( rData
);
689 bool bAllowMove
= (pDPObj
!= nullptr); // allow re-positioning when editing existing table
691 ScDBDocFunc
aFunc( *pDocSh
);
692 bool bSuccess
= aFunc
.DataPilotUpdate(pDPObj
, &aObj
, true, false, bAllowMove
);
694 CursorPosChanged(); // shells may be switched
698 pDocSh
->PostPaintExtras();
699 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged
) );
705 void ScDBFunc::DeletePivotTable()
707 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
708 ScDocument
& rDoc
= pDocSh
->GetDocument();
709 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( GetViewData().GetCurX(),
710 GetViewData().GetCurY(),
711 GetViewData().GetTabNo() );
714 ScDBDocFunc
aFunc( *pDocSh
);
715 aFunc
.RemovePivotTable(*pDPObj
, true, false);
716 CursorPosChanged(); // shells may be switched
719 ErrorMessage(STR_PIVOT_NOTFOUND
);
722 void ScDBFunc::RecalcPivotTable()
724 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
725 ScDocument
& rDoc
= GetViewData().GetDocument();
727 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( GetViewData().GetCurX(),
728 GetViewData().GetCurY(),
729 GetViewData().GetTabNo() );
732 // Remove existing data cache for the data that this datapilot uses,
733 // to force re-build data cache.
734 ScDBDocFunc
aFunc(*pDocSh
);
735 aFunc
.RefreshPivotTables(pDPObj
, false);
737 CursorPosChanged(); // shells may be switched
740 ErrorMessage(STR_PIVOT_NOTFOUND
);
743 void ScDBFunc::GetSelectedMemberList(ScDPUniqueStringSet
& rEntries
, tools::Long
& rDimension
)
745 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
746 GetViewData().GetCurY(), GetViewData().GetTabNo() );
750 tools::Long nStartDimension
= -1;
751 tools::Long nStartHierarchy
= -1;
752 tools::Long nStartLevel
= -1;
754 ScRangeListRef xRanges
;
755 GetViewData().GetMultiArea( xRanges
); // incl. cursor if nothing is selected
756 size_t nRangeCount
= xRanges
->size();
757 bool bContinue
= true;
759 for (size_t nRangePos
=0; nRangePos
< nRangeCount
&& bContinue
; nRangePos
++)
761 ScRange
const & rRange
= (*xRanges
)[nRangePos
];
762 SCCOL nStartCol
= rRange
.aStart
.Col();
763 SCROW nStartRow
= rRange
.aStart
.Row();
764 SCCOL nEndCol
= rRange
.aEnd
.Col();
765 SCROW nEndRow
= rRange
.aEnd
.Row();
766 SCTAB nTab
= rRange
.aStart
.Tab();
768 for (SCROW nRow
=nStartRow
; nRow
<=nEndRow
&& bContinue
; nRow
++)
769 for (SCCOL nCol
=nStartCol
; nCol
<=nEndCol
&& bContinue
; nCol
++)
771 sheet::DataPilotTableHeaderData aData
;
772 pDPObj
->GetHeaderPositionData(ScAddress(nCol
, nRow
, nTab
), aData
);
773 if ( aData
.Dimension
< 0 )
774 bContinue
= false; // not part of any dimension
777 if ( nStartDimension
< 0 ) // first member?
779 nStartDimension
= aData
.Dimension
;
780 nStartHierarchy
= aData
.Hierarchy
;
781 nStartLevel
= aData
.Level
;
783 if ( aData
.Dimension
!= nStartDimension
||
784 aData
.Hierarchy
!= nStartHierarchy
||
785 aData
.Level
!= nStartLevel
)
787 bContinue
= false; // cannot mix dimensions
792 // accept any part of a member description, also subtotals,
793 // but don't stop if empty parts are contained
794 if ( aData
.Flags
& sheet::MemberResultFlags::HASMEMBER
)
795 rEntries
.insert(aData
.MemberName
);
800 rDimension
= nStartDimension
; // dimension from which the found members came
802 rEntries
.clear(); // remove all if not valid
805 bool ScDBFunc::HasSelectionForDateGroup( ScDPNumGroupInfo
& rOldInfo
, sal_Int32
& rParts
)
807 // determine if the date group dialog has to be shown for the current selection
811 SCCOL nCurX
= GetViewData().GetCurX();
812 SCROW nCurY
= GetViewData().GetCurY();
813 SCTAB nTab
= GetViewData().GetTabNo();
814 ScDocument
& rDoc
= GetViewData().GetDocument();
816 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( nCurX
, nCurY
, nTab
);
819 ScDPUniqueStringSet aEntries
;
820 tools::Long nSelectDimension
= -1;
821 GetSelectedMemberList( aEntries
, nSelectDimension
);
823 if (!aEntries
.empty())
826 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
827 OUString
aBaseDimName( aDimName
);
829 bool bInGroupDim
= false;
830 bool bFoundParts
= false;
832 ScDPDimensionSaveData
* pDimData
=
833 const_cast<ScDPDimensionSaveData
*>( pDPObj
->GetSaveData()->GetExistingDimensionData() );
836 const ScDPSaveNumGroupDimension
* pNumGroupDim
= pDimData
->GetNumGroupDim( aDimName
);
837 const ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDim( aDimName
);
840 // existing num group dimension
842 if ( pNumGroupDim
->GetDatePart() != 0 )
844 // dimension has date info -> edit settings of this dimension
845 // (parts are collected below)
847 rOldInfo
= pNumGroupDim
->GetDateInfo();
850 else if ( pNumGroupDim
->GetInfo().mbDateValues
)
852 // Numerical grouping with DateValues flag is used for grouping
853 // of days with a "Number of days" value.
855 rOldInfo
= pNumGroupDim
->GetInfo();
856 rParts
= css::sheet::DataPilotFieldGroupBy::DAYS
; // not found in CollectDateParts
862 else if ( pGroupDim
)
864 // existing additional group dimension
866 if ( pGroupDim
->GetDatePart() != 0 )
868 // dimension has date info -> edit settings of this dimension
869 // (parts are collected below)
871 rOldInfo
= pGroupDim
->GetDateInfo();
872 aBaseDimName
= pGroupDim
->GetSourceDimName();
878 if ( bFound
&& !bFoundParts
)
880 // collect date parts from all group dimensions
881 rParts
= pDimData
->CollectDateParts( aBaseDimName
);
883 if ( !bFound
&& !bInGroupDim
)
885 // create new date group dimensions if the selection is a single cell
886 // in a normal dimension with date content
889 if ( (GetViewData().GetSimpleArea( aSelRange
) == SC_MARK_SIMPLE
) &&
890 aSelRange
.aStart
== aSelRange
.aEnd
)
892 SCCOL nSelCol
= aSelRange
.aStart
.Col();
893 SCROW nSelRow
= aSelRange
.aStart
.Row();
894 SCTAB nSelTab
= aSelRange
.aStart
.Tab();
895 if ( rDoc
.HasValueData( nSelCol
, nSelRow
, nSelTab
) )
897 sal_uLong nIndex
= rDoc
.GetAttr(
898 nSelCol
, nSelRow
, nSelTab
, ATTR_VALUE_FORMAT
)->GetValue();
899 SvNumFormatType nType
= rDoc
.GetFormatTable()->GetType(nIndex
);
900 if ( nType
== SvNumFormatType::DATE
|| nType
== SvNumFormatType::TIME
|| nType
== SvNumFormatType::DATETIME
)
903 // use currently selected value for automatic limits
904 if( rOldInfo
.mbAutoStart
)
905 rOldInfo
.mfStart
= rDoc
.GetValue( aSelRange
.aStart
);
906 if( rOldInfo
.mbAutoEnd
)
907 rOldInfo
.mfEnd
= rDoc
.GetValue( aSelRange
.aStart
);
918 bool ScDBFunc::HasSelectionForNumGroup( ScDPNumGroupInfo
& rOldInfo
)
920 // determine if the numeric group dialog has to be shown for the current selection
924 SCCOL nCurX
= GetViewData().GetCurX();
925 SCROW nCurY
= GetViewData().GetCurY();
926 SCTAB nTab
= GetViewData().GetTabNo();
927 ScDocument
& rDoc
= GetViewData().GetDocument();
929 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( nCurX
, nCurY
, nTab
);
932 ScDPUniqueStringSet aEntries
;
933 tools::Long nSelectDimension
= -1;
934 GetSelectedMemberList( aEntries
, nSelectDimension
);
936 if (!aEntries
.empty())
939 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
941 bool bInGroupDim
= false;
943 ScDPDimensionSaveData
* pDimData
=
944 const_cast<ScDPDimensionSaveData
*>( pDPObj
->GetSaveData()->GetExistingDimensionData() );
947 const ScDPSaveNumGroupDimension
* pNumGroupDim
= pDimData
->GetNumGroupDim( aDimName
);
950 // existing num group dimension
951 // -> edit settings of this dimension
953 rOldInfo
= pNumGroupDim
->GetInfo();
956 else if ( pDimData
->GetNamedGroupDim( aDimName
) )
957 bInGroupDim
= true; // in a group dimension
959 if ( !bFound
&& !bInGroupDim
)
961 // create a new num group dimension if the selection is a single cell
962 // in a normal dimension with numeric content
965 if ( (GetViewData().GetSimpleArea( aSelRange
) == SC_MARK_SIMPLE
) &&
966 aSelRange
.aStart
== aSelRange
.aEnd
)
968 if ( rDoc
.HasValueData( aSelRange
.aStart
.Col(), aSelRange
.aStart
.Row(),
969 aSelRange
.aStart
.Tab() ) )
972 // use currently selected value for automatic limits
973 if( rOldInfo
.mbAutoStart
)
974 rOldInfo
.mfStart
= rDoc
.GetValue( aSelRange
.aStart
);
975 if( rOldInfo
.mbAutoEnd
)
976 rOldInfo
.mfEnd
= rDoc
.GetValue( aSelRange
.aStart
);
986 void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo
& rInfo
, sal_Int32 nParts
)
988 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
989 GetViewData().GetCurY(), GetViewData().GetTabNo() );
993 ScDPUniqueStringSet aEntries
;
994 tools::Long nSelectDimension
= -1;
995 GetSelectedMemberList( aEntries
, nSelectDimension
);
997 if (aEntries
.empty())
1000 std::vector
<OUString
> aDeletedNames
;
1002 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1004 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1005 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData(); // created if not there
1007 // find the source dimension name.
1008 OUString aBaseDimName
= aDimName
;
1009 if( const ScDPSaveGroupDimension
* pBaseGroupDim
= pDimData
->GetNamedGroupDim( aDimName
) )
1010 aBaseDimName
= pBaseGroupDim
->GetSourceDimName();
1012 // Remove all group dimensions associated with this source dimension. For
1013 // date grouping, we need to remove all existing groups for the affected
1014 // source dimension and build new one(s) from scratch. Keep the deleted
1015 // names so that they can be reused during re-construction.
1016 aData
.RemoveAllGroupDimensions(aBaseDimName
, &aDeletedNames
);
1020 // create date group dimensions
1023 sal_Int32 nMask
= 1;
1024 for (sal_uInt16 nBit
=0; nBit
<32; nBit
++)
1026 if ( nParts
& nMask
)
1030 // innermost part: create NumGroupDimension (replacing original values)
1031 // Dimension name is left unchanged
1033 if ( (nParts
== sheet::DataPilotFieldGroupBy::DAYS
) && (rInfo
.mfStep
>= 1.0) )
1035 // only days, and a step value specified: use numerical grouping
1036 // with DateValues flag, not date grouping
1038 ScDPNumGroupInfo
aNumInfo( rInfo
);
1039 aNumInfo
.mbDateValues
= true;
1041 ScDPSaveNumGroupDimension
aNumGroupDim( aBaseDimName
, aNumInfo
);
1042 pDimData
->AddNumGroupDimension( aNumGroupDim
);
1046 ScDPSaveNumGroupDimension
aNumGroupDim( aBaseDimName
, rInfo
, nMask
);
1047 pDimData
->AddNumGroupDimension( aNumGroupDim
);
1054 // additional parts: create GroupDimension (shown as additional dimensions)
1055 OUString aGroupDimName
=
1056 pDimData
->CreateDateGroupDimName(nMask
, *pDPObj
, true, &aDeletedNames
);
1057 ScDPSaveGroupDimension
aGroupDim( aBaseDimName
, aGroupDimName
);
1058 aGroupDim
.SetDateInfo( rInfo
, nMask
);
1059 pDimData
->AddGroupDimension( aGroupDim
);
1062 ScDPSaveDimension
* pSaveDimension
= aData
.GetDimensionByName( aGroupDimName
);
1063 if ( pSaveDimension
->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN
)
1065 ScDPSaveDimension
* pOldDimension
= aData
.GetDimensionByName( aBaseDimName
);
1066 pSaveDimension
->SetOrientation( pOldDimension
->GetOrientation() );
1067 aData
.SetPosition( pSaveDimension
, 0 ); //! before (immediate) base
1076 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1077 pDPObj
->SetSaveData( aData
);
1078 aFunc
.RefreshPivotTableGroups(pDPObj
);
1080 // unmark cell selection
1084 void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo
& rInfo
)
1086 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1087 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1091 ScDPUniqueStringSet aEntries
;
1092 tools::Long nSelectDimension
= -1;
1093 GetSelectedMemberList( aEntries
, nSelectDimension
);
1095 if (aEntries
.empty())
1099 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1101 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1102 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData(); // created if not there
1104 ScDPSaveNumGroupDimension
* pExisting
= pDimData
->GetNumGroupDimAcc( aDimName
);
1107 // modify existing group dimension
1108 pExisting
->SetGroupInfo( rInfo
);
1112 // create new group dimension
1113 ScDPSaveNumGroupDimension
aNumGroupDim( aDimName
, rInfo
);
1114 pDimData
->AddNumGroupDimension( aNumGroupDim
);
1118 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1119 pDPObj
->SetSaveData( aData
);
1120 aFunc
.RefreshPivotTableGroups(pDPObj
);
1122 // unmark cell selection
1126 void ScDBFunc::GroupDataPilot()
1128 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1129 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1133 ScDPUniqueStringSet aEntries
;
1134 tools::Long nSelectDimension
= -1;
1135 GetSelectedMemberList( aEntries
, nSelectDimension
);
1137 if (aEntries
.empty())
1141 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1143 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1144 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData(); // created if not there
1146 // find original base
1147 OUString aBaseDimName
= aDimName
;
1148 const ScDPSaveGroupDimension
* pBaseGroupDim
= pDimData
->GetNamedGroupDim( aDimName
);
1149 if ( pBaseGroupDim
)
1151 // any entry's SourceDimName is the original base
1152 aBaseDimName
= pBaseGroupDim
->GetSourceDimName();
1155 // find existing group dimension
1156 // (using the selected dim, can be intermediate group dim)
1157 ScDPSaveGroupDimension
* pGroupDimension
= pDimData
->GetGroupDimAccForBase( aDimName
);
1159 // remove the selected items from their groups
1160 // (empty groups are removed, too)
1161 if ( pGroupDimension
)
1163 for (const OUString
& aEntryName
: aEntries
)
1165 if ( pBaseGroupDim
)
1167 // for each selected (intermediate) group, remove all its items
1168 // (same logic as for adding, below)
1169 const ScDPSaveGroupItem
* pBaseGroup
= pBaseGroupDim
->GetNamedGroup( aEntryName
);
1171 pBaseGroup
->RemoveElementsFromGroups( *pGroupDimension
); // remove all elements
1173 pGroupDimension
->RemoveFromGroups( aEntryName
);
1176 pGroupDimension
->RemoveFromGroups( aEntryName
);
1180 std::unique_ptr
<ScDPSaveGroupDimension
> pNewGroupDim
;
1181 if ( !pGroupDimension
)
1183 // create a new group dimension
1184 OUString aGroupDimName
=
1185 pDimData
->CreateGroupDimName(aBaseDimName
, *pDPObj
, false, nullptr);
1186 pNewGroupDim
.reset(new ScDPSaveGroupDimension( aBaseDimName
, aGroupDimName
));
1188 pGroupDimension
= pNewGroupDim
.get(); // make changes to the new dim if none existed
1190 if ( pBaseGroupDim
)
1192 // If it's a higher-order group dimension, pre-allocate groups for all
1193 // non-selected original groups, so the individual base members aren't
1194 // used for automatic groups (this would make the original groups hard
1196 //! Also do this when removing groups?
1197 //! Handle this case dynamically with automatic groups?
1199 tools::Long nGroupCount
= pBaseGroupDim
->GetGroupCount();
1200 for ( tools::Long nGroup
= 0; nGroup
< nGroupCount
; nGroup
++ )
1202 const ScDPSaveGroupItem
& rBaseGroup
= pBaseGroupDim
->GetGroupByIndex( nGroup
);
1204 if (!aEntries
.count(rBaseGroup
.GetGroupName()))
1206 // add an additional group for each item that is not in the selection
1207 ScDPSaveGroupItem
aGroup( rBaseGroup
.GetGroupName() );
1208 aGroup
.AddElementsFromGroup( rBaseGroup
);
1209 pGroupDimension
->AddGroupItem( aGroup
);
1214 OUString aGroupDimName
= pGroupDimension
->GetGroupDimName();
1216 ScDPSaveGroupItem
aGroup(pGroupDimension
->CreateGroupName(ScResId(STR_PIVOT_GROUP
)));
1217 for (const OUString
& aEntryName
: aEntries
)
1219 if ( pBaseGroupDim
)
1221 // for each selected (intermediate) group, add all its items
1222 const ScDPSaveGroupItem
* pBaseGroup
= pBaseGroupDim
->GetNamedGroup( aEntryName
);
1224 aGroup
.AddElementsFromGroup( *pBaseGroup
);
1226 aGroup
.AddElement( aEntryName
); // no group found -> automatic group, add the item itself
1229 aGroup
.AddElement( aEntryName
); // no group dimension, add all items directly
1232 pGroupDimension
->AddGroupItem( aGroup
);
1236 pDimData
->AddGroupDimension( *pNewGroupDim
);
1237 pNewGroupDim
.reset(); // AddGroupDimension copies the object
1238 // don't access pGroupDimension after here
1240 pGroupDimension
= nullptr;
1243 ScDPSaveDimension
* pSaveDimension
= aData
.GetDimensionByName( aGroupDimName
);
1244 if ( pSaveDimension
->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN
)
1246 ScDPSaveDimension
* pOldDimension
= aData
.GetDimensionByName( aDimName
);
1247 pSaveDimension
->SetOrientation( pOldDimension
->GetOrientation() );
1248 aData
.SetPosition( pSaveDimension
, 0 ); //! before (immediate) base
1252 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1253 pDPObj
->SetSaveData( aData
);
1254 aFunc
.RefreshPivotTableGroups(pDPObj
);
1256 // unmark cell selection
1260 void ScDBFunc::UngroupDataPilot()
1262 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1263 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1267 ScDPUniqueStringSet aEntries
;
1268 tools::Long nSelectDimension
= -1;
1269 GetSelectedMemberList( aEntries
, nSelectDimension
);
1271 if (aEntries
.empty())
1275 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1277 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1278 if (!aData
.GetExistingDimensionData())
1279 // There is nothing to ungroup.
1282 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData();
1284 ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDimAcc( aDimName
);
1285 const ScDPSaveNumGroupDimension
* pNumGroupDim
= pDimData
->GetNumGroupDim( aDimName
);
1286 if ( ( pGroupDim
&& pGroupDim
->GetDatePart() != 0 ) ||
1287 ( pNumGroupDim
&& pNumGroupDim
->GetDatePart() != 0 ) )
1289 // Date grouping: need to remove all affected group dimensions.
1290 // This is done using DateGroupDataPilot with nParts=0.
1292 DateGroupDataPilot( ScDPNumGroupInfo(), 0 );
1298 for (const auto& rEntry
: aEntries
)
1299 pGroupDim
->RemoveGroup(rEntry
);
1301 // remove group dimension if empty
1302 bool bEmptyDim
= pGroupDim
->IsEmpty();
1305 // If all remaining groups in the dimension aren't shown, remove
1306 // the dimension too, as if it was completely empty.
1307 ScDPUniqueStringSet aVisibleEntries
;
1308 pDPObj
->GetMemberResultNames( aVisibleEntries
, nSelectDimension
);
1309 bEmptyDim
= pGroupDim
->HasOnlyHidden( aVisibleEntries
);
1313 pDimData
->RemoveGroupDimension( aDimName
); // pGroupDim is deleted
1315 // also remove SaveData settings for the dimension that no longer exists
1316 aData
.RemoveDimensionByName( aDimName
);
1319 else if ( pNumGroupDim
)
1321 // remove the numerical grouping
1322 pDimData
->RemoveNumGroupDimension( aDimName
);
1323 // SaveData settings can remain unchanged - the same dimension still exists
1327 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1328 pDPObj
->SetSaveData( aData
);
1329 aFunc
.RefreshPivotTableGroups(pDPObj
);
1331 // unmark cell selection
1335 static OUString
lcl_replaceMemberNameInSubtotal(const OUString
& rSubtotal
, std::u16string_view rMemberName
)
1337 sal_Int32 n
= rSubtotal
.getLength();
1338 const sal_Unicode
* p
= rSubtotal
.getStr();
1339 OUStringBuffer aBuf
, aWordBuf
;
1340 for (sal_Int32 i
= 0; i
< n
; ++i
)
1342 sal_Unicode c
= p
[i
];
1345 OUString aWord
= aWordBuf
.makeStringAndClear();
1346 if (aWord
== rMemberName
)
1354 // Escape a backslash character.
1355 aWordBuf
.append(OUStringChar(c
) + OUStringChar(c
));
1359 // A literal '?' must be escaped with a backslash ('\');
1360 aWordBuf
.append("\\" + OUStringChar(c
));
1366 if (!aWordBuf
.isEmpty())
1368 OUString aWord
= aWordBuf
.makeStringAndClear();
1369 if (aWord
== rMemberName
)
1375 return aBuf
.makeStringAndClear();
1378 void ScDBFunc::DataPilotInput( const ScAddress
& rPos
, const OUString
& rString
)
1380 using namespace ::com::sun::star::sheet
;
1382 ScDocument
& rDoc
= GetViewData().GetDocument();
1383 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( rPos
.Col(), rPos
.Row(), rPos
.Tab() );
1387 OUString aOldText
= rDoc
.GetString(rPos
.Col(), rPos
.Row(), rPos
.Tab());
1389 if ( aOldText
== rString
)
1391 // nothing to do: silently exit
1395 TranslateId pErrorId
;
1397 pDPObj
->BuildAllDimensionMembers();
1398 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1399 bool bChange
= false;
1400 bool bNeedReloadGroups
= false;
1402 DataPilotFieldOrientation nOrient
= DataPilotFieldOrientation_HIDDEN
;
1403 tools::Long nField
= pDPObj
->GetHeaderDim( rPos
, nOrient
);
1406 // changing a field title
1407 if ( aData
.GetExistingDimensionData() )
1409 // only group dimensions can be renamed
1411 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData();
1412 ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDimAcc( aOldText
);
1415 // valid name: not empty, no existing dimension (group or other)
1416 if (!rString
.isEmpty() && !pDPObj
->IsDimNameInUse(rString
))
1418 pGroupDim
->Rename( rString
);
1420 // also rename in SaveData to preserve the field settings
1421 ScDPSaveDimension
* pSaveDim
= aData
.GetDimensionByName( aOldText
);
1422 pSaveDim
->SetName( rString
);
1427 pErrorId
= STR_INVALIDNAME
;
1430 else if (nOrient
== DataPilotFieldOrientation_COLUMN
|| nOrient
== DataPilotFieldOrientation_ROW
)
1432 bool bDataLayout
= false;
1433 OUString aDimName
= pDPObj
->GetDimName(nField
, bDataLayout
);
1434 ScDPSaveDimension
* pDim
= bDataLayout
? aData
.GetDataLayoutDimension() : aData
.GetDimensionByName(aDimName
);
1437 if (!rString
.isEmpty())
1439 if (rString
.equalsIgnoreAsciiCase(aDimName
))
1441 pDim
->RemoveLayoutName();
1444 else if (!pDPObj
->IsDimNameInUse(rString
))
1446 pDim
->SetLayoutName(rString
);
1450 pErrorId
= STR_INVALIDNAME
;
1453 pErrorId
= STR_INVALIDNAME
;
1457 else if (pDPObj
->IsDataDescriptionCell(rPos
))
1459 // There is only one data dimension.
1460 ScDPSaveDimension
* pDim
= aData
.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA
);
1463 if (!rString
.isEmpty())
1465 if (pDim
->GetName().equalsIgnoreAsciiCase(rString
))
1467 pDim
->RemoveLayoutName();
1470 else if (!pDPObj
->IsDimNameInUse(rString
))
1472 pDim
->SetLayoutName(rString
);
1476 pErrorId
= STR_INVALIDNAME
;
1479 pErrorId
= STR_INVALIDNAME
;
1484 // This is not a field header.
1485 sheet::DataPilotTableHeaderData aPosData
;
1486 pDPObj
->GetHeaderPositionData(rPos
, aPosData
);
1488 if ((aPosData
.Flags
& MemberResultFlags::HASMEMBER
) && !aOldText
.isEmpty())
1490 if ( aData
.GetExistingDimensionData() && !(aPosData
.Flags
& MemberResultFlags::SUBTOTAL
))
1493 OUString aDimName
= pDPObj
->GetDimName( aPosData
.Dimension
, bIsDataLayout
);
1495 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData();
1496 ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDimAcc( aDimName
);
1499 // valid name: not empty, no existing group in this dimension
1501 if (!rString
.isEmpty() && !pGroupDim
->GetNamedGroup(rString
))
1503 ScDPSaveGroupItem
* pGroup
= pGroupDim
->GetNamedGroupAcc( aOldText
);
1505 pGroup
->Rename( rString
); // rename the existing group
1508 // create a new group to replace the automatic group
1509 ScDPSaveGroupItem
aGroup( rString
);
1510 aGroup
.AddElement( aOldText
);
1511 pGroupDim
->AddGroupItem( aGroup
);
1514 // in both cases also adjust savedata, to preserve member settings (show details)
1515 ScDPSaveDimension
* pSaveDim
= aData
.GetDimensionByName( aDimName
);
1516 ScDPSaveMember
* pSaveMember
= pSaveDim
->GetExistingMemberByName( aOldText
);
1518 pSaveMember
->SetName( rString
);
1521 bNeedReloadGroups
= true;
1524 pErrorId
= STR_INVALIDNAME
;
1527 else if (aPosData
.Flags
& MemberResultFlags::GRANDTOTAL
)
1529 aData
.SetGrandTotalName(rString
);
1532 else if (aPosData
.Dimension
>= 0 && !aPosData
.MemberName
.isEmpty())
1534 bool bDataLayout
= false;
1535 OUString aDimName
= pDPObj
->GetDimName(static_cast<tools::Long
>(aPosData
.Dimension
), bDataLayout
);
1541 if (aPosData
.Flags
& MemberResultFlags::SUBTOTAL
)
1544 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName(aPosData
.MemberName
);
1548 if (rString
.isEmpty())
1550 pErrorId
= STR_INVALIDNAME
;
1554 if (aPosData
.MemberName
.equalsIgnoreAsciiCase(rString
))
1556 pDim
->RemoveLayoutName();
1559 else if (!pDPObj
->IsDimNameInUse(rString
))
1561 pDim
->SetLayoutName(rString
);
1565 pErrorId
= STR_INVALIDNAME
;
1574 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName(aDimName
);
1578 ScDPSaveMember
* pMem
= pDim
->GetExistingMemberByName(aPosData
.MemberName
);
1582 if (aPosData
.Flags
& MemberResultFlags::SUBTOTAL
)
1584 // Change subtotal only when the table has one data dimension.
1585 if (aData
.GetDataDimensionCount() > 1)
1588 // display name for subtotal is allowed only if the subtotal type is 'Automatic'.
1589 if (pDim
->GetSubTotalsCount() != 1)
1592 if (pDim
->GetSubTotalFunc(0) != ScGeneralFunction::AUTO
)
1595 const std::optional
<OUString
> & pLayoutName
= pMem
->GetLayoutName();
1596 OUString aMemberName
;
1598 aMemberName
= *pLayoutName
;
1600 aMemberName
= aPosData
.MemberName
;
1602 OUString aNew
= lcl_replaceMemberNameInSubtotal(rString
, aMemberName
);
1603 pDim
->SetSubtotalName(aNew
);
1608 // Check to make sure the member name isn't
1610 if (!rString
.isEmpty())
1612 if (rString
.equalsIgnoreAsciiCase(pMem
->GetName()))
1614 pMem
->RemoveLayoutName();
1617 else if (!pDim
->IsMemberNameInUse(rString
))
1619 pMem
->SetLayoutName(rString
);
1623 pErrorId
= STR_INVALIDNAME
;
1626 pErrorId
= STR_INVALIDNAME
;
1638 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1639 pDPObj
->SetSaveData( aData
);
1640 if (bNeedReloadGroups
)
1642 ScDPCollection
* pDPs
= rDoc
.GetDPCollection();
1645 o3tl::sorted_vector
<ScDPObject
*> aRefs
;
1646 // tdf#111305: Reload groups in cache after modifications.
1647 pDPs
->ReloadGroupsInCache(pDPObj
, aRefs
);
1649 } // bNeedReloadGroups
1650 aFunc
.UpdatePivotTable(*pDPObj
, true, false);
1655 pErrorId
= STR_ERR_DATAPILOT_INPUT
;
1656 ErrorMessage(pErrorId
);
1660 static void lcl_MoveToEnd( ScDPSaveDimension
& rDim
, const OUString
& rItemName
)
1662 std::unique_ptr
<ScDPSaveMember
> pNewMember
;
1663 const ScDPSaveMember
* pOldMember
= rDim
.GetExistingMemberByName( rItemName
);
1665 pNewMember
.reset(new ScDPSaveMember( *pOldMember
));
1667 pNewMember
.reset(new ScDPSaveMember( rItemName
));
1668 rDim
.AddMember( std::move(pNewMember
) );
1669 // AddMember takes ownership of the new pointer,
1670 // puts it to the end of the list even if it was in the list before.
1675 struct ScOUStringCollate
1677 CollatorWrapper
* mpCollator
;
1679 explicit ScOUStringCollate(CollatorWrapper
* pColl
) : mpCollator(pColl
) {}
1681 bool operator()(const OUString
& rStr1
, const OUString
& rStr2
) const
1683 return ( mpCollator
->compareString(rStr1
, rStr2
) < 0 );
1689 void ScDBFunc::DataPilotSort(ScDPObject
* pDPObj
, tools::Long nDimIndex
, bool bAscending
, const sal_uInt16
* pUserListId
)
1694 // We need to run this to get all members later.
1696 pDPObj
->BuildAllDimensionMembers();
1699 // Invalid dimension index. Bail out.
1702 ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
1706 ScDPSaveData
aNewSaveData(*pSaveData
);
1708 OUString aDimName
= pDPObj
->GetDimName(nDimIndex
, bDataLayout
);
1709 ScDPSaveDimension
* pSaveDim
= aNewSaveData
.GetDimensionByName(aDimName
);
1713 // manual evaluation of sort order is only needed if a user list id is given
1716 typedef ScDPSaveDimension::MemberList MemList
;
1717 const MemList
& rDimMembers
= pSaveDim
->GetMembers();
1718 vector
<OUString
> aMembers
;
1719 std::unordered_set
<OUString
> aMemberSet
;
1720 size_t nMemberCount
= 0;
1721 for (ScDPSaveMember
* pMem
: rDimMembers
)
1723 aMembers
.push_back(pMem
->GetName());
1724 aMemberSet
.insert(pMem
->GetName());
1728 // Sort the member list in ascending order.
1729 ScOUStringCollate
aCollate( &ScGlobal::GetCollator() );
1730 std::stable_sort(aMembers
.begin(), aMembers
.end(), aCollate
);
1732 // Collect and rank those custom sort strings that also exist in the member name list.
1734 typedef std::unordered_map
<OUString
, sal_uInt16
> UserSortMap
;
1735 UserSortMap aSubStrs
;
1736 sal_uInt16 nSubCount
= 0;
1737 ScUserList
& rUserList
= ScGlobal::GetUserList();
1738 size_t nUserListSize
= rUserList
.size();
1739 if (!nUserListSize
|| *pUserListId
>= static_cast<sal_uInt16
>(nUserListSize
))
1742 const ScUserListData
& rData
= rUserList
[*pUserListId
];
1743 sal_uInt16 n
= rData
.GetSubCount();
1744 for (sal_uInt16 i
= 0; i
< n
; ++i
)
1746 OUString aSub
= rData
.GetSubStr(i
);
1747 if (!aMemberSet
.count(aSub
))
1748 // This string doesn't exist in the member name set. Don't add this.
1751 aSubStrs
.emplace(aSub
, nSubCount
++);
1754 // Rank all members.
1756 vector
<OUString
> aRankedNames(nMemberCount
);
1757 sal_uInt16 nCurStrId
= 0;
1758 for (auto const& aMemberName
: aMembers
)
1760 sal_uInt16 nRank
= 0;
1761 UserSortMap::const_iterator itrSub
= aSubStrs
.find(aMemberName
);
1762 if (itrSub
== aSubStrs
.end())
1763 nRank
= nSubCount
+ nCurStrId
++;
1765 nRank
= itrSub
->second
;
1768 nRank
= static_cast< sal_uInt16
>( nMemberCount
- nRank
- 1 );
1770 aRankedNames
[nRank
] = aMemberName
;
1773 // Re-order ScDPSaveMember instances with the new ranks.
1774 for (auto const& aRankedName
: aRankedNames
)
1776 const ScDPSaveMember
* pOldMem
= pSaveDim
->GetExistingMemberByName(aRankedName
);
1778 // All members are supposed to be present.
1781 pSaveDim
->AddMember(std::unique_ptr
<ScDPSaveMember
>(new ScDPSaveMember(*pOldMem
)));
1784 // Set the sorting mode to manual for now. We may introduce a new sorting
1787 sheet::DataPilotFieldSortInfo aSortInfo
;
1788 aSortInfo
.Mode
= sheet::DataPilotFieldSortMode::MANUAL
;
1789 pSaveDim
->SetSortInfo(&aSortInfo
);
1793 // without user list id, just apply sorting mode
1795 sheet::DataPilotFieldSortInfo aSortInfo
;
1796 aSortInfo
.Mode
= sheet::DataPilotFieldSortMode::NAME
;
1797 aSortInfo
.IsAscending
= bAscending
;
1798 pSaveDim
->SetSortInfo(&aSortInfo
);
1801 // Update the datapilot with the newly sorted field members.
1803 std::unique_ptr
<ScDPObject
> pNewObj(new ScDPObject(*pDPObj
));
1804 pNewObj
->SetSaveData(aNewSaveData
);
1805 ScDBDocFunc
aFunc(*GetViewData().GetDocShell());
1807 aFunc
.DataPilotUpdate(pDPObj
, pNewObj
.get(), true, false);
1810 bool ScDBFunc::DataPilotMove( const ScRange
& rSource
, const ScAddress
& rDest
)
1813 ScDocument
& rDoc
= GetViewData().GetDocument();
1814 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( rSource
.aStart
.Col(), rSource
.aStart
.Row(), rSource
.aStart
.Tab() );
1815 if ( pDPObj
&& pDPObj
== rDoc
.GetDPAtCursor( rDest
.Col(), rDest
.Row(), rDest
.Tab() ) )
1817 sheet::DataPilotTableHeaderData aDestData
;
1818 pDPObj
->GetHeaderPositionData( rDest
, aDestData
);
1819 bool bValid
= ( aDestData
.Dimension
>= 0 ); // dropping onto a field
1821 // look through the source range
1822 std::unordered_set
< OUString
> aMembersSet
; // for lookup
1823 std::vector
< OUString
> aMembersVector
; // members in original order, for inserting
1824 aMembersVector
.reserve( std::max( static_cast<SCSIZE
>( rSource
.aEnd
.Col() - rSource
.aStart
.Col() + 1 ),
1825 static_cast<SCSIZE
>( rSource
.aEnd
.Row() - rSource
.aStart
.Row() + 1 ) ) );
1826 for (SCROW nRow
= rSource
.aStart
.Row(); bValid
&& nRow
<= rSource
.aEnd
.Row(); ++nRow
)
1827 for (SCCOL nCol
= rSource
.aStart
.Col(); bValid
&& nCol
<= rSource
.aEnd
.Col(); ++nCol
)
1829 sheet::DataPilotTableHeaderData aSourceData
;
1830 pDPObj
->GetHeaderPositionData( ScAddress( nCol
, nRow
, rSource
.aStart
.Tab() ), aSourceData
);
1831 if ( aSourceData
.Dimension
== aDestData
.Dimension
&& !aSourceData
.MemberName
.isEmpty() )
1833 if ( aMembersSet
.insert( aSourceData
.MemberName
).second
)
1835 aMembersVector
.push_back( aSourceData
.MemberName
);
1837 // duplicates are ignored
1840 bValid
= false; // empty (subtotal) or different field
1846 OUString aDimName
= pDPObj
->GetDimName( aDestData
.Dimension
, bIsDataLayout
);
1847 if ( !bIsDataLayout
)
1849 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1850 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName( aDimName
);
1852 // get all member names in source order
1853 uno::Sequence
<OUString
> aMemberNames
;
1854 pDPObj
->GetMemberNames( aDestData
.Dimension
, aMemberNames
);
1856 bool bInserted
= false;
1858 for (const OUString
& aMemberStr
: aMemberNames
)
1860 if ( !bInserted
&& aMemberStr
== aDestData
.MemberName
)
1862 // insert dragged items before this item
1863 for ( const auto& rMember
: aMembersVector
)
1864 lcl_MoveToEnd( *pDim
, rMember
);
1868 if ( aMembersSet
.find( aMemberStr
) == aMembersSet
.end() ) // skip dragged items
1869 lcl_MoveToEnd( *pDim
, aMemberStr
);
1871 // insert dragged item at end if dest wasn't found (for example, empty)
1873 for ( const auto& rMember
: aMembersVector
)
1874 lcl_MoveToEnd( *pDim
, rMember
);
1876 // Items that were in SaveData, but not in the source, end up at the start of the list.
1878 // set flag for manual sorting
1879 sheet::DataPilotFieldSortInfo aSortInfo
;
1880 aSortInfo
.Mode
= sheet::DataPilotFieldSortMode::MANUAL
;
1881 pDim
->SetSortInfo( &aSortInfo
);
1884 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1885 std::unique_ptr
<ScDPObject
> pNewObj(new ScDPObject( *pDPObj
));
1886 pNewObj
->SetSaveData( aData
);
1887 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
.get(), true, false ); //! bApi for drag&drop?
1890 Unmark(); // entry was moved - no use in leaving the old cell selected
1900 bool ScDBFunc::HasSelectionForDrillDown( css::sheet::DataPilotFieldOrientation
& rOrientation
)
1904 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1905 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1908 ScDPUniqueStringSet aEntries
;
1909 tools::Long nSelectDimension
= -1;
1910 GetSelectedMemberList( aEntries
, nSelectDimension
);
1912 if (!aEntries
.empty())
1915 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1916 if ( !bIsDataLayout
)
1918 ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
1919 ScDPSaveDimension
* pDim
= pSaveData
->GetExistingDimensionByName( aDimName
);
1922 css::sheet::DataPilotFieldOrientation nDimOrient
= pDim
->GetOrientation();
1923 ScDPSaveDimension
* pInner
= pSaveData
->GetInnermostDimension( nDimOrient
);
1924 if ( pDim
== pInner
)
1926 rOrientation
= nDimOrient
;
1937 void ScDBFunc::SetDataPilotDetails(bool bShow
, const OUString
* pNewDimensionName
)
1939 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1940 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1944 ScDPUniqueStringSet aEntries
;
1945 tools::Long nSelectDimension
= -1;
1946 GetSelectedMemberList( aEntries
, nSelectDimension
);
1948 if (aEntries
.empty())
1952 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1953 if ( bIsDataLayout
)
1956 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1957 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName( aDimName
);
1959 if ( bShow
&& pNewDimensionName
)
1961 // add the new dimension with the same orientation, at the end
1963 ScDPSaveDimension
* pNewDim
= aData
.GetDimensionByName( *pNewDimensionName
);
1964 ScDPSaveDimension
* pDuplicated
= nullptr;
1965 if ( pNewDim
->GetOrientation() == sheet::DataPilotFieldOrientation_DATA
)
1967 // Need to duplicate the dimension, create column/row in addition to data:
1968 // The duplicated dimension inherits the existing settings, pNewDim is modified below.
1969 pDuplicated
= aData
.DuplicateDimension( *pNewDimensionName
);
1972 css::sheet::DataPilotFieldOrientation nOrientation
= pDim
->GetOrientation();
1973 pNewDim
->SetOrientation( nOrientation
);
1975 tools::Long nPosition
= LONG_MAX
;
1976 aData
.SetPosition( pNewDim
, nPosition
);
1978 ScDPSaveDimension
* pDataLayout
= aData
.GetDataLayoutDimension();
1979 if ( pDataLayout
->GetOrientation() == nOrientation
&&
1980 aData
.GetDataDimensionCount() <= 1 )
1982 // If there is only one data dimension, the data layout dimension
1983 // must still be the last one in its orientation.
1984 aData
.SetPosition( pDataLayout
, nPosition
);
1989 // The duplicated (data) dimension needs to be behind the original dimension
1990 aData
.SetPosition( pDuplicated
, nPosition
);
1993 // Hide details for all visible members (selected are changed below).
1994 //! Use all members from source level instead (including non-visible)?
1996 ScDPUniqueStringSet aVisibleEntries
;
1997 pDPObj
->GetMemberResultNames( aVisibleEntries
, nSelectDimension
);
1999 for (const OUString
& aVisName
: aVisibleEntries
)
2001 ScDPSaveMember
* pMember
= pDim
->GetMemberByName( aVisName
);
2002 pMember
->SetShowDetails( false );
2006 for (const auto& rEntry
: aEntries
)
2008 ScDPSaveMember
* pMember
= pDim
->GetMemberByName(rEntry
);
2009 pMember
->SetShowDetails( bShow
);
2013 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
2014 std::unique_ptr
<ScDPObject
> pNewObj(new ScDPObject( *pDPObj
));
2015 pNewObj
->SetSaveData( aData
);
2016 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
.get(), true, false );
2019 // unmark cell selection
2023 void ScDBFunc::ShowDataPilotSourceData( ScDPObject
& rDPObj
, const Sequence
<sheet::DataPilotFieldFilter
>& rFilters
)
2025 ScDocument
& rDoc
= GetViewData().GetDocument();
2026 if (rDoc
.GetDocumentShell()->IsReadOnly())
2028 ErrorMessage(STR_READONLYERR
);
2032 Reference
<sheet::XDimensionsSupplier
> xDimSupplier
= rDPObj
.GetSource();
2033 Reference
<container::XNameAccess
> xDims
= xDimSupplier
->getDimensions();
2034 Reference
<sheet::XDrillDownDataSupplier
> xDDSupplier(xDimSupplier
, UNO_QUERY
);
2035 if (!xDDSupplier
.is())
2038 Sequence
< Sequence
<Any
> > aTabData
= xDDSupplier
->getDrillDownData(rFilters
);
2039 sal_Int32 nRowSize
= aTabData
.getLength();
2041 // There is no data to show. Bail out.
2044 SCCOL nColSize
= aTabData
[0].getLength();
2046 SCTAB nNewTab
= GetViewData().GetTabNo();
2048 ScDocumentUniquePtr
pInsDoc(new ScDocument(SCDOCMODE_CLIP
));
2049 pInsDoc
->ResetClip( &rDoc
, nNewTab
);
2050 for (SCROW nRow
= 0; nRow
< nRowSize
; ++nRow
)
2052 for (SCCOL nCol
= 0; nCol
< nColSize
; ++nCol
)
2054 const Any
& rAny
= aTabData
[nRow
][nCol
];
2059 pInsDoc
->SetString(ScAddress(nCol
,nRow
,nNewTab
), aStr
);
2061 else if (rAny
>>= fVal
)
2062 pInsDoc
->SetValue(nCol
, nRow
, nNewTab
, fVal
);
2066 // set number format (important for dates)
2067 for (SCCOL nCol
= 0; nCol
< nColSize
; ++nCol
)
2070 if (!(aTabData
[0][nCol
] >>= aStr
))
2073 Reference
<XPropertySet
> xPropSet(xDims
->getByName(aStr
), UNO_QUERY
);
2077 Any any
= xPropSet
->getPropertyValue( SC_UNO_DP_NUMBERFO
);
2078 sal_Int32 nNumFmt
= 0;
2079 if (!(any
>>= nNumFmt
))
2082 ScPatternAttr
aPattern(pInsDoc
->getCellAttributeHelper());
2083 aPattern
.GetItemSet().Put( SfxUInt32Item(ATTR_VALUE_FORMAT
, static_cast<sal_uInt32
>(nNumFmt
)) );
2084 pInsDoc
->ApplyPatternAreaTab(nCol
, 1, nCol
, nRowSize
-1, nNewTab
, aPattern
);
2089 pInsDoc
->GetCellArea( nNewTab
, nEndCol
, nEndRow
);
2090 pInsDoc
->SetClipArea( ScRange( 0, 0, nNewTab
, nEndCol
, nEndRow
, nNewTab
) );
2092 SfxUndoManager
* pMgr
= GetViewData().GetDocShell()->GetUndoManager();
2093 OUString aUndo
= ScResId( STR_UNDO_DOOUTLINE
);
2094 pMgr
->EnterListAction( aUndo
, aUndo
, 0, GetViewData().GetViewShell()->GetViewShellId() );
2096 OUString aNewTabName
;
2097 rDoc
.CreateValidTabName(aNewTabName
);
2098 if ( InsertTable(aNewTabName
, nNewTab
) )
2099 PasteFromClip( InsertDeleteFlags::ALL
, pInsDoc
.get() );
2101 pMgr
->LeaveListAction();
2104 // repeat data base operations (sorting, filtering, subtotals)
2106 void ScDBFunc::RepeatDB( bool bRecord
)
2108 SCCOL nCurX
= GetViewData().GetCurX();
2109 SCROW nCurY
= GetViewData().GetCurY();
2110 SCTAB nTab
= GetViewData().GetTabNo();
2111 ScDocument
& rDoc
= GetViewData().GetDocument();
2112 ScDBData
* pDBData
= GetDBData();
2113 if (bRecord
&& !rDoc
.IsUndoEnabled())
2116 ScQueryParam aQueryParam
;
2117 pDBData
->GetQueryParam( aQueryParam
);
2118 bool bQuery
= aQueryParam
.GetEntry(0).bDoQuery
;
2120 ScSortParam aSortParam
;
2121 pDBData
->GetSortParam( aSortParam
);
2122 bool bSort
= aSortParam
.maKeyState
[0].bDoSort
;
2124 ScSubTotalParam aSubTotalParam
;
2125 pDBData
->GetSubTotalParam( aSubTotalParam
);
2126 bool bSubTotal
= aSubTotalParam
.aGroups
[0].bActive
&& !aSubTotalParam
.bRemoveOnly
;
2128 if ( bQuery
|| bSort
|| bSubTotal
)
2130 bool bQuerySize
= false;
2133 if (bQuery
&& !aQueryParam
.bInplace
)
2135 ScDBData
* pDest
= rDoc
.GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
2136 aQueryParam
.nDestTab
, ScDBDataPortion::TOP_LEFT
);
2137 if (pDest
&& pDest
->IsDoSize())
2139 pDest
->GetArea( aOldQuery
);
2149 pDBData
->GetArea( nDummy
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
2151 //! undo only needed data ?
2153 ScDocumentUniquePtr pUndoDoc
;
2154 std::unique_ptr
<ScOutlineTable
> pUndoTab
;
2155 std::unique_ptr
<ScRangeName
> pUndoRange
;
2156 std::unique_ptr
<ScDBCollection
> pUndoDB
;
2160 SCTAB nTabCount
= rDoc
.GetTableCount();
2161 pUndoDoc
.reset(new ScDocument( SCDOCMODE_UNDO
));
2162 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
2165 pUndoTab
.reset(new ScOutlineTable( *pTable
));
2167 SCCOLROW nOutStartCol
; // row/column status
2168 SCCOLROW nOutStartRow
;
2169 SCCOLROW nOutEndCol
;
2170 SCCOLROW nOutEndRow
;
2171 pTable
->GetColArray().GetRange( nOutStartCol
, nOutEndCol
);
2172 pTable
->GetRowArray().GetRange( nOutStartRow
, nOutEndRow
);
2174 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, true, true );
2175 rDoc
.CopyToDocument( static_cast<SCCOL
>(nOutStartCol
), 0, nTab
, static_cast<SCCOL
>(nOutEndCol
), rDoc
.MaxRow(), nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
2176 rDoc
.CopyToDocument( 0, nOutStartRow
, nTab
, rDoc
.MaxCol(), nOutEndRow
, nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
2179 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, false, true );
2181 // Record data range - including filter results
2182 rDoc
.CopyToDocument( 0,nStartRow
,nTab
, rDoc
.MaxCol(),nEndRow
,nTab
, InsertDeleteFlags::ALL
, false, *pUndoDoc
);
2184 // all formulas for reference
2185 rDoc
.CopyToDocument( 0,0,0, rDoc
.MaxCol(),rDoc
.MaxRow(),nTabCount
-1, InsertDeleteFlags::FORMULA
, false, *pUndoDoc
);
2187 // data base and other ranges
2188 ScRangeName
* pDocRange
= rDoc
.GetRangeName();
2189 if (!pDocRange
->empty())
2190 pUndoRange
.reset(new ScRangeName( *pDocRange
));
2191 ScDBCollection
* pDocDB
= rDoc
.GetDBCollection();
2192 if (!pDocDB
->empty())
2193 pUndoDB
.reset(new ScDBCollection( *pDocDB
));
2196 if (bSort
&& bSubTotal
)
2198 // sort without subtotals
2200 aSubTotalParam
.bRemoveOnly
= true; // is reset below
2201 DoSubTotals( aSubTotalParam
, false );
2206 pDBData
->GetSortParam( aSortParam
); // range may have changed
2207 Sort( aSortParam
, false, false);
2211 pDBData
->GetQueryParam( aQueryParam
); // range may have changed
2213 if (pDBData
->GetAdvancedQuerySource(aAdvSource
))
2215 rDoc
.CreateQueryParam(aAdvSource
, aQueryParam
);
2216 Query( aQueryParam
, &aAdvSource
, false );
2219 Query( aQueryParam
, nullptr, false );
2221 // if not inplace the sheet may have changed
2222 if ( !aQueryParam
.bInplace
&& aQueryParam
.nDestTab
!= nTab
)
2227 pDBData
->GetSubTotalParam( aSubTotalParam
); // range may have changed
2228 aSubTotalParam
.bRemoveOnly
= false;
2229 DoSubTotals( aSubTotalParam
, false );
2236 SCROW nDummyRow
, nNewEndRow
;
2237 pDBData
->GetArea( nDummyTab
, nDummyCol
,nDummyRow
, nDummyCol
,nNewEndRow
);
2239 const ScRange
* pOld
= nullptr;
2240 const ScRange
* pNew
= nullptr;
2243 ScDBData
* pDest
= rDoc
.GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
2244 aQueryParam
.nDestTab
, ScDBDataPortion::TOP_LEFT
);
2247 pDest
->GetArea( aNewQuery
);
2253 GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
2254 std::make_unique
<ScUndoRepeatDB
>( GetViewData().GetDocShell(), nTab
,
2255 nStartCol
, nStartRow
, nEndCol
, nEndRow
,
2258 std::move(pUndoDoc
), std::move(pUndoTab
),
2259 std::move(pUndoRange
), std::move(pUndoDB
),
2263 GetViewData().GetDocShell()->PostPaint(
2264 ScRange(0, 0, nTab
, rDoc
.MaxCol(), rDoc
.MaxRow(), nTab
),
2265 PaintPartFlags::Grid
| PaintPartFlags::Left
| PaintPartFlags::Top
| PaintPartFlags::Size
);
2267 else // "no not execute any operations"
2268 ErrorMessage(STR_MSSG_REPEATDB_0
);
2271 void ScDBFunc::OnLOKShowHideColRow(bool bColumns
, SCCOLROW nStart
)
2273 if (!comphelper::LibreOfficeKit::isActive())
2276 SCTAB nCurrentTabIndex
= GetViewData().GetTabNo();
2277 SfxViewShell
* pThisViewShell
= GetViewData().GetViewShell();
2278 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
2281 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(pViewShell
);
2282 if (pTabViewShell
&& pTabViewShell
->GetDocId() == pThisViewShell
->GetDocId())
2286 if (ScPositionHelper
* pPosHelper
= pTabViewShell
->GetViewData().GetLOKWidthHelper(nCurrentTabIndex
))
2287 pPosHelper
->invalidateByIndex(nStart
);
2291 if (ScPositionHelper
* pPosHelper
= pTabViewShell
->GetViewData().GetLOKHeightHelper(nCurrentTabIndex
))
2292 pPosHelper
->invalidateByIndex(nStart
);
2295 if (pTabViewShell
->getPart() == nCurrentTabIndex
)
2297 pTabViewShell
->ShowCursor();
2298 pTabViewShell
->MarkDataChanged();
2301 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
2305 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */