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 <docpool.hxx>
56 #include <patattr.hxx>
57 #include <unonames.hxx>
58 #include <userlist.hxx>
59 #include <queryentry.hxx>
60 #include <markdata.hxx>
61 #include <tabvwsh.hxx>
62 #include <generalfunction.hxx>
63 #include <sortparam.hxx>
65 #include <comphelper/lok.hxx>
66 #include <osl/diagnose.h>
69 #include <string_view>
70 #include <unordered_set>
71 #include <unordered_map>
75 using namespace com::sun::star
;
76 using ::com::sun::star::uno::Any
;
77 using ::com::sun::star::uno::Sequence
;
78 using ::com::sun::star::uno::Reference
;
79 using ::com::sun::star::uno::UNO_QUERY
;
80 using ::com::sun::star::beans::XPropertySet
;
81 using ::com::sun::star::container::XNameAccess
;
82 using ::com::sun::star::sheet::XDimensionsSupplier
;
87 // create outline grouping
89 void ScDBFunc::MakeOutline( bool bColumns
, bool bRecord
)
92 if (GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
94 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
95 ScOutlineDocFunc
aFunc(*pDocSh
);
96 aFunc
.MakeOutline( aRange
, bColumns
, bRecord
, false );
98 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), bColumns
? COLUMN_HEADER
: ROW_HEADER
, GetViewData().GetTabNo());
99 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
100 bColumns
, !bColumns
, false /* bSizes*/,
101 false /* bHidden */, false /* bFiltered */,
102 true /* bGroups */, GetViewData().GetTabNo());
105 ErrorMessage(STR_NOMULTISELECT
);
108 // delete outline grouping
110 void ScDBFunc::RemoveOutline( bool bColumns
, bool bRecord
)
113 if (GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
115 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
116 ScOutlineDocFunc
aFunc(*pDocSh
);
117 aFunc
.RemoveOutline( aRange
, bColumns
, bRecord
, false );
119 ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), bColumns
? COLUMN_HEADER
: ROW_HEADER
, GetViewData().GetTabNo());
120 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
121 bColumns
, !bColumns
, false /* bSizes*/,
122 true /* bHidden */, true /* bFiltered */,
123 true /* bGroups */, GetViewData().GetTabNo());
126 ErrorMessage(STR_NOMULTISELECT
);
129 // menu status: delete outlines
131 void ScDBFunc::TestRemoveOutline( bool& rCol
, bool& rRow
)
133 bool bColFound
= false;
134 bool bRowFound
= false;
136 SCCOL nStartCol
, nEndCol
;
137 SCROW nStartRow
, nEndRow
;
138 SCTAB nStartTab
, nEndTab
;
139 if (GetViewData().GetSimpleArea(nStartCol
,nStartRow
,nStartTab
,nEndCol
,nEndRow
,nEndTab
) == SC_MARK_SIMPLE
)
141 SCTAB nTab
= nStartTab
;
142 ScDocument
& rDoc
= GetViewData().GetDocument();
143 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
146 ScOutlineEntry
* pEntry
;
149 bool bColMarked
= ( nStartRow
== 0 && nEndRow
== rDoc
.MaxRow() );
150 bool bRowMarked
= ( nStartCol
== 0 && nEndCol
== rDoc
.MaxCol() );
154 if ( !bRowMarked
|| bColMarked
) // not when entire rows are marked
156 ScOutlineArray
& rArray
= pTable
->GetColArray();
157 ScSubOutlineIterator
aColIter( &rArray
);
160 pEntry
=aColIter
.GetNext();
163 nStart
= pEntry
->GetStart();
164 nEnd
= pEntry
->GetEnd();
165 if ( nStartCol
<=static_cast<SCCOL
>(nEnd
) && nEndCol
>=static_cast<SCCOL
>(nStart
) )
172 if ( !bColMarked
|| bRowMarked
) // not when entire columns are marked
174 ScOutlineArray
& rArray
= pTable
->GetRowArray();
175 ScSubOutlineIterator
aRowIter( &rArray
);
178 pEntry
=aRowIter
.GetNext();
181 nStart
= pEntry
->GetStart();
182 nEnd
= pEntry
->GetEnd();
183 if ( nStartRow
<=nEnd
&& nEndRow
>=nStart
)
194 void ScDBFunc::RemoveAllOutlines( bool bRecord
)
196 SCTAB nTab
= GetViewData().GetTabNo();
197 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
198 ScOutlineDocFunc
aFunc(*pDocSh
);
200 bool bOk
= aFunc
.RemoveAllOutlines( nTab
, bRecord
);
204 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
205 true /* bColumns */, true /* bRows */, false /* bSizes*/,
206 true /* bHidden */, true /* bFiltered */,
207 true /* bGroups */, nTab
);
208 UpdateScrollBars(BOTH_HEADERS
);
214 void ScDBFunc::AutoOutline( )
216 ScDocument
& rDoc
= GetViewData().GetDocument();
217 SCTAB nTab
= GetViewData().GetTabNo();
218 ScRange
aRange( 0,0,nTab
, rDoc
.MaxCol(),rDoc
.MaxRow(),nTab
); // the complete sheet, if nothing is marked
219 ScMarkData
& rMark
= GetViewData().GetMarkData();
220 if ( rMark
.IsMarked() || rMark
.IsMultiMarked() )
223 rMark
.GetMultiMarkArea( aRange
);
226 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
227 ScOutlineDocFunc
aFunc(*pDocSh
);
228 aFunc
.AutoOutline( aRange
, true );
231 // select outline level
233 void ScDBFunc::SelectLevel( bool bColumns
, sal_uInt16 nLevel
, bool bRecord
)
235 SCTAB nTab
= GetViewData().GetTabNo();
236 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
237 ScOutlineDocFunc
aFunc(*pDocSh
);
239 bool bOk
= aFunc
.SelectLevel( nTab
, bColumns
, nLevel
, bRecord
, true/*bPaint*/ );
243 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
244 bColumns
, !bColumns
, false /* bSizes*/,
245 true /* bHidden */, true /* bFiltered */,
246 true /* bGroups */, nTab
);
247 UpdateScrollBars(bColumns
? COLUMN_HEADER
: ROW_HEADER
);
251 // show individual outline groups
253 void ScDBFunc::SetOutlineState( bool bColumns
, sal_uInt16 nLevel
, sal_uInt16 nEntry
, bool bHidden
)
255 const sal_uInt16 nHeadEntry
= static_cast< sal_uInt16
>( -1 );
256 if ( nEntry
== nHeadEntry
)
257 SelectLevel( bColumns
, sal::static_int_cast
<sal_uInt16
>(nLevel
) );
261 ShowOutline( bColumns
, sal::static_int_cast
<sal_uInt16
>(nLevel
), sal::static_int_cast
<sal_uInt16
>(nEntry
) );
263 HideOutline( bColumns
, sal::static_int_cast
<sal_uInt16
>(nLevel
), sal::static_int_cast
<sal_uInt16
>(nEntry
) );
267 void ScDBFunc::ShowOutline( bool bColumns
, sal_uInt16 nLevel
, sal_uInt16 nEntry
, bool bRecord
, bool bPaint
)
269 SCTAB nTab
= GetViewData().GetTabNo();
270 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
271 ScOutlineDocFunc
aFunc(*pDocSh
);
273 aFunc
.ShowOutline( nTab
, bColumns
, nLevel
, nEntry
, bRecord
, bPaint
);
277 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
278 bColumns
, !bColumns
, false /* bSizes*/,
279 true /* bHidden */, true /* bFiltered */,
280 true /* bGroups */, nTab
);
281 UpdateScrollBars(bColumns
? COLUMN_HEADER
: ROW_HEADER
);
285 // hide individual outline groups
287 void ScDBFunc::HideOutline( bool bColumns
, sal_uInt16 nLevel
, sal_uInt16 nEntry
, bool bRecord
, bool bPaint
)
289 SCTAB nTab
= GetViewData().GetTabNo();
290 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
291 ScOutlineDocFunc
aFunc(*pDocSh
);
293 bool bOk
= aFunc
.HideOutline( nTab
, bColumns
, nLevel
, nEntry
, bRecord
, bPaint
);
297 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
298 bColumns
, !bColumns
, false /* bSizes*/,
299 true /* bHidden */, true /* bFiltered */,
300 true /* bGroups */, nTab
);
301 UpdateScrollBars(bColumns
? COLUMN_HEADER
: ROW_HEADER
);
305 // menu status: show/hide marked range
307 bool ScDBFunc::OutlinePossible(bool bHide
)
309 bool bEnable
= false;
318 if (GetViewData().GetSimpleArea(nStartCol
,nStartRow
,nStartTab
,nEndCol
,nEndRow
,nEndTab
) == SC_MARK_SIMPLE
)
320 ScDocument
& rDoc
= GetViewData().GetDocument();
321 SCTAB nTab
= GetViewData().GetTabNo();
322 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
330 ScOutlineArray
& rColArray
= pTable
->GetColArray();
331 ScSubOutlineIterator
aColIter( &rColArray
);
334 ScOutlineEntry
* pEntry
= aColIter
.GetNext();
337 nStart
= pEntry
->GetStart();
338 nEnd
= pEntry
->GetEnd();
341 if ( nStartCol
<=static_cast<SCCOL
>(nEnd
) && nEndCol
>=static_cast<SCCOL
>(nStart
) )
342 if (!pEntry
->IsHidden())
347 if ( nStart
>=nStartCol
&& nEnd
<=nEndCol
)
348 if (pEntry
->IsHidden())
355 ScOutlineArray
& rRowArray
= pTable
->GetRowArray();
356 ScSubOutlineIterator
aRowIter( &rRowArray
);
359 ScOutlineEntry
* pEntry
= aRowIter
.GetNext();
362 nStart
= pEntry
->GetStart();
363 nEnd
= pEntry
->GetEnd();
366 if ( nStartRow
<=nEnd
&& nEndRow
>=nStart
)
367 if (!pEntry
->IsHidden())
372 if ( nStart
>=nStartRow
&& nEnd
<=nEndRow
)
373 if (pEntry
->IsHidden())
385 void ScDBFunc::ShowMarkedOutlines( bool bRecord
)
388 if (GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
390 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
391 ScOutlineDocFunc
aFunc(*pDocSh
);
392 bool bDone
= aFunc
.ShowMarkedOutlines( aRange
, bRecord
);
395 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
396 GetViewData().GetViewShell(), true, true,
397 false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
398 true /* bGroups */, GetViewData().GetTabNo());
403 ErrorMessage(STR_NOMULTISELECT
);
408 void ScDBFunc::HideMarkedOutlines( bool bRecord
)
411 if (GetViewData().GetSimpleArea(aRange
) == SC_MARK_SIMPLE
)
413 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
414 ScOutlineDocFunc
aFunc(*pDocSh
);
415 bool bDone
= aFunc
.HideMarkedOutlines( aRange
, bRecord
);
418 ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
419 GetViewData().GetViewShell(), true, true,
420 false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
421 true /* bGroups */, GetViewData().GetTabNo());
426 ErrorMessage(STR_NOMULTISELECT
);
431 void ScDBFunc::DoSubTotals( const ScSubTotalParam
& rParam
, bool bRecord
,
432 const ScSortParam
* pForceNewSort
)
434 bool bDo
= !rParam
.bRemoveOnly
; // sal_False = only delete
436 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
437 ScDocument
& rDoc
= pDocSh
->GetDocument();
438 ScMarkData
& rMark
= GetViewData().GetMarkData();
439 SCTAB nTab
= GetViewData().GetTabNo();
440 if (bRecord
&& !rDoc
.IsUndoEnabled())
443 ScDBData
* pDBData
= rDoc
.GetDBAtArea( nTab
, rParam
.nCol1
, rParam
.nRow1
,
444 rParam
.nCol2
, rParam
.nRow2
);
447 OSL_FAIL( "SubTotals: no DBData" );
451 ScEditableTester
aTester( rDoc
, nTab
, 0,rParam
.nRow1
+1, rDoc
.MaxCol(),rDoc
.MaxRow() );
452 if (!aTester
.IsEditable())
454 ErrorMessage(aTester
.GetMessageId());
458 if (rDoc
.HasAttrib( rParam
.nCol1
, rParam
.nRow1
+1, nTab
,
459 rParam
.nCol2
, rParam
.nRow2
, nTab
, HasAttrFlags::Merged
| HasAttrFlags::Overlapped
))
461 ErrorMessage(STR_MSSG_INSERTCELLS_0
); // do not insert into merged
465 weld::WaitObject
aWait(GetViewData().GetDialogParent());
469 if (rDoc
.TestRemoveSubTotals( nTab
, rParam
))
471 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
472 VclMessageType::Question
, VclButtonsType::YesNo
,
473 ScResId(STR_MSSG_DOSUBTOTALS_1
))); // "delete data?"
474 xBox
->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0
)); // "StarCalc"
475 xBox
->set_default_response(RET_YES
);
476 bOk
= xBox
->run() == RET_YES
;
483 ScDocShellModificator
aModificator( *pDocSh
);
485 ScSubTotalParam
aNewParam( rParam
); // change end of range
486 ScDocumentUniquePtr pUndoDoc
;
487 std::unique_ptr
<ScOutlineTable
> pUndoTab
;
488 std::unique_ptr
<ScRangeName
> pUndoRange
;
489 std::unique_ptr
<ScDBCollection
> pUndoDB
;
491 if (bRecord
) // record old data
493 bool bOldFilter
= bDo
&& rParam
.bDoSort
;
494 SCTAB nTabCount
= rDoc
.GetTableCount();
495 pUndoDoc
.reset(new ScDocument( SCDOCMODE_UNDO
));
496 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
499 pUndoTab
.reset(new ScOutlineTable( *pTable
));
501 SCCOLROW nOutStartCol
; // row/column status
502 SCCOLROW nOutStartRow
;
505 pTable
->GetColArray().GetRange( nOutStartCol
, nOutEndCol
);
506 pTable
->GetRowArray().GetRange( nOutStartRow
, nOutEndRow
);
508 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, true, true );
509 rDoc
.CopyToDocument( static_cast<SCCOL
>(nOutStartCol
), 0, nTab
, static_cast<SCCOL
>(nOutEndCol
), rDoc
.MaxRow(), nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
510 rDoc
.CopyToDocument( 0, nOutStartRow
, nTab
, rDoc
.MaxCol(), nOutEndRow
, nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
513 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, false, bOldFilter
);
515 // record data range - including filter results
516 rDoc
.CopyToDocument( 0,rParam
.nRow1
+1,nTab
, rDoc
.MaxCol(),rParam
.nRow2
,nTab
,
517 InsertDeleteFlags::ALL
, false, *pUndoDoc
);
519 // all formulas for reference
520 rDoc
.CopyToDocument( 0,0,0, rDoc
.MaxCol(),rDoc
.MaxRow(),nTabCount
-1,
521 InsertDeleteFlags::FORMULA
, false, *pUndoDoc
);
523 // database and other ranges
524 ScRangeName
* pDocRange
= rDoc
.GetRangeName();
525 if (!pDocRange
->empty())
526 pUndoRange
.reset(new ScRangeName( *pDocRange
));
527 ScDBCollection
* pDocDB
= rDoc
.GetDBCollection();
528 if (!pDocDB
->empty())
529 pUndoDB
.reset(new ScDBCollection( *pDocDB
));
532 ScOutlineTable
* pOut
= rDoc
.GetOutlineTable( nTab
);
535 // Remove all existing outlines in the specified range.
536 ScOutlineArray
& rRowArray
= pOut
->GetRowArray();
537 sal_uInt16 nDepth
= rRowArray
.GetDepth();
538 for (sal_uInt16 i
= 0; i
< nDepth
; ++i
)
541 rRowArray
.Remove(aNewParam
.nRow1
, aNewParam
.nRow2
, bSize
);
546 rDoc
.RemoveSubTotals( nTab
, aNewParam
);
547 bool bSuccess
= true;
551 if ( rParam
.bDoSort
|| pForceNewSort
)
553 pDBData
->SetArea( nTab
, aNewParam
.nCol1
,aNewParam
.nRow1
, aNewParam
.nCol2
,aNewParam
.nRow2
);
555 // set subtotal fields before sorting
556 // (duplicate values are dropped, so that they can be called again)
558 ScSortParam aOldSort
;
559 pDBData
->GetSortParam( aOldSort
);
560 ScSortParam
aSortParam( aNewParam
, pForceNewSort
? *pForceNewSort
: aOldSort
);
561 Sort( aSortParam
, false, false );
564 bSuccess
= rDoc
.DoSubTotals( nTab
, aNewParam
);
566 ScRange
aDirtyRange( aNewParam
.nCol1
, aNewParam
.nRow1
, nTab
,
567 aNewParam
.nCol2
, aNewParam
.nRow2
, nTab
);
568 rDoc
.SetDirty( aDirtyRange
, true );
572 pDocSh
->GetUndoManager()->AddUndoAction(
573 std::make_unique
<ScUndoSubTotals
>( pDocSh
, nTab
,
574 rParam
, aNewParam
.nRow2
,
575 std::move(pUndoDoc
), std::move(pUndoTab
), // pUndoDBData,
576 std::move(pUndoRange
), std::move(pUndoDB
) ) );
581 // "Can not insert any rows"
582 ErrorMessage(STR_MSSG_DOSUBTOTALS_2
);
586 pDBData
->SetSubTotalParam( aNewParam
);
587 pDBData
->SetArea( nTab
, aNewParam
.nCol1
,aNewParam
.nRow1
, aNewParam
.nCol2
,aNewParam
.nRow2
);
588 rDoc
.CompileDBFormula();
592 rMark
.SetMarkArea( ScRange( aNewParam
.nCol1
,aNewParam
.nRow1
,nTab
,
593 aNewParam
.nCol2
,aNewParam
.nRow2
,nTab
) );
596 pDocSh
->PostPaint(ScRange(0, 0, nTab
, rDoc
.MaxCol(), rDoc
.MaxRow(), nTab
),
597 PaintPartFlags::Grid
| PaintPartFlags::Left
| PaintPartFlags::Top
| PaintPartFlags::Size
);
599 aModificator
.SetDocumentModified();
606 void ScDBFunc::Consolidate( const ScConsolidateParam
& rParam
)
608 ScDocShell
* pDocShell
= GetViewData().GetDocShell();
609 pDocShell
->DoConsolidate( rParam
);
610 SetTabNo( rParam
.nTab
, true );
615 static OUString
lcl_MakePivotTabName( std::u16string_view rPrefix
, SCTAB nNumber
)
617 OUString aName
= rPrefix
+ OUString::number( nNumber
);
621 bool ScDBFunc::MakePivotTable(
622 const ScDPSaveData
& rData
, const ScRange
& rDest
, bool bNewTable
,
623 const ScDPObject
& rSource
)
625 // error message if no fields are set
626 // this must be removed when drag&drop of fields from a toolbox is available
628 if ( rData
.IsEmpty() )
630 ErrorMessage(STR_PIVOT_NODATA
);
634 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
635 ScDocument
& rDoc
= GetViewData().GetDocument();
636 bool bUndo
= rDoc
.IsUndoEnabled();
638 ScRange aDestRange
= rDest
;
641 SCTAB nSrcTab
= GetViewData().GetTabNo();
643 OUString
aName( ScResId(STR_PIVOT_TABLE
) );
646 rDoc
.GetName( nSrcTab
, aStr
);
647 aName
+= "_" + aStr
+ "_";
649 SCTAB nNewTab
= nSrcTab
+1;
652 while ( !rDoc
.InsertTab( nNewTab
, lcl_MakePivotTabName( aName
, i
) ) && i
<= MAXTAB
)
655 bool bAppend
= ( nNewTab
+1 == rDoc
.GetTableCount() );
658 pDocSh
->GetUndoManager()->AddUndoAction(
659 std::make_unique
<ScUndoInsertTab
>( pDocSh
, nNewTab
, bAppend
, lcl_MakePivotTabName( aName
, i
) ));
662 GetViewData().InsertTab( nNewTab
);
663 SetTabNo(nNewTab
, true);
665 aDestRange
= ScRange( 0, 0, nNewTab
);
668 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor(
669 aDestRange
.aStart
.Col(), aDestRange
.aStart
.Row(), aDestRange
.aStart
.Tab() );
671 ScDPObject
aObj( rSource
);
672 aObj
.SetOutRange( aDestRange
);
673 if ( pDPObj
&& !rData
.GetExistingDimensionData() )
675 // copy dimension data from old object - lost in the dialog
676 //! change the dialog to keep the dimension data
678 ScDPSaveData
aNewData( rData
);
679 const ScDPSaveData
* pOldData
= pDPObj
->GetSaveData();
682 const ScDPDimensionSaveData
* pDimSave
= pOldData
->GetExistingDimensionData();
683 aNewData
.SetDimensionData( pDimSave
);
685 aObj
.SetSaveData( aNewData
);
688 aObj
.SetSaveData( rData
);
690 bool bAllowMove
= (pDPObj
!= nullptr); // allow re-positioning when editing existing table
692 ScDBDocFunc
aFunc( *pDocSh
);
693 bool bSuccess
= aFunc
.DataPilotUpdate(pDPObj
, &aObj
, true, false, bAllowMove
);
695 CursorPosChanged(); // shells may be switched
699 pDocSh
->PostPaintExtras();
700 SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged
) );
706 void ScDBFunc::DeletePivotTable()
708 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
709 ScDocument
& rDoc
= pDocSh
->GetDocument();
710 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( GetViewData().GetCurX(),
711 GetViewData().GetCurY(),
712 GetViewData().GetTabNo() );
715 ScDBDocFunc
aFunc( *pDocSh
);
716 aFunc
.RemovePivotTable(*pDPObj
, true, false);
717 CursorPosChanged(); // shells may be switched
720 ErrorMessage(STR_PIVOT_NOTFOUND
);
723 void ScDBFunc::RecalcPivotTable()
725 ScDocShell
* pDocSh
= GetViewData().GetDocShell();
726 ScDocument
& rDoc
= GetViewData().GetDocument();
728 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( GetViewData().GetCurX(),
729 GetViewData().GetCurY(),
730 GetViewData().GetTabNo() );
733 // Remove existing data cache for the data that this datapilot uses,
734 // to force re-build data cache.
735 ScDBDocFunc
aFunc(*pDocSh
);
736 aFunc
.RefreshPivotTables(pDPObj
, false);
738 CursorPosChanged(); // shells may be switched
741 ErrorMessage(STR_PIVOT_NOTFOUND
);
744 void ScDBFunc::GetSelectedMemberList(ScDPUniqueStringSet
& rEntries
, tools::Long
& rDimension
)
746 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
747 GetViewData().GetCurY(), GetViewData().GetTabNo() );
751 tools::Long nStartDimension
= -1;
752 tools::Long nStartHierarchy
= -1;
753 tools::Long nStartLevel
= -1;
755 ScRangeListRef xRanges
;
756 GetViewData().GetMultiArea( xRanges
); // incl. cursor if nothing is selected
757 size_t nRangeCount
= xRanges
->size();
758 bool bContinue
= true;
760 for (size_t nRangePos
=0; nRangePos
< nRangeCount
&& bContinue
; nRangePos
++)
762 ScRange
const & rRange
= (*xRanges
)[nRangePos
];
763 SCCOL nStartCol
= rRange
.aStart
.Col();
764 SCROW nStartRow
= rRange
.aStart
.Row();
765 SCCOL nEndCol
= rRange
.aEnd
.Col();
766 SCROW nEndRow
= rRange
.aEnd
.Row();
767 SCTAB nTab
= rRange
.aStart
.Tab();
769 for (SCROW nRow
=nStartRow
; nRow
<=nEndRow
&& bContinue
; nRow
++)
770 for (SCCOL nCol
=nStartCol
; nCol
<=nEndCol
&& bContinue
; nCol
++)
772 sheet::DataPilotTableHeaderData aData
;
773 pDPObj
->GetHeaderPositionData(ScAddress(nCol
, nRow
, nTab
), aData
);
774 if ( aData
.Dimension
< 0 )
775 bContinue
= false; // not part of any dimension
778 if ( nStartDimension
< 0 ) // first member?
780 nStartDimension
= aData
.Dimension
;
781 nStartHierarchy
= aData
.Hierarchy
;
782 nStartLevel
= aData
.Level
;
784 if ( aData
.Dimension
!= nStartDimension
||
785 aData
.Hierarchy
!= nStartHierarchy
||
786 aData
.Level
!= nStartLevel
)
788 bContinue
= false; // cannot mix dimensions
793 // accept any part of a member description, also subtotals,
794 // but don't stop if empty parts are contained
795 if ( aData
.Flags
& sheet::MemberResultFlags::HASMEMBER
)
796 rEntries
.insert(aData
.MemberName
);
801 rDimension
= nStartDimension
; // dimension from which the found members came
803 rEntries
.clear(); // remove all if not valid
806 bool ScDBFunc::HasSelectionForDateGroup( ScDPNumGroupInfo
& rOldInfo
, sal_Int32
& rParts
)
808 // determine if the date group dialog has to be shown for the current selection
812 SCCOL nCurX
= GetViewData().GetCurX();
813 SCROW nCurY
= GetViewData().GetCurY();
814 SCTAB nTab
= GetViewData().GetTabNo();
815 ScDocument
& rDoc
= GetViewData().GetDocument();
817 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( nCurX
, nCurY
, nTab
);
820 ScDPUniqueStringSet aEntries
;
821 tools::Long nSelectDimension
= -1;
822 GetSelectedMemberList( aEntries
, nSelectDimension
);
824 if (!aEntries
.empty())
827 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
828 OUString
aBaseDimName( aDimName
);
830 bool bInGroupDim
= false;
831 bool bFoundParts
= false;
833 ScDPDimensionSaveData
* pDimData
=
834 const_cast<ScDPDimensionSaveData
*>( pDPObj
->GetSaveData()->GetExistingDimensionData() );
837 const ScDPSaveNumGroupDimension
* pNumGroupDim
= pDimData
->GetNumGroupDim( aDimName
);
838 const ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDim( aDimName
);
841 // existing num group dimension
843 if ( pNumGroupDim
->GetDatePart() != 0 )
845 // dimension has date info -> edit settings of this dimension
846 // (parts are collected below)
848 rOldInfo
= pNumGroupDim
->GetDateInfo();
851 else if ( pNumGroupDim
->GetInfo().mbDateValues
)
853 // Numerical grouping with DateValues flag is used for grouping
854 // of days with a "Number of days" value.
856 rOldInfo
= pNumGroupDim
->GetInfo();
857 rParts
= css::sheet::DataPilotFieldGroupBy::DAYS
; // not found in CollectDateParts
863 else if ( pGroupDim
)
865 // existing additional group dimension
867 if ( pGroupDim
->GetDatePart() != 0 )
869 // dimension has date info -> edit settings of this dimension
870 // (parts are collected below)
872 rOldInfo
= pGroupDim
->GetDateInfo();
873 aBaseDimName
= pGroupDim
->GetSourceDimName();
879 if ( bFound
&& !bFoundParts
)
881 // collect date parts from all group dimensions
882 rParts
= pDimData
->CollectDateParts( aBaseDimName
);
884 if ( !bFound
&& !bInGroupDim
)
886 // create new date group dimensions if the selection is a single cell
887 // in a normal dimension with date content
890 if ( (GetViewData().GetSimpleArea( aSelRange
) == SC_MARK_SIMPLE
) &&
891 aSelRange
.aStart
== aSelRange
.aEnd
)
893 SCCOL nSelCol
= aSelRange
.aStart
.Col();
894 SCROW nSelRow
= aSelRange
.aStart
.Row();
895 SCTAB nSelTab
= aSelRange
.aStart
.Tab();
896 if ( rDoc
.HasValueData( nSelCol
, nSelRow
, nSelTab
) )
898 sal_uLong nIndex
= rDoc
.GetAttr(
899 nSelCol
, nSelRow
, nSelTab
, ATTR_VALUE_FORMAT
)->GetValue();
900 SvNumFormatType nType
= rDoc
.GetFormatTable()->GetType(nIndex
);
901 if ( nType
== SvNumFormatType::DATE
|| nType
== SvNumFormatType::TIME
|| nType
== SvNumFormatType::DATETIME
)
904 // use currently selected value for automatic limits
905 if( rOldInfo
.mbAutoStart
)
906 rOldInfo
.mfStart
= rDoc
.GetValue( aSelRange
.aStart
);
907 if( rOldInfo
.mbAutoEnd
)
908 rOldInfo
.mfEnd
= rDoc
.GetValue( aSelRange
.aStart
);
919 bool ScDBFunc::HasSelectionForNumGroup( ScDPNumGroupInfo
& rOldInfo
)
921 // determine if the numeric group dialog has to be shown for the current selection
925 SCCOL nCurX
= GetViewData().GetCurX();
926 SCROW nCurY
= GetViewData().GetCurY();
927 SCTAB nTab
= GetViewData().GetTabNo();
928 ScDocument
& rDoc
= GetViewData().GetDocument();
930 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( nCurX
, nCurY
, nTab
);
933 ScDPUniqueStringSet aEntries
;
934 tools::Long nSelectDimension
= -1;
935 GetSelectedMemberList( aEntries
, nSelectDimension
);
937 if (!aEntries
.empty())
940 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
942 bool bInGroupDim
= false;
944 ScDPDimensionSaveData
* pDimData
=
945 const_cast<ScDPDimensionSaveData
*>( pDPObj
->GetSaveData()->GetExistingDimensionData() );
948 const ScDPSaveNumGroupDimension
* pNumGroupDim
= pDimData
->GetNumGroupDim( aDimName
);
951 // existing num group dimension
952 // -> edit settings of this dimension
954 rOldInfo
= pNumGroupDim
->GetInfo();
957 else if ( pDimData
->GetNamedGroupDim( aDimName
) )
958 bInGroupDim
= true; // in a group dimension
960 if ( !bFound
&& !bInGroupDim
)
962 // create a new num group dimension if the selection is a single cell
963 // in a normal dimension with numeric content
966 if ( (GetViewData().GetSimpleArea( aSelRange
) == SC_MARK_SIMPLE
) &&
967 aSelRange
.aStart
== aSelRange
.aEnd
)
969 if ( rDoc
.HasValueData( aSelRange
.aStart
.Col(), aSelRange
.aStart
.Row(),
970 aSelRange
.aStart
.Tab() ) )
973 // use currently selected value for automatic limits
974 if( rOldInfo
.mbAutoStart
)
975 rOldInfo
.mfStart
= rDoc
.GetValue( aSelRange
.aStart
);
976 if( rOldInfo
.mbAutoEnd
)
977 rOldInfo
.mfEnd
= rDoc
.GetValue( aSelRange
.aStart
);
987 void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo
& rInfo
, sal_Int32 nParts
)
989 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
990 GetViewData().GetCurY(), GetViewData().GetTabNo() );
994 ScDPUniqueStringSet aEntries
;
995 tools::Long nSelectDimension
= -1;
996 GetSelectedMemberList( aEntries
, nSelectDimension
);
998 if (aEntries
.empty())
1001 std::vector
<OUString
> aDeletedNames
;
1003 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1005 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1006 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData(); // created if not there
1008 // find the source dimension name.
1009 OUString aBaseDimName
= aDimName
;
1010 if( const ScDPSaveGroupDimension
* pBaseGroupDim
= pDimData
->GetNamedGroupDim( aDimName
) )
1011 aBaseDimName
= pBaseGroupDim
->GetSourceDimName();
1013 // Remove all group dimensions associated with this source dimension. For
1014 // date grouping, we need to remove all existing groups for the affected
1015 // source dimension and build new one(s) from scratch. Keep the deleted
1016 // names so that they can be reused during re-construction.
1017 aData
.RemoveAllGroupDimensions(aBaseDimName
, &aDeletedNames
);
1021 // create date group dimensions
1024 sal_Int32 nMask
= 1;
1025 for (sal_uInt16 nBit
=0; nBit
<32; nBit
++)
1027 if ( nParts
& nMask
)
1031 // innermost part: create NumGroupDimension (replacing original values)
1032 // Dimension name is left unchanged
1034 if ( (nParts
== sheet::DataPilotFieldGroupBy::DAYS
) && (rInfo
.mfStep
>= 1.0) )
1036 // only days, and a step value specified: use numerical grouping
1037 // with DateValues flag, not date grouping
1039 ScDPNumGroupInfo
aNumInfo( rInfo
);
1040 aNumInfo
.mbDateValues
= true;
1042 ScDPSaveNumGroupDimension
aNumGroupDim( aBaseDimName
, aNumInfo
);
1043 pDimData
->AddNumGroupDimension( aNumGroupDim
);
1047 ScDPSaveNumGroupDimension
aNumGroupDim( aBaseDimName
, rInfo
, nMask
);
1048 pDimData
->AddNumGroupDimension( aNumGroupDim
);
1055 // additional parts: create GroupDimension (shown as additional dimensions)
1056 OUString aGroupDimName
=
1057 pDimData
->CreateDateGroupDimName(nMask
, *pDPObj
, true, &aDeletedNames
);
1058 ScDPSaveGroupDimension
aGroupDim( aBaseDimName
, aGroupDimName
);
1059 aGroupDim
.SetDateInfo( rInfo
, nMask
);
1060 pDimData
->AddGroupDimension( aGroupDim
);
1063 ScDPSaveDimension
* pSaveDimension
= aData
.GetDimensionByName( aGroupDimName
);
1064 if ( pSaveDimension
->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN
)
1066 ScDPSaveDimension
* pOldDimension
= aData
.GetDimensionByName( aBaseDimName
);
1067 pSaveDimension
->SetOrientation( pOldDimension
->GetOrientation() );
1068 aData
.SetPosition( pSaveDimension
, 0 ); //! before (immediate) base
1077 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1078 pDPObj
->SetSaveData( aData
);
1079 aFunc
.RefreshPivotTableGroups(pDPObj
);
1081 // unmark cell selection
1085 void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo
& rInfo
)
1087 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1088 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1092 ScDPUniqueStringSet aEntries
;
1093 tools::Long nSelectDimension
= -1;
1094 GetSelectedMemberList( aEntries
, nSelectDimension
);
1096 if (aEntries
.empty())
1100 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1102 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1103 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData(); // created if not there
1105 ScDPSaveNumGroupDimension
* pExisting
= pDimData
->GetNumGroupDimAcc( aDimName
);
1108 // modify existing group dimension
1109 pExisting
->SetGroupInfo( rInfo
);
1113 // create new group dimension
1114 ScDPSaveNumGroupDimension
aNumGroupDim( aDimName
, rInfo
);
1115 pDimData
->AddNumGroupDimension( aNumGroupDim
);
1119 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1120 pDPObj
->SetSaveData( aData
);
1121 aFunc
.RefreshPivotTableGroups(pDPObj
);
1123 // unmark cell selection
1127 void ScDBFunc::GroupDataPilot()
1129 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1130 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1134 ScDPUniqueStringSet aEntries
;
1135 tools::Long nSelectDimension
= -1;
1136 GetSelectedMemberList( aEntries
, nSelectDimension
);
1138 if (aEntries
.empty())
1142 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1144 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1145 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData(); // created if not there
1147 // find original base
1148 OUString aBaseDimName
= aDimName
;
1149 const ScDPSaveGroupDimension
* pBaseGroupDim
= pDimData
->GetNamedGroupDim( aDimName
);
1150 if ( pBaseGroupDim
)
1152 // any entry's SourceDimName is the original base
1153 aBaseDimName
= pBaseGroupDim
->GetSourceDimName();
1156 // find existing group dimension
1157 // (using the selected dim, can be intermediate group dim)
1158 ScDPSaveGroupDimension
* pGroupDimension
= pDimData
->GetGroupDimAccForBase( aDimName
);
1160 // remove the selected items from their groups
1161 // (empty groups are removed, too)
1162 if ( pGroupDimension
)
1164 for (const OUString
& aEntryName
: aEntries
)
1166 if ( pBaseGroupDim
)
1168 // for each selected (intermediate) group, remove all its items
1169 // (same logic as for adding, below)
1170 const ScDPSaveGroupItem
* pBaseGroup
= pBaseGroupDim
->GetNamedGroup( aEntryName
);
1172 pBaseGroup
->RemoveElementsFromGroups( *pGroupDimension
); // remove all elements
1174 pGroupDimension
->RemoveFromGroups( aEntryName
);
1177 pGroupDimension
->RemoveFromGroups( aEntryName
);
1181 std::unique_ptr
<ScDPSaveGroupDimension
> pNewGroupDim
;
1182 if ( !pGroupDimension
)
1184 // create a new group dimension
1185 OUString aGroupDimName
=
1186 pDimData
->CreateGroupDimName(aBaseDimName
, *pDPObj
, false, nullptr);
1187 pNewGroupDim
.reset(new ScDPSaveGroupDimension( aBaseDimName
, aGroupDimName
));
1189 pGroupDimension
= pNewGroupDim
.get(); // make changes to the new dim if none existed
1191 if ( pBaseGroupDim
)
1193 // If it's a higher-order group dimension, pre-allocate groups for all
1194 // non-selected original groups, so the individual base members aren't
1195 // used for automatic groups (this would make the original groups hard
1197 //! Also do this when removing groups?
1198 //! Handle this case dynamically with automatic groups?
1200 tools::Long nGroupCount
= pBaseGroupDim
->GetGroupCount();
1201 for ( tools::Long nGroup
= 0; nGroup
< nGroupCount
; nGroup
++ )
1203 const ScDPSaveGroupItem
& rBaseGroup
= pBaseGroupDim
->GetGroupByIndex( nGroup
);
1205 if (!aEntries
.count(rBaseGroup
.GetGroupName()))
1207 // add an additional group for each item that is not in the selection
1208 ScDPSaveGroupItem
aGroup( rBaseGroup
.GetGroupName() );
1209 aGroup
.AddElementsFromGroup( rBaseGroup
);
1210 pGroupDimension
->AddGroupItem( aGroup
);
1215 OUString aGroupDimName
= pGroupDimension
->GetGroupDimName();
1217 OUString aGroupName
= pGroupDimension
->CreateGroupName(ScResId(STR_PIVOT_GROUP
));
1218 ScDPSaveGroupItem
aGroup( aGroupName
);
1219 for (const OUString
& aEntryName
: aEntries
)
1221 if ( pBaseGroupDim
)
1223 // for each selected (intermediate) group, add all its items
1224 const ScDPSaveGroupItem
* pBaseGroup
= pBaseGroupDim
->GetNamedGroup( aEntryName
);
1226 aGroup
.AddElementsFromGroup( *pBaseGroup
);
1228 aGroup
.AddElement( aEntryName
); // no group found -> automatic group, add the item itself
1231 aGroup
.AddElement( aEntryName
); // no group dimension, add all items directly
1234 pGroupDimension
->AddGroupItem( aGroup
);
1238 pDimData
->AddGroupDimension( *pNewGroupDim
);
1239 pNewGroupDim
.reset(); // AddGroupDimension copies the object
1240 // don't access pGroupDimension after here
1242 pGroupDimension
= nullptr;
1245 ScDPSaveDimension
* pSaveDimension
= aData
.GetDimensionByName( aGroupDimName
);
1246 if ( pSaveDimension
->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN
)
1248 ScDPSaveDimension
* pOldDimension
= aData
.GetDimensionByName( aDimName
);
1249 pSaveDimension
->SetOrientation( pOldDimension
->GetOrientation() );
1250 aData
.SetPosition( pSaveDimension
, 0 ); //! before (immediate) base
1254 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1255 pDPObj
->SetSaveData( aData
);
1256 aFunc
.RefreshPivotTableGroups(pDPObj
);
1258 // unmark cell selection
1262 void ScDBFunc::UngroupDataPilot()
1264 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1265 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1269 ScDPUniqueStringSet aEntries
;
1270 tools::Long nSelectDimension
= -1;
1271 GetSelectedMemberList( aEntries
, nSelectDimension
);
1273 if (aEntries
.empty())
1277 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1279 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1280 if (!aData
.GetExistingDimensionData())
1281 // There is nothing to ungroup.
1284 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData();
1286 ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDimAcc( aDimName
);
1287 const ScDPSaveNumGroupDimension
* pNumGroupDim
= pDimData
->GetNumGroupDim( aDimName
);
1288 if ( ( pGroupDim
&& pGroupDim
->GetDatePart() != 0 ) ||
1289 ( pNumGroupDim
&& pNumGroupDim
->GetDatePart() != 0 ) )
1291 // Date grouping: need to remove all affected group dimensions.
1292 // This is done using DateGroupDataPilot with nParts=0.
1294 DateGroupDataPilot( ScDPNumGroupInfo(), 0 );
1300 for (const auto& rEntry
: aEntries
)
1301 pGroupDim
->RemoveGroup(rEntry
);
1303 // remove group dimension if empty
1304 bool bEmptyDim
= pGroupDim
->IsEmpty();
1307 // If all remaining groups in the dimension aren't shown, remove
1308 // the dimension too, as if it was completely empty.
1309 ScDPUniqueStringSet aVisibleEntries
;
1310 pDPObj
->GetMemberResultNames( aVisibleEntries
, nSelectDimension
);
1311 bEmptyDim
= pGroupDim
->HasOnlyHidden( aVisibleEntries
);
1315 pDimData
->RemoveGroupDimension( aDimName
); // pGroupDim is deleted
1317 // also remove SaveData settings for the dimension that no longer exists
1318 aData
.RemoveDimensionByName( aDimName
);
1321 else if ( pNumGroupDim
)
1323 // remove the numerical grouping
1324 pDimData
->RemoveNumGroupDimension( aDimName
);
1325 // SaveData settings can remain unchanged - the same dimension still exists
1329 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1330 pDPObj
->SetSaveData( aData
);
1331 aFunc
.RefreshPivotTableGroups(pDPObj
);
1333 // unmark cell selection
1337 static OUString
lcl_replaceMemberNameInSubtotal(const OUString
& rSubtotal
, std::u16string_view rMemberName
)
1339 sal_Int32 n
= rSubtotal
.getLength();
1340 const sal_Unicode
* p
= rSubtotal
.getStr();
1341 OUStringBuffer aBuf
, aWordBuf
;
1342 for (sal_Int32 i
= 0; i
< n
; ++i
)
1344 sal_Unicode c
= p
[i
];
1347 OUString aWord
= aWordBuf
.makeStringAndClear();
1348 if (aWord
== rMemberName
)
1356 // Escape a backslash character.
1362 // A literal '?' must be escaped with a backslash ('\');
1363 aWordBuf
.append('\\');
1370 if (!aWordBuf
.isEmpty())
1372 OUString aWord
= aWordBuf
.makeStringAndClear();
1373 if (aWord
== rMemberName
)
1379 return aBuf
.makeStringAndClear();
1382 void ScDBFunc::DataPilotInput( const ScAddress
& rPos
, const OUString
& rString
)
1384 using namespace ::com::sun::star::sheet
;
1386 ScDocument
& rDoc
= GetViewData().GetDocument();
1387 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( rPos
.Col(), rPos
.Row(), rPos
.Tab() );
1391 OUString aOldText
= rDoc
.GetString(rPos
.Col(), rPos
.Row(), rPos
.Tab());
1393 if ( aOldText
== rString
)
1395 // nothing to do: silently exit
1399 TranslateId pErrorId
;
1401 pDPObj
->BuildAllDimensionMembers();
1402 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1403 bool bChange
= false;
1404 bool bNeedReloadGroups
= false;
1406 DataPilotFieldOrientation nOrient
= DataPilotFieldOrientation_HIDDEN
;
1407 tools::Long nField
= pDPObj
->GetHeaderDim( rPos
, nOrient
);
1410 // changing a field title
1411 if ( aData
.GetExistingDimensionData() )
1413 // only group dimensions can be renamed
1415 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData();
1416 ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDimAcc( aOldText
);
1419 // valid name: not empty, no existing dimension (group or other)
1420 if (!rString
.isEmpty() && !pDPObj
->IsDimNameInUse(rString
))
1422 pGroupDim
->Rename( rString
);
1424 // also rename in SaveData to preserve the field settings
1425 ScDPSaveDimension
* pSaveDim
= aData
.GetDimensionByName( aOldText
);
1426 pSaveDim
->SetName( rString
);
1431 pErrorId
= STR_INVALIDNAME
;
1434 else if (nOrient
== DataPilotFieldOrientation_COLUMN
|| nOrient
== DataPilotFieldOrientation_ROW
)
1436 bool bDataLayout
= false;
1437 OUString aDimName
= pDPObj
->GetDimName(nField
, bDataLayout
);
1438 ScDPSaveDimension
* pDim
= bDataLayout
? aData
.GetDataLayoutDimension() : aData
.GetDimensionByName(aDimName
);
1441 if (!rString
.isEmpty())
1443 if (rString
.equalsIgnoreAsciiCase(aDimName
))
1445 pDim
->RemoveLayoutName();
1448 else if (!pDPObj
->IsDimNameInUse(rString
))
1450 pDim
->SetLayoutName(rString
);
1454 pErrorId
= STR_INVALIDNAME
;
1457 pErrorId
= STR_INVALIDNAME
;
1461 else if (pDPObj
->IsDataDescriptionCell(rPos
))
1463 // There is only one data dimension.
1464 ScDPSaveDimension
* pDim
= aData
.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA
);
1467 if (!rString
.isEmpty())
1469 if (pDim
->GetName().equalsIgnoreAsciiCase(rString
))
1471 pDim
->RemoveLayoutName();
1474 else if (!pDPObj
->IsDimNameInUse(rString
))
1476 pDim
->SetLayoutName(rString
);
1480 pErrorId
= STR_INVALIDNAME
;
1483 pErrorId
= STR_INVALIDNAME
;
1488 // This is not a field header.
1489 sheet::DataPilotTableHeaderData aPosData
;
1490 pDPObj
->GetHeaderPositionData(rPos
, aPosData
);
1492 if ((aPosData
.Flags
& MemberResultFlags::HASMEMBER
) && !aOldText
.isEmpty())
1494 if ( aData
.GetExistingDimensionData() && !(aPosData
.Flags
& MemberResultFlags::SUBTOTAL
))
1497 OUString aDimName
= pDPObj
->GetDimName( aPosData
.Dimension
, bIsDataLayout
);
1499 ScDPDimensionSaveData
* pDimData
= aData
.GetDimensionData();
1500 ScDPSaveGroupDimension
* pGroupDim
= pDimData
->GetNamedGroupDimAcc( aDimName
);
1503 // valid name: not empty, no existing group in this dimension
1505 if (!rString
.isEmpty() && !pGroupDim
->GetNamedGroup(rString
))
1507 ScDPSaveGroupItem
* pGroup
= pGroupDim
->GetNamedGroupAcc( aOldText
);
1509 pGroup
->Rename( rString
); // rename the existing group
1512 // create a new group to replace the automatic group
1513 ScDPSaveGroupItem
aGroup( rString
);
1514 aGroup
.AddElement( aOldText
);
1515 pGroupDim
->AddGroupItem( aGroup
);
1518 // in both cases also adjust savedata, to preserve member settings (show details)
1519 ScDPSaveDimension
* pSaveDim
= aData
.GetDimensionByName( aDimName
);
1520 ScDPSaveMember
* pSaveMember
= pSaveDim
->GetExistingMemberByName( aOldText
);
1522 pSaveMember
->SetName( rString
);
1525 bNeedReloadGroups
= true;
1528 pErrorId
= STR_INVALIDNAME
;
1531 else if (aPosData
.Flags
& MemberResultFlags::GRANDTOTAL
)
1533 aData
.SetGrandTotalName(rString
);
1536 else if (aPosData
.Dimension
>= 0 && !aPosData
.MemberName
.isEmpty())
1538 bool bDataLayout
= false;
1539 OUString aDimName
= pDPObj
->GetDimName(static_cast<tools::Long
>(aPosData
.Dimension
), bDataLayout
);
1545 if (aPosData
.Flags
& MemberResultFlags::SUBTOTAL
)
1548 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName(aPosData
.MemberName
);
1552 if (rString
.isEmpty())
1554 pErrorId
= STR_INVALIDNAME
;
1558 if (aPosData
.MemberName
.equalsIgnoreAsciiCase(rString
))
1560 pDim
->RemoveLayoutName();
1563 else if (!pDPObj
->IsDimNameInUse(rString
))
1565 pDim
->SetLayoutName(rString
);
1569 pErrorId
= STR_INVALIDNAME
;
1578 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName(aDimName
);
1582 ScDPSaveMember
* pMem
= pDim
->GetExistingMemberByName(aPosData
.MemberName
);
1586 if (aPosData
.Flags
& MemberResultFlags::SUBTOTAL
)
1588 // Change subtotal only when the table has one data dimension.
1589 if (aData
.GetDataDimensionCount() > 1)
1592 // display name for subtotal is allowed only if the subtotal type is 'Automatic'.
1593 if (pDim
->GetSubTotalsCount() != 1)
1596 if (pDim
->GetSubTotalFunc(0) != ScGeneralFunction::AUTO
)
1599 const std::optional
<OUString
> & pLayoutName
= pMem
->GetLayoutName();
1600 OUString aMemberName
;
1602 aMemberName
= *pLayoutName
;
1604 aMemberName
= aPosData
.MemberName
;
1606 OUString aNew
= lcl_replaceMemberNameInSubtotal(rString
, aMemberName
);
1607 pDim
->SetSubtotalName(aNew
);
1612 // Check to make sure the member name isn't
1614 if (!rString
.isEmpty())
1616 if (rString
.equalsIgnoreAsciiCase(pMem
->GetName()))
1618 pMem
->RemoveLayoutName();
1621 else if (!pDim
->IsMemberNameInUse(rString
))
1623 pMem
->SetLayoutName(rString
);
1627 pErrorId
= STR_INVALIDNAME
;
1630 pErrorId
= STR_INVALIDNAME
;
1642 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1643 pDPObj
->SetSaveData( aData
);
1644 if (bNeedReloadGroups
)
1646 ScDPCollection
* pDPs
= rDoc
.GetDPCollection();
1649 o3tl::sorted_vector
<ScDPObject
*> aRefs
;
1650 // tdf#111305: Reload groups in cache after modifications.
1651 pDPs
->ReloadGroupsInCache(pDPObj
, aRefs
);
1653 } // bNeedReloadGroups
1654 aFunc
.UpdatePivotTable(*pDPObj
, true, false);
1659 pErrorId
= STR_ERR_DATAPILOT_INPUT
;
1660 ErrorMessage(pErrorId
);
1664 static void lcl_MoveToEnd( ScDPSaveDimension
& rDim
, const OUString
& rItemName
)
1666 std::unique_ptr
<ScDPSaveMember
> pNewMember
;
1667 const ScDPSaveMember
* pOldMember
= rDim
.GetExistingMemberByName( rItemName
);
1669 pNewMember
.reset(new ScDPSaveMember( *pOldMember
));
1671 pNewMember
.reset(new ScDPSaveMember( rItemName
));
1672 rDim
.AddMember( std::move(pNewMember
) );
1673 // AddMember takes ownership of the new pointer,
1674 // puts it to the end of the list even if it was in the list before.
1679 struct ScOUStringCollate
1681 CollatorWrapper
* mpCollator
;
1683 explicit ScOUStringCollate(CollatorWrapper
* pColl
) : mpCollator(pColl
) {}
1685 bool operator()(const OUString
& rStr1
, const OUString
& rStr2
) const
1687 return ( mpCollator
->compareString(rStr1
, rStr2
) < 0 );
1693 void ScDBFunc::DataPilotSort(ScDPObject
* pDPObj
, tools::Long nDimIndex
, bool bAscending
, const sal_uInt16
* pUserListId
)
1698 // We need to run this to get all members later.
1700 pDPObj
->BuildAllDimensionMembers();
1703 // Invalid dimension index. Bail out.
1706 ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
1710 ScDPSaveData
aNewSaveData(*pSaveData
);
1712 OUString aDimName
= pDPObj
->GetDimName(nDimIndex
, bDataLayout
);
1713 ScDPSaveDimension
* pSaveDim
= aNewSaveData
.GetDimensionByName(aDimName
);
1717 // manual evaluation of sort order is only needed if a user list id is given
1720 typedef ScDPSaveDimension::MemberList MemList
;
1721 const MemList
& rDimMembers
= pSaveDim
->GetMembers();
1722 vector
<OUString
> aMembers
;
1723 std::unordered_set
<OUString
> aMemberSet
;
1724 size_t nMemberCount
= 0;
1725 for (ScDPSaveMember
* pMem
: rDimMembers
)
1727 aMembers
.push_back(pMem
->GetName());
1728 aMemberSet
.insert(pMem
->GetName());
1732 // Sort the member list in ascending order.
1733 ScOUStringCollate
aCollate( &ScGlobal::GetCollator() );
1734 std::stable_sort(aMembers
.begin(), aMembers
.end(), aCollate
);
1736 // Collect and rank those custom sort strings that also exist in the member name list.
1738 typedef std::unordered_map
<OUString
, sal_uInt16
> UserSortMap
;
1739 UserSortMap aSubStrs
;
1740 sal_uInt16 nSubCount
= 0;
1741 ScUserList
* pUserList
= ScGlobal::GetUserList();
1746 size_t n
= pUserList
->size();
1747 if (!n
|| *pUserListId
>= static_cast<sal_uInt16
>(n
))
1751 const ScUserListData
& rData
= (*pUserList
)[*pUserListId
];
1752 sal_uInt16 n
= rData
.GetSubCount();
1753 for (sal_uInt16 i
= 0; i
< n
; ++i
)
1755 OUString aSub
= rData
.GetSubStr(i
);
1756 if (!aMemberSet
.count(aSub
))
1757 // This string doesn't exist in the member name set. Don't add this.
1760 aSubStrs
.emplace(aSub
, nSubCount
++);
1763 // Rank all members.
1765 vector
<OUString
> aRankedNames(nMemberCount
);
1766 sal_uInt16 nCurStrId
= 0;
1767 for (auto const& aMemberName
: aMembers
)
1769 sal_uInt16 nRank
= 0;
1770 UserSortMap::const_iterator itrSub
= aSubStrs
.find(aMemberName
);
1771 if (itrSub
== aSubStrs
.end())
1772 nRank
= nSubCount
+ nCurStrId
++;
1774 nRank
= itrSub
->second
;
1777 nRank
= static_cast< sal_uInt16
>( nMemberCount
- nRank
- 1 );
1779 aRankedNames
[nRank
] = aMemberName
;
1782 // Re-order ScDPSaveMember instances with the new ranks.
1783 for (auto const& aRankedName
: aRankedNames
)
1785 const ScDPSaveMember
* pOldMem
= pSaveDim
->GetExistingMemberByName(aRankedName
);
1787 // All members are supposed to be present.
1790 pSaveDim
->AddMember(std::unique_ptr
<ScDPSaveMember
>(new ScDPSaveMember(*pOldMem
)));
1793 // Set the sorting mode to manual for now. We may introduce a new sorting
1796 sheet::DataPilotFieldSortInfo aSortInfo
;
1797 aSortInfo
.Mode
= sheet::DataPilotFieldSortMode::MANUAL
;
1798 pSaveDim
->SetSortInfo(&aSortInfo
);
1802 // without user list id, just apply sorting mode
1804 sheet::DataPilotFieldSortInfo aSortInfo
;
1805 aSortInfo
.Mode
= sheet::DataPilotFieldSortMode::NAME
;
1806 aSortInfo
.IsAscending
= bAscending
;
1807 pSaveDim
->SetSortInfo(&aSortInfo
);
1810 // Update the datapilot with the newly sorted field members.
1812 std::unique_ptr
<ScDPObject
> pNewObj(new ScDPObject(*pDPObj
));
1813 pNewObj
->SetSaveData(aNewSaveData
);
1814 ScDBDocFunc
aFunc(*GetViewData().GetDocShell());
1816 aFunc
.DataPilotUpdate(pDPObj
, pNewObj
.get(), true, false);
1819 bool ScDBFunc::DataPilotMove( const ScRange
& rSource
, const ScAddress
& rDest
)
1822 ScDocument
& rDoc
= GetViewData().GetDocument();
1823 ScDPObject
* pDPObj
= rDoc
.GetDPAtCursor( rSource
.aStart
.Col(), rSource
.aStart
.Row(), rSource
.aStart
.Tab() );
1824 if ( pDPObj
&& pDPObj
== rDoc
.GetDPAtCursor( rDest
.Col(), rDest
.Row(), rDest
.Tab() ) )
1826 sheet::DataPilotTableHeaderData aDestData
;
1827 pDPObj
->GetHeaderPositionData( rDest
, aDestData
);
1828 bool bValid
= ( aDestData
.Dimension
>= 0 ); // dropping onto a field
1830 // look through the source range
1831 std::unordered_set
< OUString
> aMembersSet
; // for lookup
1832 std::vector
< OUString
> aMembersVector
; // members in original order, for inserting
1833 aMembersVector
.reserve( std::max( static_cast<SCSIZE
>( rSource
.aEnd
.Col() - rSource
.aStart
.Col() + 1 ),
1834 static_cast<SCSIZE
>( rSource
.aEnd
.Row() - rSource
.aStart
.Row() + 1 ) ) );
1835 for (SCROW nRow
= rSource
.aStart
.Row(); bValid
&& nRow
<= rSource
.aEnd
.Row(); ++nRow
)
1836 for (SCCOL nCol
= rSource
.aStart
.Col(); bValid
&& nCol
<= rSource
.aEnd
.Col(); ++nCol
)
1838 sheet::DataPilotTableHeaderData aSourceData
;
1839 pDPObj
->GetHeaderPositionData( ScAddress( nCol
, nRow
, rSource
.aStart
.Tab() ), aSourceData
);
1840 if ( aSourceData
.Dimension
== aDestData
.Dimension
&& !aSourceData
.MemberName
.isEmpty() )
1842 if ( aMembersSet
.insert( aSourceData
.MemberName
).second
)
1844 aMembersVector
.push_back( aSourceData
.MemberName
);
1846 // duplicates are ignored
1849 bValid
= false; // empty (subtotal) or different field
1855 OUString aDimName
= pDPObj
->GetDimName( aDestData
.Dimension
, bIsDataLayout
);
1856 if ( !bIsDataLayout
)
1858 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1859 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName( aDimName
);
1861 // get all member names in source order
1862 uno::Sequence
<OUString
> aMemberNames
;
1863 pDPObj
->GetMemberNames( aDestData
.Dimension
, aMemberNames
);
1865 bool bInserted
= false;
1867 for (const OUString
& aMemberStr
: std::as_const(aMemberNames
))
1869 if ( !bInserted
&& aMemberStr
== aDestData
.MemberName
)
1871 // insert dragged items before this item
1872 for ( const auto& rMember
: aMembersVector
)
1873 lcl_MoveToEnd( *pDim
, rMember
);
1877 if ( aMembersSet
.find( aMemberStr
) == aMembersSet
.end() ) // skip dragged items
1878 lcl_MoveToEnd( *pDim
, aMemberStr
);
1880 // insert dragged item at end if dest wasn't found (for example, empty)
1882 for ( const auto& rMember
: aMembersVector
)
1883 lcl_MoveToEnd( *pDim
, rMember
);
1885 // Items that were in SaveData, but not in the source, end up at the start of the list.
1887 // set flag for manual sorting
1888 sheet::DataPilotFieldSortInfo aSortInfo
;
1889 aSortInfo
.Mode
= sheet::DataPilotFieldSortMode::MANUAL
;
1890 pDim
->SetSortInfo( &aSortInfo
);
1893 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
1894 std::unique_ptr
<ScDPObject
> pNewObj(new ScDPObject( *pDPObj
));
1895 pNewObj
->SetSaveData( aData
);
1896 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
.get(), true, false ); //! bApi for drag&drop?
1899 Unmark(); // entry was moved - no use in leaving the old cell selected
1909 bool ScDBFunc::HasSelectionForDrillDown( css::sheet::DataPilotFieldOrientation
& rOrientation
)
1913 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1914 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1917 ScDPUniqueStringSet aEntries
;
1918 tools::Long nSelectDimension
= -1;
1919 GetSelectedMemberList( aEntries
, nSelectDimension
);
1921 if (!aEntries
.empty())
1924 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1925 if ( !bIsDataLayout
)
1927 ScDPSaveData
* pSaveData
= pDPObj
->GetSaveData();
1928 ScDPSaveDimension
* pDim
= pSaveData
->GetExistingDimensionByName( aDimName
);
1931 css::sheet::DataPilotFieldOrientation nDimOrient
= pDim
->GetOrientation();
1932 ScDPSaveDimension
* pInner
= pSaveData
->GetInnermostDimension( nDimOrient
);
1933 if ( pDim
== pInner
)
1935 rOrientation
= nDimOrient
;
1946 void ScDBFunc::SetDataPilotDetails(bool bShow
, const OUString
* pNewDimensionName
)
1948 ScDPObject
* pDPObj
= GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1949 GetViewData().GetCurY(), GetViewData().GetTabNo() );
1953 ScDPUniqueStringSet aEntries
;
1954 tools::Long nSelectDimension
= -1;
1955 GetSelectedMemberList( aEntries
, nSelectDimension
);
1957 if (aEntries
.empty())
1961 OUString aDimName
= pDPObj
->GetDimName( nSelectDimension
, bIsDataLayout
);
1962 if ( bIsDataLayout
)
1965 ScDPSaveData
aData( *pDPObj
->GetSaveData() );
1966 ScDPSaveDimension
* pDim
= aData
.GetDimensionByName( aDimName
);
1968 if ( bShow
&& pNewDimensionName
)
1970 // add the new dimension with the same orientation, at the end
1972 ScDPSaveDimension
* pNewDim
= aData
.GetDimensionByName( *pNewDimensionName
);
1973 ScDPSaveDimension
* pDuplicated
= nullptr;
1974 if ( pNewDim
->GetOrientation() == sheet::DataPilotFieldOrientation_DATA
)
1976 // Need to duplicate the dimension, create column/row in addition to data:
1977 // The duplicated dimension inherits the existing settings, pNewDim is modified below.
1978 pDuplicated
= aData
.DuplicateDimension( *pNewDimensionName
);
1981 css::sheet::DataPilotFieldOrientation nOrientation
= pDim
->GetOrientation();
1982 pNewDim
->SetOrientation( nOrientation
);
1984 tools::Long nPosition
= LONG_MAX
;
1985 aData
.SetPosition( pNewDim
, nPosition
);
1987 ScDPSaveDimension
* pDataLayout
= aData
.GetDataLayoutDimension();
1988 if ( pDataLayout
->GetOrientation() == nOrientation
&&
1989 aData
.GetDataDimensionCount() <= 1 )
1991 // If there is only one data dimension, the data layout dimension
1992 // must still be the last one in its orientation.
1993 aData
.SetPosition( pDataLayout
, nPosition
);
1998 // The duplicated (data) dimension needs to be behind the original dimension
1999 aData
.SetPosition( pDuplicated
, nPosition
);
2002 // Hide details for all visible members (selected are changed below).
2003 //! Use all members from source level instead (including non-visible)?
2005 ScDPUniqueStringSet aVisibleEntries
;
2006 pDPObj
->GetMemberResultNames( aVisibleEntries
, nSelectDimension
);
2008 for (const OUString
& aVisName
: aVisibleEntries
)
2010 ScDPSaveMember
* pMember
= pDim
->GetMemberByName( aVisName
);
2011 pMember
->SetShowDetails( false );
2015 for (const auto& rEntry
: aEntries
)
2017 ScDPSaveMember
* pMember
= pDim
->GetMemberByName(rEntry
);
2018 pMember
->SetShowDetails( bShow
);
2022 ScDBDocFunc
aFunc( *GetViewData().GetDocShell() );
2023 std::unique_ptr
<ScDPObject
> pNewObj(new ScDPObject( *pDPObj
));
2024 pNewObj
->SetSaveData( aData
);
2025 aFunc
.DataPilotUpdate( pDPObj
, pNewObj
.get(), true, false );
2028 // unmark cell selection
2032 void ScDBFunc::ShowDataPilotSourceData( ScDPObject
& rDPObj
, const Sequence
<sheet::DataPilotFieldFilter
>& rFilters
)
2034 ScDocument
& rDoc
= GetViewData().GetDocument();
2035 if (rDoc
.GetDocumentShell()->IsReadOnly())
2037 ErrorMessage(STR_READONLYERR
);
2041 Reference
<sheet::XDimensionsSupplier
> xDimSupplier
= rDPObj
.GetSource();
2042 Reference
<container::XNameAccess
> xDims
= xDimSupplier
->getDimensions();
2043 Reference
<sheet::XDrillDownDataSupplier
> xDDSupplier(xDimSupplier
, UNO_QUERY
);
2044 if (!xDDSupplier
.is())
2047 Sequence
< Sequence
<Any
> > aTabData
= xDDSupplier
->getDrillDownData(rFilters
);
2048 sal_Int32 nRowSize
= aTabData
.getLength();
2050 // There is no data to show. Bail out.
2053 SCCOL nColSize
= aTabData
[0].getLength();
2055 SCTAB nNewTab
= GetViewData().GetTabNo();
2057 ScDocumentUniquePtr
pInsDoc(new ScDocument(SCDOCMODE_CLIP
));
2058 pInsDoc
->ResetClip( &rDoc
, nNewTab
);
2059 for (SCROW nRow
= 0; nRow
< nRowSize
; ++nRow
)
2061 for (SCCOL nCol
= 0; nCol
< nColSize
; ++nCol
)
2063 const Any
& rAny
= aTabData
[nRow
][nCol
];
2068 pInsDoc
->SetString(ScAddress(nCol
,nRow
,nNewTab
), aStr
);
2070 else if (rAny
>>= fVal
)
2071 pInsDoc
->SetValue(nCol
, nRow
, nNewTab
, fVal
);
2075 // set number format (important for dates)
2076 for (SCCOL nCol
= 0; nCol
< nColSize
; ++nCol
)
2079 if (!(aTabData
[0][nCol
] >>= aStr
))
2082 Reference
<XPropertySet
> xPropSet(xDims
->getByName(aStr
), UNO_QUERY
);
2086 Any any
= xPropSet
->getPropertyValue( SC_UNO_DP_NUMBERFO
);
2087 sal_Int32 nNumFmt
= 0;
2088 if (!(any
>>= nNumFmt
))
2091 ScPatternAttr
aPattern( pInsDoc
->GetPool() );
2092 aPattern
.GetItemSet().Put( SfxUInt32Item(ATTR_VALUE_FORMAT
, static_cast<sal_uInt32
>(nNumFmt
)) );
2093 pInsDoc
->ApplyPatternAreaTab(nCol
, 1, nCol
, nRowSize
-1, nNewTab
, aPattern
);
2098 pInsDoc
->GetCellArea( nNewTab
, nEndCol
, nEndRow
);
2099 pInsDoc
->SetClipArea( ScRange( 0, 0, nNewTab
, nEndCol
, nEndRow
, nNewTab
) );
2101 SfxUndoManager
* pMgr
= GetViewData().GetDocShell()->GetUndoManager();
2102 OUString aUndo
= ScResId( STR_UNDO_DOOUTLINE
);
2103 pMgr
->EnterListAction( aUndo
, aUndo
, 0, GetViewData().GetViewShell()->GetViewShellId() );
2105 OUString aNewTabName
;
2106 rDoc
.CreateValidTabName(aNewTabName
);
2107 if ( InsertTable(aNewTabName
, nNewTab
) )
2108 PasteFromClip( InsertDeleteFlags::ALL
, pInsDoc
.get() );
2110 pMgr
->LeaveListAction();
2113 // repeat data base operations (sorting, filtering, subtotals)
2115 void ScDBFunc::RepeatDB( bool bRecord
)
2117 SCCOL nCurX
= GetViewData().GetCurX();
2118 SCROW nCurY
= GetViewData().GetCurY();
2119 SCTAB nTab
= GetViewData().GetTabNo();
2120 ScDocument
& rDoc
= GetViewData().GetDocument();
2121 ScDBData
* pDBData
= GetDBData();
2122 if (bRecord
&& !rDoc
.IsUndoEnabled())
2125 ScQueryParam aQueryParam
;
2126 pDBData
->GetQueryParam( aQueryParam
);
2127 bool bQuery
= aQueryParam
.GetEntry(0).bDoQuery
;
2129 ScSortParam aSortParam
;
2130 pDBData
->GetSortParam( aSortParam
);
2131 bool bSort
= aSortParam
.maKeyState
[0].bDoSort
;
2133 ScSubTotalParam aSubTotalParam
;
2134 pDBData
->GetSubTotalParam( aSubTotalParam
);
2135 bool bSubTotal
= aSubTotalParam
.bGroupActive
[0] && !aSubTotalParam
.bRemoveOnly
;
2137 if ( bQuery
|| bSort
|| bSubTotal
)
2139 bool bQuerySize
= false;
2142 if (bQuery
&& !aQueryParam
.bInplace
)
2144 ScDBData
* pDest
= rDoc
.GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
2145 aQueryParam
.nDestTab
, ScDBDataPortion::TOP_LEFT
);
2146 if (pDest
&& pDest
->IsDoSize())
2148 pDest
->GetArea( aOldQuery
);
2158 pDBData
->GetArea( nDummy
, nStartCol
, nStartRow
, nEndCol
, nEndRow
);
2160 //! undo only needed data ?
2162 ScDocumentUniquePtr pUndoDoc
;
2163 std::unique_ptr
<ScOutlineTable
> pUndoTab
;
2164 std::unique_ptr
<ScRangeName
> pUndoRange
;
2165 std::unique_ptr
<ScDBCollection
> pUndoDB
;
2169 SCTAB nTabCount
= rDoc
.GetTableCount();
2170 pUndoDoc
.reset(new ScDocument( SCDOCMODE_UNDO
));
2171 ScOutlineTable
* pTable
= rDoc
.GetOutlineTable( nTab
);
2174 pUndoTab
.reset(new ScOutlineTable( *pTable
));
2176 SCCOLROW nOutStartCol
; // row/column status
2177 SCCOLROW nOutStartRow
;
2178 SCCOLROW nOutEndCol
;
2179 SCCOLROW nOutEndRow
;
2180 pTable
->GetColArray().GetRange( nOutStartCol
, nOutEndCol
);
2181 pTable
->GetRowArray().GetRange( nOutStartRow
, nOutEndRow
);
2183 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, true, true );
2184 rDoc
.CopyToDocument( static_cast<SCCOL
>(nOutStartCol
), 0, nTab
, static_cast<SCCOL
>(nOutEndCol
), rDoc
.MaxRow(), nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
2185 rDoc
.CopyToDocument( 0, nOutStartRow
, nTab
, rDoc
.MaxCol(), nOutEndRow
, nTab
, InsertDeleteFlags::NONE
, false, *pUndoDoc
);
2188 pUndoDoc
->InitUndo( rDoc
, nTab
, nTab
, false, true );
2190 // Record data range - including filter results
2191 rDoc
.CopyToDocument( 0,nStartRow
,nTab
, rDoc
.MaxCol(),nEndRow
,nTab
, InsertDeleteFlags::ALL
, false, *pUndoDoc
);
2193 // all formulas for reference
2194 rDoc
.CopyToDocument( 0,0,0, rDoc
.MaxCol(),rDoc
.MaxRow(),nTabCount
-1, InsertDeleteFlags::FORMULA
, false, *pUndoDoc
);
2196 // data base and other ranges
2197 ScRangeName
* pDocRange
= rDoc
.GetRangeName();
2198 if (!pDocRange
->empty())
2199 pUndoRange
.reset(new ScRangeName( *pDocRange
));
2200 ScDBCollection
* pDocDB
= rDoc
.GetDBCollection();
2201 if (!pDocDB
->empty())
2202 pUndoDB
.reset(new ScDBCollection( *pDocDB
));
2205 if (bSort
&& bSubTotal
)
2207 // sort without subtotals
2209 aSubTotalParam
.bRemoveOnly
= true; // is reset below
2210 DoSubTotals( aSubTotalParam
, false );
2215 pDBData
->GetSortParam( aSortParam
); // range may have changed
2216 Sort( aSortParam
, false, false);
2220 pDBData
->GetQueryParam( aQueryParam
); // range may have changed
2222 if (pDBData
->GetAdvancedQuerySource(aAdvSource
))
2224 rDoc
.CreateQueryParam(aAdvSource
, aQueryParam
);
2225 Query( aQueryParam
, &aAdvSource
, false );
2228 Query( aQueryParam
, nullptr, false );
2230 // if not inplace the sheet may have changed
2231 if ( !aQueryParam
.bInplace
&& aQueryParam
.nDestTab
!= nTab
)
2236 pDBData
->GetSubTotalParam( aSubTotalParam
); // range may have changed
2237 aSubTotalParam
.bRemoveOnly
= false;
2238 DoSubTotals( aSubTotalParam
, false );
2245 SCROW nDummyRow
, nNewEndRow
;
2246 pDBData
->GetArea( nDummyTab
, nDummyCol
,nDummyRow
, nDummyCol
,nNewEndRow
);
2248 const ScRange
* pOld
= nullptr;
2249 const ScRange
* pNew
= nullptr;
2252 ScDBData
* pDest
= rDoc
.GetDBAtCursor( aQueryParam
.nDestCol
, aQueryParam
.nDestRow
,
2253 aQueryParam
.nDestTab
, ScDBDataPortion::TOP_LEFT
);
2256 pDest
->GetArea( aNewQuery
);
2262 GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
2263 std::make_unique
<ScUndoRepeatDB
>( GetViewData().GetDocShell(), nTab
,
2264 nStartCol
, nStartRow
, nEndCol
, nEndRow
,
2267 std::move(pUndoDoc
), std::move(pUndoTab
),
2268 std::move(pUndoRange
), std::move(pUndoDB
),
2272 GetViewData().GetDocShell()->PostPaint(
2273 ScRange(0, 0, nTab
, rDoc
.MaxCol(), rDoc
.MaxRow(), nTab
),
2274 PaintPartFlags::Grid
| PaintPartFlags::Left
| PaintPartFlags::Top
| PaintPartFlags::Size
);
2276 else // "no not execute any operations"
2277 ErrorMessage(STR_MSSG_REPEATDB_0
);
2280 void ScDBFunc::OnLOKShowHideColRow(bool bColumns
, SCCOLROW nStart
)
2282 if (!comphelper::LibreOfficeKit::isActive())
2285 SCTAB nCurrentTabIndex
= GetViewData().GetTabNo();
2286 SfxViewShell
* pThisViewShell
= GetViewData().GetViewShell();
2287 SfxViewShell
* pViewShell
= SfxViewShell::GetFirst();
2290 ScTabViewShell
* pTabViewShell
= dynamic_cast<ScTabViewShell
*>(pViewShell
);
2291 if (pTabViewShell
&& pTabViewShell
->GetDocId() == pThisViewShell
->GetDocId())
2295 if (ScPositionHelper
* pPosHelper
= pTabViewShell
->GetViewData().GetLOKWidthHelper(nCurrentTabIndex
))
2296 pPosHelper
->invalidateByIndex(nStart
);
2300 if (ScPositionHelper
* pPosHelper
= pTabViewShell
->GetViewData().GetLOKHeightHelper(nCurrentTabIndex
))
2301 pPosHelper
->invalidateByIndex(nStart
);
2304 if (pTabViewShell
->getPart() == nCurrentTabIndex
)
2306 pTabViewShell
->ShowCursor();
2307 pTabViewShell
->MarkDataChanged();
2310 pViewShell
= SfxViewShell::GetNext(*pViewShell
);
2314 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */