LibreOffice Module sc (master)  1
dbfunc3.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <dbfunc.hxx>
21 #include <scitems.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/weld.hxx>
24 #include <svl/zforlist.hxx>
25 #include <sfx2/app.hxx>
27 #include <com/sun/star/beans/XPropertySet.hpp>
28 #include <com/sun/star/container/XNameAccess.hpp>
29 #include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
30 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
31 #include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
32 #include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
33 #include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
34 #include <com/sun/star/sheet/MemberResultFlags.hpp>
35 #include <com/sun/star/sheet/XDimensionsSupplier.hpp>
36 #include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
37 
38 #include <global.hxx>
39 #include <scresid.hxx>
40 #include <globstr.hrc>
41 #include <undotab.hxx>
42 #include <undodat.hxx>
43 #include <dbdata.hxx>
44 #include <rangenam.hxx>
45 #include <docsh.hxx>
46 #include <olinetab.hxx>
47 #include <olinefun.hxx>
48 #include <dpobject.hxx>
49 #include <dpsave.hxx>
50 #include <dpdimsave.hxx>
51 #include <dbdocfun.hxx>
52 #include <dpoutput.hxx>
53 #include <editable.hxx>
54 #include <docpool.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>
63 
64 #include <comphelper/lok.hxx>
65 #include <osl/diagnose.h>
66 
67 #include <memory>
68 #include <string_view>
69 #include <unordered_set>
70 #include <unordered_map>
71 #include <vector>
72 #include <algorithm>
73 
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;
82 using ::std::vector;
83 
84 // outliner
85 
86 // create outline grouping
87 
88 void ScDBFunc::MakeOutline( bool bColumns, bool bRecord )
89 {
90  ScRange aRange;
91  if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
92  {
93  ScDocShell* pDocSh = GetViewData().GetDocShell();
94  ScOutlineDocFunc aFunc(*pDocSh);
95  aFunc.MakeOutline( aRange, bColumns, bRecord, false );
96 
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());
102  }
103  else
104  ErrorMessage(STR_NOMULTISELECT);
105 }
106 
107 // delete outline grouping
108 
109 void ScDBFunc::RemoveOutline( bool bColumns, bool bRecord )
110 {
111  ScRange aRange;
112  if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
113  {
114  ScDocShell* pDocSh = GetViewData().GetDocShell();
115  ScOutlineDocFunc aFunc(*pDocSh);
116  aFunc.RemoveOutline( aRange, bColumns, bRecord, false );
117 
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());
123  }
124  else
125  ErrorMessage(STR_NOMULTISELECT);
126 }
127 
128 // menu status: delete outlines
129 
130 void ScDBFunc::TestRemoveOutline( bool& rCol, bool& rRow )
131 {
132  bool bColFound = false;
133  bool bRowFound = false;
134 
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)
139  {
140  SCTAB nTab = nStartTab;
141  ScDocument& rDoc = GetViewData().GetDocument();
142  ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
143  if (pTable)
144  {
145  ScOutlineEntry* pEntry;
146  SCCOLROW nStart;
147  SCCOLROW nEnd;
148  bool bColMarked = ( nStartRow == 0 && nEndRow == rDoc.MaxRow() );
149  bool bRowMarked = ( nStartCol == 0 && nEndCol == rDoc.MaxCol() );
150 
151  // columns
152 
153  if ( !bRowMarked || bColMarked ) // not when entire rows are marked
154  {
155  ScOutlineArray& rArray = pTable->GetColArray();
156  ScSubOutlineIterator aColIter( &rArray );
157  while (!bColFound)
158  {
159  pEntry=aColIter.GetNext();
160  if (!pEntry)
161  break;
162  nStart = pEntry->GetStart();
163  nEnd = pEntry->GetEnd();
164  if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
165  bColFound = true;
166  }
167  }
168 
169  // rows
170 
171  if ( !bColMarked || bRowMarked ) // not when entire columns are marked
172  {
173  ScOutlineArray& rArray = pTable->GetRowArray();
174  ScSubOutlineIterator aRowIter( &rArray );
175  while (!bRowFound)
176  {
177  pEntry=aRowIter.GetNext();
178  if (!pEntry)
179  break;
180  nStart = pEntry->GetStart();
181  nEnd = pEntry->GetEnd();
182  if ( nStartRow<=nEnd && nEndRow>=nStart )
183  bRowFound = true;
184  }
185  }
186  }
187  }
188 
189  rCol = bColFound;
190  rRow = bRowFound;
191 }
192 
193 void ScDBFunc::RemoveAllOutlines( bool bRecord )
194 {
195  SCTAB nTab = GetViewData().GetTabNo();
196  ScDocShell* pDocSh = GetViewData().GetDocShell();
197  ScOutlineDocFunc aFunc(*pDocSh);
198 
199  bool bOk = aFunc.RemoveAllOutlines( nTab, bRecord );
200 
201  if (bOk)
202  {
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);
208  }
209 }
210 
211 // auto outlines
212 
214 {
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() )
220  {
221  rMark.MarkToMulti();
222  rMark.GetMultiMarkArea( aRange );
223  }
224 
225  ScDocShell* pDocSh = GetViewData().GetDocShell();
226  ScOutlineDocFunc aFunc(*pDocSh);
227  aFunc.AutoOutline( aRange, true );
228 }
229 
230 // select outline level
231 
232 void ScDBFunc::SelectLevel( bool bColumns, sal_uInt16 nLevel, bool bRecord )
233 {
234  SCTAB nTab = GetViewData().GetTabNo();
235  ScDocShell* pDocSh = GetViewData().GetDocShell();
236  ScOutlineDocFunc aFunc(*pDocSh);
237 
238  bool bOk = aFunc.SelectLevel( nTab, bColumns, nLevel, bRecord, true/*bPaint*/ );
239 
240  if (bOk)
241  {
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);
247  }
248 }
249 
250 // show individual outline groups
251 
252 void ScDBFunc::SetOutlineState( bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bHidden)
253 {
254  const sal_uInt16 nHeadEntry = static_cast< sal_uInt16 >( -1 );
255  if ( nEntry == nHeadEntry)
256  SelectLevel( bColumns, sal::static_int_cast<sal_uInt16>(nLevel) );
257  else
258  {
259  if ( !bHidden )
260  ShowOutline( bColumns, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
261  else
262  HideOutline( bColumns, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
263  }
264 }
265 
266 void ScDBFunc::ShowOutline( bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bRecord, bool bPaint )
267 {
268  SCTAB nTab = GetViewData().GetTabNo();
269  ScDocShell* pDocSh = GetViewData().GetDocShell();
270  ScOutlineDocFunc aFunc(*pDocSh);
271 
272  aFunc.ShowOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint );
273 
274  if ( bPaint )
275  {
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);
281  }
282 }
283 
284 // hide individual outline groups
285 
286 void ScDBFunc::HideOutline( bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bRecord, bool bPaint )
287 {
288  SCTAB nTab = GetViewData().GetTabNo();
289  ScDocShell* pDocSh = GetViewData().GetDocShell();
290  ScOutlineDocFunc aFunc(*pDocSh);
291 
292  bool bOk = aFunc.HideOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint );
293 
294  if ( bOk && bPaint )
295  {
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);
301  }
302 }
303 
304 // menu status: show/hide marked range
305 
307 {
308  bool bEnable = false;
309 
310  SCCOL nStartCol;
311  SCROW nStartRow;
312  SCTAB nStartTab;
313  SCCOL nEndCol;
314  SCROW nEndRow;
315  SCTAB nEndTab;
316 
317  if (GetViewData().GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
318  {
319  ScDocument& rDoc = GetViewData().GetDocument();
320  SCTAB nTab = GetViewData().GetTabNo();
321  ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
322  if (pTable)
323  {
324  SCCOLROW nStart;
325  SCCOLROW nEnd;
326 
327  // columns
328 
329  ScOutlineArray& rColArray = pTable->GetColArray();
330  ScSubOutlineIterator aColIter( &rColArray );
331  while (!bEnable)
332  {
333  ScOutlineEntry* pEntry = aColIter.GetNext();
334  if (!pEntry)
335  break;
336  nStart = pEntry->GetStart();
337  nEnd = pEntry->GetEnd();
338  if ( bHide )
339  {
340  if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
341  if (!pEntry->IsHidden())
342  bEnable = true;
343  }
344  else
345  {
346  if ( nStart>=nStartCol && nEnd<=nEndCol )
347  if (pEntry->IsHidden())
348  bEnable = true;
349  }
350  }
351 
352  // rows
353 
354  ScOutlineArray& rRowArray = pTable->GetRowArray();
355  ScSubOutlineIterator aRowIter( &rRowArray );
356  for (;;)
357  {
358  ScOutlineEntry* pEntry = aRowIter.GetNext();
359  if (!pEntry)
360  break;
361  nStart = pEntry->GetStart();
362  nEnd = pEntry->GetEnd();
363  if ( bHide )
364  {
365  if ( nStartRow<=nEnd && nEndRow>=nStart )
366  if (!pEntry->IsHidden())
367  bEnable = true;
368  }
369  else
370  {
371  if ( nStart>=nStartRow && nEnd<=nEndRow )
372  if (pEntry->IsHidden())
373  bEnable = true;
374  }
375  }
376  }
377  }
378 
379  return bEnable;
380 }
381 
382 // show marked range
383 
384 void ScDBFunc::ShowMarkedOutlines( bool bRecord )
385 {
386  ScRange aRange;
387  if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
388  {
389  ScDocShell* pDocSh = GetViewData().GetDocShell();
390  ScOutlineDocFunc aFunc(*pDocSh);
391  bool bDone = aFunc.ShowMarkedOutlines( aRange, bRecord );
392  if (bDone)
393  {
395  GetViewData().GetViewShell(), true, true,
396  false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
397  true /* bGroups */, GetViewData().GetTabNo());
398  UpdateScrollBars();
399  }
400  }
401  else
402  ErrorMessage(STR_NOMULTISELECT);
403 }
404 
405 // hide marked range
406 
407 void ScDBFunc::HideMarkedOutlines( bool bRecord )
408 {
409  ScRange aRange;
410  if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
411  {
412  ScDocShell* pDocSh = GetViewData().GetDocShell();
413  ScOutlineDocFunc aFunc(*pDocSh);
414  bool bDone = aFunc.HideMarkedOutlines( aRange, bRecord );
415  if (bDone)
416  {
418  GetViewData().GetViewShell(), true, true,
419  false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
420  true /* bGroups */, GetViewData().GetTabNo());
421  UpdateScrollBars();
422  }
423  }
424  else
425  ErrorMessage(STR_NOMULTISELECT);
426 }
427 
428 // sub totals
429 
430 void ScDBFunc::DoSubTotals( const ScSubTotalParam& rParam, bool bRecord,
431  const ScSortParam* pForceNewSort )
432 {
433  bool bDo = !rParam.bRemoveOnly; // sal_False = only delete
434 
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())
440  bRecord = false;
441 
442  ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
443  rParam.nCol2, rParam.nRow2 );
444  if (!pDBData)
445  {
446  OSL_FAIL( "SubTotals: no DBData" );
447  return;
448  }
449 
450  ScEditableTester aTester( rDoc, nTab, 0,rParam.nRow1+1, rDoc.MaxCol(),rDoc.MaxRow() );
451  if (!aTester.IsEditable())
452  {
453  ErrorMessage(aTester.GetMessageId());
454  return;
455  }
456 
457  if (rDoc.HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
458  rParam.nCol2, rParam.nRow2, nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
459  {
460  ErrorMessage(STR_MSSG_INSERTCELLS_0); // do not insert into merged
461  return;
462  }
463 
464  weld::WaitObject aWait(GetViewData().GetDialogParent());
465  bool bOk = true;
466  if (rParam.bReplace)
467  {
468  if (rDoc.TestRemoveSubTotals( nTab, rParam ))
469  {
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;
476  }
477  }
478 
479  if (!bOk)
480  return;
481 
482  ScDocShellModificator aModificator( *pDocSh );
483 
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;
489 
490  if (bRecord) // record old data
491  {
492  bool bOldFilter = bDo && rParam.bDoSort;
493  SCTAB nTabCount = rDoc.GetTableCount();
494  pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
495  ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
496  if (pTable)
497  {
498  pUndoTab.reset(new ScOutlineTable( *pTable ));
499 
500  SCCOLROW nOutStartCol; // row/column status
501  SCCOLROW nOutStartRow;
502  SCCOLROW nOutEndCol;
503  SCCOLROW nOutEndRow;
504  pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
505  pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
506 
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 );
510  }
511  else
512  pUndoDoc->InitUndo( rDoc, nTab, nTab, false, bOldFilter );
513 
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 );
517 
518  // all formulas for reference
519  rDoc.CopyToDocument( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),nTabCount-1,
520  InsertDeleteFlags::FORMULA, false, *pUndoDoc );
521 
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 ));
529  }
530 
531  ScOutlineTable* pOut = rDoc.GetOutlineTable( nTab );
532  if (pOut)
533  {
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)
538  {
539  bool bSize;
540  rRowArray.Remove(aNewParam.nRow1, aNewParam.nRow2, bSize);
541  }
542  }
543 
544  if (rParam.bReplace)
545  rDoc.RemoveSubTotals( nTab, aNewParam );
546  bool bSuccess = true;
547  if (bDo)
548  {
549  // Sort
550  if ( rParam.bDoSort || pForceNewSort )
551  {
552  pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
553 
554  // set subtotal fields before sorting
555  // (duplicate values are dropped, so that they can be called again)
556 
557  ScSortParam aOldSort;
558  pDBData->GetSortParam( aOldSort );
559  ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
560  Sort( aSortParam, false, false );
561  }
562 
563  bSuccess = rDoc.DoSubTotals( nTab, aNewParam );
564  }
565  ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
566  aNewParam.nCol2, aNewParam.nRow2, nTab );
567  rDoc.SetDirty( aDirtyRange, true );
568 
569  if (bRecord)
570  {
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) ) );
576  }
577 
578  if (!bSuccess)
579  {
580  // "Can not insert any rows"
581  ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
582  }
583 
584  // store
585  pDBData->SetSubTotalParam( aNewParam );
586  pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
587  rDoc.CompileDBFormula();
588 
589  DoneBlockMode();
590  InitOwnBlockMode();
591  rMark.SetMarkArea( ScRange( aNewParam.nCol1,aNewParam.nRow1,nTab,
592  aNewParam.nCol2,aNewParam.nRow2,nTab ) );
593  MarkDataChanged();
594 
595  pDocSh->PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
597 
598  aModificator.SetDocumentModified();
599 
600  SelectionChanged();
601 }
602 
603 // consolidate
604 
606 {
607  ScDocShell* pDocShell = GetViewData().GetDocShell();
608  pDocShell->DoConsolidate( rParam );
609  SetTabNo( rParam.nTab, true );
610 }
611 
612 // pivot
613 
614 static OUString lcl_MakePivotTabName( std::u16string_view rPrefix, SCTAB nNumber )
615 {
616  OUString aName = rPrefix + OUString::number( nNumber );
617  return aName;
618 }
619 
621  const ScDPSaveData& rData, const ScRange& rDest, bool bNewTable,
622  const ScDPObject& rSource )
623 {
624  // error message if no fields are set
625  // this must be removed when drag&drop of fields from a toolbox is available
626 
627  if ( rData.IsEmpty() )
628  {
629  ErrorMessage(STR_PIVOT_NODATA);
630  return false;
631  }
632 
633  ScDocShell* pDocSh = GetViewData().GetDocShell();
634  ScDocument& rDoc = GetViewData().GetDocument();
635  bool bUndo = rDoc.IsUndoEnabled();
636 
637  ScRange aDestRange = rDest;
638  if ( bNewTable )
639  {
640  SCTAB nSrcTab = GetViewData().GetTabNo();
641 
642  OUString aName( ScResId(STR_PIVOT_TABLE) );
643  OUString aStr;
644 
645  rDoc.GetName( nSrcTab, aStr );
646  aName += "_" + aStr + "_";
647 
648  SCTAB nNewTab = nSrcTab+1;
649 
650  SCTAB i=1;
651  while ( !rDoc.InsertTab( nNewTab, lcl_MakePivotTabName( aName, i ) ) && i <= MAXTAB )
652  i++;
653 
654  bool bAppend = ( nNewTab+1 == rDoc.GetTableCount() );
655  if (bUndo)
656  {
657  pDocSh->GetUndoManager()->AddUndoAction(
658  std::make_unique<ScUndoInsertTab>( pDocSh, nNewTab, bAppend, lcl_MakePivotTabName( aName, i ) ));
659  }
660 
661  GetViewData().InsertTab( nNewTab );
662  SetTabNo(nNewTab, true);
663 
664  aDestRange = ScRange( 0, 0, nNewTab );
665  }
666 
667  ScDPObject* pDPObj = rDoc.GetDPAtCursor(
668  aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aStart.Tab() );
669 
670  ScDPObject aObj( rSource );
671  aObj.SetOutRange( aDestRange );
672  if ( pDPObj && !rData.GetExistingDimensionData() )
673  {
674  // copy dimension data from old object - lost in the dialog
676 
677  ScDPSaveData aNewData( rData );
678  const ScDPSaveData* pOldData = pDPObj->GetSaveData();
679  if ( pOldData )
680  {
681  const ScDPDimensionSaveData* pDimSave = pOldData->GetExistingDimensionData();
682  aNewData.SetDimensionData( pDimSave );
683  }
684  aObj.SetSaveData( aNewData );
685  }
686  else
687  aObj.SetSaveData( rData );
688 
689  bool bAllowMove = (pDPObj != nullptr); // allow re-positioning when editing existing table
690 
691  ScDBDocFunc aFunc( *pDocSh );
692  bool bSuccess = aFunc.DataPilotUpdate(pDPObj, &aObj, true, false, bAllowMove);
693 
694  CursorPosChanged(); // shells may be switched
695 
696  if ( bNewTable )
697  {
698  pDocSh->PostPaintExtras();
699  SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
700  }
701 
702  return bSuccess;
703 }
704 
706 {
707  ScDocShell* pDocSh = GetViewData().GetDocShell();
708  ScDocument& rDoc = pDocSh->GetDocument();
709  ScDPObject* pDPObj = rDoc.GetDPAtCursor( GetViewData().GetCurX(),
710  GetViewData().GetCurY(),
711  GetViewData().GetTabNo() );
712  if ( pDPObj )
713  {
714  ScDBDocFunc aFunc( *pDocSh );
715  aFunc.RemovePivotTable(*pDPObj, true, false);
716  CursorPosChanged(); // shells may be switched
717  }
718  else
719  ErrorMessage(STR_PIVOT_NOTFOUND);
720 }
721 
723 {
724  ScDocShell* pDocSh = GetViewData().GetDocShell();
725  ScDocument& rDoc = GetViewData().GetDocument();
726 
727  ScDPObject* pDPObj = rDoc.GetDPAtCursor( GetViewData().GetCurX(),
728  GetViewData().GetCurY(),
729  GetViewData().GetTabNo() );
730  if (pDPObj)
731  {
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);
736 
737  CursorPosChanged(); // shells may be switched
738  }
739  else
740  ErrorMessage(STR_PIVOT_NOTFOUND);
741 }
742 
744 {
745  ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
746  GetViewData().GetCurY(), GetViewData().GetTabNo() );
747  if ( !pDPObj )
748  return;
749 
750  tools::Long nStartDimension = -1;
751  tools::Long nStartHierarchy = -1;
752  tools::Long nStartLevel = -1;
753 
754  ScRangeListRef xRanges;
755  GetViewData().GetMultiArea( xRanges ); // incl. cursor if nothing is selected
756  size_t nRangeCount = xRanges->size();
757  bool bContinue = true;
758 
759  for (size_t nRangePos=0; nRangePos < nRangeCount && bContinue; nRangePos++)
760  {
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();
767 
768  for (SCROW nRow=nStartRow; nRow<=nEndRow && bContinue; nRow++)
769  for (SCCOL nCol=nStartCol; nCol<=nEndCol && bContinue; nCol++)
770  {
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
775  else
776  {
777  if ( nStartDimension < 0 ) // first member?
778  {
779  nStartDimension = aData.Dimension;
780  nStartHierarchy = aData.Hierarchy;
781  nStartLevel = aData.Level;
782  }
783  if ( aData.Dimension != nStartDimension ||
784  aData.Hierarchy != nStartHierarchy ||
785  aData.Level != nStartLevel )
786  {
787  bContinue = false; // cannot mix dimensions
788  }
789  }
790  if ( bContinue )
791  {
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);
796  }
797  }
798  }
799 
800  rDimension = nStartDimension; // dimension from which the found members came
801  if (!bContinue)
802  rEntries.clear(); // remove all if not valid
803 }
804 
805 bool ScDBFunc::HasSelectionForDateGroup( ScDPNumGroupInfo& rOldInfo, sal_Int32& rParts )
806 {
807  // determine if the date group dialog has to be shown for the current selection
808 
809  bool bFound = false;
810 
811  SCCOL nCurX = GetViewData().GetCurX();
812  SCROW nCurY = GetViewData().GetCurY();
813  SCTAB nTab = GetViewData().GetTabNo();
814  ScDocument& rDoc = GetViewData().GetDocument();
815 
816  ScDPObject* pDPObj = rDoc.GetDPAtCursor( nCurX, nCurY, nTab );
817  if ( pDPObj )
818  {
820  tools::Long nSelectDimension = -1;
821  GetSelectedMemberList( aEntries, nSelectDimension );
822 
823  if (!aEntries.empty())
824  {
825  bool bIsDataLayout;
826  OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
827  OUString aBaseDimName( aDimName );
828 
829  bool bInGroupDim = false;
830  bool bFoundParts = false;
831 
832  ScDPDimensionSaveData* pDimData =
833  const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
834  if ( pDimData )
835  {
836  const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
837  const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( aDimName );
838  if ( pNumGroupDim )
839  {
840  // existing num group dimension
841 
842  if ( pNumGroupDim->GetDatePart() != 0 )
843  {
844  // dimension has date info -> edit settings of this dimension
845  // (parts are collected below)
846 
847  rOldInfo = pNumGroupDim->GetDateInfo();
848  bFound = true;
849  }
850  else if ( pNumGroupDim->GetInfo().mbDateValues )
851  {
852  // Numerical grouping with DateValues flag is used for grouping
853  // of days with a "Number of days" value.
854 
855  rOldInfo = pNumGroupDim->GetInfo();
856  rParts = css::sheet::DataPilotFieldGroupBy::DAYS; // not found in CollectDateParts
857  bFoundParts = true;
858  bFound = true;
859  }
860  bInGroupDim = true;
861  }
862  else if ( pGroupDim )
863  {
864  // existing additional group dimension
865 
866  if ( pGroupDim->GetDatePart() != 0 )
867  {
868  // dimension has date info -> edit settings of this dimension
869  // (parts are collected below)
870 
871  rOldInfo = pGroupDim->GetDateInfo();
872  aBaseDimName = pGroupDim->GetSourceDimName();
873  bFound = true;
874  }
875  bInGroupDim = true;
876  }
877  }
878  if ( bFound && !bFoundParts )
879  {
880  // collect date parts from all group dimensions
881  rParts = pDimData->CollectDateParts( aBaseDimName );
882  }
883  if ( !bFound && !bInGroupDim )
884  {
885  // create new date group dimensions if the selection is a single cell
886  // in a normal dimension with date content
887 
888  ScRange aSelRange;
889  if ( (GetViewData().GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
890  aSelRange.aStart == aSelRange.aEnd )
891  {
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 ) )
896  {
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 )
901  {
902  bFound = true;
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 );
908  }
909  }
910  }
911  }
912  }
913  }
914 
915  return bFound;
916 }
917 
919 {
920  // determine if the numeric group dialog has to be shown for the current selection
921 
922  bool bFound = false;
923 
924  SCCOL nCurX = GetViewData().GetCurX();
925  SCROW nCurY = GetViewData().GetCurY();
926  SCTAB nTab = GetViewData().GetTabNo();
927  ScDocument& rDoc = GetViewData().GetDocument();
928 
929  ScDPObject* pDPObj = rDoc.GetDPAtCursor( nCurX, nCurY, nTab );
930  if ( pDPObj )
931  {
933  tools::Long nSelectDimension = -1;
934  GetSelectedMemberList( aEntries, nSelectDimension );
935 
936  if (!aEntries.empty())
937  {
938  bool bIsDataLayout;
939  OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
940 
941  bool bInGroupDim = false;
942 
943  ScDPDimensionSaveData* pDimData =
944  const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
945  if ( pDimData )
946  {
947  const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
948  if ( pNumGroupDim )
949  {
950  // existing num group dimension
951  // -> edit settings of this dimension
952 
953  rOldInfo = pNumGroupDim->GetInfo();
954  bFound = true;
955  }
956  else if ( pDimData->GetNamedGroupDim( aDimName ) )
957  bInGroupDim = true; // in a group dimension
958  }
959  if ( !bFound && !bInGroupDim )
960  {
961  // create a new num group dimension if the selection is a single cell
962  // in a normal dimension with numeric content
963 
964  ScRange aSelRange;
965  if ( (GetViewData().GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
966  aSelRange.aStart == aSelRange.aEnd )
967  {
968  if ( rDoc.HasValueData( aSelRange.aStart.Col(), aSelRange.aStart.Row(),
969  aSelRange.aStart.Tab() ) )
970  {
971  bFound = true;
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 );
977  }
978  }
979  }
980  }
981  }
982 
983  return bFound;
984 }
985 
986 void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo& rInfo, sal_Int32 nParts )
987 {
988  ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
989  GetViewData().GetCurY(), GetViewData().GetTabNo() );
990  if (!pDPObj)
991  return;
992 
994  tools::Long nSelectDimension = -1;
995  GetSelectedMemberList( aEntries, nSelectDimension );
996 
997  if (aEntries.empty())
998  return;
999 
1000  std::vector<OUString> aDeletedNames;
1001  bool bIsDataLayout;
1002  OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1003 
1004  ScDPSaveData aData( *pDPObj->GetSaveData() );
1005  ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1006 
1007  // find the source dimension name.
1008  OUString aBaseDimName = aDimName;
1009  if( const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName ) )
1010  aBaseDimName = pBaseGroupDim->GetSourceDimName();
1011 
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);
1017 
1018  if ( nParts )
1019  {
1020  // create date group dimensions
1021 
1022  bool bFirst = true;
1023  sal_Int32 nMask = 1;
1024  for (sal_uInt16 nBit=0; nBit<32; nBit++)
1025  {
1026  if ( nParts & nMask )
1027  {
1028  if ( bFirst )
1029  {
1030  // innermost part: create NumGroupDimension (replacing original values)
1031  // Dimension name is left unchanged
1032 
1033  if ( (nParts == sheet::DataPilotFieldGroupBy::DAYS) && (rInfo.mfStep >= 1.0) )
1034  {
1035  // only days, and a step value specified: use numerical grouping
1036  // with DateValues flag, not date grouping
1037 
1038  ScDPNumGroupInfo aNumInfo( rInfo );
1039  aNumInfo.mbDateValues = true;
1040 
1041  ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, aNumInfo );
1042  pDimData->AddNumGroupDimension( aNumGroupDim );
1043  }
1044  else
1045  {
1046  ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, rInfo, nMask );
1047  pDimData->AddNumGroupDimension( aNumGroupDim );
1048  }
1049 
1050  bFirst = false;
1051  }
1052  else
1053  {
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 );
1060 
1061  // set orientation
1062  ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
1063  if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
1064  {
1065  ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aBaseDimName );
1066  pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
1067  aData.SetPosition( pSaveDimension, 0 );
1068  }
1069  }
1070  }
1071  nMask *= 2;
1072  }
1073  }
1074 
1075  // apply changes
1076  ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
1077  pDPObj->SetSaveData( aData );
1078  aFunc.RefreshPivotTableGroups(pDPObj);
1079 
1080  // unmark cell selection
1081  Unmark();
1082 }
1083 
1085 {
1086  ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1087  GetViewData().GetCurY(), GetViewData().GetTabNo() );
1088  if (!pDPObj)
1089  return;
1090 
1092  tools::Long nSelectDimension = -1;
1093  GetSelectedMemberList( aEntries, nSelectDimension );
1094 
1095  if (aEntries.empty())
1096  return;
1097 
1098  bool bIsDataLayout;
1099  OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1100 
1101  ScDPSaveData aData( *pDPObj->GetSaveData() );
1102  ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1103 
1104  ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( aDimName );
1105  if ( pExisting )
1106  {
1107  // modify existing group dimension
1108  pExisting->SetGroupInfo( rInfo );
1109  }
1110  else
1111  {
1112  // create new group dimension
1113  ScDPSaveNumGroupDimension aNumGroupDim( aDimName, rInfo );
1114  pDimData->AddNumGroupDimension( aNumGroupDim );
1115  }
1116 
1117  // apply changes
1118  ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
1119  pDPObj->SetSaveData( aData );
1120  aFunc.RefreshPivotTableGroups(pDPObj);
1121 
1122  // unmark cell selection
1123  Unmark();
1124 }
1125 
1127 {
1128  ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1129  GetViewData().GetCurY(), GetViewData().GetTabNo() );
1130  if (!pDPObj)
1131  return;
1132 
1134  tools::Long nSelectDimension = -1;
1135  GetSelectedMemberList( aEntries, nSelectDimension );
1136 
1137  if (aEntries.empty())
1138  return;
1139 
1140  bool bIsDataLayout;
1141  OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1142 
1143  ScDPSaveData aData( *pDPObj->GetSaveData() );
1144  ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
1145 
1146  // find original base
1147  OUString aBaseDimName = aDimName;
1148  const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
1149  if ( pBaseGroupDim )
1150  {
1151  // any entry's SourceDimName is the original base
1152  aBaseDimName = pBaseGroupDim->GetSourceDimName();
1153  }
1154 
1155  // find existing group dimension
1156  // (using the selected dim, can be intermediate group dim)
1157  ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
1158 
1159  // remove the selected items from their groups
1160  // (empty groups are removed, too)
1161  if ( pGroupDimension )
1162  {
1163  for (const OUString& aEntryName : aEntries)
1164  {
1165  if ( pBaseGroupDim )
1166  {
1167  // for each selected (intermediate) group, remove all its items
1168  // (same logic as for adding, below)
1169  const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
1170  if ( pBaseGroup )
1171  pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements
1172  else
1173  pGroupDimension->RemoveFromGroups( aEntryName );
1174  }
1175  else
1176  pGroupDimension->RemoveFromGroups( aEntryName );
1177  }
1178  }
1179 
1180  std::unique_ptr<ScDPSaveGroupDimension> pNewGroupDim;
1181  if ( !pGroupDimension )
1182  {
1183  // create a new group dimension
1184  OUString aGroupDimName =
1185  pDimData->CreateGroupDimName(aBaseDimName, *pDPObj, false, nullptr);
1186  pNewGroupDim.reset(new ScDPSaveGroupDimension( aBaseDimName, aGroupDimName ));
1187 
1188  pGroupDimension = pNewGroupDim.get(); // make changes to the new dim if none existed
1189 
1190  if ( pBaseGroupDim )
1191  {
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
1195  // to find).
1198 
1199  tools::Long nGroupCount = pBaseGroupDim->GetGroupCount();
1200  for ( tools::Long nGroup = 0; nGroup < nGroupCount; nGroup++ )
1201  {
1202  const ScDPSaveGroupItem& rBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
1203 
1204  if (!aEntries.count(rBaseGroup.GetGroupName()))
1205  {
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 );
1210  }
1211  }
1212  }
1213  }
1214  OUString aGroupDimName = pGroupDimension->GetGroupDimName();
1215 
1216  OUString aGroupName = pGroupDimension->CreateGroupName(ScResId(STR_PIVOT_GROUP));
1217  ScDPSaveGroupItem aGroup( aGroupName );
1218  for (const OUString& aEntryName : aEntries)
1219  {
1220  if ( pBaseGroupDim )
1221  {
1222  // for each selected (intermediate) group, add all its items
1223  const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
1224  if ( pBaseGroup )
1225  aGroup.AddElementsFromGroup( *pBaseGroup );
1226  else
1227  aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself
1228  }
1229  else
1230  aGroup.AddElement( aEntryName ); // no group dimension, add all items directly
1231  }
1232 
1233  pGroupDimension->AddGroupItem( aGroup );
1234 
1235  if ( pNewGroupDim )
1236  {
1237  pDimData->AddGroupDimension( *pNewGroupDim );
1238  pNewGroupDim.reset(); // AddGroupDimension copies the object
1239  // don't access pGroupDimension after here
1240  }
1241  pGroupDimension = nullptr;
1242 
1243  // set orientation
1244  ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
1245  if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
1246  {
1247  ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aDimName );
1248  pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
1249  aData.SetPosition( pSaveDimension, 0 );
1250  }
1251 
1252  // apply changes
1253  ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
1254  pDPObj->SetSaveData( aData );
1255  aFunc.RefreshPivotTableGroups(pDPObj);
1256 
1257  // unmark cell selection
1258  Unmark();
1259 }
1260 
1262 {
1263  ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1264  GetViewData().GetCurY(), GetViewData().GetTabNo() );
1265  if (!pDPObj)
1266  return;
1267 
1269  tools::Long nSelectDimension = -1;
1270  GetSelectedMemberList( aEntries, nSelectDimension );
1271 
1272  if (aEntries.empty())
1273  return;
1274 
1275  bool bIsDataLayout;
1276  OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1277 
1278  ScDPSaveData aData( *pDPObj->GetSaveData() );
1279  if (!aData.GetExistingDimensionData())
1280  // There is nothing to ungroup.
1281  return;
1282 
1283  ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1284 
1285  ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
1286  const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
1287  if ( ( pGroupDim && pGroupDim->GetDatePart() != 0 ) ||
1288  ( pNumGroupDim && pNumGroupDim->GetDatePart() != 0 ) )
1289  {
1290  // Date grouping: need to remove all affected group dimensions.
1291  // This is done using DateGroupDataPilot with nParts=0.
1292 
1293  DateGroupDataPilot( ScDPNumGroupInfo(), 0 );
1294  return;
1295  }
1296 
1297  if ( pGroupDim )
1298  {
1299  for (const auto& rEntry : aEntries)
1300  pGroupDim->RemoveGroup(rEntry);
1301 
1302  // remove group dimension if empty
1303  bool bEmptyDim = pGroupDim->IsEmpty();
1304  if ( !bEmptyDim )
1305  {
1306  // If all remaining groups in the dimension aren't shown, remove
1307  // the dimension too, as if it was completely empty.
1308  ScDPUniqueStringSet aVisibleEntries;
1309  pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
1310  bEmptyDim = pGroupDim->HasOnlyHidden( aVisibleEntries );
1311  }
1312  if ( bEmptyDim )
1313  {
1314  pDimData->RemoveGroupDimension( aDimName ); // pGroupDim is deleted
1315 
1316  // also remove SaveData settings for the dimension that no longer exists
1317  aData.RemoveDimensionByName( aDimName );
1318  }
1319  }
1320  else if ( pNumGroupDim )
1321  {
1322  // remove the numerical grouping
1323  pDimData->RemoveNumGroupDimension( aDimName );
1324  // SaveData settings can remain unchanged - the same dimension still exists
1325  }
1326 
1327  // apply changes
1328  ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
1329  pDPObj->SetSaveData( aData );
1330  aFunc.RefreshPivotTableGroups(pDPObj);
1331 
1332  // unmark cell selection
1333  Unmark();
1334 }
1335 
1336 static OUString lcl_replaceMemberNameInSubtotal(const OUString& rSubtotal, std::u16string_view rMemberName)
1337 {
1338  sal_Int32 n = rSubtotal.getLength();
1339  const sal_Unicode* p = rSubtotal.getStr();
1340  OUStringBuffer aBuf, aWordBuf;
1341  for (sal_Int32 i = 0; i < n; ++i)
1342  {
1343  sal_Unicode c = p[i];
1344  if (c == ' ')
1345  {
1346  OUString aWord = aWordBuf.makeStringAndClear();
1347  if (aWord == rMemberName)
1348  aBuf.append('?');
1349  else
1350  aBuf.append(aWord);
1351  aBuf.append(c);
1352  }
1353  else if (c == '\\')
1354  {
1355  // Escape a backslash character.
1356  aWordBuf.append(c);
1357  aWordBuf.append(c);
1358  }
1359  else if (c == '?')
1360  {
1361  // A literal '?' must be escaped with a backslash ('\');
1362  aWordBuf.append('\\');
1363  aWordBuf.append(c);
1364  }
1365  else
1366  aWordBuf.append(c);
1367  }
1368 
1369  if (!aWordBuf.isEmpty())
1370  {
1371  OUString aWord = aWordBuf.makeStringAndClear();
1372  if (aWord == rMemberName)
1373  aBuf.append('?');
1374  else
1375  aBuf.append(aWord);
1376  }
1377 
1378  return aBuf.makeStringAndClear();
1379 }
1380 
1381 void ScDBFunc::DataPilotInput( const ScAddress& rPos, const OUString& rString )
1382 {
1383  using namespace ::com::sun::star::sheet;
1384 
1385  ScDocument& rDoc = GetViewData().GetDocument();
1386  ScDPObject* pDPObj = rDoc.GetDPAtCursor( rPos.Col(), rPos.Row(), rPos.Tab() );
1387  if (!pDPObj)
1388  return;
1389 
1390  OUString aOldText = rDoc.GetString(rPos.Col(), rPos.Row(), rPos.Tab());
1391 
1392  if ( aOldText == rString )
1393  {
1394  // nothing to do: silently exit
1395  return;
1396  }
1397 
1398  const char* pErrorId = nullptr;
1399 
1400  pDPObj->BuildAllDimensionMembers();
1401  ScDPSaveData aData( *pDPObj->GetSaveData() );
1402  bool bChange = false;
1403  bool bNeedReloadGroups = false;
1404 
1405  DataPilotFieldOrientation nOrient = DataPilotFieldOrientation_HIDDEN;
1406  tools::Long nField = pDPObj->GetHeaderDim( rPos, nOrient );
1407  if ( nField >= 0 )
1408  {
1409  // changing a field title
1410  if ( aData.GetExistingDimensionData() )
1411  {
1412  // only group dimensions can be renamed
1413 
1414  ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1415  ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aOldText );
1416  if ( pGroupDim )
1417  {
1418  // valid name: not empty, no existing dimension (group or other)
1419  if (!rString.isEmpty() && !pDPObj->IsDimNameInUse(rString))
1420  {
1421  pGroupDim->Rename( rString );
1422 
1423  // also rename in SaveData to preserve the field settings
1424  ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aOldText );
1425  pSaveDim->SetName( rString );
1426 
1427  bChange = true;
1428  }
1429  else
1430  pErrorId = STR_INVALIDNAME;
1431  }
1432  }
1433  else if (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW)
1434  {
1435  bool bDataLayout = false;
1436  OUString aDimName = pDPObj->GetDimName(nField, bDataLayout);
1437  ScDPSaveDimension* pDim = bDataLayout ? aData.GetDataLayoutDimension() : aData.GetDimensionByName(aDimName);
1438  if (pDim)
1439  {
1440  if (!rString.isEmpty())
1441  {
1442  if (rString.equalsIgnoreAsciiCase(aDimName))
1443  {
1444  pDim->RemoveLayoutName();
1445  bChange = true;
1446  }
1447  else if (!pDPObj->IsDimNameInUse(rString))
1448  {
1449  pDim->SetLayoutName(rString);
1450  bChange = true;
1451  }
1452  else
1453  pErrorId = STR_INVALIDNAME;
1454  }
1455  else
1456  pErrorId = STR_INVALIDNAME;
1457  }
1458  }
1459  }
1460  else if (pDPObj->IsDataDescriptionCell(rPos))
1461  {
1462  // There is only one data dimension.
1463  ScDPSaveDimension* pDim = aData.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA);
1464  if (pDim)
1465  {
1466  if (!rString.isEmpty())
1467  {
1468  if (pDim->GetName().equalsIgnoreAsciiCase(rString))
1469  {
1470  pDim->RemoveLayoutName();
1471  bChange = true;
1472  }
1473  else if (!pDPObj->IsDimNameInUse(rString))
1474  {
1475  pDim->SetLayoutName(rString);
1476  bChange = true;
1477  }
1478  else
1479  pErrorId = STR_INVALIDNAME;
1480  }
1481  else
1482  pErrorId = STR_INVALIDNAME;
1483  }
1484  }
1485  else
1486  {
1487  // This is not a field header.
1488  sheet::DataPilotTableHeaderData aPosData;
1489  pDPObj->GetHeaderPositionData(rPos, aPosData);
1490 
1491  if ((aPosData.Flags & MemberResultFlags::HASMEMBER) && !aOldText.isEmpty())
1492  {
1493  if ( aData.GetExistingDimensionData() && !(aPosData.Flags & MemberResultFlags::SUBTOTAL))
1494  {
1495  bool bIsDataLayout;
1496  OUString aDimName = pDPObj->GetDimName( aPosData.Dimension, bIsDataLayout );
1497 
1498  ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
1499  ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
1500  if ( pGroupDim )
1501  {
1502  // valid name: not empty, no existing group in this dimension
1504  if (!rString.isEmpty() && !pGroupDim->GetNamedGroup(rString))
1505  {
1506  ScDPSaveGroupItem* pGroup = pGroupDim->GetNamedGroupAcc( aOldText );
1507  if ( pGroup )
1508  pGroup->Rename( rString ); // rename the existing group
1509  else
1510  {
1511  // create a new group to replace the automatic group
1512  ScDPSaveGroupItem aGroup( rString );
1513  aGroup.AddElement( aOldText );
1514  pGroupDim->AddGroupItem( aGroup );
1515  }
1516 
1517  // in both cases also adjust savedata, to preserve member settings (show details)
1518  ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aDimName );
1519  ScDPSaveMember* pSaveMember = pSaveDim->GetExistingMemberByName( aOldText );
1520  if ( pSaveMember )
1521  pSaveMember->SetName( rString );
1522 
1523  bChange = true;
1524  bNeedReloadGroups = true;
1525  }
1526  else
1527  pErrorId = STR_INVALIDNAME;
1528  }
1529  }
1530  else if (aPosData.Flags & MemberResultFlags::GRANDTOTAL)
1531  {
1532  aData.SetGrandTotalName(rString);
1533  bChange = true;
1534  }
1535  else if (aPosData.Dimension >= 0 && !aPosData.MemberName.isEmpty())
1536  {
1537  bool bDataLayout = false;
1538  OUString aDimName = pDPObj->GetDimName(static_cast<tools::Long>(aPosData.Dimension), bDataLayout);
1539  if (bDataLayout)
1540  {
1541  // data dimension
1542  do
1543  {
1544  if (aPosData.Flags & MemberResultFlags::SUBTOTAL)
1545  break;
1546 
1547  ScDPSaveDimension* pDim = aData.GetDimensionByName(aPosData.MemberName);
1548  if (!pDim)
1549  break;
1550 
1551  if (rString.isEmpty())
1552  {
1553  pErrorId = STR_INVALIDNAME;
1554  break;
1555  }
1556 
1557  if (aPosData.MemberName.equalsIgnoreAsciiCase(rString))
1558  {
1559  pDim->RemoveLayoutName();
1560  bChange = true;
1561  }
1562  else if (!pDPObj->IsDimNameInUse(rString))
1563  {
1564  pDim->SetLayoutName(rString);
1565  bChange = true;
1566  }
1567  else
1568  pErrorId = STR_INVALIDNAME;
1569  }
1570  while (false);
1571  }
1572  else
1573  {
1574  // field member
1575  do
1576  {
1577  ScDPSaveDimension* pDim = aData.GetDimensionByName(aDimName);
1578  if (!pDim)
1579  break;
1580 
1581  ScDPSaveMember* pMem = pDim->GetExistingMemberByName(aPosData.MemberName);
1582  if (!pMem)
1583  break;
1584 
1585  if (aPosData.Flags & MemberResultFlags::SUBTOTAL)
1586  {
1587  // Change subtotal only when the table has one data dimension.
1588  if (aData.GetDataDimensionCount() > 1)
1589  break;
1590 
1591  // display name for subtotal is allowed only if the subtotal type is 'Automatic'.
1592  if (pDim->GetSubTotalsCount() != 1)
1593  break;
1594 
1595  if (pDim->GetSubTotalFunc(0) != ScGeneralFunction::AUTO)
1596  break;
1597 
1598  const std::optional<OUString> & pLayoutName = pMem->GetLayoutName();
1599  OUString aMemberName;
1600  if (pLayoutName)
1601  aMemberName = *pLayoutName;
1602  else
1603  aMemberName = aPosData.MemberName;
1604 
1605  OUString aNew = lcl_replaceMemberNameInSubtotal(rString, aMemberName);
1606  pDim->SetSubtotalName(aNew);
1607  bChange = true;
1608  }
1609  else
1610  {
1611  // Check to make sure the member name isn't
1612  // already used.
1613  if (!rString.isEmpty())
1614  {
1615  if (rString.equalsIgnoreAsciiCase(pMem->GetName()))
1616  {
1617  pMem->RemoveLayoutName();
1618  bChange = true;
1619  }
1620  else if (!pDim->IsMemberNameInUse(rString))
1621  {
1622  pMem->SetLayoutName(rString);
1623  bChange = true;
1624  }
1625  else
1626  pErrorId = STR_INVALIDNAME;
1627  }
1628  else
1629  pErrorId = STR_INVALIDNAME;
1630  }
1631  }
1632  while (false);
1633  }
1634  }
1635  }
1636  }
1637 
1638  if ( bChange )
1639  {
1640  // apply changes
1641  ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
1642  pDPObj->SetSaveData( aData );
1643  if (bNeedReloadGroups)
1644  {
1645  ScDPCollection* pDPs = rDoc.GetDPCollection();
1646  if (pDPs)
1647  {
1649  // tdf#111305: Reload groups in cache after modifications.
1650  pDPs->ReloadGroupsInCache(pDPObj, aRefs);
1651  } // pDPs
1652  } // bNeedReloadGroups
1653  aFunc.UpdatePivotTable(*pDPObj, true, false);
1654  }
1655  else
1656  {
1657  if (!pErrorId)
1658  pErrorId = STR_ERR_DATAPILOT_INPUT;
1659  ErrorMessage(pErrorId);
1660  }
1661 }
1662 
1663 static void lcl_MoveToEnd( ScDPSaveDimension& rDim, const OUString& rItemName )
1664 {
1665  std::unique_ptr<ScDPSaveMember> pNewMember;
1666  const ScDPSaveMember* pOldMember = rDim.GetExistingMemberByName( rItemName );
1667  if ( pOldMember )
1668  pNewMember.reset(new ScDPSaveMember( *pOldMember ));
1669  else
1670  pNewMember.reset(new ScDPSaveMember( rItemName ));
1671  rDim.AddMember( std::move(pNewMember) );
1672  // AddMember takes ownership of the new pointer,
1673  // puts it to the end of the list even if it was in the list before.
1674 }
1675 
1676 namespace {
1677 
1678 struct ScOUStringCollate
1679 {
1680  CollatorWrapper* mpCollator;
1681 
1682  explicit ScOUStringCollate(CollatorWrapper* pColl) : mpCollator(pColl) {}
1683 
1684  bool operator()(const OUString& rStr1, const OUString& rStr2) const
1685  {
1686  return ( mpCollator->compareString(rStr1, rStr2) < 0 );
1687  }
1688 };
1689 
1690 }
1691 
1692 void ScDBFunc::DataPilotSort(ScDPObject* pDPObj, tools::Long nDimIndex, bool bAscending, const sal_uInt16* pUserListId)
1693 {
1694  if (!pDPObj)
1695  return;
1696 
1697  // We need to run this to get all members later.
1698  if ( pUserListId )
1699  pDPObj->BuildAllDimensionMembers();
1700 
1701  if (nDimIndex < 0)
1702  // Invalid dimension index. Bail out.
1703  return;
1704 
1705  ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1706  if (!pSaveData)
1707  return;
1708 
1709  ScDPSaveData aNewSaveData(*pSaveData);
1710  bool bDataLayout;
1711  OUString aDimName = pDPObj->GetDimName(nDimIndex, bDataLayout);
1712  ScDPSaveDimension* pSaveDim = aNewSaveData.GetDimensionByName(aDimName);
1713  if (!pSaveDim)
1714  return;
1715 
1716  // manual evaluation of sort order is only needed if a user list id is given
1717  if ( pUserListId )
1718  {
1719  typedef ScDPSaveDimension::MemberList MemList;
1720  const MemList& rDimMembers = pSaveDim->GetMembers();
1721  vector<OUString> aMembers;
1722  std::unordered_set<OUString> aMemberSet;
1723  size_t nMemberCount = 0;
1724  for (ScDPSaveMember* pMem : rDimMembers)
1725  {
1726  aMembers.push_back(pMem->GetName());
1727  aMemberSet.insert(pMem->GetName());
1728  ++nMemberCount;
1729  }
1730 
1731  // Sort the member list in ascending order.
1732  ScOUStringCollate aCollate( ScGlobal::GetCollator() );
1733  std::stable_sort(aMembers.begin(), aMembers.end(), aCollate);
1734 
1735  // Collect and rank those custom sort strings that also exist in the member name list.
1736 
1737  typedef std::unordered_map<OUString, sal_uInt16> UserSortMap;
1738  UserSortMap aSubStrs;
1739  sal_uInt16 nSubCount = 0;
1740  ScUserList* pUserList = ScGlobal::GetUserList();
1741  if (!pUserList)
1742  return;
1743 
1744  {
1745  size_t n = pUserList->size();
1746  if (!n || *pUserListId >= static_cast<sal_uInt16>(n))
1747  return;
1748  }
1749 
1750  const ScUserListData& rData = (*pUserList)[*pUserListId];
1751  sal_uInt16 n = rData.GetSubCount();
1752  for (sal_uInt16 i = 0; i < n; ++i)
1753  {
1754  OUString aSub = rData.GetSubStr(i);
1755  if (!aMemberSet.count(aSub))
1756  // This string doesn't exist in the member name set. Don't add this.
1757  continue;
1758 
1759  aSubStrs.emplace(aSub, nSubCount++);
1760  }
1761 
1762  // Rank all members.
1763 
1764  vector<OUString> aRankedNames(nMemberCount);
1765  sal_uInt16 nCurStrId = 0;
1766  for (auto const& aMemberName : aMembers)
1767  {
1768  sal_uInt16 nRank = 0;
1769  UserSortMap::const_iterator itrSub = aSubStrs.find(aMemberName);
1770  if (itrSub == aSubStrs.end())
1771  nRank = nSubCount + nCurStrId++;
1772  else
1773  nRank = itrSub->second;
1774 
1775  if (!bAscending)
1776  nRank = static_cast< sal_uInt16 >( nMemberCount - nRank - 1 );
1777 
1778  aRankedNames[nRank] = aMemberName;
1779  }
1780 
1781  // Re-order ScDPSaveMember instances with the new ranks.
1782  for (auto const& aRankedName : aRankedNames)
1783  {
1784  const ScDPSaveMember* pOldMem = pSaveDim->GetExistingMemberByName(aRankedName);
1785  if (!pOldMem)
1786  // All members are supposed to be present.
1787  continue;
1788 
1789  pSaveDim->AddMember(std::unique_ptr<ScDPSaveMember>(new ScDPSaveMember(*pOldMem)));
1790  }
1791 
1792  // Set the sorting mode to manual for now. We may introduce a new sorting
1793  // mode later on.
1794 
1795  sheet::DataPilotFieldSortInfo aSortInfo;
1796  aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
1797  pSaveDim->SetSortInfo(&aSortInfo);
1798  }
1799  else
1800  {
1801  // without user list id, just apply sorting mode
1802 
1803  sheet::DataPilotFieldSortInfo aSortInfo;
1804  aSortInfo.Mode = sheet::DataPilotFieldSortMode::NAME;
1805  aSortInfo.IsAscending = bAscending;
1806  pSaveDim->SetSortInfo(&aSortInfo);
1807  }
1808 
1809  // Update the datapilot with the newly sorted field members.
1810 
1811  std::unique_ptr<ScDPObject> pNewObj(new ScDPObject(*pDPObj));
1812  pNewObj->SetSaveData(aNewSaveData);
1813  ScDBDocFunc aFunc(*GetViewData().GetDocShell());
1814 
1815  aFunc.DataPilotUpdate(pDPObj, pNewObj.get(), true, false);
1816 }
1817 
1818 bool ScDBFunc::DataPilotMove( const ScRange& rSource, const ScAddress& rDest )
1819 {
1820  bool bRet = false;
1821  ScDocument& rDoc = GetViewData().GetDocument();
1822  ScDPObject* pDPObj = rDoc.GetDPAtCursor( rSource.aStart.Col(), rSource.aStart.Row(), rSource.aStart.Tab() );
1823  if ( pDPObj && pDPObj == rDoc.GetDPAtCursor( rDest.Col(), rDest.Row(), rDest.Tab() ) )
1824  {
1825  sheet::DataPilotTableHeaderData aDestData;
1826  pDPObj->GetHeaderPositionData( rDest, aDestData );
1827  bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
1828 
1829  // look through the source range
1830  std::unordered_set< OUString > aMembersSet; // for lookup
1831  std::vector< OUString > aMembersVector; // members in original order, for inserting
1832  aMembersVector.reserve( std::max( static_cast<SCSIZE>( rSource.aEnd.Col() - rSource.aStart.Col() + 1 ),
1833  static_cast<SCSIZE>( rSource.aEnd.Row() - rSource.aStart.Row() + 1 ) ) );
1834  for (SCROW nRow = rSource.aStart.Row(); bValid && nRow <= rSource.aEnd.Row(); ++nRow )
1835  for (SCCOL nCol = rSource.aStart.Col(); bValid && nCol <= rSource.aEnd.Col(); ++nCol )
1836  {
1837  sheet::DataPilotTableHeaderData aSourceData;
1838  pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, rSource.aStart.Tab() ), aSourceData );
1839  if ( aSourceData.Dimension == aDestData.Dimension && !aSourceData.MemberName.isEmpty() )
1840  {
1841  if ( aMembersSet.insert( aSourceData.MemberName ).second )
1842  {
1843  aMembersVector.push_back( aSourceData.MemberName );
1844  }
1845  // duplicates are ignored
1846  }
1847  else
1848  bValid = false; // empty (subtotal) or different field
1849  }
1850 
1851  if ( bValid )
1852  {
1853  bool bIsDataLayout;
1854  OUString aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
1855  if ( !bIsDataLayout )
1856  {
1857  ScDPSaveData aData( *pDPObj->GetSaveData() );
1858  ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
1859 
1860  // get all member names in source order
1861  uno::Sequence<OUString> aMemberNames;
1862  pDPObj->GetMemberNames( aDestData.Dimension, aMemberNames );
1863 
1864  bool bInserted = false;
1865 
1866  for (const OUString& aMemberStr : std::as_const(aMemberNames))
1867  {
1868  if ( !bInserted && aMemberStr == aDestData.MemberName )
1869  {
1870  // insert dragged items before this item
1871  for ( const auto& rMember : aMembersVector )
1872  lcl_MoveToEnd( *pDim, rMember );
1873  bInserted = true;
1874  }
1875 
1876  if ( aMembersSet.find( aMemberStr ) == aMembersSet.end() ) // skip dragged items
1877  lcl_MoveToEnd( *pDim, aMemberStr );
1878  }
1879  // insert dragged item at end if dest wasn't found (for example, empty)
1880  if ( !bInserted )
1881  for ( const auto& rMember : aMembersVector )
1882  lcl_MoveToEnd( *pDim, rMember );
1883 
1884  // Items that were in SaveData, but not in the source, end up at the start of the list.
1885 
1886  // set flag for manual sorting
1887  sheet::DataPilotFieldSortInfo aSortInfo;
1888  aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
1889  pDim->SetSortInfo( &aSortInfo );
1890 
1891  // apply changes
1892  ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
1893  std::unique_ptr<ScDPObject> pNewObj(new ScDPObject( *pDPObj ));
1894  pNewObj->SetSaveData( aData );
1895  aFunc.DataPilotUpdate( pDPObj, pNewObj.get(), true, false );
1896  pNewObj.reset();
1897 
1898  Unmark(); // entry was moved - no use in leaving the old cell selected
1899 
1900  bRet = true;
1901  }
1902  }
1903  }
1904 
1905  return bRet;
1906 }
1907 
1908 bool ScDBFunc::HasSelectionForDrillDown( css::sheet::DataPilotFieldOrientation& rOrientation )
1909 {
1910  bool bRet = false;
1911 
1912  ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1913  GetViewData().GetCurY(), GetViewData().GetTabNo() );
1914  if ( pDPObj )
1915  {
1917  tools::Long nSelectDimension = -1;
1918  GetSelectedMemberList( aEntries, nSelectDimension );
1919 
1920  if (!aEntries.empty())
1921  {
1922  bool bIsDataLayout;
1923  OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1924  if ( !bIsDataLayout )
1925  {
1926  ScDPSaveData* pSaveData = pDPObj->GetSaveData();
1927  ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName( aDimName );
1928  if ( pDim )
1929  {
1930  css::sheet::DataPilotFieldOrientation nDimOrient = pDim->GetOrientation();
1931  ScDPSaveDimension* pInner = pSaveData->GetInnermostDimension( nDimOrient );
1932  if ( pDim == pInner )
1933  {
1934  rOrientation = nDimOrient;
1935  bRet = true;
1936  }
1937  }
1938  }
1939  }
1940  }
1941 
1942  return bRet;
1943 }
1944 
1945 void ScDBFunc::SetDataPilotDetails(bool bShow, const OUString* pNewDimensionName)
1946 {
1947  ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
1948  GetViewData().GetCurY(), GetViewData().GetTabNo() );
1949  if ( !pDPObj )
1950  return;
1951 
1953  tools::Long nSelectDimension = -1;
1954  GetSelectedMemberList( aEntries, nSelectDimension );
1955 
1956  if (aEntries.empty())
1957  return;
1958 
1959  bool bIsDataLayout;
1960  OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
1961  if ( bIsDataLayout )
1962  return;
1963 
1964  ScDPSaveData aData( *pDPObj->GetSaveData() );
1965  ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
1966 
1967  if ( bShow && pNewDimensionName )
1968  {
1969  // add the new dimension with the same orientation, at the end
1970 
1971  ScDPSaveDimension* pNewDim = aData.GetDimensionByName( *pNewDimensionName );
1972  ScDPSaveDimension* pDuplicated = nullptr;
1973  if ( pNewDim->GetOrientation() == sheet::DataPilotFieldOrientation_DATA )
1974  {
1975  // Need to duplicate the dimension, create column/row in addition to data:
1976  // The duplicated dimension inherits the existing settings, pNewDim is modified below.
1977  pDuplicated = aData.DuplicateDimension( *pNewDimensionName );
1978  }
1979 
1980  css::sheet::DataPilotFieldOrientation nOrientation = pDim->GetOrientation();
1981  pNewDim->SetOrientation( nOrientation );
1982 
1983  tools::Long nPosition = LONG_MAX;
1984  aData.SetPosition( pNewDim, nPosition );
1985 
1986  ScDPSaveDimension* pDataLayout = aData.GetDataLayoutDimension();
1987  if ( pDataLayout->GetOrientation() == nOrientation &&
1988  aData.GetDataDimensionCount() <= 1 )
1989  {
1990  // If there is only one data dimension, the data layout dimension
1991  // must still be the last one in its orientation.
1992  aData.SetPosition( pDataLayout, nPosition );
1993  }
1994 
1995  if ( pDuplicated )
1996  {
1997  // The duplicated (data) dimension needs to be behind the original dimension
1998  aData.SetPosition( pDuplicated, nPosition );
1999  }
2000 
2001  // Hide details for all visible members (selected are changed below).
2003 
2004  ScDPUniqueStringSet aVisibleEntries;
2005  pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
2006 
2007  for (const OUString& aVisName : aVisibleEntries)
2008  {
2009  ScDPSaveMember* pMember = pDim->GetMemberByName( aVisName );
2010  pMember->SetShowDetails( false );
2011  }
2012  }
2013 
2014  for (const auto& rEntry : aEntries)
2015  {
2016  ScDPSaveMember* pMember = pDim->GetMemberByName(rEntry);
2017  pMember->SetShowDetails( bShow );
2018  }
2019 
2020  // apply changes
2021  ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
2022  std::unique_ptr<ScDPObject> pNewObj(new ScDPObject( *pDPObj ));
2023  pNewObj->SetSaveData( aData );
2024  aFunc.DataPilotUpdate( pDPObj, pNewObj.get(), true, false );
2025  pNewObj.reset();
2026 
2027  // unmark cell selection
2028  Unmark();
2029 }
2030 
2031 void ScDBFunc::ShowDataPilotSourceData( ScDPObject& rDPObj, const Sequence<sheet::DataPilotFieldFilter>& rFilters )
2032 {
2033  ScDocument& rDoc = GetViewData().GetDocument();
2034  if (rDoc.GetDocumentShell()->IsReadOnly())
2035  {
2036  ErrorMessage(STR_READONLYERR);
2037  return;
2038  }
2039 
2040  Reference<sheet::XDimensionsSupplier> xDimSupplier = rDPObj.GetSource();
2041  Reference<container::XNameAccess> xDims = xDimSupplier->getDimensions();
2042  Reference<sheet::XDrillDownDataSupplier> xDDSupplier(xDimSupplier, UNO_QUERY);
2043  if (!xDDSupplier.is())
2044  return;
2045 
2046  Sequence< Sequence<Any> > aTabData = xDDSupplier->getDrillDownData(rFilters);
2047  sal_Int32 nRowSize = aTabData.getLength();
2048  if (nRowSize <= 1)
2049  // There is no data to show. Bail out.
2050  return;
2051 
2052  SCCOL nColSize = aTabData[0].getLength();
2053 
2054  SCTAB nNewTab = GetViewData().GetTabNo();
2055 
2057  pInsDoc->ResetClip( &rDoc, nNewTab );
2058  for (SCROW nRow = 0; nRow < nRowSize; ++nRow)
2059  {
2060  for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
2061  {
2062  const Any& rAny = aTabData[nRow][nCol];
2063  OUString aStr;
2064  double fVal;
2065  if (rAny >>= aStr)
2066  {
2067  pInsDoc->SetString(ScAddress(nCol,nRow,nNewTab), aStr);
2068  }
2069  else if (rAny >>= fVal)
2070  pInsDoc->SetValue(nCol, nRow, nNewTab, fVal);
2071  }
2072  }
2073 
2074  // set number format (important for dates)
2075  for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
2076  {
2077  OUString aStr;
2078  if (!(aTabData[0][nCol] >>= aStr))
2079  continue;
2080 
2081  Reference<XPropertySet> xPropSet(xDims->getByName(aStr), UNO_QUERY);
2082  if (!xPropSet.is())
2083  continue;
2084 
2085  Any any = xPropSet->getPropertyValue( SC_UNO_DP_NUMBERFO );
2086  sal_Int32 nNumFmt = 0;
2087  if (!(any >>= nNumFmt))
2088  continue;
2089 
2090  ScPatternAttr aPattern( pInsDoc->GetPool() );
2091  aPattern.GetItemSet().Put( SfxUInt32Item(ATTR_VALUE_FORMAT, static_cast<sal_uInt32>(nNumFmt)) );
2092  pInsDoc->ApplyPatternAreaTab(nCol, 1, nCol, nRowSize-1, nNewTab, aPattern);
2093  }
2094 
2095  SCCOL nEndCol = 0;
2096  SCROW nEndRow = 0;
2097  pInsDoc->GetCellArea( nNewTab, nEndCol, nEndRow );
2098  pInsDoc->SetClipArea( ScRange( 0, 0, nNewTab, nEndCol, nEndRow, nNewTab ) );
2099 
2100  SfxUndoManager* pMgr = GetViewData().GetDocShell()->GetUndoManager();
2101  OUString aUndo = ScResId( STR_UNDO_DOOUTLINE );
2102  pMgr->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
2103 
2104  OUString aNewTabName;
2105  rDoc.CreateValidTabName(aNewTabName);
2106  if ( InsertTable(aNewTabName, nNewTab) )
2107  PasteFromClip( InsertDeleteFlags::ALL, pInsDoc.get() );
2108 
2109  pMgr->LeaveListAction();
2110 }
2111 
2112 // repeat data base operations (sorting, filtering, subtotals)
2113 
2114 void ScDBFunc::RepeatDB( bool bRecord )
2115 {
2116  SCCOL nCurX = GetViewData().GetCurX();
2117  SCROW nCurY = GetViewData().GetCurY();
2118  SCTAB nTab = GetViewData().GetTabNo();
2119  ScDocument& rDoc = GetViewData().GetDocument();
2120  ScDBData* pDBData = GetDBData();
2121  if (bRecord && !rDoc.IsUndoEnabled())
2122  bRecord = false;
2123 
2124  ScQueryParam aQueryParam;
2125  pDBData->GetQueryParam( aQueryParam );
2126  bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
2127 
2128  ScSortParam aSortParam;
2129  pDBData->GetSortParam( aSortParam );
2130  bool bSort = aSortParam.maKeyState[0].bDoSort;
2131 
2132  ScSubTotalParam aSubTotalParam;
2133  pDBData->GetSubTotalParam( aSubTotalParam );
2134  bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
2135 
2136  if ( bQuery || bSort || bSubTotal )
2137  {
2138  bool bQuerySize = false;
2139  ScRange aOldQuery;
2140  ScRange aNewQuery;
2141  if (bQuery && !aQueryParam.bInplace)
2142  {
2143  ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
2144  aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
2145  if (pDest && pDest->IsDoSize())
2146  {
2147  pDest->GetArea( aOldQuery );
2148  bQuerySize = true;
2149  }
2150  }
2151 
2152  SCTAB nDummy;
2153  SCCOL nStartCol;
2154  SCROW nStartRow;
2155  SCCOL nEndCol;
2156  SCROW nEndRow;
2157  pDBData->GetArea( nDummy, nStartCol, nStartRow, nEndCol, nEndRow );
2158 
2160 
2161  ScDocumentUniquePtr pUndoDoc;
2162  std::unique_ptr<ScOutlineTable> pUndoTab;
2163  std::unique_ptr<ScRangeName> pUndoRange;
2164  std::unique_ptr<ScDBCollection> pUndoDB;
2165 
2166  if (bRecord)
2167  {
2168  SCTAB nTabCount = rDoc.GetTableCount();
2169  pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
2170  ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
2171  if (pTable)
2172  {
2173  pUndoTab.reset(new ScOutlineTable( *pTable ));
2174 
2175  SCCOLROW nOutStartCol; // row/column status
2176  SCCOLROW nOutStartRow;
2177  SCCOLROW nOutEndCol;
2178  SCCOLROW nOutEndRow;
2179  pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
2180  pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
2181 
2182  pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
2183  rDoc.CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
2184  rDoc.CopyToDocument( 0, nOutStartRow, nTab, rDoc.MaxCol(), nOutEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
2185  }
2186  else
2187  pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
2188 
2189  // Record data range - including filter results
2190  rDoc.CopyToDocument( 0,nStartRow,nTab, rDoc.MaxCol(),nEndRow,nTab, InsertDeleteFlags::ALL, false, *pUndoDoc );
2191 
2192  // all formulas for reference
2193  rDoc.CopyToDocument( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),nTabCount-1, InsertDeleteFlags::FORMULA, false, *pUndoDoc );
2194 
2195  // data base and other ranges
2196  ScRangeName* pDocRange = rDoc.GetRangeName();
2197  if (!pDocRange->empty())
2198  pUndoRange.reset(new ScRangeName( *pDocRange ));
2199  ScDBCollection* pDocDB = rDoc.GetDBCollection();
2200  if (!pDocDB->empty())
2201  pUndoDB.reset(new ScDBCollection( *pDocDB ));
2202  }
2203 
2204  if (bSort && bSubTotal)
2205  {
2206  // sort without subtotals
2207 
2208  aSubTotalParam.bRemoveOnly = true; // is reset below
2209  DoSubTotals( aSubTotalParam, false );
2210  }
2211 
2212  if (bSort)
2213  {
2214  pDBData->GetSortParam( aSortParam ); // range may have changed
2215  Sort( aSortParam, false, false);
2216  }
2217  if (bQuery)
2218  {
2219  pDBData->GetQueryParam( aQueryParam ); // range may have changed
2220  ScRange aAdvSource;
2221  if (pDBData->GetAdvancedQuerySource(aAdvSource))
2222  {
2223  rDoc.CreateQueryParam(aAdvSource, aQueryParam);
2224  Query( aQueryParam, &aAdvSource, false );
2225  }
2226  else
2227  Query( aQueryParam, nullptr, false );
2228 
2229  // if not inplace the sheet may have changed
2230  if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
2231  SetTabNo( nTab );
2232  }
2233  if (bSubTotal)
2234  {
2235  pDBData->GetSubTotalParam( aSubTotalParam ); // range may have changed
2236  aSubTotalParam.bRemoveOnly = false;
2237  DoSubTotals( aSubTotalParam, false );
2238  }
2239 
2240  if (bRecord)
2241  {
2242  SCTAB nDummyTab;
2243  SCCOL nDummyCol;
2244  SCROW nDummyRow, nNewEndRow;
2245  pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
2246 
2247  const ScRange* pOld = nullptr;
2248  const ScRange* pNew = nullptr;
2249  if (bQuerySize)
2250  {
2251  ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
2252  aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
2253  if (pDest)
2254  {
2255  pDest->GetArea( aNewQuery );
2256  pOld = &aOldQuery;
2257  pNew = &aNewQuery;
2258  }
2259  }
2260 
2261  GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
2262  std::make_unique<ScUndoRepeatDB>( GetViewData().GetDocShell(), nTab,
2263  nStartCol, nStartRow, nEndCol, nEndRow,
2264  nNewEndRow,
2265  nCurX, nCurY,
2266  std::move(pUndoDoc), std::move(pUndoTab),
2267  std::move(pUndoRange), std::move(pUndoDB),
2268  pOld, pNew ) );
2269  }
2270 
2271  GetViewData().GetDocShell()->PostPaint(
2272  ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
2274  }
2275  else // "no not execute any operations"
2276  ErrorMessage(STR_MSSG_REPEATDB_0);
2277 }
2278 
2279 void ScDBFunc::OnLOKShowHideColRow(bool bColumns, SCCOLROW nStart)
2280 {
2282  return;
2283 
2284  SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
2285  SfxViewShell* pThisViewShell = GetViewData().GetViewShell();
2286  SfxViewShell* pViewShell = SfxViewShell::GetFirst();
2287  while (pViewShell)
2288  {
2289  ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
2290  if (pTabViewShell && pTabViewShell->GetDocId() == pThisViewShell->GetDocId())
2291  {
2292  if (bColumns)
2293  {
2294  if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKWidthHelper(nCurrentTabIndex))
2295  pPosHelper->invalidateByIndex(nStart);
2296  }
2297  else
2298  {
2299  if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nCurrentTabIndex))
2300  pPosHelper->invalidateByIndex(nStart);
2301  }
2302 
2303  if (pTabViewShell->getPart() == nCurrentTabIndex)
2304  {
2305  pTabViewShell->ShowCursor();
2306  pTabViewShell->MarkDataChanged();
2307  }
2308  }
2309  pViewShell = SfxViewShell::GetNext(*pViewShell);
2310  }
2311 }
2312 
2313 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
::std::vector< ScSortKeyState > maKeyState
Definition: sortparam.hxx:60
bool bGroupActive[MAXSUBTOTAL]
active groups
const ScDPDimensionSaveData * GetExistingDimensionData() const
Definition: dpsave.hxx:348
SC_DLLPUBLIC ScDPObject * GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: documen3.cxx:377
const OUString & GetGroupDimName() const
Definition: dpdimsave.hxx:107
void RecalcPivotTable()
Definition: dbfunc3.cxx:722
function is determined automatically.
Collection of user-defined sort lists.
Definition: userlist.hxx:66
bool IsDimNameInUse(std::u16string_view rName) const
Definition: dpobject.cxx:1171
void GetHeaderPositionData(const ScAddress &rPos, css::sheet::DataPilotTableHeaderData &rData)
Definition: dpobject.cxx:1291
sal_Int32 nIndex
SC_DLLPUBLIC ScDBCollection * GetDBCollection() const
Definition: document.hxx:814
ScAddress aStart
Definition: address.hxx:499
void DataPilotInput(const ScAddress &rPos, const OUString &rString)
Definition: dbfunc3.cxx:1381
void ShowDataPilotSourceData(ScDPObject &rDPObj, const css::uno::Sequence< css::sheet::DataPilotFieldFilter > &rFilters)
Definition: dbfunc3.cxx:2031
void UngroupDataPilot()
Definition: dbfunc3.cxx:1261
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:42
This class has to do with handling exclusively grouped dimensions? TODO: Find out what this class doe...
Definition: dpdimsave.hxx:163
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
SCCOL nCol1
selected area
void Rename(const OUString &rNewName)
Definition: dpdimsave.cxx:83
void SetOrientation(css::sheet::DataPilotFieldOrientation nNew)
Definition: dpsave.cxx:317
SC_DLLPUBLIC bool IsHidden() const
Definition: olinetab.hxx:49
SCROW Row() const
Definition: address.hxx:261
bool RemoveAllOutlines(SCTAB nTab, bool bRecord)
Definition: olinefun.cxx:201
void MarkToMulti()
Definition: markdata.cxx:224
bool MakePivotTable(const ScDPSaveData &rData, const ScRange &rDest, bool bNewTable, const ScDPObject &rSource)
Definition: dbfunc3.cxx:620
bool IsMemberNameInUse(const OUString &rName) const
Definition: dpsave.cxx:368
const MemberList & GetMembers() const
Definition: dpsave.hxx:128
css::sheet::DataPilotFieldOrientation GetOrientation() const
Definition: dpsave.hxx:202
SC_DLLPUBLIC void GetSortParam(ScSortParam &rSortParam) const
Definition: dbdata.cxx:401
SC_DLLPUBLIC SCCOLROW GetEnd() const
Definition: olinetab.cxx:42
static void lcl_MoveToEnd(ScDPSaveDimension &rDim, const OUString &rItemName)
Definition: dbfunc3.cxx:1663
int getPart() const override
See SfxViewShell::getPart().
Definition: tabvwshc.cxx:439
ScGeneralFunction GetSubTotalFunc(tools::Long nIndex) const
Definition: dpsave.hxx:152
sal_uIntPtr sal_uLong
long Long
SC_DLLPUBLIC ScRangeName * GetRangeName(SCTAB nTab) const
Definition: documen3.cxx:168
Classes to save Data Pilot settings that create new dimensions (fields).
Definition: dpdimsave.hxx:46
const OUString & GetGroupName() const
Definition: dpdimsave.hxx:65
sal_Int64 n
SC_DLLPUBLIC ScDPCollection * GetDPCollection()
Definition: documen3.cxx:365
ViewShellDocId GetDocId() const override
void SetOutRange(const ScRange &rRange)
Definition: dpobject.cxx:401
static SC_DLLPUBLIC CollatorWrapper * GetCollator()
Definition: global.cxx:1040
const OUString & GetSourceDimName() const
Definition: dpdimsave.hxx:108
void RemoveGroupDimension(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:582
aBuf
SvNumFormatType GetType(sal_uInt32 nFIndex) const
void MakeOutline(bool bColumns, bool bRecord=true)
Definition: dbfunc3.cxx:88
const SfxItemSet & GetItemSet() const
const ContentProperties & rData
void PostPaintExtras()
Definition: docsh3.cxx:197
SC_DLLPUBLIC const ScDBData * GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
Definition: documen3.cxx:338
size_t size() const
Definition: userlist.cxx:345
ScAddress aEnd
Definition: address.hxx:500
bool bDoSort
presort
sal_Int32 GetDatePart() const
Definition: dpdimsave.hxx:152
ScDPSaveMember * GetExistingMemberByName(const OUString &rName)
Definition: dpsave.cxx:448
SC_DLLPUBLIC bool CreateQueryParam(const ScRange &rRange, ScQueryParam &rQueryParam)
Definition: documen3.cxx:1479
void RemoveNumGroupDimension(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:607
const ScDPNumGroupInfo & GetDateInfo() const
Definition: dpdimsave.hxx:153
void SetName(const OUString &rNew)
Definition: dpsave.cxx:309
static OUString lcl_MakePivotTabName(std::u16string_view rPrefix, SCTAB nNumber)
Definition: dbfunc3.cxx:614
bool DoSubTotals(SCTAB nTab, ScSubTotalParam &rParam)
Definition: documen3.cxx:777
SC_DLLPUBLIC bool HasAttrib(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, HasAttrFlags nMask) const
Definition: document.cxx:5205
bool IsDoSize() const
Definition: dbdata.hxx:136
static void notifyAllViewsSheetGeomInvalidation(const SfxViewShell *pForViewShell, bool bColumns, bool bRows, bool bSizes, bool bHidden, bool bFiltered, bool bGroups, SCTAB nCurrentTabIndex)
Emits a LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY for all views whose current tab is equal to nCurrentTa...
Definition: tabvwshc.cxx:560
void HideMarkedOutlines(bool bRecord=true)
Definition: dbfunc3.cxx:407
virtual void ShowCursor(bool bOn) override
Definition: tabvwsh4.cxx:467
bool HasSelectionForDateGroup(ScDPNumGroupInfo &rOldInfo, sal_Int32 &rParts)
Definition: dbfunc3.cxx:805
SfxApplication * SfxGetpApp()
void ShowOutline(bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bRecord=true, bool bPaint=true)
Definition: dbfunc3.cxx:266
bool UpdatePivotTable(ScDPObject &rDPObj, bool bRecord, bool bApi)
Definition: dbdocfun.cxx:1561
Query
virtual SfxUndoManager * GetUndoManager() override
Definition: docsh.cxx:2901
void DateGroupDataPilot(const ScDPNumGroupInfo &rInfo, sal_Int32 nParts)
Definition: dbfunc3.cxx:986
sal_uInt16 sal_Unicode
Stores individual user-defined sort list.
Definition: userlist.hxx:32
RET_YES
const ScDPSaveGroupDimension * GetNamedGroupDim(const OUString &rGroupDimName) const
Definition: dpdimsave.cxx:637
void RefreshPivotTables(const ScDPObject *pDPObj, bool bApi)
Reload the referenced pivot cache, and refresh all pivot tables that reference the cache...
Definition: dbdocfun.cxx:1635
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:872
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:23
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:313
bool empty() const
Definition: rangenam.cxx:809
void MarkDataChanged()
Definition: tabview3.cxx:1746
size_t GetDepth() const
Definition: olinetab.hxx:110
static SfxViewShell * GetNext(const SfxViewShell &rPrev, bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3517
void DataPilotSort(ScDPObject *pDPObject, tools::Long nDimIndex, bool bAscending, const sal_uInt16 *pUserListId=nullptr)
Definition: dbfunc3.cxx:1692
void CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, InsertDeleteFlags nFlags, bool bMarked, ScDocument &rDestDoc, const ScMarkData *pMarks=nullptr, bool bColRowFlags=true)
Definition: document.cxx:2050
void DoSubTotals(const ScSubTotalParam &rParam, bool bRecord=true, const ScSortParam *pForceNewSort=nullptr)
Definition: dbfunc3.cxx:430
oslFileHandle & pOut
Sort
SC_DLLPUBLIC const ScQueryEntry & GetEntry(SCSIZE n) const
Definition: queryparam.cxx:124
const OUString & GetName() const
Definition: dpsave.hxx:66
SCTAB Tab() const
Definition: address.hxx:270
bool ReloadGroupsInCache(const ScDPObject *pDPObj, o3tl::sorted_vector< ScDPObject * > &rRefs)
Definition: dpobject.cxx:3432
void MakeOutline(const ScRange &rRange, bool bColumns, bool bRecord, bool bApi)
Definition: olinefun.cxx:80
void AddElementsFromGroup(const ScDPSaveGroupItem &rGroup)
Definition: dpdimsave.cxx:49
size_t GetSubCount() const
Definition: userlist.cxx:109
bool IsEmpty() const
Definition: dpsave.cxx:1148
bool HasSelectionForNumGroup(ScDPNumGroupInfo &rOldInfo)
Definition: dbfunc3.cxx:918
void SetGroupInfo(const ScDPNumGroupInfo &rNew)
Definition: dpdimsave.cxx:526
sal_Int32 GetDatePart() const
Definition: dpdimsave.hxx:110
bool IsDataDescriptionCell(const ScAddress &rPos)
Data description cell displays the description of a data dimension if and only if there is only one d...
Definition: dpobject.cxx:499
ScViewData & GetViewData()
Definition: tabview.hxx:333
std::vector< ScDPSaveMember * > MemberList
Definition: dpsave.hxx:115
SC_DLLPUBLIC const SfxPoolItem * GetAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: document.cxx:4745
void GetRange(SCCOLROW &rStart, SCCOLROW &rEnd) const
Definition: olinetab.cxx:555
void SetOutlineState(bool bColumn, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bHidden)
Definition: dbfunc3.cxx:252
constexpr OUStringLiteral aData
ScDPSaveGroupDimension * GetNamedGroupDimAcc(const OUString &rGroupDimName)
Definition: dpdimsave.cxx:663
ScDPSaveDimension * GetInnermostDimension(css::sheet::DataPilotFieldOrientation nOrientation)
Definition: dpsave.cxx:918
void SetLayoutName(const OUString &rName)
Definition: dpsave.cxx:379
SC_DLLPUBLIC double GetValue(const ScAddress &rPos) const
Definition: document.cxx:3659
void SetArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: dbdata.cxx:322
tools::Long GetGroupCount() const
Definition: dpdimsave.cxx:200
void SetMarkArea(const ScRange &rRange)
Definition: markdata.cxx:97
void AutoOutline()
Definition: dbfunc3.cxx:213
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:871
void RepeatDB(bool bRecord=true)
Definition: dbfunc3.cxx:2114
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:440
virtual void AddUndoAction(std::unique_ptr< SfxUndoAction > pAction, bool bTryMerg=false)
const ScDPSaveGroupItem & GetGroupByIndex(tools::Long nIndex) const
Definition: dpdimsave.cxx:205
void RemoveOutline(const ScRange &rRange, bool bColumns, bool bRecord, bool bApi)
Definition: olinefun.cxx:138
tools::Long GetSubTotalsCount() const
Definition: dpsave.hxx:149
SC_DLLPUBLIC void SetDimensionData(const ScDPDimensionSaveData *pNew)
Definition: dpsave.cxx:1202
bool HideMarkedOutlines(const ScRange &rRange, bool bRecord)
Definition: olinefun.cxx:540
int i
Represents a group dimension that introduces a new hierarchy for an existing dimension.
Definition: dpdimsave.hxx:135
bool empty() const
Definition: dbdata.cxx:1517
SC_DLLPUBLIC SCCOLROW GetStart() const
Definition: olinetab.hxx:42
SC_DLLPUBLIC void SetLayoutName(const OUString &rName)
Definition: dpsave.cxx:118
css::uno::Reference< css::sheet::XDimensionsSupplier > const & GetSource()
Definition: dpobject.cxx:515
std::unique_ptr< ScDocument, o3tl::default_delete< ScDocument > > ScDocumentUniquePtr
Definition: document.hxx:2621
const ScOutlineArray & GetRowArray() const
Definition: olinetab.hxx:160
void RemoveGroup(const OUString &rGroupName)
Definition: dpdimsave.cxx:226
sal_Int16 SCCOL
Definition: types.hxx:21
const ScOutlineArray & GetColArray() const
Definition: olinetab.hxx:158
bool DataPilotUpdate(ScDPObject *pOldObj, const ScDPObject *pNewObj, bool bRecord, bool bApi, bool bAllowMove=false)
Definition: dbdocfun.cxx:1266
void OnLOKShowHideColRow(bool bColumns, SCCOLROW nStartRow)
Definition: dbfunc3.cxx:2279
void SetSaveData(const ScDPSaveData &rData)
Definition: dpobject.cxx:386
void SetName(const OUString &rNew)
Definition: dpsave.cxx:110
const Any & any
SC_DLLPUBLIC void CreateValidTabName(OUString &rName) const
Definition: document.cxx:391
bool OutlinePossible(bool bHide)
Definition: dbfunc3.cxx:306
size_t size() const
Definition: rangelst.hxx:89
static SC_DLLPUBLIC ScUserList * GetUserList()
Definition: global.cxx:274
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
SC_DLLPUBLIC bool InsertTab(SCTAB nPos, const OUString &rName, bool bExternalDocument=false, bool bUndoDeleteTab=false)
Definition: document.cxx:503
SvNumFormatType
bool Remove(SCCOLROW nBlockStart, SCCOLROW nBlockEnd, bool &rSizeChanged)
Definition: olinetab.cxx:395
ScDPSaveData * GetSaveData() const
Definition: dpobject.hxx:140
void Consolidate(const ScConsolidateParam &rParam)
Definition: dbfunc3.cxx:605
void RemoveAllOutlines(bool bRecord=true)
Definition: dbfunc3.cxx:193
const ScDPNumGroupInfo & GetDateInfo() const
Definition: dpdimsave.hxx:111
void AutoOutline(const ScRange &rRange, bool bRecord)
Definition: olinefun.cxx:253
void SelectLevel(bool bColumns, sal_uInt16 nLevel, bool bRecord=true)
Definition: dbfunc3.cxx:232
SC_DLLPUBLIC ScDPSaveDimension * GetExistingDimensionByName(std::u16string_view rName) const
Definition: dpsave.cxx:845
void ShowMarkedOutlines(bool bRecord=true)
Definition: dbfunc3.cxx:384
const SCTAB MAXTAB
Definition: address.hxx:70
SC_DLLPUBLIC bool HasValueData(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3796
static SfxViewShell * GetFirst(bool bOnlyVisible=true, const std::function< bool(const SfxViewShell *)> &isViewShell=nullptr)
static void notifyAllViewsHeaderInvalidation(const SfxViewShell *pForViewShell, HeaderType eHeaderType, SCTAB nCurrentTabIndex)
Emits a LOK_CALLBACK_INVALIDATE_HEADER for all views whose current tab is equal to nCurrentTabIndex...
Definition: tabvwshc.cxx:502
void PostPaint(SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, PaintPartFlags nPart, sal_uInt16 nExtFlags=0)
Definition: docsh3.cxx:100
void GetArea(SCTAB &rTab, SCCOL &rCol1, SCROW &rRow1, SCCOL &rCol2, SCROW &rRow2) const
Definition: dbdata.cxx:300
void CompileDBFormula()
Definition: documen4.cxx:557
SfxViewShell * GetViewShell() const
const long LONG_MAX
SCCOL Col() const
Definition: address.hxx:266
bool IsReadOnly() const
void GetSubTotalParam(ScSubTotalParam &rSubTotalParam) const
Definition: dbdata.cxx:463
size_t LeaveListAction()
SC_DLLPUBLIC void SetShowDetails(bool bSet)
Definition: dpsave.cxx:105
void RemoveSubTotals(SCTAB nTab, ScSubTotalParam &rParam)
Definition: documen3.cxx:771
top left cell of area
bool bReplace
replace existing results
bool SelectLevel(SCTAB nTab, bool bColumns, sal_uInt16 nLevel, bool bRecord, bool bPaint)
Definition: olinefun.cxx:314
OUString GetDimName(tools::Long nDim, bool &rIsDataLayout, sal_Int32 *pFlags=nullptr)
Definition: dpobject.cxx:1195
bool GetMemberNames(sal_Int32 nDim, css::uno::Sequence< OUString > &rNames)
Definition: dpobject.cxx:996
bool DataPilotMove(const ScRange &rSource, const ScAddress &rDest)
Definition: dbfunc3.cxx:1818
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
sal_Int32 SCROW
Definition: types.hxx:17
bool RemovePivotTable(ScDPObject &rDPObj, bool bRecord, bool bApi)
Definition: dbdocfun.cxx:1368
void SetDirty(const ScRange &, bool bIncludeEmptyCells)
Definition: document.cxx:3888
OUString ScResId(std::string_view aId)
Definition: scdll.cxx:89
void GetSelectedMemberList(ScDPUniqueStringSet &rEntries, tools::Long &rDimension)
Definition: dbfunc3.cxx:743
void HideOutline(bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bRecord=true, bool bPaint=true)
Definition: dbfunc3.cxx:286
ScOutlineEntry * GetNext()
Definition: olinetab.cxx:810
bool ShowMarkedOutlines(const ScRange &rRange, bool bRecord)
Definition: olinefun.cxx:426
bool HasOnlyHidden(const ScDPUniqueStringSet &rVisible)
Definition: dpdimsave.cxx:241
void RemoveElementsFromGroups(ScDPSaveGroupDimension &rDimension) const
remove this group's elements from their groups in rDimension (rDimension must be a different dimensio...
Definition: dpdimsave.cxx:88
ScDPSaveGroupItem * GetNamedGroupAcc(const OUString &rGroupName)
Definition: dpdimsave.cxx:188
void SetSubtotalName(const OUString &rName)
Definition: dpsave.cxx:353
std::unordered_set< OUString > ScDPUniqueStringSet
Definition: dptypes.hxx:16
void RemoveFromGroups(const OUString &rItemName)
Definition: dpdimsave.cxx:211
OUString aName
const OUString & GetName() const
Definition: dpsave.hxx:139
void GroupDataPilot()
Definition: dbfunc3.cxx:1126
void RemoveLayoutName()
Definition: dpsave.cxx:389
Represents a new group dimension whose dimension ID is higher than the highest source dimension ID...
Definition: dpdimsave.hxx:90
static OUString lcl_replaceMemberNameInSubtotal(const OUString &rSubtotal, std::u16string_view rMemberName)
Definition: dbfunc3.cxx:1336
SC_DLLPUBLIC ScOutlineTable * GetOutlineTable(SCTAB nTab, bool bCreate=false)
Definition: documen3.cxx:736
void Rename(const OUString &rNewName)
Definition: dpdimsave.cxx:249
virtual void EnterListAction(const OUString &rComment, const OUString &rRepeatComment, sal_uInt16 nId, ViewShellId nViewShellId)
void NumGroupDataPilot(const ScDPNumGroupInfo &rInfo)
Definition: dbfunc3.cxx:1084
void AddElement(const OUString &rName)
Definition: dpdimsave.cxx:44
void * p
void DeletePivotTable()
Definition: dbfunc3.cxx:705
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:400
const ScDPSaveGroupItem * GetNamedGroup(const OUString &rGroupName) const
Definition: dpdimsave.cxx:183
void GetMemberResultNames(ScDPUniqueStringSet &rNames, tools::Long nDimension)
Definition: dpobject.cxx:1419
const ScDocument & GetDocument() const
Definition: docsh.hxx:216
sal_Int32 CollectDateParts(const OUString &rBaseDimName) const
Definition: dpdimsave.cxx:699
SC_DLLPUBLIC void GetQueryParam(ScQueryParam &rQueryParam) const
Definition: dbdata.cxx:424
bool TestRemoveSubTotals(SCTAB nTab, const ScSubTotalParam &rParam)
Definition: documen3.cxx:766
void SetDataPilotDetails(bool bShow, const OUString *pNewDimensionName=nullptr)
Definition: dbfunc3.cxx:1945
ScPositionHelper & GetLOKWidthHelper()
Definition: viewdata.hxx:409
char aEntryName[20]
void SetDocumentModified()
Definition: docsh.cxx:3254
bool HasSelectionForDrillDown(css::sheet::DataPilotFieldOrientation &rOrientation)
Definition: dbfunc3.cxx:1908
const ScDPNumGroupInfo & GetInfo() const
Definition: dpdimsave.hxx:150
void DoConsolidate(const ScConsolidateParam &rParam, bool bRecord=true)
Definition: docsh5.cxx:501
void SetSubTotalParam(const ScSubTotalParam &rSubTotalParam)
Definition: dbdata.cxx:475
ScXMLEditAttributeMap::Entry const aEntries[]
SfxObjectShell * GetDocumentShell() const
Definition: document.hxx:1057
SC_DLLPUBLIC bool GetAdvancedQuerySource(ScRange &rSource) const
Definition: dbdata.cxx:457
bool IsUndoEnabled() const
Definition: document.hxx:1535
void ShowOutline(SCTAB nTab, bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bRecord, bool bPaint)
Definition: olinefun.cxx:635
void RemoveOutline(bool bColumns, bool bRecord=true)
Definition: dbfunc3.cxx:109
SC_DLLPUBLIC const std::optional< OUString > & GetLayoutName() const
Definition: dpsave.cxx:123
ScPositionHelper & GetLOKHeightHelper()
Definition: viewdata.hxx:410
const ScDPSaveNumGroupDimension * GetNumGroupDim(const OUString &rGroupDimName) const
Definition: dpdimsave.cxx:652
const ScDBData * GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, ScDBDataPortion ePortion) const
Definition: documen3.cxx:322
void RemoveLayoutName()
Definition: dpsave.cxx:128
void BuildAllDimensionMembers()
Definition: dpobject.cxx:959
void RefreshPivotTableGroups(ScDPObject *pDPObj)
Refresh the group dimensions of all pivot tables referencing the same cache.
Definition: dbdocfun.cxx:1653
void TestRemoveOutline(bool &rCol, bool &rRow)
Definition: dbfunc3.cxx:130
aStr
SC_DLLPUBLIC bool GetName(SCTAB nTab, OUString &rName) const
Definition: document.cxx:212
void AddGroupItem(const ScDPSaveGroupItem &rItem)
Definition: dpdimsave.cxx:149
SC_DLLPUBLIC ScDPSaveDimension * GetDimensionByName(const OUString &rName)
Get a dimension object by its name.
Definition: dpsave.cxx:834
#define SC_UNO_DP_NUMBERFO
Definition: unonames.hxx:610
static weld::MessageDialog * CreateMessageDialog(weld::Widget *pParent, VclMessageType eMessageType, VclButtonsType eButtonType, const OUString &rPrimaryMessage, bool bMobile=false)
Create before modifications of the document and destroy thereafter.
Definition: docsh.hxx:451
tools::Long GetHeaderDim(const ScAddress &rPos, css::sheet::DataPilotFieldOrientation &rOrient)
Definition: dpobject.cxx:1404
sal_Int16 SCTAB
Definition: types.hxx:22
bool HideOutline(SCTAB nTab, bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bRecord, bool bPaint)
Definition: olinefun.cxx:723
void SetDateInfo(const ScDPNumGroupInfo &rInfo, sal_Int32 nPart)
Definition: dpdimsave.cxx:143
OUString CreateGroupName(std::u16string_view rPrefix)
Definition: dpdimsave.cxx:154
void AddMember(std::unique_ptr< ScDPSaveMember > pMember)
Definition: dpsave.cxx:292
bool IsEmpty() const
Definition: dpdimsave.cxx:236
OUString GetSubStr(sal_uInt16 nIndex) const
Definition: userlist.cxx:140
void SetSortInfo(const css::sheet::DataPilotFieldSortInfo *pNew)
Definition: dpsave.cxx:402