LibreOffice Module sc (master)  1
table3.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 
21 #include <comphelper/random.hxx>
22 #include <unotools/textsearch.hxx>
23 #include <svl/numformat.hxx>
24 #include <svl/zforlist.hxx>
25 #include <svl/zformat.hxx>
27 #include <stdlib.h>
28 #include <com/sun/star/i18n/KParseTokens.hpp>
29 #include <com/sun/star/i18n/KParseType.hpp>
30 #include <sal/log.hxx>
31 #include <osl/diagnose.h>
32 
33 #include <refdata.hxx>
34 #include <table.hxx>
35 #include <scitems.hxx>
36 #include <formulacell.hxx>
37 #include <document.hxx>
38 #include <globstr.hrc>
39 #include <scresid.hxx>
40 #include <global.hxx>
41 #include <stlpool.hxx>
42 #include <patattr.hxx>
43 #include <subtotal.hxx>
44 #include <markdata.hxx>
45 #include <rangelst.hxx>
46 #include <userlist.hxx>
47 #include <progress.hxx>
48 #include <cellform.hxx>
49 #include <queryparam.hxx>
50 #include <queryentry.hxx>
51 #include <subtotalparam.hxx>
52 #include <docpool.hxx>
53 #include <cellvalue.hxx>
54 #include <tokenarray.hxx>
55 #include <mtvcellfunc.hxx>
56 #include <columnspanset.hxx>
57 #include <fstalgorithm.hxx>
58 #include <listenercontext.hxx>
59 #include <sharedformula.hxx>
60 #include <stlsheet.hxx>
61 #include <refhint.hxx>
62 #include <listenerquery.hxx>
63 #include <bcaslot.hxx>
64 #include <reordermap.hxx>
65 #include <drwlayer.hxx>
66 #include <conditio.hxx>
67 #include <queryevaluator.hxx>
68 
69 #include <svl/sharedstringpool.hxx>
70 
71 #include <memory>
72 #include <set>
73 #include <unordered_set>
74 #include <vector>
75 #include <mdds/flat_segment_tree.hpp>
76 
77 using namespace ::com::sun::star;
78 
79 namespace naturalsort {
80 
81 using namespace ::com::sun::star::i18n;
82 
104 static bool SplitString( const OUString &sWhole,
105  OUString &sPrefix, OUString &sSuffix, double &fNum )
106 {
107  // Get prefix element, search for any digit and stop.
108  sal_Int32 nPos = 0;
109  while (nPos < sWhole.getLength())
110  {
111  const sal_uInt16 nType = ScGlobal::getCharClass().getCharacterType( sWhole, nPos);
112  if (nType & KCharacterType::DIGIT)
113  break;
114  sWhole.iterateCodePoints( &nPos );
115  }
116 
117  // Return FALSE if no numeral element is found
118  if ( nPos == sWhole.getLength() )
119  return false;
120 
121  // Get numeral element
122  const OUString& sUser = ScGlobal::getLocaleData().getNumDecimalSep();
123  ParseResult aPRNum = ScGlobal::getCharClass().parsePredefinedToken(
124  KParseType::ANY_NUMBER, sWhole, nPos,
125  KParseTokens::ANY_NUMBER, "", KParseTokens::ANY_NUMBER, sUser );
126 
127  if ( aPRNum.EndPos == nPos )
128  {
129  SAL_WARN("sc.core","naturalsort::SplitString - digit found but no number parsed, pos " <<
130  nPos << " : " << sWhole);
131  return false;
132  }
133 
134  sPrefix = sWhole.copy( 0, nPos );
135  fNum = aPRNum.Value;
136  sSuffix = sWhole.copy( aPRNum.EndPos );
137 
138  return true;
139 }
140 
164 static short Compare( const OUString &sInput1, const OUString &sInput2,
165  const bool bCaseSens, const ScUserListData* pData, const CollatorWrapper *pCW )
166 {
167  OUString sStr1( sInput1 ), sStr2( sInput2 ), sPre1, sSuf1, sPre2, sSuf2;
168 
169  do
170  {
171  double nNum1, nNum2;
172  bool bNumFound1 = SplitString( sStr1, sPre1, sSuf1, nNum1 );
173  bool bNumFound2 = SplitString( sStr2, sPre2, sSuf2, nNum2 );
174 
175  short nPreRes; // Prefix comparison result
176  if ( pData )
177  {
178  if ( bCaseSens )
179  {
180  if ( !bNumFound1 || !bNumFound2 )
181  return static_cast<short>(pData->Compare( sStr1, sStr2 ));
182  else
183  nPreRes = pData->Compare( sPre1, sPre2 );
184  }
185  else
186  {
187  if ( !bNumFound1 || !bNumFound2 )
188  return static_cast<short>(pData->ICompare( sStr1, sStr2 ));
189  else
190  nPreRes = pData->ICompare( sPre1, sPre2 );
191  }
192  }
193  else
194  {
195  if ( !bNumFound1 || !bNumFound2 )
196  return static_cast<short>(pCW->compareString( sStr1, sStr2 ));
197  else
198  nPreRes = static_cast<short>(pCW->compareString( sPre1, sPre2 ));
199  }
200 
201  // Prefix strings differ. Return immediately.
202  if ( nPreRes != 0 ) return nPreRes;
203 
204  if ( nNum1 != nNum2 )
205  {
206  if ( nNum1 < nNum2 ) return -1;
207  return (nNum1 > nNum2) ? 1 : 0;
208  }
209 
210  // The prefix and the first numerical elements are equal, but the suffix
211  // strings may still differ. Stay in the loop.
212 
213  sStr1 = sSuf1;
214  sStr2 = sSuf2;
215 
216  } while (true);
217 
218  return 0;
219 }
220 
221 }
222 
223 namespace {
224 
225 struct ScSortInfo final
226 {
227  ScRefCellValue maCell;
228  SCCOLROW nOrg;
229 };
230 
231 }
232 
234 {
235 public:
236 
237  struct Cell
238  {
241  const ScPostIt* mpNote;
242  std::vector<SdrObject*> maDrawObjects;
244 
245  Cell() : mpAttr(nullptr), mpNote(nullptr), mpPattern(nullptr) {}
246  };
247 
248  struct Row
249  {
250  std::vector<Cell> maCells;
251 
252  bool mbHidden:1;
253  bool mbFiltered:1;
254 
255  explicit Row( size_t nColSize ) : maCells(nColSize, Cell()), mbHidden(false), mbFiltered(false) {}
256  };
257 
258  typedef std::vector<Row> RowsType;
259 
260 private:
261  std::unique_ptr<RowsType> mpRows;
262 
263  std::vector<std::unique_ptr<ScSortInfo[]>> mvppInfo;
266 
267  std::vector<SCCOLROW> maOrderIndices;
270 
271 public:
272  ScSortInfoArray(const ScSortInfoArray&) = delete;
273  const ScSortInfoArray& operator=(const ScSortInfoArray&) = delete;
274 
275  ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
276  mvppInfo(nSorts),
277  nStart( nInd1 ),
278  mnLastIndex(nInd2),
279  mbKeepQuery(false),
280  mbUpdateRefs(false)
281  {
282  SCSIZE nCount( nInd2 - nInd1 + 1 );
283  if (nSorts)
284  {
285  for ( sal_uInt16 nSort = 0; nSort < nSorts; nSort++ )
286  {
287  mvppInfo[nSort].reset(new ScSortInfo[nCount]);
288  }
289  }
290 
291  for (size_t i = 0; i < nCount; ++i)
292  maOrderIndices.push_back(i+nStart);
293  }
294 
295  void SetKeepQuery( bool b ) { mbKeepQuery = b; }
296 
297  bool IsKeepQuery() const { return mbKeepQuery; }
298 
299  void SetUpdateRefs( bool b ) { mbUpdateRefs = b; }
300 
301  bool IsUpdateRefs() const { return mbUpdateRefs; }
302 
306  std::unique_ptr<ScSortInfo[]> const & GetFirstArray() const
307  {
308  return mvppInfo[0];
309  }
310 
314  ScSortInfo & Get( sal_uInt16 nSort, SCCOLROW nInd )
315  {
316  return mvppInfo[nSort][ nInd - nStart ];
317  }
318 
322  void Swap( SCCOLROW nInd1, SCCOLROW nInd2 )
323  {
324  if (nInd1 == nInd2) // avoid self-move-assign
325  return;
326  SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart);
327  SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart);
328  for ( sal_uInt16 nSort = 0; nSort < static_cast<sal_uInt16>(mvppInfo.size()); nSort++ )
329  {
330  auto & ppInfo = mvppInfo[nSort];
331  std::swap(ppInfo[n1], ppInfo[n2]);
332  }
333 
334  std::swap(maOrderIndices[n1], maOrderIndices[n2]);
335 
336  if (mpRows)
337  {
338  // Swap rows in data table.
339  RowsType& rRows = *mpRows;
340  std::swap(rRows[n1], rRows[n2]);
341  }
342  }
343 
344  void SetOrderIndices( std::vector<SCCOLROW>&& rIndices )
345  {
346  maOrderIndices = std::move(rIndices);
347  }
348 
353  void ReorderByRow( const std::vector<SCCOLROW>& rIndices )
354  {
355  if (!mpRows)
356  return;
357 
358  RowsType& rRows = *mpRows;
359 
360  std::vector<SCCOLROW> aOrderIndices2;
361  aOrderIndices2.reserve(rIndices.size());
362 
363  RowsType aRows2;
364  aRows2.reserve(rRows.size());
365 
366  for (const auto& rIndex : rIndices)
367  {
368  size_t nPos = rIndex - nStart; // switch to an offset to top row.
369  aRows2.push_back(rRows[nPos]);
370  aOrderIndices2.push_back(maOrderIndices[nPos]);
371  }
372 
373  rRows.swap(aRows2);
374  maOrderIndices.swap(aOrderIndices2);
375  }
376 
377  sal_uInt16 GetUsedSorts() const { return mvppInfo.size(); }
378 
379  SCCOLROW GetStart() const { return nStart; }
380  SCCOLROW GetLast() const { return mnLastIndex; }
381 
382  const std::vector<SCCOLROW>& GetOrderIndices() const { return maOrderIndices; }
383 
384  RowsType& InitDataRows( size_t nRowSize, size_t nColSize )
385  {
386  mpRows.reset(new RowsType);
387  mpRows->resize(nRowSize, Row(nColSize));
388  return *mpRows;
389  }
390 
391  RowsType* GetDataRows()
392  {
393  return mpRows.get();
394  }
395 };
396 
397 // Assume that we can handle 512MB, which with a ~100 bytes
398 // ScSortInfoArray::Cell element for 500MB are about 5 million cells plus
399 // overhead in one chunk.
400 constexpr sal_Int32 kSortCellsChunk = 500 * 1024 * 1024 / sizeof(ScSortInfoArray::Cell);
401 
402 namespace {
403 
404 void initDataRows(
405  ScSortInfoArray& rArray, ScTable& rTab, ScColContainer& rCols,
406  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
407  bool bHiddenFiltered, bool bPattern, bool bCellNotes, bool bCellDrawObjects, bool bOnlyDataAreaExtras )
408 {
409  // Fill row-wise data table.
410  ScSortInfoArray::RowsType& rRows = rArray.InitDataRows(nRow2-nRow1+1, nCol2-nCol1+1);
411 
412  const std::vector<SCCOLROW>& rOrderIndices = rArray.GetOrderIndices();
413  assert(!bOnlyDataAreaExtras || (rOrderIndices.size() == static_cast<size_t>(nRow2 - nRow1 + 1)
414  && nRow1 == rArray.GetStart()));
415 
416  ScDrawLayer* pDrawLayer = (bCellDrawObjects ? rTab.GetDoc().GetDrawLayer() : nullptr);
417  for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
418  {
419  ScColumn& rCol = rCols[nCol];
420 
421  // Skip reordering of cell formats if the whole span is on the same pattern entry.
422  bool bUniformPattern = rCol.GetPatternCount(nRow1, nRow2) < 2u;
423 
425  rCol.InitBlockPosition(aBlockPos);
426  std::map<SCROW, std::vector<SdrObject*>> aRowDrawObjects;
427  if (pDrawLayer)
428  aRowDrawObjects = pDrawLayer->GetObjectsAnchoredToRange(rTab.GetTab(), nCol, nRow1, nRow2);
429 
430  for (SCROW nR = nRow1; nR <= nRow2; ++nR)
431  {
432  const SCROW nRow = (bOnlyDataAreaExtras ? rOrderIndices[nR - rArray.GetStart()] : nR);
433  ScSortInfoArray::Row& rRow = rRows[nR-nRow1];
434  ScSortInfoArray::Cell& rCell = rRow.maCells[nCol-nCol1];
435  if (!bOnlyDataAreaExtras)
436  {
437  rCell.maCell = rCol.GetCellValue(aBlockPos, nRow);
438  rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow);
439  }
440  if (bCellNotes)
441  rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow);
442  if (pDrawLayer)
443  rCell.maDrawObjects = aRowDrawObjects[nRow];
444 
445  if (!bUniformPattern && bPattern)
446  rCell.mpPattern = rCol.GetPattern(nRow);
447  }
448  }
449 
450  if (!bOnlyDataAreaExtras && bHiddenFiltered)
451  {
452  for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
453  {
454  ScSortInfoArray::Row& rRow = rRows[nRow-nRow1];
455  rRow.mbHidden = rTab.RowHidden(nRow);
456  rRow.mbFiltered = rTab.RowFiltered(nRow);
457  }
458  }
459 }
460 
461 }
462 
463 std::unique_ptr<ScSortInfoArray> ScTable::CreateSortInfoArray( const sc::ReorderParam& rParam )
464 {
465  std::unique_ptr<ScSortInfoArray> pArray;
466 
467  if (rParam.mbByRow)
468  {
469  // Create a sort info array with just the data table.
470  SCROW nRow1 = rParam.maSortRange.aStart.Row();
471  SCROW nRow2 = rParam.maSortRange.aEnd.Row();
472  SCCOL nCol1 = rParam.maSortRange.aStart.Col();
473  SCCOL nCol2 = rParam.maSortRange.aEnd.Col();
474 
475  pArray.reset(new ScSortInfoArray(0, nRow1, nRow2));
476  pArray->SetKeepQuery(rParam.mbHiddenFiltered);
477  pArray->SetUpdateRefs(rParam.mbUpdateRefs);
478 
479  initDataRows( *pArray, *this, aCol, nCol1, nRow1, nCol2, nRow2, rParam.mbHiddenFiltered,
480  rParam.maDataAreaExtras.mbCellFormats, true, true, false);
481  }
482  else
483  {
484  SCCOLROW nCol1 = rParam.maSortRange.aStart.Col();
485  SCCOLROW nCol2 = rParam.maSortRange.aEnd.Col();
486 
487  pArray.reset(new ScSortInfoArray(0, nCol1, nCol2));
488  pArray->SetKeepQuery(rParam.mbHiddenFiltered);
489  pArray->SetUpdateRefs(rParam.mbUpdateRefs);
490  }
491 
492  return pArray;
493 }
494 
495 std::unique_ptr<ScSortInfoArray> ScTable::CreateSortInfoArray(
496  const ScSortParam& rSortParam, SCCOLROW nInd1, SCCOLROW nInd2,
497  bool bKeepQuery, bool bUpdateRefs )
498 {
499  sal_uInt16 nUsedSorts = 1;
500  while ( nUsedSorts < rSortParam.GetSortKeyCount() && rSortParam.maKeyState[nUsedSorts].bDoSort )
501  nUsedSorts++;
502  std::unique_ptr<ScSortInfoArray> pArray(new ScSortInfoArray( nUsedSorts, nInd1, nInd2 ));
503  pArray->SetKeepQuery(bKeepQuery);
504  pArray->SetUpdateRefs(bUpdateRefs);
505 
506  if ( rSortParam.bByRow )
507  {
508  for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
509  {
510  SCCOL nCol = static_cast<SCCOL>(rSortParam.maKeyState[nSort].nField);
511  ScColumn* pCol = &aCol[nCol];
513  pCol->InitBlockPosition(aBlockPos);
514  for ( SCROW nRow = nInd1; nRow <= nInd2; nRow++ )
515  {
516  ScSortInfo & rInfo = pArray->Get( nSort, nRow );
517  rInfo.maCell = pCol->GetCellValue(aBlockPos, nRow);
518  rInfo.nOrg = nRow;
519  }
520  }
521 
522  initDataRows( *pArray, *this, aCol, rSortParam.nCol1, nInd1, rSortParam.nCol2, nInd2, bKeepQuery,
523  rSortParam.aDataAreaExtras.mbCellFormats, true, true, false);
524  }
525  else
526  {
527  for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
528  {
529  SCROW nRow = rSortParam.maKeyState[nSort].nField;
530  for ( SCCOL nCol = static_cast<SCCOL>(nInd1);
531  nCol <= static_cast<SCCOL>(nInd2); nCol++ )
532  {
533  ScSortInfo & rInfo = pArray->Get( nSort, nCol );
534  rInfo.maCell = GetCellValue(nCol, nRow);
535  rInfo.nOrg = nCol;
536  }
537  }
538  }
539  return pArray;
540 }
541 
542 namespace {
543 
544 struct SortedColumn
545 {
546  typedef mdds::flat_segment_tree<SCROW, const ScPatternAttr*> PatRangeType;
547 
548  sc::CellStoreType maCells;
549  sc::CellTextAttrStoreType maCellTextAttrs;
550  sc::BroadcasterStoreType maBroadcasters;
551  sc::CellNoteStoreType maCellNotes;
552  std::vector<std::vector<SdrObject*>> maCellDrawObjects;
553 
554  PatRangeType maPatterns;
555  PatRangeType::const_iterator miPatternPos;
556 
557  SortedColumn(const SortedColumn&) = delete;
558  const SortedColumn operator=(const SortedColumn&) = delete;
559 
560  explicit SortedColumn( size_t nTopEmptyRows, const ScSheetLimits& rSheetLimits ) :
561  maCells(nTopEmptyRows),
562  maCellTextAttrs(nTopEmptyRows),
563  maBroadcasters(nTopEmptyRows),
564  maCellNotes(nTopEmptyRows),
565  maPatterns(0, rSheetLimits.GetMaxRowCount(), nullptr),
566  miPatternPos(maPatterns.begin()) {}
567 
568  void setPattern( SCROW nRow, const ScPatternAttr* pPat )
569  {
570  miPatternPos = maPatterns.insert(miPatternPos, nRow, nRow+1, pPat).first;
571  }
572 };
573 
574 struct SortedRowFlags
575 {
576  typedef mdds::flat_segment_tree<SCROW,bool> FlagsType;
577 
578  FlagsType maRowsHidden;
579  FlagsType maRowsFiltered;
580  FlagsType::const_iterator miPosHidden;
581  FlagsType::const_iterator miPosFiltered;
582 
583  SortedRowFlags(const ScSheetLimits& rSheetLimits) :
584  maRowsHidden(0, rSheetLimits.GetMaxRowCount(), false),
585  maRowsFiltered(0, rSheetLimits.GetMaxRowCount(), false),
586  miPosHidden(maRowsHidden.begin()),
587  miPosFiltered(maRowsFiltered.begin()) {}
588 
589  void setRowHidden( SCROW nRow, bool b )
590  {
591  miPosHidden = maRowsHidden.insert(miPosHidden, nRow, nRow+1, b).first;
592  }
593 
594  void setRowFiltered( SCROW nRow, bool b )
595  {
596  miPosFiltered = maRowsFiltered.insert(miPosFiltered, nRow, nRow+1, b).first;
597  }
598 
599  void swap( SortedRowFlags& r )
600  {
601  maRowsHidden.swap(r.maRowsHidden);
602  maRowsFiltered.swap(r.maRowsFiltered);
603 
604  // Just reset the position hints.
605  miPosHidden = maRowsHidden.begin();
606  miPosFiltered = maRowsFiltered.begin();
607  }
608 };
609 
610 struct PatternSpan
611 {
612  SCROW mnRow1;
613  SCROW mnRow2;
614  const ScPatternAttr* mpPattern;
615 
616  PatternSpan( SCROW nRow1, SCROW nRow2, const ScPatternAttr* pPat ) :
617  mnRow1(nRow1), mnRow2(nRow2), mpPattern(pPat) {}
618 };
619 
620 }
621 
623 {
624  return pSortCollator == &ScGlobal::GetCollator() ||
626 }
627 
629 {
630  if ( !rPar.aCollatorLocale.Language.isEmpty() )
631  {
635  rPar.aCollatorLocale, (rPar.bCaseSens ? 0 : SC_COLLATOR_IGNORES) );
636  }
637  else
638  { // SYSTEM
641  }
642 }
643 
645 {
646  if ( pSortCollator )
647  {
648  if ( !IsSortCollatorGlobal() )
649  delete pSortCollator;
650  pSortCollator = nullptr;
651  }
652 }
653 
654 namespace {
655 
656 template<typename Hint, typename ReorderMap, typename Index>
657 class ReorderNotifier
658 {
659  Hint maHint;
660 public:
661  ReorderNotifier( const ReorderMap& rMap, SCTAB nTab, Index nPos1, Index nPos2 ) :
662  maHint(rMap, nTab, nPos1, nPos2) {}
663 
664  void operator() ( SvtListener* p )
665  {
666  p->Notify(maHint);
667  }
668 };
669 
670 class FormulaGroupPosCollector
671 {
672  sc::RefQueryFormulaGroup& mrQuery;
673 
674 public:
675  explicit FormulaGroupPosCollector( sc::RefQueryFormulaGroup& rQuery ) : mrQuery(rQuery) {}
676 
677  void operator() ( const SvtListener* p )
678  {
679  p->Query(mrQuery);
680  }
681 };
682 
683 void fillSortedColumnArray(
684  std::vector<std::unique_ptr<SortedColumn>>& rSortedCols,
685  SortedRowFlags& rRowFlags,
686  std::vector<SvtListener*>& rCellListeners,
687  ScSortInfoArray* pArray, SCTAB nTab, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress, const ScTable* pTable,
688  bool bOnlyDataAreaExtras )
689 {
690  assert(!bOnlyDataAreaExtras || !pArray->IsUpdateRefs());
691 
692  SCROW nRow1 = pArray->GetStart();
693  ScSortInfoArray::RowsType* pRows = pArray->GetDataRows();
694  std::vector<SCCOLROW> aOrderIndices = pArray->GetOrderIndices();
695 
696  size_t nColCount = nCol2 - nCol1 + 1;
697  std::vector<std::unique_ptr<SortedColumn>> aSortedCols; // storage for copied cells.
698  SortedRowFlags aRowFlags(pTable->GetDoc().GetSheetLimits());
699  aSortedCols.reserve(nColCount);
700  for (size_t i = 0; i < nColCount; ++i)
701  {
702  // In the sorted column container, element positions and row
703  // positions must match, else formula cells may mis-behave during
704  // grouping.
705  aSortedCols.push_back(std::make_unique<SortedColumn>(nRow1, pTable->GetDoc().GetSheetLimits()));
706  }
707 
708  for (size_t i = 0; i < pRows->size(); ++i)
709  {
710  const SCROW nRow = nRow1 + i;
711 
712  ScSortInfoArray::Row& rRow = (*pRows)[i];
713  for (size_t j = 0; j < rRow.maCells.size(); ++j)
714  {
715  ScSortInfoArray::Cell& rCell = rRow.maCells[j];
716 
717  // If bOnlyDataAreaExtras,
718  // sc::CellStoreType aSortedCols.at(j)->maCells
719  // and
720  // sc::CellTextAttrStoreType aSortedCols.at(j)->maCellTextAttrs
721  // are by definition all empty mdds::multi_type_vector, so nothing
722  // needs to be done to push *all* empty.
723 
724  if (!bOnlyDataAreaExtras)
725  {
726  sc::CellStoreType& rCellStore = aSortedCols.at(j)->maCells;
727  switch (rCell.maCell.meType)
728  {
729  case CELLTYPE_STRING:
730  assert(rCell.mpAttr);
731  rCellStore.push_back(*rCell.maCell.mpString);
732  break;
733  case CELLTYPE_VALUE:
734  assert(rCell.mpAttr);
735  rCellStore.push_back(rCell.maCell.mfValue);
736  break;
737  case CELLTYPE_EDIT:
738  assert(rCell.mpAttr);
739  rCellStore.push_back(rCell.maCell.mpEditText->Clone().release());
740  break;
741  case CELLTYPE_FORMULA:
742  {
743  assert(rCell.mpAttr);
744  ScAddress aOldPos = rCell.maCell.mpFormula->aPos;
745 
746  const ScAddress aCellPos(nCol1 + j, nRow, nTab);
747  ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone( aCellPos );
748  if (pArray->IsUpdateRefs())
749  {
750  pNew->CopyAllBroadcasters(*rCell.maCell.mpFormula);
751  pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos);
752  }
753  else
754  {
755  pNew->GetCode()->AdjustReferenceOnMovedOriginIfOtherSheet(aOldPos, aCellPos);
756  }
757 
758  if (!rCellListeners.empty())
759  {
760  // Original source cells will be deleted during
761  // sc::CellStoreType::transfer(), SvtListener is a base
762  // class, so we need to replace it.
763  auto it( ::std::find( rCellListeners.begin(), rCellListeners.end(), rCell.maCell.mpFormula));
764  if (it != rCellListeners.end())
765  *it = pNew;
766  }
767 
768  rCellStore.push_back(pNew);
769  }
770  break;
771  default:
772  //assert(!rCell.mpAttr);
773  // This assert doesn't hold, for example
774  // CopyCellsFromClipHandler may omit copying cells during
775  // PasteSpecial for which CopyTextAttrsFromClipHandler
776  // still copies a CellTextAttr. So if that really is not
777  // expected then fix it there.
778  rCellStore.push_back_empty();
779  }
780 
781  sc::CellTextAttrStoreType& rAttrStore = aSortedCols.at(j)->maCellTextAttrs;
782  if (rCell.mpAttr)
783  rAttrStore.push_back(*rCell.mpAttr);
784  else
785  rAttrStore.push_back_empty();
786  }
787 
788  if (pArray->IsUpdateRefs())
789  {
790  // At this point each broadcaster instance is managed by 2
791  // containers. We will release those in the original storage
792  // below before transferring them to the document.
793  const SvtBroadcaster* pBroadcaster = pTable->GetBroadcaster( nCol1 + j, aOrderIndices[i]);
794  sc::BroadcasterStoreType& rBCStore = aSortedCols.at(j)->maBroadcasters;
795  if (pBroadcaster)
796  // A const pointer would be implicitly converted to a bool type.
797  rBCStore.push_back(const_cast<SvtBroadcaster*>(pBroadcaster));
798  else
799  rBCStore.push_back_empty();
800  }
801 
802  // The same with cell note instances ...
803  sc::CellNoteStoreType& rNoteStore = aSortedCols.at(j)->maCellNotes;
804  if (rCell.mpNote)
805  rNoteStore.push_back(const_cast<ScPostIt*>(rCell.mpNote));
806  else
807  rNoteStore.push_back_empty();
808 
809  // Add cell anchored images
810  aSortedCols.at(j)->maCellDrawObjects.push_back(rCell.maDrawObjects);
811 
812  if (rCell.mpPattern)
813  aSortedCols.at(j)->setPattern(nRow, rCell.mpPattern);
814  }
815 
816  if (!bOnlyDataAreaExtras && pArray->IsKeepQuery())
817  {
818  // Hidden and filtered flags are first converted to segments.
819  aRowFlags.setRowHidden(nRow, rRow.mbHidden);
820  aRowFlags.setRowFiltered(nRow, rRow.mbFiltered);
821  }
822 
823  if (pProgress)
824  pProgress->SetStateOnPercent(i);
825  }
826 
827  rSortedCols.swap(aSortedCols);
828  rRowFlags.swap(aRowFlags);
829 }
830 
831 void expandRowRange( ScRange& rRange, SCROW nTop, SCROW nBottom )
832 {
833  if (nTop < rRange.aStart.Row())
834  rRange.aStart.SetRow(nTop);
835 
836  if (rRange.aEnd.Row() < nBottom)
837  rRange.aEnd.SetRow(nBottom);
838 }
839 
840 class FormulaCellCollectAction : public sc::ColumnSpanSet::ColumnAction
841 {
842  std::vector<ScFormulaCell*>& mrCells;
843  ScColumn* mpCol;
844 
845 public:
846  explicit FormulaCellCollectAction( std::vector<ScFormulaCell*>& rCells ) :
847  mrCells(rCells), mpCol(nullptr) {}
848 
849  virtual void startColumn( ScColumn* pCol ) override
850  {
851  mpCol = pCol;
852  }
853 
854  virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override
855  {
856  assert(mpCol);
857 
858  if (!bVal)
859  return;
860 
861  mpCol->CollectFormulaCells(mrCells, nRow1, nRow2);
862  }
863 };
864 
865 class ListenerStartAction : public sc::ColumnSpanSet::ColumnAction
866 {
867  ScColumn* mpCol;
868 
869  std::shared_ptr<sc::ColumnBlockPositionSet> mpPosSet;
870  sc::StartListeningContext maStartCxt;
871  sc::EndListeningContext maEndCxt;
872 
873 public:
874  explicit ListenerStartAction( ScDocument& rDoc ) :
875  mpCol(nullptr),
876  mpPosSet(std::make_shared<sc::ColumnBlockPositionSet>(rDoc)),
877  maStartCxt(rDoc, mpPosSet),
878  maEndCxt(rDoc, mpPosSet) {}
879 
880  virtual void startColumn( ScColumn* pCol ) override
881  {
882  mpCol = pCol;
883  }
884 
885  virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override
886  {
887  assert(mpCol);
888 
889  if (!bVal)
890  return;
891 
892  mpCol->StartListeningFormulaCells(maStartCxt, maEndCxt, nRow1, nRow2);
893  }
894 };
895 
896 }
897 
899  SCCOL nDataCol1, SCCOL nDataCol2,
900  const ScDataAreaExtras& rDataAreaExtras, ScProgress* pProgress )
901 {
902  const SCROW nRow1 = pArray->GetStart();
903  const SCROW nLastRow = pArray->GetLast();
904  const SCCOL nChunkCols = std::max<SCCOL>( 1, kSortCellsChunk / (nLastRow - nRow1 + 1));
905  // Before data area.
906  for (SCCOL nCol = rDataAreaExtras.mnStartCol; nCol < nDataCol1; nCol += nChunkCols)
907  {
908  const SCCOL nEndCol = std::min<SCCOL>( nCol + nChunkCols - 1, nDataCol1 - 1);
909  initDataRows( *pArray, *this, aCol, nCol, nRow1, nEndCol, nLastRow, false,
910  rDataAreaExtras.mbCellFormats, rDataAreaExtras.mbCellNotes, rDataAreaExtras.mbCellDrawObjects, true);
911  SortReorderByRow( pArray, nCol, nEndCol, pProgress, true);
912  }
913  // Behind data area.
914  for (SCCOL nCol = nDataCol2 + 1; nCol <= rDataAreaExtras.mnEndCol; nCol += nChunkCols)
915  {
916  const SCCOL nEndCol = std::min<SCCOL>( nCol + nChunkCols - 1, rDataAreaExtras.mnEndCol);
917  initDataRows( *pArray, *this, aCol, nCol, nRow1, nEndCol, nLastRow, false,
918  rDataAreaExtras.mbCellFormats, rDataAreaExtras.mbCellNotes, rDataAreaExtras.mbCellDrawObjects, true);
919  SortReorderByRow( pArray, nCol, nEndCol, pProgress, true);
920  }
921 }
922 
924  SCROW nDataRow1, SCROW nDataRow2, const ScDataAreaExtras& rDataAreaExtras, ScProgress* pProgress )
925 {
926  const SCCOL nCol1 = static_cast<SCCOL>(pArray->GetStart());
927  const SCCOL nLastCol = static_cast<SCCOL>(pArray->GetLast());
928  const SCROW nChunkRows = std::max<SCROW>( 1, kSortCellsChunk / (nLastCol - nCol1 + 1));
929  // Above data area.
930  for (SCROW nRow = rDataAreaExtras.mnStartRow; nRow < nDataRow1; nRow += nChunkRows)
931  {
932  const SCROW nEndRow = std::min<SCROW>( nRow + nChunkRows - 1, nDataRow1 - 1);
933  SortReorderByColumn( pArray, nRow, nEndRow, rDataAreaExtras.mbCellFormats, pProgress);
934  }
935  // Below data area.
936  for (SCROW nRow = nDataRow2 + 1; nRow <= rDataAreaExtras.mnEndRow; nRow += nChunkRows)
937  {
938  const SCROW nEndRow = std::min<SCROW>( nRow + nChunkRows - 1, rDataAreaExtras.mnEndRow);
939  SortReorderByColumn( pArray, nRow, nEndRow, rDataAreaExtras.mbCellFormats, pProgress);
940  }
941 }
942 
944  const ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2, bool bPattern, ScProgress* pProgress )
945 {
946  SCCOLROW nStart = pArray->GetStart();
947  SCCOLROW nLast = pArray->GetLast();
948 
949  std::vector<SCCOLROW> aIndices = pArray->GetOrderIndices();
950  size_t nCount = aIndices.size();
951 
952  // Cut formula grouping at row and reference boundaries before the reordering.
953  ScRange aSortRange(nStart, nRow1, nTab, nLast, nRow2, nTab);
954  for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol)
955  aCol[nCol].SplitFormulaGroupByRelativeRef(aSortRange);
956 
957  // Collect all listeners of cell broadcasters of sorted range.
958  std::vector<SvtListener*> aCellListeners;
959 
960  if (!pArray->IsUpdateRefs())
961  {
962  // Collect listeners of cell broadcasters.
963  for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol)
964  aCol[nCol].CollectListeners(aCellListeners, nRow1, nRow2);
965 
966  // Remove any duplicate listener entries. We must ensure that we
967  // notify each unique listener only once.
968  std::sort(aCellListeners.begin(), aCellListeners.end());
969  aCellListeners.erase(std::unique(aCellListeners.begin(), aCellListeners.end()), aCellListeners.end());
970 
971  // Notify the cells' listeners to stop listening.
972  /* TODO: for performance this could be enhanced to stop and later
973  * restart only listening to within the reordered range and keep
974  * listening to everything outside untouched. */
976  for (auto const & l : aCellListeners)
977  l->Notify(aHint);
978  }
979 
980  // table to keep track of column index to position in the index table.
981  std::vector<SCCOLROW> aPosTable(nCount);
982  for (size_t i = 0; i < nCount; ++i)
983  aPosTable[aIndices[i]-nStart] = i;
984 
985  SCCOLROW nDest = nStart;
986  for (size_t i = 0; i < nCount; ++i, ++nDest)
987  {
988  SCCOLROW nSrc = aIndices[i];
989  if (nDest != nSrc)
990  {
991  aCol[nDest].Swap(aCol[nSrc], nRow1, nRow2, bPattern);
992 
993  // Update the position of the index that was originally equal to nDest.
994  size_t nPos = aPosTable[nDest-nStart];
995  aIndices[nPos] = nSrc;
996  aPosTable[nSrc-nStart] = nPos;
997  }
998 
999  if (pProgress)
1000  pProgress->SetStateOnPercent(i);
1001  }
1002 
1003  // Reset formula cell positions which became out-of-sync after column reordering.
1004  bool bUpdateRefs = pArray->IsUpdateRefs();
1005  for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol)
1006  aCol[nCol].ResetFormulaCellPositions(nRow1, nRow2, bUpdateRefs);
1007 
1008  if (pArray->IsUpdateRefs())
1009  {
1010  // Set up column reorder map (for later broadcasting of reference updates).
1011  sc::ColRowReorderMapType aColMap;
1012  const std::vector<SCCOLROW>& rOldIndices = pArray->GetOrderIndices();
1013  for (size_t i = 0, n = rOldIndices.size(); i < n; ++i)
1014  {
1015  SCCOL nNew = i + nStart;
1016  SCCOL nOld = rOldIndices[i];
1017  aColMap.emplace(nOld, nNew);
1018  }
1019 
1020  // Collect all listeners within sorted range ahead of time.
1021  std::vector<SvtListener*> aListeners;
1022 
1023  for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol)
1024  aCol[nCol].CollectListeners(aListeners, nRow1, nRow2);
1025 
1026  // Get all area listeners that listen on one column within the range
1027  // and end their listening.
1028  ScRange aMoveRange( nStart, nRow1, nTab, nLast, nRow2, nTab);
1029  std::vector<sc::AreaListener> aAreaListeners = rDocument.GetBASM()->GetAllListeners(
1031  {
1032  for (auto& rAreaListener : aAreaListeners)
1033  {
1034  rDocument.EndListeningArea(rAreaListener.maArea, rAreaListener.mbGroupListening, rAreaListener.mpListener);
1035  aListeners.push_back( rAreaListener.mpListener);
1036  }
1037  }
1038 
1039  // Remove any duplicate listener entries and notify all listeners
1040  // afterward. We must ensure that we notify each unique listener only
1041  // once.
1042  std::sort(aListeners.begin(), aListeners.end());
1043  aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end());
1044  ReorderNotifier<sc::RefColReorderHint, sc::ColRowReorderMapType, SCCOL> aFunc(aColMap, nTab, nRow1, nRow2);
1045  std::for_each(aListeners.begin(), aListeners.end(), aFunc);
1046 
1047  // Re-start area listeners on the reordered columns.
1048  {
1049  for (auto& rAreaListener : aAreaListeners)
1050  {
1051  ScRange aNewRange = rAreaListener.maArea;
1052  sc::ColRowReorderMapType::const_iterator itCol = aColMap.find( aNewRange.aStart.Col());
1053  if (itCol != aColMap.end())
1054  {
1055  aNewRange.aStart.SetCol( itCol->second);
1056  aNewRange.aEnd.SetCol( itCol->second);
1057  }
1058  rDocument.StartListeningArea(aNewRange, rAreaListener.mbGroupListening, rAreaListener.mpListener);
1059  }
1060  }
1061  }
1062  else // !(pArray->IsUpdateRefs())
1063  {
1064  // Notify the cells' listeners to (re-)start listening.
1066  for (auto const & l : aCellListeners)
1067  l->Notify(aHint);
1068  }
1069 
1070  // Re-join formulas at row boundaries now that all the references have
1071  // been adjusted for column reordering.
1072  for (SCCOL nCol = nStart; nCol <= static_cast<SCCOL>(nLast); ++nCol)
1073  {
1074  sc::CellStoreType& rCells = aCol[nCol].maCells;
1075  sc::CellStoreType::position_type aPos = rCells.position(nRow1);
1077  if (nRow2 < rDocument.MaxRow())
1078  {
1079  aPos = rCells.position(aPos.first, nRow2+1);
1081  }
1082  }
1083 }
1084 
1086  ScProgress* pProgress, bool bOnlyDataAreaExtras )
1087 {
1088  assert(!pArray->IsUpdateRefs());
1089 
1090  if (nCol2 < nCol1)
1091  return;
1092 
1093  // bOnlyDataAreaExtras:
1094  // Data area extras by definition do not have any cell content so no
1095  // formula cells either, so that handling doesn't need to be executed.
1096  // However, there may be listeners of formulas listening to broadcasters of
1097  // empty cells.
1098 
1099  SCROW nRow1 = pArray->GetStart();
1100  SCROW nRow2 = pArray->GetLast();
1101 
1102  // Collect all listeners of cell broadcasters of sorted range.
1103  std::vector<SvtListener*> aCellListeners;
1104 
1105  // When the update ref mode is disabled, we need to detach all formula
1106  // cells in the sorted range before reordering, and re-start them
1107  // afterward.
1108  if (!bOnlyDataAreaExtras)
1109  {
1111  DetachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2);
1112  }
1113 
1114  // Collect listeners of cell broadcasters.
1115  for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1116  aCol[nCol].CollectListeners(aCellListeners, nRow1, nRow2);
1117 
1118  // Remove any duplicate listener entries. We must ensure that we notify
1119  // each unique listener only once.
1120  std::sort(aCellListeners.begin(), aCellListeners.end());
1121  aCellListeners.erase(std::unique(aCellListeners.begin(), aCellListeners.end()), aCellListeners.end());
1122 
1123  // Notify the cells' listeners to stop listening.
1124  /* TODO: for performance this could be enhanced to stop and later
1125  * restart only listening to within the reordered range and keep
1126  * listening to everything outside untouched. */
1127  {
1129  for (auto const & l : aCellListeners)
1130  l->Notify(aHint);
1131  }
1132 
1133  // Split formula groups at the sort range boundaries (if applicable).
1134  if (!bOnlyDataAreaExtras)
1135  {
1136  std::vector<SCROW> aRowBounds
1137  {
1138  nRow1,
1139  nRow2+1
1140  };
1141  for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1142  SplitFormulaGroups(nCol, aRowBounds);
1143  }
1144 
1145  // Cells in the data rows only reference values in the document. Make
1146  // a copy before updating the document.
1147  std::vector<std::unique_ptr<SortedColumn>> aSortedCols; // storage for copied cells.
1148  SortedRowFlags aRowFlags(GetDoc().GetSheetLimits());
1149  fillSortedColumnArray(aSortedCols, aRowFlags, aCellListeners, pArray, nTab, nCol1, nCol2,
1150  pProgress, this, bOnlyDataAreaExtras);
1151 
1152  for (size_t i = 0, n = aSortedCols.size(); i < n; ++i)
1153  {
1154  SCCOL nThisCol = i + nCol1;
1155 
1156  if (!bOnlyDataAreaExtras)
1157  {
1158  {
1159  sc::CellStoreType& rDest = aCol[nThisCol].maCells;
1160  sc::CellStoreType& rSrc = aSortedCols[i]->maCells;
1161  rSrc.transfer(nRow1, nRow2, rDest, nRow1);
1162  }
1163 
1164  {
1165  sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs;
1166  sc::CellTextAttrStoreType& rSrc = aSortedCols[i]->maCellTextAttrs;
1167  rSrc.transfer(nRow1, nRow2, rDest, nRow1);
1168  }
1169  }
1170 
1171  {
1172  sc::CellNoteStoreType& rSrc = aSortedCols[i]->maCellNotes;
1173  sc::CellNoteStoreType& rDest = aCol[nThisCol].maCellNotes;
1174 
1175  // Do the same as broadcaster storage transfer (to prevent double deletion).
1176  rDest.release_range(nRow1, nRow2);
1177  rSrc.transfer(nRow1, nRow2, rDest, nRow1);
1178  aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2);
1179  }
1180 
1181  // Update draw object positions
1182  aCol[nThisCol].UpdateDrawObjects(aSortedCols[i]->maCellDrawObjects, nRow1, nRow2);
1183 
1184  {
1185  // Get all row spans where the pattern is not NULL.
1186  std::vector<PatternSpan> aSpans =
1187  sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>(
1188  aSortedCols[i]->maPatterns);
1189 
1190  for (const auto& rSpan : aSpans)
1191  {
1192  assert(rSpan.mpPattern); // should never be NULL.
1193  rDocument.GetPool()->Put(*rSpan.mpPattern);
1194  }
1195 
1196  for (const auto& rSpan : aSpans)
1197  {
1198  aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, *rSpan.mpPattern);
1199  rDocument.GetPool()->Remove(*rSpan.mpPattern);
1200  }
1201  }
1202 
1203  aCol[nThisCol].CellStorageModified();
1204  }
1205 
1206  if (!bOnlyDataAreaExtras && pArray->IsKeepQuery())
1207  {
1208  aRowFlags.maRowsHidden.build_tree();
1209  aRowFlags.maRowsFiltered.build_tree();
1210 
1211  // Remove all flags in the range first.
1212  SetRowHidden(nRow1, nRow2, false);
1213  SetRowFiltered(nRow1, nRow2, false);
1214 
1215  std::vector<sc::RowSpan> aSpans =
1216  sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsHidden, nRow1);
1217 
1218  for (const auto& rSpan : aSpans)
1219  SetRowHidden(rSpan.mnRow1, rSpan.mnRow2, true);
1220 
1221  aSpans = sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsFiltered, nRow1);
1222 
1223  for (const auto& rSpan : aSpans)
1224  SetRowFiltered(rSpan.mnRow1, rSpan.mnRow2, true);
1225  }
1226 
1227  // Notify the cells' listeners to (re-)start listening.
1228  {
1230  for (auto const & l : aCellListeners)
1231  l->Notify(aHint);
1232  }
1233 
1234  if (!bOnlyDataAreaExtras)
1235  {
1236  // Re-group columns in the sorted range too.
1237  for (SCCOL i = nCol1; i <= nCol2; ++i)
1239 
1240  {
1242  AttachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2);
1243  }
1244  }
1245 }
1246 
1248  ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress )
1249 {
1250  assert(pArray->IsUpdateRefs());
1251 
1252  if (nCol2 < nCol1)
1253  return;
1254 
1255  SCROW nRow1 = pArray->GetStart();
1256  SCROW nRow2 = pArray->GetLast();
1257 
1258  ScRange aMoveRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1259  sc::ColumnSpanSet aGrpListenerRanges;
1260 
1261  {
1262  // Get the range of formula group listeners within sorted range (if any).
1263  sc::QueryRange aQuery;
1264 
1266  std::vector<sc::AreaListener> aGrpListeners =
1267  pBASM->GetAllListeners(
1269 
1270  {
1271  for (const auto& rGrpListener : aGrpListeners)
1272  {
1273  assert(rGrpListener.mbGroupListening);
1274  SvtListener* pGrpLis = rGrpListener.mpListener;
1275  pGrpLis->Query(aQuery);
1276  rDocument.EndListeningArea(rGrpListener.maArea, rGrpListener.mbGroupListening, pGrpLis);
1277  }
1278  }
1279 
1280  ScRangeList aTmp;
1281  aQuery.swapRanges(aTmp);
1282 
1283  // If the range is within the sorted range, we need to expand its rows
1284  // to the top and bottom of the sorted range, since the formula cells
1285  // could be anywhere in the sorted range after reordering.
1286  for (size_t i = 0, n = aTmp.size(); i < n; ++i)
1287  {
1288  ScRange aRange = aTmp[i];
1289  if (!aMoveRange.Intersects(aRange))
1290  {
1291  // Doesn't overlap with the sorted range at all.
1292  aGrpListenerRanges.set(GetDoc(), aRange, true);
1293  continue;
1294  }
1295 
1296  if (aMoveRange.aStart.Col() <= aRange.aStart.Col() && aRange.aEnd.Col() <= aMoveRange.aEnd.Col())
1297  {
1298  // Its column range is within the column range of the sorted range.
1299  expandRowRange(aRange, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row());
1300  aGrpListenerRanges.set(GetDoc(), aRange, true);
1301  continue;
1302  }
1303 
1304  // It intersects with the sorted range, but its column range is
1305  // not within the column range of the sorted range. Split it into
1306  // 2 ranges.
1307  ScRange aR1 = aRange;
1308  ScRange aR2 = aRange;
1309  if (aRange.aStart.Col() < aMoveRange.aStart.Col())
1310  {
1311  // Left half is outside the sorted range while the right half is inside.
1312  aR1.aEnd.SetCol(aMoveRange.aStart.Col()-1);
1313  aR2.aStart.SetCol(aMoveRange.aStart.Col());
1314  expandRowRange(aR2, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row());
1315  }
1316  else
1317  {
1318  // Left half is inside the sorted range while the right half is outside.
1319  aR1.aEnd.SetCol(aMoveRange.aEnd.Col()-1);
1320  aR2.aStart.SetCol(aMoveRange.aEnd.Col());
1321  expandRowRange(aR1, aMoveRange.aStart.Row(), aMoveRange.aEnd.Row());
1322  }
1323 
1324  aGrpListenerRanges.set(GetDoc(), aR1, true);
1325  aGrpListenerRanges.set(GetDoc(), aR2, true);
1326  }
1327  }
1328 
1329  // Split formula groups at the sort range boundaries (if applicable).
1330  std::vector<SCROW> aRowBounds
1331  {
1332  nRow1,
1333  nRow2+1
1334  };
1335  for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1336  SplitFormulaGroups(nCol, aRowBounds);
1337 
1338  // Cells in the data rows only reference values in the document. Make
1339  // a copy before updating the document.
1340  std::vector<std::unique_ptr<SortedColumn>> aSortedCols; // storage for copied cells.
1341  SortedRowFlags aRowFlags(GetDoc().GetSheetLimits());
1342  std::vector<SvtListener*> aListenersDummy;
1343  fillSortedColumnArray(aSortedCols, aRowFlags, aListenersDummy, pArray, nTab, nCol1, nCol2, pProgress, this, false);
1344 
1345  for (size_t i = 0, n = aSortedCols.size(); i < n; ++i)
1346  {
1347  SCCOL nThisCol = i + nCol1;
1348 
1349  {
1350  sc::CellStoreType& rDest = aCol[nThisCol].maCells;
1351  sc::CellStoreType& rSrc = aSortedCols[i]->maCells;
1352  rSrc.transfer(nRow1, nRow2, rDest, nRow1);
1353  }
1354 
1355  {
1356  sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs;
1357  sc::CellTextAttrStoreType& rSrc = aSortedCols[i]->maCellTextAttrs;
1358  rSrc.transfer(nRow1, nRow2, rDest, nRow1);
1359  }
1360 
1361  {
1362  sc::BroadcasterStoreType& rSrc = aSortedCols[i]->maBroadcasters;
1363  sc::BroadcasterStoreType& rDest = aCol[nThisCol].maBroadcasters;
1364 
1365  // Release current broadcasters first, to prevent them from getting deleted.
1366  rDest.release_range(nRow1, nRow2);
1367 
1368  // Transfer sorted broadcaster segment to the document.
1369  rSrc.transfer(nRow1, nRow2, rDest, nRow1);
1370  }
1371 
1372  {
1373  sc::CellNoteStoreType& rSrc = aSortedCols[i]->maCellNotes;
1374  sc::CellNoteStoreType& rDest = aCol[nThisCol].maCellNotes;
1375 
1376  // Do the same as broadcaster storage transfer (to prevent double deletion).
1377  rDest.release_range(nRow1, nRow2);
1378  rSrc.transfer(nRow1, nRow2, rDest, nRow1);
1379  aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2);
1380  }
1381 
1382  // Update draw object positions
1383  aCol[nThisCol].UpdateDrawObjects(aSortedCols[i]->maCellDrawObjects, nRow1, nRow2);
1384 
1385  {
1386  // Get all row spans where the pattern is not NULL.
1387  std::vector<PatternSpan> aSpans =
1388  sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>(
1389  aSortedCols[i]->maPatterns);
1390 
1391  for (const auto& rSpan : aSpans)
1392  {
1393  assert(rSpan.mpPattern); // should never be NULL.
1394  rDocument.GetPool()->Put(*rSpan.mpPattern);
1395  }
1396 
1397  for (const auto& rSpan : aSpans)
1398  {
1399  aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, *rSpan.mpPattern);
1400  rDocument.GetPool()->Remove(*rSpan.mpPattern);
1401  }
1402  }
1403 
1404  aCol[nThisCol].CellStorageModified();
1405  }
1406 
1407  if (pArray->IsKeepQuery())
1408  {
1409  aRowFlags.maRowsHidden.build_tree();
1410  aRowFlags.maRowsFiltered.build_tree();
1411 
1412  // Remove all flags in the range first.
1413  SetRowHidden(nRow1, nRow2, false);
1414  SetRowFiltered(nRow1, nRow2, false);
1415 
1416  std::vector<sc::RowSpan> aSpans =
1417  sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsHidden, nRow1);
1418 
1419  for (const auto& rSpan : aSpans)
1420  SetRowHidden(rSpan.mnRow1, rSpan.mnRow2, true);
1421 
1422  aSpans = sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsFiltered, nRow1);
1423 
1424  for (const auto& rSpan : aSpans)
1425  SetRowFiltered(rSpan.mnRow1, rSpan.mnRow2, true);
1426  }
1427 
1428  // Set up row reorder map (for later broadcasting of reference updates).
1429  sc::ColRowReorderMapType aRowMap;
1430  const std::vector<SCCOLROW>& rOldIndices = pArray->GetOrderIndices();
1431  for (size_t i = 0, n = rOldIndices.size(); i < n; ++i)
1432  {
1433  SCROW nNew = i + nRow1;
1434  SCROW nOld = rOldIndices[i];
1435  aRowMap.emplace(nOld, nNew);
1436  }
1437 
1438  // Collect all listeners within sorted range ahead of time.
1439  std::vector<SvtListener*> aListeners;
1440 
1441  // Collect listeners of cell broadcasters.
1442  for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1443  aCol[nCol].CollectListeners(aListeners, nRow1, nRow2);
1444 
1445  // Get all area listeners that listen on one row within the range and end
1446  // their listening.
1447  std::vector<sc::AreaListener> aAreaListeners = rDocument.GetBASM()->GetAllListeners(
1448  aMoveRange, sc::AreaOverlapType::OneRowInside);
1449  {
1450  for (auto& rAreaListener : aAreaListeners)
1451  {
1452  rDocument.EndListeningArea(rAreaListener.maArea, rAreaListener.mbGroupListening, rAreaListener.mpListener);
1453  aListeners.push_back( rAreaListener.mpListener);
1454  }
1455  }
1456 
1457  {
1458  // Get all formula cells from the former group area listener ranges.
1459 
1460  std::vector<ScFormulaCell*> aFCells;
1461  FormulaCellCollectAction aAction(aFCells);
1462  aGrpListenerRanges.executeColumnAction(rDocument, aAction);
1463 
1464  aListeners.insert( aListeners.end(), aFCells.begin(), aFCells.end() );
1465  }
1466 
1467  // Remove any duplicate listener entries. We must ensure that we notify
1468  // each unique listener only once.
1469  std::sort(aListeners.begin(), aListeners.end());
1470  aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end());
1471 
1472  // Collect positions of all shared formula cells outside the sorted range,
1473  // and make them unshared before notifying them.
1474  sc::RefQueryFormulaGroup aFormulaGroupPos;
1475  aFormulaGroupPos.setSkipRange(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab));
1476 
1477  std::for_each(aListeners.begin(), aListeners.end(), FormulaGroupPosCollector(aFormulaGroupPos));
1478  const sc::RefQueryFormulaGroup::TabsType& rGroupTabs = aFormulaGroupPos.getAllPositions();
1479  for (const auto& [rTab, rCols] : rGroupTabs)
1480  {
1481  for (const auto& [nCol, rCol] : rCols)
1482  {
1483  std::vector<SCROW> aBounds(rCol);
1484  rDocument.UnshareFormulaCells(rTab, nCol, aBounds);
1485  }
1486  }
1487 
1488  // Notify the listeners to update their references.
1489  ReorderNotifier<sc::RefRowReorderHint, sc::ColRowReorderMapType, SCROW> aFunc(aRowMap, nTab, nCol1, nCol2);
1490  std::for_each(aListeners.begin(), aListeners.end(), aFunc);
1491 
1492  // Re-group formulas in affected columns.
1493  for (const auto& [rTab, rCols] : rGroupTabs)
1494  {
1495  for (const auto& rEntry : rCols)
1496  rDocument.RegroupFormulaCells(rTab, rEntry.first);
1497  }
1498 
1499  // Re-start area listeners on the reordered rows.
1500  for (const auto& rAreaListener : aAreaListeners)
1501  {
1502  ScRange aNewRange = rAreaListener.maArea;
1503  sc::ColRowReorderMapType::const_iterator itRow = aRowMap.find( aNewRange.aStart.Row());
1504  if (itRow != aRowMap.end())
1505  {
1506  aNewRange.aStart.SetRow( itRow->second);
1507  aNewRange.aEnd.SetRow( itRow->second);
1508  }
1509  rDocument.StartListeningArea(aNewRange, rAreaListener.mbGroupListening, rAreaListener.mpListener);
1510  }
1511 
1512  // Re-group columns in the sorted range too.
1513  for (SCCOL i = nCol1; i <= nCol2; ++i)
1515 
1516  {
1517  // Re-start area listeners on the old group listener ranges.
1518  ListenerStartAction aAction(rDocument);
1519  aGrpListenerRanges.executeColumnAction(rDocument, aAction);
1520  }
1521 }
1522 
1524  sal_uInt16 nSort,
1525  ScRefCellValue& rCell1, SCCOL nCell1Col, SCROW nCell1Row,
1526  ScRefCellValue& rCell2, SCCOL nCell2Col, SCROW nCell2Row ) const
1527 {
1528  short nRes = 0;
1529 
1530  CellType eType1 = rCell1.meType, eType2 = rCell2.meType;
1531 
1532  if (!rCell1.isEmpty())
1533  {
1534  if (!rCell2.isEmpty())
1535  {
1536  bool bErr1 = false;
1537  bool bStr1 = ( eType1 != CELLTYPE_VALUE );
1538  if (eType1 == CELLTYPE_FORMULA)
1539  {
1540  if (rCell1.mpFormula->GetErrCode() != FormulaError::NONE)
1541  {
1542  bErr1 = true;
1543  bStr1 = false;
1544  }
1545  else if (rCell1.mpFormula->IsValue())
1546  {
1547  bStr1 = false;
1548  }
1549  }
1550 
1551  bool bErr2 = false;
1552  bool bStr2 = ( eType2 != CELLTYPE_VALUE );
1553  if (eType2 == CELLTYPE_FORMULA)
1554  {
1555  if (rCell2.mpFormula->GetErrCode() != FormulaError::NONE)
1556  {
1557  bErr2 = true;
1558  bStr2 = false;
1559  }
1560  else if (rCell2.mpFormula->IsValue())
1561  {
1562  bStr2 = false;
1563  }
1564  }
1565 
1566  if ( bStr1 && bStr2 ) // only compare strings as strings!
1567  {
1568  OUString aStr1;
1569  OUString aStr2;
1570  if (eType1 == CELLTYPE_STRING)
1571  aStr1 = rCell1.mpString->getString();
1572  else
1573  aStr1 = GetString(nCell1Col, nCell1Row);
1574  if (eType2 == CELLTYPE_STRING)
1575  aStr2 = rCell2.mpString->getString();
1576  else
1577  aStr2 = GetString(nCell2Col, nCell2Row);
1578 
1579  bool bUserDef = aSortParam.bUserDef; // custom sort order
1580  bool bNaturalSort = aSortParam.bNaturalSort; // natural sort
1581  bool bCaseSens = aSortParam.bCaseSens; // case sensitivity
1582 
1583  ScUserList* pList = ScGlobal::GetUserList();
1584  if (bUserDef && pList && pList->size() > aSortParam.nUserIndex )
1585  {
1586  const ScUserListData& rData = (*pList)[aSortParam.nUserIndex];
1587 
1588  if ( bNaturalSort )
1589  nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, &rData, pSortCollator );
1590  else
1591  {
1592  if ( bCaseSens )
1593  nRes = sal::static_int_cast<short>( rData.Compare(aStr1, aStr2) );
1594  else
1595  nRes = sal::static_int_cast<short>( rData.ICompare(aStr1, aStr2) );
1596  }
1597 
1598  }
1599  if (!bUserDef)
1600  {
1601  if ( bNaturalSort )
1602  nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, nullptr, pSortCollator );
1603  else
1604  nRes = static_cast<short>( pSortCollator->compareString( aStr1, aStr2 ) );
1605  }
1606  }
1607  else if ( bStr1 ) // String <-> Number or Error
1608  {
1609  if (bErr2)
1610  nRes = -1; // String in front of Error
1611  else
1612  nRes = 1; // Number in front of String
1613  }
1614  else if ( bStr2 ) // Number or Error <-> String
1615  {
1616  if (bErr1)
1617  nRes = 1; // String in front of Error
1618  else
1619  nRes = -1; // Number in front of String
1620  }
1621  else if (bErr1 && bErr2)
1622  {
1623  // nothing, two Errors are equal
1624  }
1625  else if (bErr1) // Error <-> Number
1626  {
1627  nRes = 1; // Number in front of Error
1628  }
1629  else if (bErr2) // Number <-> Error
1630  {
1631  nRes = -1; // Number in front of Error
1632  }
1633  else // Mixed numbers
1634  {
1635  double nVal1 = rCell1.getValue();
1636  double nVal2 = rCell2.getValue();
1637  if (nVal1 < nVal2)
1638  nRes = -1;
1639  else if (nVal1 > nVal2)
1640  nRes = 1;
1641  }
1642  if ( !aSortParam.maKeyState[nSort].bAscending )
1643  nRes = -nRes;
1644  }
1645  else
1646  nRes = -1;
1647  }
1648  else
1649  {
1650  if (!rCell2.isEmpty())
1651  nRes = 1;
1652  else
1653  nRes = 0; // both empty
1654  }
1655  return nRes;
1656 }
1657 
1658 short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nIndex2 ) const
1659 {
1660  short nRes;
1661  sal_uInt16 nSort = 0;
1662  do
1663  {
1664  ScSortInfo& rInfo1 = pArray->Get( nSort, nIndex1 );
1665  ScSortInfo& rInfo2 = pArray->Get( nSort, nIndex2 );
1666  if ( aSortParam.bByRow )
1667  nRes = CompareCell( nSort,
1668  rInfo1.maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), rInfo1.nOrg,
1669  rInfo2.maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), rInfo2.nOrg );
1670  else
1671  nRes = CompareCell( nSort,
1672  rInfo1.maCell, static_cast<SCCOL>(rInfo1.nOrg), aSortParam.maKeyState[nSort].nField,
1673  rInfo2.maCell, static_cast<SCCOL>(rInfo2.nOrg), aSortParam.maKeyState[nSort].nField );
1674  } while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() );
1675  if( nRes == 0 )
1676  {
1677  ScSortInfo& rInfo1 = pArray->Get( 0, nIndex1 );
1678  ScSortInfo& rInfo2 = pArray->Get( 0, nIndex2 );
1679  if( rInfo1.nOrg < rInfo2.nOrg )
1680  nRes = -1;
1681  else if( rInfo1.nOrg > rInfo2.nOrg )
1682  nRes = 1;
1683  }
1684  return nRes;
1685 }
1686 
1688 {
1689  if ((nHi - nLo) == 1)
1690  {
1691  if (Compare(pArray, nLo, nHi) > 0)
1692  pArray->Swap( nLo, nHi );
1693  }
1694  else
1695  {
1696  SCCOLROW ni = nLo;
1697  SCCOLROW nj = nHi;
1698  do
1699  {
1700  while ((ni <= nHi) && (Compare(pArray, ni, nLo)) < 0)
1701  ni++;
1702  while ((nj >= nLo) && (Compare(pArray, nLo, nj)) < 0)
1703  nj--;
1704  if (ni <= nj)
1705  {
1706  if (ni != nj)
1707  pArray->Swap( ni, nj );
1708  ni++;
1709  nj--;
1710  }
1711  } while (ni < nj);
1712  if ((nj - nLo) < (nHi - ni))
1713  {
1714  if (nLo < nj)
1715  QuickSort(pArray, nLo, nj);
1716  if (ni < nHi)
1717  QuickSort(pArray, ni, nHi);
1718  }
1719  else
1720  {
1721  if (ni < nHi)
1722  QuickSort(pArray, ni, nHi);
1723  if (nLo < nj)
1724  QuickSort(pArray, nLo, nj);
1725  }
1726  }
1727 }
1728 
1729 short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
1730 {
1731  short nRes;
1732  sal_uInt16 nSort = 0;
1733  const sal_uInt32 nMaxSorts = aSortParam.GetSortKeyCount();
1734  if (aSortParam.bByRow)
1735  {
1736  do
1737  {
1738  SCCOL nCol = static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField);
1739  ScRefCellValue aCell1 = aCol[nCol].GetCellValue(nIndex1);
1740  ScRefCellValue aCell2 = aCol[nCol].GetCellValue(nIndex2);
1741  nRes = CompareCell(nSort, aCell1, nCol, nIndex1, aCell2, nCol, nIndex2);
1742  } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
1743  }
1744  else
1745  {
1746  do
1747  {
1748  SCROW nRow = aSortParam.maKeyState[nSort].nField;
1749  ScRefCellValue aCell1 = aCol[nIndex1].GetCellValue(nRow);
1750  ScRefCellValue aCell2 = aCol[nIndex2].GetCellValue(nRow);
1751  nRes = CompareCell( nSort, aCell1, static_cast<SCCOL>(nIndex1),
1752  nRow, aCell2, static_cast<SCCOL>(nIndex2), nRow );
1753  } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
1754  }
1755  return nRes;
1756 }
1757 
1758 bool ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) const // over aSortParam
1759 {
1760  for (SCCOLROW i=nStart; i<nEnd; i++)
1761  {
1762  if (Compare( i, i+1 ) > 0)
1763  return false;
1764  }
1765  return true;
1766 }
1767 
1768 void ScTable::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 )
1769 {
1770  SCROW nRow;
1771  int nMax = nRow2 - nRow1;
1772  for (SCROW i = nRow1; (i + 4) <= nRow2; i += 4)
1773  {
1775  pArray->Swap(i, nRow1 + nRow);
1776  }
1777 }
1778 
1780  const ScSortParam& rSortParam, bool bKeepQuery, bool bUpdateRefs,
1781  ScProgress* pProgress, sc::ReorderParam* pUndo )
1782 {
1783  InitSortCollator( rSortParam );
1784  bGlobalKeepQuery = bKeepQuery;
1785 
1786  if (pUndo)
1787  {
1788  // Copy over the basic sort parameters.
1789  pUndo->maDataAreaExtras = rSortParam.aDataAreaExtras;
1790  pUndo->mbByRow = rSortParam.bByRow;
1791  pUndo->mbHiddenFiltered = bKeepQuery;
1792  pUndo->mbUpdateRefs = bUpdateRefs;
1793  pUndo->mbHasHeaders = rSortParam.bHasHeader;
1794  }
1795 
1796  // It is assumed that the data area has already been trimmed as necessary.
1797 
1798  aSortParam = rSortParam; // must be assigned before calling IsSorted()
1799  if (rSortParam.bByRow)
1800  {
1801  const SCROW nLastRow = rSortParam.nRow2;
1802  const SCROW nRow1 = (rSortParam.bHasHeader ? rSortParam.nRow1 + 1 : rSortParam.nRow1);
1803  if (nRow1 < nLastRow && !IsSorted(nRow1, nLastRow))
1804  {
1805  if(pProgress)
1806  pProgress->SetState( 0, nLastRow-nRow1 );
1807 
1808  std::unique_ptr<ScSortInfoArray> pArray( CreateSortInfoArray(
1809  aSortParam, nRow1, nLastRow, bKeepQuery, bUpdateRefs));
1810 
1811  if ( nLastRow - nRow1 > 255 )
1812  DecoladeRow(pArray.get(), nRow1, nLastRow);
1813 
1814  QuickSort(pArray.get(), nRow1, nLastRow);
1815  if (pArray->IsUpdateRefs())
1816  SortReorderByRowRefUpdate(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress);
1817  else
1818  {
1819  SortReorderByRow(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress, false);
1820  if (rSortParam.aDataAreaExtras.anyExtrasWanted())
1822  rSortParam.aDataAreaExtras, pProgress);
1823  }
1824 
1825  if (pUndo)
1826  {
1827  // Stored is the first data row without header row.
1828  pUndo->maSortRange = ScRange(rSortParam.nCol1, nRow1, nTab, rSortParam.nCol2, nLastRow, nTab);
1829  pUndo->maDataAreaExtras.mnStartRow = nRow1;
1830  pUndo->maOrderIndices = pArray->GetOrderIndices();
1831  }
1832  }
1833  }
1834  else
1835  {
1836  const SCCOL nLastCol = rSortParam.nCol2;
1837  const SCCOL nCol1 = (rSortParam.bHasHeader ? rSortParam.nCol1 + 1 : rSortParam.nCol1);
1838  if (nCol1 < nLastCol && !IsSorted(nCol1, nLastCol))
1839  {
1840  if(pProgress)
1841  pProgress->SetState( 0, nLastCol-nCol1 );
1842 
1843  std::unique_ptr<ScSortInfoArray> pArray( CreateSortInfoArray(
1844  aSortParam, nCol1, nLastCol, bKeepQuery, bUpdateRefs));
1845 
1846  QuickSort(pArray.get(), nCol1, nLastCol);
1847  SortReorderByColumn(pArray.get(), rSortParam.nRow1, rSortParam.nRow2,
1848  rSortParam.aDataAreaExtras.mbCellFormats, pProgress);
1849  if (rSortParam.aDataAreaExtras.anyExtrasWanted() && !pArray->IsUpdateRefs())
1850  SortReorderAreaExtrasByColumn( pArray.get(),
1851  rSortParam.nRow1, rSortParam.nRow2, rSortParam.aDataAreaExtras, pProgress);
1852 
1853  if (pUndo)
1854  {
1855  // Stored is the first data column without header column.
1856  pUndo->maSortRange = ScRange(nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab);
1857  pUndo->maDataAreaExtras.mnStartCol = nCol1;
1858  pUndo->maOrderIndices = pArray->GetOrderIndices();
1859  }
1860  }
1861  }
1863 }
1864 
1865 void ScTable::Reorder( const sc::ReorderParam& rParam )
1866 {
1867  if (rParam.maOrderIndices.empty())
1868  return;
1869 
1870  std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(rParam));
1871  if (!pArray)
1872  return;
1873 
1874  if (rParam.mbByRow)
1875  {
1876  // Re-play sorting from the known sort indices.
1877  pArray->ReorderByRow(rParam.maOrderIndices);
1878  if (pArray->IsUpdateRefs())
1880  pArray.get(), rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr);
1881  else
1882  {
1883  SortReorderByRow( pArray.get(),
1884  rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr, false);
1885  if (rParam.maDataAreaExtras.anyExtrasWanted())
1886  SortReorderAreaExtrasByRow( pArray.get(),
1887  rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(),
1888  rParam.maDataAreaExtras, nullptr);
1889  }
1890  }
1891  else
1892  {
1893  // Ordering by column is much simpler. Just set the order indices and we are done.
1894  pArray->SetOrderIndices(std::vector(rParam.maOrderIndices));
1896  pArray.get(), rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(),
1897  rParam.maDataAreaExtras.mbCellFormats, nullptr);
1898  if (rParam.maDataAreaExtras.anyExtrasWanted() && !pArray->IsUpdateRefs())
1899  SortReorderAreaExtrasByColumn( pArray.get(),
1900  rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(),
1901  rParam.maDataAreaExtras, nullptr);
1902  }
1903 }
1904 
1905 namespace {
1906 
1907 class SubTotalRowFinder
1908 {
1909  const ScTable& mrTab;
1910  const ScSubTotalParam& mrParam;
1911 
1912 public:
1913  SubTotalRowFinder(const ScTable& rTab, const ScSubTotalParam& rParam) :
1914  mrTab(rTab), mrParam(rParam) {}
1915 
1916  bool operator() (size_t nRow, const ScFormulaCell* pCell)
1917  {
1918  if (!pCell->IsSubTotal())
1919  return false;
1920 
1921  SCCOL nStartCol = mrParam.nCol1;
1922  SCCOL nEndCol = mrParam.nCol2;
1923 
1924  for (SCCOL nCol : mrTab.GetColumnsRange(0, nStartCol - 1))
1925  {
1926  if (mrTab.HasData(nCol, nRow))
1927  return true;
1928  }
1929  for (SCCOL nCol : mrTab.GetColumnsRange(nEndCol + 1, mrTab.GetDoc().MaxCol()))
1930  {
1931  if (mrTab.HasData(nCol, nRow))
1932  return true;
1933  }
1934  return false;
1935  }
1936 };
1937 
1938 }
1939 
1941 {
1942  SCCOL nStartCol = rParam.nCol1;
1943  SCROW nStartRow = rParam.nRow1 + 1; // Header
1944  SCCOL nEndCol = ClampToAllocatedColumns(rParam.nCol2);
1945  SCROW nEndRow = rParam.nRow2;
1946 
1947  for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
1948  {
1949  const sc::CellStoreType& rCells = aCol[nCol].maCells;
1950  SubTotalRowFinder aFunc(*this, rParam);
1951  std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
1952  sc::FindFormula(rCells, nStartRow, nEndRow, aFunc);
1953  if (aPos.first != rCells.end())
1954  return true;
1955  }
1956  return false;
1957 }
1958 
1959 namespace {
1960 
1961 struct RemoveSubTotalsHandler
1962 {
1963  std::set<SCROW> aRemoved;
1964 
1965  void operator() (size_t nRow, const ScFormulaCell* p)
1966  {
1967  if (p->IsSubTotal())
1968  aRemoved.insert(nRow);
1969  }
1970 };
1971 
1972 }
1973 
1975 {
1976  SCCOL nStartCol = rParam.nCol1;
1977  SCROW nStartRow = rParam.nRow1 + 1; // Header
1978  SCCOL nEndCol = ClampToAllocatedColumns(rParam.nCol2);
1979  SCROW nEndRow = rParam.nRow2; // will change
1980 
1981  RemoveSubTotalsHandler aFunc;
1982  for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
1983  {
1984  const sc::CellStoreType& rCells = aCol[nCol].maCells;
1985  sc::ParseFormula(rCells.begin(), rCells, nStartRow, nEndRow, aFunc);
1986  }
1987 
1988  auto& aRows = aFunc.aRemoved;
1989 
1990  std::for_each(aRows.rbegin(), aRows.rend(), [this](const SCROW nRow) {
1991  RemoveRowBreak(nRow+1, false, true);
1992  rDocument.DeleteRow(0, nTab, rDocument.MaxCol(), nTab, nRow, 1);
1993  });
1994 
1995  rParam.nRow2 -= aRows.size();
1996 }
1997 
1998 // Delete hard number formats (for result formulas)
1999 
2000 static void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow )
2001 {
2002  const ScPatternAttr* pPattern = pTab->GetPattern( nCol, nRow );
2003  if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, false )
2004  == SfxItemState::SET )
2005  {
2006  auto pNewPattern = std::make_unique<ScPatternAttr>( *pPattern );
2007  SfxItemSet& rSet = pNewPattern->GetItemSet();
2008  rSet.ClearItem( ATTR_VALUE_FORMAT );
2010  pTab->SetPattern( nCol, nRow, std::move(pNewPattern) );
2011  }
2012 }
2013 
2014 namespace {
2015 
2016 struct RowEntry
2017 {
2018  sal_uInt16 nGroupNo;
2019  SCROW nSubStartRow;
2020  SCROW nDestRow;
2021  SCROW nFuncStart;
2022  SCROW nFuncEnd;
2023 };
2024 
2025 }
2026 
2028 {
2029  switch ( id )
2030  {
2031  case SUBTOTAL_FUNC_AVE: return STR_FUN_TEXT_AVG;
2032  case SUBTOTAL_FUNC_CNT:
2033  case SUBTOTAL_FUNC_CNT2: return STR_FUN_TEXT_COUNT;
2034  case SUBTOTAL_FUNC_MAX: return STR_FUN_TEXT_MAX;
2035  case SUBTOTAL_FUNC_MIN: return STR_FUN_TEXT_MIN;
2036  case SUBTOTAL_FUNC_PROD: return STR_FUN_TEXT_PRODUCT;
2037  case SUBTOTAL_FUNC_STD:
2038  case SUBTOTAL_FUNC_STDP: return STR_FUN_TEXT_STDDEV;
2039  case SUBTOTAL_FUNC_SUM: return STR_FUN_TEXT_SUM;
2040  case SUBTOTAL_FUNC_VAR:
2041  case SUBTOTAL_FUNC_VARP: return STR_FUN_TEXT_VAR;
2042  default:
2043  {
2044  return STR_EMPTYDATA;
2045  // added to avoid warnings
2046  }
2047  }
2048 }
2049 
2050 // new intermediate results
2051 // rParam.nRow2 is changed!
2052 
2054 {
2055  SCCOL nStartCol = rParam.nCol1;
2056  SCROW nStartRow = rParam.nRow1 + 1; // Header
2057  SCCOL nEndCol = rParam.nCol2;
2058  SCROW nEndRow = rParam.nRow2; // will change
2059  sal_uInt16 i;
2060 
2061  // Remove empty rows at the end
2062  // so that all exceeding (rDocument.MaxRow()) can be found by InsertRow (#35180#)
2063  // If sorted, all empty rows are at the end.
2064  SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM );
2065  nEndRow -= nEmpty;
2066 
2067  sal_uInt16 nLevelCount = 0; // Number of levels
2068  bool bDoThis = true;
2069  for (i=0; i<MAXSUBTOTAL && bDoThis; i++)
2070  if (rParam.bGroupActive[i])
2071  nLevelCount = i+1;
2072  else
2073  bDoThis = false;
2074 
2075  if (nLevelCount==0) // do nothing
2076  return true;
2077 
2078  SCCOL* nGroupCol = rParam.nField; // columns which will be used when grouping
2079 
2080  // With (blank) as a separate category, subtotal rows from
2081  // the other columns must always be tested
2082  // (previously only when a column occurred more than once)
2083  bool bTestPrevSub = ( nLevelCount > 1 );
2084 
2085  OUString aSubString;
2086 
2087  bool bIgnoreCase = !rParam.bCaseSens;
2088 
2089  OUString aCompString[MAXSUBTOTAL];
2090 
2091  //TODO: sort?
2092 
2093  ScStyleSheet* pStyle = static_cast<ScStyleSheet*>(rDocument.GetStyleSheetPool()->Find(
2094  ScResId(STR_STYLENAME_RESULT), SfxStyleFamily::Para ));
2095 
2096  bool bSpaceLeft = true; // Success when inserting?
2097 
2098  // For performance reasons collect formula entries so their
2099  // references don't have to be tested for updates each time a new row is
2100  // inserted
2101  RowEntry aRowEntry;
2102  ::std::vector< RowEntry > aRowVector;
2103 
2104  for (sal_uInt16 nLevel=0; nLevel<nLevelCount && bSpaceLeft; nLevel++)
2105  {
2106  aRowEntry.nGroupNo = nLevelCount - nLevel - 1;
2107 
2108  // how many results per level
2109  SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo];
2110  // result functions
2111  ScSubTotalFunc* pResFunc = rParam.pFunctions[aRowEntry.nGroupNo].get();
2112 
2113  if (nResCount > 0) // otherwise only sort
2114  {
2115  for (i=0; i<=aRowEntry.nGroupNo; i++)
2116  {
2117  aSubString = GetString( nGroupCol[i], nStartRow );
2118  if ( bIgnoreCase )
2119  aCompString[i] = ScGlobal::getCharClass().uppercase( aSubString );
2120  else
2121  aCompString[i] = aSubString;
2122  } // aSubString stays on the last
2123 
2124  bool bBlockVis = false; // group visible?
2125  aRowEntry.nSubStartRow = nStartRow;
2126  for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++)
2127  {
2128  bool bChanged;
2129  if (nRow>nEndRow)
2130  bChanged = true;
2131  else
2132  {
2133  bChanged = false;
2134  OUString aString;
2135  for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++)
2136  {
2137  aString = GetString( nGroupCol[i], nRow );
2138  if (bIgnoreCase)
2139  aString = ScGlobal::getCharClass().uppercase(aString);
2140  // when sorting, blanks are separate group
2141  // otherwise blank cells are allowed below
2142  bChanged = ( ( !aString.isEmpty() || rParam.bDoSort ) &&
2143  aString != aCompString[i] );
2144  }
2145  if ( bChanged && bTestPrevSub )
2146  {
2147  // No group change on rows that will contain subtotal formulas
2148  bChanged = std::none_of(aRowVector.begin(), aRowVector.end(),
2149  [&nRow](const RowEntry& rEntry) { return rEntry.nDestRow == nRow; });
2150  }
2151  }
2152  if ( bChanged )
2153  {
2154  aRowEntry.nDestRow = nRow;
2155  aRowEntry.nFuncStart = aRowEntry.nSubStartRow;
2156  aRowEntry.nFuncEnd = nRow-1;
2157 
2158  bSpaceLeft = rDocument.InsertRow( 0, nTab, rDocument.MaxCol(), nTab,
2159  aRowEntry.nDestRow, 1 );
2160  DBShowRow( aRowEntry.nDestRow, bBlockVis );
2161  if ( rParam.bPagebreak && nRow < rDocument.MaxRow() &&
2162  aRowEntry.nSubStartRow != nStartRow && nLevel == 0)
2163  SetRowBreak(aRowEntry.nSubStartRow, false, true);
2164 
2165  if (bSpaceLeft)
2166  {
2167  for ( auto& rRowEntry : aRowVector)
2168  {
2169  if ( aRowEntry.nDestRow <= rRowEntry.nSubStartRow )
2170  ++rRowEntry.nSubStartRow;
2171  if ( aRowEntry.nDestRow <= rRowEntry.nDestRow )
2172  ++rRowEntry.nDestRow;
2173  if ( aRowEntry.nDestRow <= rRowEntry.nFuncStart )
2174  ++rRowEntry.nFuncStart;
2175  if ( aRowEntry.nDestRow <= rRowEntry.nFuncEnd )
2176  ++rRowEntry.nFuncEnd;
2177  }
2178  // collect formula positions
2179  aRowVector.push_back( aRowEntry );
2180 
2181  OUString aOutString = aSubString;
2182  if (aOutString.isEmpty())
2183  aOutString = ScResId( STR_EMPTYDATA );
2184  aOutString += " ";
2185  TranslateId pStrId = STR_TABLE_ERGEBNIS;
2186  if ( nResCount == 1 )
2187  pStrId = lcl_GetSubTotalStrId(pResFunc[0]);
2188  aOutString += ScResId(pStrId);
2189  SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString );
2190  ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle );
2191 
2192  ++nRow;
2193  ++nEndRow;
2194  aRowEntry.nSubStartRow = nRow;
2195  for (i=0; i<=aRowEntry.nGroupNo; i++)
2196  {
2197  aSubString = GetString( nGroupCol[i], nRow );
2198  if ( bIgnoreCase )
2199  aCompString[i] = ScGlobal::getCharClass().uppercase( aSubString );
2200  else
2201  aCompString[i] = aSubString;
2202  }
2203  }
2204  }
2205  bBlockVis = !RowFiltered(nRow);
2206  }
2207  }
2208  }
2209 
2210  if (!aRowVector.empty())
2211  {
2212  // generate global total
2213  SCROW nGlobalStartRow = aRowVector[0].nSubStartRow;
2214  SCROW nGlobalStartFunc = aRowVector[0].nFuncStart;
2215  SCROW nGlobalEndRow = 0;
2216  SCROW nGlobalEndFunc = 0;
2217  for (const auto& rRowEntry : aRowVector)
2218  {
2219  nGlobalEndRow = (nGlobalEndRow < rRowEntry.nDestRow) ? rRowEntry.nDestRow : nGlobalEndRow;
2220  nGlobalEndFunc = (nGlobalEndFunc < rRowEntry.nFuncEnd) ? rRowEntry.nFuncEnd : nGlobalEndRow;
2221  }
2222 
2223  for (sal_uInt16 nLevel = 0; nLevel<nLevelCount; nLevel++)
2224  {
2225  const sal_uInt16 nGroupNo = nLevelCount - nLevel - 1;
2226  const ScSubTotalFunc* pResFunc = rParam.pFunctions[nGroupNo].get();
2227  if (!pResFunc)
2228  {
2229  // No subtotal function given for this group => no formula or
2230  // label and do not insert a row.
2231  continue;
2232  }
2233 
2234  // increment end row
2235  nGlobalEndRow++;
2236 
2237  // add row entry for formula
2238  aRowEntry.nGroupNo = nGroupNo;
2239  aRowEntry.nSubStartRow = nGlobalStartRow;
2240  aRowEntry.nFuncStart = nGlobalStartFunc;
2241  aRowEntry.nDestRow = nGlobalEndRow;
2242  aRowEntry.nFuncEnd = nGlobalEndFunc;
2243 
2244  // increment row
2245  nGlobalEndFunc++;
2246 
2247  bSpaceLeft = rDocument.InsertRow(0, nTab, rDocument.MaxCol(), nTab, aRowEntry.nDestRow, 1);
2248 
2249  if (bSpaceLeft)
2250  {
2251  aRowVector.push_back(aRowEntry);
2252  nEndRow++;
2253  DBShowRow(aRowEntry.nDestRow, true);
2254 
2255  // insert label
2256  OUString label = ScResId(STR_TABLE_GRAND) + " " + ScResId(lcl_GetSubTotalStrId(pResFunc[0]));
2257  SetString(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, label);
2258  ApplyStyle(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle);
2259  }
2260  }
2261  }
2262 
2263  // now insert the formulas
2264  ScComplexRefData aRef;
2265  aRef.InitFlags();
2266  aRef.Ref1.SetAbsTab(nTab);
2267  aRef.Ref2.SetAbsTab(nTab);
2268  for (const auto& rRowEntry : aRowVector)
2269  {
2270  SCCOL nResCount = rParam.nSubTotals[rRowEntry.nGroupNo];
2271  SCCOL* nResCols = rParam.pSubTotals[rRowEntry.nGroupNo].get();
2272  ScSubTotalFunc* pResFunc = rParam.pFunctions[rRowEntry.nGroupNo].get();
2273  for ( SCCOL nResult=0; nResult < nResCount; ++nResult )
2274  {
2275  aRef.Ref1.SetAbsCol(nResCols[nResult]);
2276  aRef.Ref1.SetAbsRow(rRowEntry.nFuncStart);
2277  aRef.Ref2.SetAbsCol(nResCols[nResult]);
2278  aRef.Ref2.SetAbsRow(rRowEntry.nFuncEnd);
2279 
2281  aArr.AddOpCode( ocSubTotal );
2282  aArr.AddOpCode( ocOpen );
2283  aArr.AddDouble( static_cast<double>(pResFunc[nResult]) );
2284  aArr.AddOpCode( ocSep );
2285  aArr.AddDoubleReference( aRef );
2286  aArr.AddOpCode( ocClose );
2287  aArr.AddOpCode( ocStop );
2288  ScFormulaCell* pCell = new ScFormulaCell(
2289  rDocument, ScAddress(nResCols[nResult], rRowEntry.nDestRow, nTab), aArr);
2290  if ( rParam.bIncludePattern )
2291  pCell->SetNeedNumberFormat(true);
2292 
2293  SetFormulaCell(nResCols[nResult], rRowEntry.nDestRow, pCell);
2294  if ( nResCols[nResult] != nGroupCol[rRowEntry.nGroupNo] )
2295  {
2296  ApplyStyle( nResCols[nResult], rRowEntry.nDestRow, pStyle );
2297 
2298  lcl_RemoveNumberFormat( this, nResCols[nResult], rRowEntry.nDestRow );
2299  }
2300  }
2301 
2302  }
2303 
2304  //TODO: according to setting, shift intermediate-sum rows up?
2305 
2306  //TODO: create Outlines directly?
2307 
2308  if (bSpaceLeft)
2309  DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
2310 
2311  rParam.nRow2 = nEndRow; // new end
2312  return bSpaceLeft;
2313 }
2314 
2316 {
2317  bool bSortCollatorInitialized = false;
2318  SCSIZE nEntryCount = rParam.GetEntryCount();
2319  SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1);
2320  SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1);
2321  for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ )
2322  {
2323  ScQueryEntry& rEntry = rParam.GetEntry(i);
2324  ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
2325 
2326  for (ScQueryEntry::Item& rItem : rItems)
2327  {
2328  switch (rEntry.eOp)
2329  {
2330  case SC_TOPVAL:
2331  case SC_BOTVAL:
2332  case SC_TOPPERC:
2333  case SC_BOTPERC:
2334  {
2335  ScSortParam aLocalSortParam(rParam, static_cast<SCCOL>(rEntry.nField));
2336  aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare
2337  if (!bSortCollatorInitialized)
2338  {
2339  bSortCollatorInitialized = true;
2340  InitSortCollator(aLocalSortParam);
2341  }
2342  std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nRow1, rParam.nRow2, bGlobalKeepQuery, false));
2343  DecoladeRow(pArray.get(), nRow1, rParam.nRow2);
2344  QuickSort(pArray.get(), nRow1, rParam.nRow2);
2345  std::unique_ptr<ScSortInfo[]> const& ppInfo = pArray->GetFirstArray();
2346  SCSIZE nValidCount = nCount;
2347  // Don't count note or blank cells, they are sorted to the end
2348  while (nValidCount > 0 && ppInfo[nValidCount - 1].maCell.isEmpty())
2349  nValidCount--;
2350  // Don't count Strings, they are between Value and blank
2351  while (nValidCount > 0 && ppInfo[nValidCount - 1].maCell.hasString())
2352  nValidCount--;
2353  if (nValidCount > 0)
2354  {
2355  if (rItem.meType == ScQueryEntry::ByString)
2356  { // by string ain't going to work
2357  rItem.meType = ScQueryEntry::ByValue;
2358  rItem.mfVal = 10; // 10 and 10% respectively
2359  }
2360  SCSIZE nVal = (rItem.mfVal >= 1 ? static_cast<SCSIZE>(rItem.mfVal) : 1);
2361  SCSIZE nOffset = 0;
2362  switch (rEntry.eOp)
2363  {
2364  case SC_TOPVAL:
2365  {
2366  rEntry.eOp = SC_GREATER_EQUAL;
2367  if (nVal > nValidCount)
2368  nVal = nValidCount;
2369  nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount
2370  }
2371  break;
2372  case SC_BOTVAL:
2373  {
2374  rEntry.eOp = SC_LESS_EQUAL;
2375  if (nVal > nValidCount)
2376  nVal = nValidCount;
2377  nOffset = nVal - 1; // 1 <= nVal <= nValidCount
2378  }
2379  break;
2380  case SC_TOPPERC:
2381  {
2382  rEntry.eOp = SC_GREATER_EQUAL;
2383  if (nVal > 100)
2384  nVal = 100;
2385  nOffset = nValidCount - (nValidCount * nVal / 100);
2386  if (nOffset >= nValidCount)
2387  nOffset = nValidCount - 1;
2388  }
2389  break;
2390  case SC_BOTPERC:
2391  {
2392  rEntry.eOp = SC_LESS_EQUAL;
2393  if (nVal > 100)
2394  nVal = 100;
2395  nOffset = (nValidCount * nVal / 100);
2396  if (nOffset >= nValidCount)
2397  nOffset = nValidCount - 1;
2398  }
2399  break;
2400  default:
2401  {
2402  // added to avoid warnings
2403  }
2404  }
2405  ScRefCellValue aCell = ppInfo[nOffset].maCell;
2406  if (aCell.hasNumeric())
2407  rItem.mfVal = aCell.getValue();
2408  else
2409  {
2410  OSL_FAIL("TopTenQuery: pCell no ValueData");
2411  rEntry.eOp = SC_GREATER_EQUAL;
2412  rItem.mfVal = 0;
2413  }
2414  }
2415  else
2416  {
2417  rEntry.eOp = SC_GREATER_EQUAL;
2418  rItem.meType = ScQueryEntry::ByValue;
2419  rItem.mfVal = 0;
2420  }
2421  }
2422  break;
2423  default:
2424  {
2425  // added to avoid warnings
2426  }
2427  }
2428  }
2429  }
2430  if ( bSortCollatorInitialized )
2432 }
2433 
2434 namespace {
2435 
2436 bool CanOptimizeQueryStringToNumber( const SvNumberFormatter* pFormatter, sal_uInt32 nFormatIndex, bool& bDateFormat )
2437 {
2438  // tdf#105629: ScQueryEntry::ByValue queries are faster than ScQueryEntry::ByString.
2439  // The problem with this optimization is that the autofilter dialog apparently converts
2440  // the value to text and then converts that back to a number for filtering.
2441  // If that leads to any change of value (such as when time is rounded to seconds),
2442  // even matching values will be filtered out. Therefore query by value only for formats
2443  // where no such change should occur.
2444  if(const SvNumberformat* pEntry = pFormatter->GetEntry(nFormatIndex))
2445  {
2446  switch(pEntry->GetType())
2447  {
2448  case SvNumFormatType::NUMBER:
2449  case SvNumFormatType::FRACTION:
2450  case SvNumFormatType::SCIENTIFIC:
2451  return true;
2452  case SvNumFormatType::DATE:
2453  case SvNumFormatType::DATETIME:
2454  bDateFormat = true;
2455  break;
2456  default:
2457  break;
2458  }
2459  }
2460  return false;
2461 }
2462 
2463 class PrepareQueryItem
2464 {
2465  const ScDocument& mrDoc;
2466  const bool mbRoundForFilter;
2467 public:
2468  explicit PrepareQueryItem(const ScDocument& rDoc, bool bRoundForFilter) :
2469  mrDoc(rDoc), mbRoundForFilter(bRoundForFilter) {}
2470 
2471  void operator() (ScQueryEntry::Item& rItem)
2472  {
2473  rItem.mbRoundForFilter = mbRoundForFilter;
2474 
2475  if (rItem.meType != ScQueryEntry::ByString && rItem.meType != ScQueryEntry::ByDate)
2476  return;
2477 
2478  sal_uInt32 nIndex = 0;
2479  bool bNumber = mrDoc.GetFormatTable()->
2480  IsNumberFormat(rItem.maString.getString(), nIndex, rItem.mfVal);
2481 
2482  // Advanced Filter creates only ByString queries that need to be
2483  // converted to ByValue if appropriate. rItem.mfVal now holds the value
2484  // if bNumber==true.
2485 
2486  if (rItem.meType == ScQueryEntry::ByString)
2487  {
2488  bool bDateFormat = false;
2489  if (bNumber && CanOptimizeQueryStringToNumber( mrDoc.GetFormatTable(), nIndex, bDateFormat ))
2490  rItem.meType = ScQueryEntry::ByValue;
2491  if (!bDateFormat)
2492  return;
2493  }
2494 
2495  // Double-check if the query by date is really appropriate.
2496 
2497  if (bNumber && ((nIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0))
2498  {
2499  const SvNumberformat* pEntry = mrDoc.GetFormatTable()->GetEntry(nIndex);
2500  if (pEntry)
2501  {
2502  SvNumFormatType nNumFmtType = pEntry->GetType();
2503  if (!(nNumFmtType & SvNumFormatType::DATE) || (nNumFmtType & SvNumFormatType::TIME))
2504  rItem.meType = ScQueryEntry::ByValue; // not a date only
2505  else
2506  rItem.meType = ScQueryEntry::ByDate; // date only
2507  }
2508  else
2509  rItem.meType = ScQueryEntry::ByValue; // what the ... not a date
2510  }
2511  else
2512  rItem.meType = ScQueryEntry::ByValue; // not a date
2513  }
2514 };
2515 
2516 void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam, bool bRoundForFilter )
2517 {
2518  bool bTopTen = false;
2519  SCSIZE nEntryCount = rParam.GetEntryCount();
2520 
2521  for ( SCSIZE i = 0; i < nEntryCount; ++i )
2522  {
2523  ScQueryEntry& rEntry = rParam.GetEntry(i);
2524  if (!rEntry.bDoQuery)
2525  continue;
2526 
2527  ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
2528  std::for_each(rItems.begin(), rItems.end(), PrepareQueryItem(*pDoc, bRoundForFilter));
2529 
2530  if ( !bTopTen )
2531  {
2532  switch ( rEntry.eOp )
2533  {
2534  case SC_TOPVAL:
2535  case SC_BOTVAL:
2536  case SC_TOPPERC:
2537  case SC_BOTPERC:
2538  {
2539  bTopTen = true;
2540  }
2541  break;
2542  default:
2543  {
2544  }
2545  }
2546  }
2547  }
2548 
2549  if ( bTopTen )
2550  {
2551  pTab->TopTenQuery( rParam );
2552  }
2553 }
2554 
2555 }
2556 
2558 {
2559  lcl_PrepareQuery(&rDocument, this, rQueryParam, false);
2560 }
2561 
2562 SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub)
2563 {
2564  ScQueryParam aParam( rParamOrg );
2565  typedef std::unordered_set<OUString> StrSetType;
2566  StrSetType aStrSet;
2567 
2568  bool bStarted = false;
2569  bool bOldResult = true;
2570  SCROW nOldStart = 0;
2571  SCROW nOldEnd = 0;
2572 
2573  SCSIZE nCount = 0;
2574  SCROW nOutRow = 0;
2575  SCROW nHeader = aParam.bHasHeader ? 1 : 0;
2576 
2577  lcl_PrepareQuery(&rDocument, this, aParam, true);
2578 
2579  if (!aParam.bInplace)
2580  {
2581  nOutRow = aParam.nDestRow + nHeader;
2582  if (nHeader > 0)
2583  CopyData( aParam.nCol1, aParam.nRow1, aParam.nCol2, aParam.nRow1,
2584  aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
2585  }
2586 
2587  sc::TableColumnBlockPositionSet blockPos( GetDoc(), nTab ); // cache mdds access
2588  ScQueryEvaluator queryEvaluator(GetDoc(), *this, aParam);
2589 
2590  SCROW nRealRow2 = aParam.nRow2;
2591  for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j)
2592  {
2593  bool bResult; // Filter result
2594  bool bValid = queryEvaluator.ValidQuery(j, nullptr, &blockPos);
2595  if (!bValid && bKeepSub) // Keep subtotals
2596  {
2597  for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
2598  {
2599  ScRefCellValue aCell = GetCellValue(nCol, j);
2600  if (aCell.meType != CELLTYPE_FORMULA)
2601  continue;
2602 
2603  if (!aCell.mpFormula->IsSubTotal())
2604  continue;
2605 
2606  if (RefVisible(aCell.mpFormula))
2607  bValid = true;
2608  }
2609  }
2610  if (bValid)
2611  {
2612  if (aParam.bDuplicate)
2613  bResult = true;
2614  else
2615  {
2616  OUStringBuffer aStr;
2617  for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++)
2618  {
2619  OUString aCellStr = GetString(k, j);
2620  aStr.append(aCellStr + u"\x0001");
2621  }
2622 
2623  bResult = aStrSet.insert(aStr.makeStringAndClear()).second; // unique if inserted.
2624  }
2625  }
2626  else
2627  bResult = false;
2628 
2629  if (aParam.bInplace)
2630  {
2631  if (bResult == bOldResult && bStarted)
2632  nOldEnd = j;
2633  else
2634  {
2635  if (bStarted)
2636  DBShowRows(nOldStart,nOldEnd, bOldResult);
2637  nOldStart = nOldEnd = j;
2638  bOldResult = bResult;
2639  }
2640  bStarted = true;
2641  }
2642  else
2643  {
2644  if (bResult)
2645  {
2646  CopyData( aParam.nCol1,j, aParam.nCol2,j, aParam.nDestCol,nOutRow,aParam.nDestTab );
2647  if( nTab == aParam.nDestTab ) // copy to self, changes may invalidate caching position hints
2648  blockPos.invalidate();
2649  ++nOutRow;
2650  }
2651  }
2652  if (bResult)
2653  ++nCount;
2654  }
2655 
2656  if (aParam.bInplace && bStarted)
2657  DBShowRows(nOldStart,nOldEnd, bOldResult);
2658 
2659  if (aParam.bInplace)
2660  SetDrawPageSize();
2661 
2662  return nCount;
2663 }
2664 
2665 bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2666 {
2667  bool bValid = true;
2668  std::unique_ptr<SCCOL[]> pFields(new SCCOL[nCol2-nCol1+1]);
2669  OUString aCellStr;
2670  SCCOL nCol = nCol1;
2671  OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2672  SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2673  SCROW nDBRow1 = rQueryParam.nRow1;
2674  SCCOL nDBCol2 = rQueryParam.nCol2;
2675  // First row must be column headers
2676  while (bValid && (nCol <= nCol2))
2677  {
2678  OUString aQueryStr = GetUpperCellString(nCol, nRow1);
2679  bool bFound = false;
2680  SCCOL i = rQueryParam.nCol1;
2681  while (!bFound && (i <= nDBCol2))
2682  {
2683  if ( nTab == nDBTab )
2684  aCellStr = GetUpperCellString(i, nDBRow1);
2685  else
2686  aCellStr = rDocument.GetUpperCellString(i, nDBRow1, nDBTab);
2687  bFound = (aCellStr == aQueryStr);
2688  if (!bFound) i++;
2689  }
2690  if (bFound)
2691  pFields[nCol - nCol1] = i;
2692  else
2693  bValid = false;
2694  nCol++;
2695  }
2696  if (bValid)
2697  {
2698  sal_uLong nVisible = 0;
2699  for ( nCol=nCol1; nCol<=nCol2; nCol++ )
2700  nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
2701 
2702  if ( nVisible > SCSIZE_MAX / sizeof(void*) )
2703  {
2704  OSL_FAIL("too many filter criteria");
2705  nVisible = 0;
2706  }
2707 
2708  SCSIZE nNewEntries = nVisible;
2709  rQueryParam.Resize( nNewEntries );
2710 
2711  SCSIZE nIndex = 0;
2712  SCROW nRow = nRow1 + 1;
2714  while (nRow <= nRow2)
2715  {
2716  nCol = nCol1;
2717  while (nCol <= nCol2)
2718  {
2719  aCellStr = GetInputString( nCol, nRow );
2720  if (!aCellStr.isEmpty())
2721  {
2722  if (nIndex < nNewEntries)
2723  {
2724  rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1];
2725  rQueryParam.FillInExcelSyntax(rPool, aCellStr, nIndex, nullptr);
2726  nIndex++;
2727  if (nIndex < nNewEntries)
2728  rQueryParam.GetEntry(nIndex).eConnect = SC_AND;
2729  }
2730  else
2731  bValid = false;
2732  }
2733  nCol++;
2734  }
2735  nRow++;
2736  if (nIndex < nNewEntries)
2737  rQueryParam.GetEntry(nIndex).eConnect = SC_OR;
2738  }
2739  }
2740  return bValid;
2741 }
2742 
2743 bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2744 {
2745  // A valid StarQuery must be at least 4 columns wide. To be precise it
2746  // should be exactly 4 columns ...
2747  // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
2748  // column Excel style query range immediately left to itself would result
2749  // in a circular reference when the field name or operator or value (first
2750  // to third query range column) is obtained (#i58354#). Furthermore, if the
2751  // range wasn't sufficiently specified data changes wouldn't flag formula
2752  // cells for recalculation.
2753  if (nCol2 - nCol1 < 3)
2754  return false;
2755 
2756  bool bValid;
2757  OUString aCellStr;
2758  SCSIZE nIndex = 0;
2759  SCROW nRow = nRow1;
2760  OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2761  SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2762  SCROW nDBRow1 = rQueryParam.nRow1;
2763  SCCOL nDBCol2 = rQueryParam.nCol2;
2764 
2765  SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1);
2766  rQueryParam.Resize( nNewEntries );
2768 
2769  do
2770  {
2771  ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex);
2772 
2773  bValid = false;
2774  // First column AND/OR
2775  if (nIndex > 0)
2776  {
2777  aCellStr = GetUpperCellString(nCol1, nRow);
2778  if ( aCellStr == ScResId(STR_TABLE_AND) )
2779  {
2780  rEntry.eConnect = SC_AND;
2781  bValid = true;
2782  }
2783  else if ( aCellStr == ScResId(STR_TABLE_OR) )
2784  {
2785  rEntry.eConnect = SC_OR;
2786  bValid = true;
2787  }
2788  }
2789  // Second column field name
2790  if ((nIndex < 1) || bValid)
2791  {
2792  bool bFound = false;
2793  aCellStr = GetUpperCellString(nCol1 + 1, nRow);
2794  for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++)
2795  {
2796  OUString aFieldStr;
2797  if ( nTab == nDBTab )
2798  aFieldStr = GetUpperCellString(i, nDBRow1);
2799  else
2800  aFieldStr = rDocument.GetUpperCellString(i, nDBRow1, nDBTab);
2801  bFound = (aCellStr == aFieldStr);
2802  if (bFound)
2803  {
2804  rEntry.nField = i;
2805  bValid = true;
2806  }
2807  else
2808  bValid = false;
2809  }
2810  }
2811  // Third column operator =<>...
2812  if (bValid)
2813  {
2814  aCellStr = GetUpperCellString(nCol1 + 2, nRow);
2815  if (aCellStr.startsWith("<"))
2816  {
2817  if (aCellStr[1] == '>')
2818  rEntry.eOp = SC_NOT_EQUAL;
2819  else if (aCellStr[1] == '=')
2820  rEntry.eOp = SC_LESS_EQUAL;
2821  else
2822  rEntry.eOp = SC_LESS;
2823  }
2824  else if (aCellStr.startsWith(">"))
2825  {
2826  if (aCellStr[1] == '=')
2827  rEntry.eOp = SC_GREATER_EQUAL;
2828  else
2829  rEntry.eOp = SC_GREATER;
2830  }
2831  else if (aCellStr.startsWith("="))
2832  rEntry.eOp = SC_EQUAL;
2833 
2834  }
2835  // Fourth column values
2836  if (bValid)
2837  {
2838  OUString aStr = GetString(nCol1 + 3, nRow);
2839  rEntry.GetQueryItem().maString = rPool.intern(aStr);
2840  rEntry.bDoQuery = true;
2841  }
2842  nIndex++;
2843  nRow++;
2844  }
2845  while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ );
2846  return bValid;
2847 }
2848 
2849 bool ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2850 {
2851  SCSIZE i, nCount;
2852  PutInOrder(nCol1, nCol2);
2853  PutInOrder(nRow1, nRow2);
2854 
2855  nCount = rQueryParam.GetEntryCount();
2856  for (i=0; i < nCount; i++)
2857  rQueryParam.GetEntry(i).Clear();
2858 
2859  // Standard query table
2860  bool bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2861  // Excel Query table
2862  if (!bValid)
2863  bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2864 
2865  SvNumberFormatter* pFormatter = rDocument.GetFormatTable();
2866  nCount = rQueryParam.GetEntryCount();
2867  if (bValid)
2868  {
2869  // query type must be set
2870  for (i=0; i < nCount; i++)
2871  {
2872  ScQueryEntry::Item& rItem = rQueryParam.GetEntry(i).GetQueryItem();
2873  sal_uInt32 nIndex = 0;
2874  bool bNumber = pFormatter->IsNumberFormat(
2875  rItem.maString.getString(), nIndex, rItem.mfVal);
2876  bool bDateFormat = false;
2877  rItem.meType = bNumber && CanOptimizeQueryStringToNumber( pFormatter, nIndex, bDateFormat )
2879  }
2880  }
2881  else
2882  {
2883  for (i=0; i < nCount; i++)
2884  rQueryParam.GetEntry(i).Clear();
2885  }
2886  return bValid;
2887 }
2888 
2889 bool ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const
2890 {
2891  if (nStartRow == nEndRow)
2892  // Assume only data.
2893  /* XXX NOTE: previous behavior still checked this one row and could
2894  * evaluate it has header row, but that doesn't make much sense. */
2895  return false;
2896 
2897  if (nStartCol == nEndCol)
2898  {
2899  CellType eFirstCellType = GetCellType(nStartCol, nStartRow);
2900  CellType eSecondCellType = GetCellType(nStartCol, nStartRow+1);
2901  return ((eFirstCellType == CELLTYPE_STRING || eFirstCellType == CELLTYPE_EDIT) &&
2902  (eSecondCellType != CELLTYPE_STRING && eSecondCellType != CELLTYPE_EDIT));
2903  }
2904 
2905  for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2906  {
2907  CellType eType = GetCellType( nCol, nStartRow );
2908  // Any non-text cell in first row => not headers.
2909  if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
2910  return false;
2911  }
2912 
2913  // First row all text cells, any non-text cell in second row => headers.
2914  SCROW nTestRow = nStartRow + 1;
2915  for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2916  {
2917  CellType eType = GetCellType( nCol, nTestRow );
2918  if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
2919  return true;
2920  }
2921 
2922  // Also second row all text cells => first row not headers.
2923  return false;
2924 }
2925 
2926 bool ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const
2927 {
2928  if (nStartCol == nEndCol)
2929  // Assume only data.
2930  /* XXX NOTE: previous behavior still checked this one column and could
2931  * evaluate it has header column, but that doesn't make much sense. */
2932  return false;
2933 
2934  if (nStartRow == nEndRow)
2935  {
2936  CellType eFirstCellType = GetCellType(nStartCol, nStartRow);
2937  CellType eSecondCellType = GetCellType(nStartCol+1, nStartRow);
2938  return ((eFirstCellType == CELLTYPE_STRING || eFirstCellType == CELLTYPE_EDIT) &&
2939  (eSecondCellType != CELLTYPE_STRING && eSecondCellType != CELLTYPE_EDIT));
2940  }
2941 
2942  for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
2943  {
2944  CellType eType = GetCellType( nStartCol, nRow );
2945  // Any non-text cell in first column => not headers.
2946  if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
2947  return false;
2948  }
2949 
2950  // First column all text cells, any non-text cell in second column => headers.
2951  SCCOL nTestCol = nStartCol + 1;
2952  for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
2953  {
2954  CellType eType = GetCellType( nRow, nTestCol );
2955  if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
2956  return true;
2957  }
2958 
2959  // Also second column all text cells => first column not headers.
2960  return false;
2961 }
2962 
2963 void ScTable::GetFilterEntries( SCCOL nCol, SCROW nRow1, SCROW nRow2, ScFilterEntries& rFilterEntries, bool bFiltering )
2964 {
2965  if (nCol >= aCol.size())
2966  return;
2967 
2968  sc::ColumnBlockConstPosition aBlockPos;
2969  aCol[nCol].InitBlockPosition(aBlockPos);
2970  aCol[nCol].GetFilterEntries(aBlockPos, nRow1, nRow2, rFilterEntries, bFiltering);
2971 }
2972 
2974  SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, ScFilterEntries& rFilterEntries, bool bFiltering )
2975 {
2976  if (nCol >= aCol.size())
2977  return;
2978 
2979  sc::ColumnBlockConstPosition aBlockPos;
2980  aCol[nCol].InitBlockPosition(aBlockPos);
2981 
2982  // remove the entry for this column from the query parameter
2983  ScQueryParam aParam( rParam );
2984  aParam.RemoveEntryByField(nCol);
2985 
2986  lcl_PrepareQuery(&rDocument, this, aParam, true);
2987  ScQueryEvaluator queryEvaluator(GetDoc(), *this, aParam);
2988  for ( SCROW j = nRow1; j <= nRow2; ++j )
2989  {
2990  if (queryEvaluator.ValidQuery(j))
2991  {
2992  aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries, bFiltering);
2993  }
2994  }
2995 }
2996 
2997 bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, std::set<ScTypedStrData>& rStrings)
2998 {
2999  return aCol[nCol].GetDataEntries( nRow, rStrings);
3000 }
3001 
3003 {
3004  sal_uLong nCellCount = 0;
3005 
3006  for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3007  nCellCount += aCol[nCol].GetCellCount();
3008 
3009  return nCellCount;
3010 }
3011 
3013 {
3014  sal_uLong nCellCount = 0;
3015 
3016  for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3017  nCellCount += aCol[nCol].GetWeightedCount();
3018 
3019  return nCellCount;
3020 }
3021 
3023 {
3024  sal_uLong nCellCount = 0;
3025 
3026  for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3027  nCellCount += aCol[nCol].GetWeightedCount(nStartRow, nEndRow);
3028 
3029  return nCellCount;
3030 }
3031 
3033 {
3034  sal_uLong nCodeCount = 0;
3035 
3036  for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3037  if ( aCol[nCol].GetCellCount() )
3038  nCodeCount += aCol[nCol].GetCodeCount();
3039 
3040  return nCodeCount;
3041 }
3042 
3043 sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart,
3044  SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
3045 {
3046  if ( IsColValid( nCol ) )
3047  return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet );
3048  else
3049  return 0;
3050 }
3051 
3053  sal_uInt16& nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const
3054 {
3055  if ( IsColValid( nCol ) )
3056  return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd );
3057  else
3058  return 0;
3059 }
3060 
3062 {
3063  ScRangeList aRanges = rMark.GetMarkedRangesForTab( nTab );
3064  ScRange aMarkArea( ScAddress::UNINITIALIZED );
3065  if (rMark.IsMultiMarked())
3066  rMark.GetMultiMarkArea( aMarkArea );
3067  else if (rMark.IsMarked())
3068  rMark.GetMarkArea( aMarkArea );
3069  else
3070  {
3071  assert(!"ScTable::UpdateSelectionFunction - called without anything marked");
3072  aMarkArea.aStart.SetCol(0);
3073  aMarkArea.aEnd.SetCol(rDocument.MaxCol());
3074  }
3075  const SCCOL nStartCol = aMarkArea.aStart.Col();
3076  const SCCOL nEndCol = ClampToAllocatedColumns(aMarkArea.aEnd.Col());
3077  for (SCCOL nCol = nStartCol; nCol <= nEndCol && !rData.getError(); ++nCol)
3078  {
3079  if (mpColFlags && ColHidden(nCol))
3080  continue;
3081 
3082  aCol[nCol].UpdateSelectionFunction(aRanges, rData, *mpHiddenRows);
3083  }
3084 }
3085 
3086 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void AdjustReferenceOnMovedOrigin(const ScAddress &rOldPos, const ScAddress &rNewPos)
Adjust all internal references on base position change.
Definition: token.cxx:4471
::std::vector< ScSortKeyState > maKeyState
Definition: sortparam.hxx:121
bool bGroupActive[MAXSUBTOTAL]
active groups
std::map< SCROW, std::vector< SdrObject * > > GetObjectsAnchoredToRange(SCTAB nTab, SCCOL nCol, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:2489
void PrepareQuery(ScQueryParam &rQueryParam)
Definition: table3.cxx:2557
formula::FormulaToken * AddDoubleReference(const ScComplexRefData &rRef)
Definition: token.cxx:2281
ocStop
sal_uInt16 nUserIndex
Definition: sortparam.hxx:110
SCTAB nTab
Definition: table.hxx:205
const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow) const
Definition: table2.cxx:2193
Collection of user-defined sort lists.
Definition: userlist.hxx:66
void DeleteRow(SCCOL nStartCol, SCTAB nStartTab, SCCOL nEndCol, SCTAB nEndTab, SCROW nStartRow, SCSIZE nSize, ScDocument *pRefUndoDoc=nullptr, bool *pUndoOutline=nullptr, const ScMarkData *pTabMark=nullptr)
Definition: document.cxx:1359
bool HasColHeader(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const
Definition: table3.cxx:2889
sal_Int32 Compare(const OUString &rSubStr1, const OUString &rSubStr2) const
Definition: userlist.cxx:148
sal_Int32 nIndex
Row(size_t nColSize)
Definition: table3.cxx:255
mdds::mtv::soa::multi_type_vector< CNoteFunc > CellNoteStoreType
ScFormulaCell * SetFormulaCell(SCCOL nCol, SCROW nRow, ScFormulaCell *pCell)
Takes ownership of pCell.
Definition: table2.cxx:1705
OUString getString() const
SCCOL nField[MAXSUBTOTAL]
associated field
ScAddress aStart
Definition: address.hxx:499
sal_Int32 getCharacterType(const OUString &rStr, sal_Int32 nPos) const
SharedString intern(const OUString &rStr)
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:567
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:42
sal_uLong GetWeightedCount() const
Definition: table3.cxx:3012
bool mbUpdateRefs
Definition: table3.cxx:269
constexpr TypedWhichId< SvxLanguageItem > ATTR_LANGUAGE_FORMAT(147)
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:89
std::unordered_map< SCTAB, ColsType > TabsType
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.cxx:371
void DestroySortCollator()
Definition: table3.cxx:644
SCCOL nCol1
selected area
SCROW Row() const
Definition: address.hxx:261
void loadCollatorAlgorithm(const OUString &rAlgorithm, const css::lang::Locale &rLocale, sal_Int32 nOption)
const Item & GetQueryItem() const
Definition: queryentry.hxx:85
const AutoFormatPatternEntry * mpPattern
css::lang::Locale aCollatorLocale
Definition: sortparam.hxx:122
void RegroupFormulaCells(SCTAB nTab, SCCOL nCol)
Definition: document10.cxx:360
void InitSortCollator(const ScSortParam &rPar)
Definition: table3.cxx:628
const std::vector< SCCOLROW > & GetOrderIndices() const
Definition: table3.cxx:382
SCCOLROW nStart
Definition: table3.cxx:264
void SortReorderByColumn(const ScSortInfoArray *pArray, SCROW nRow1, SCROW nRow2, bool bPattern, ScProgress *pProgress)
Definition: table3.cxx:943
SCTAB GetTab() const
Definition: table.hxx:283
void InitFlags()
Definition: refdata.hxx:128
bool isEmpty() const
Definition: cellvalue.cxx:670
int n1
ScFormulaCell * Clone() const
std::pair< iterator, bool > emplace(Args &&...args)
Definition: reordermap.hxx:29
void CopyData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, SCCOL nDestCol, SCROW nDestRow, SCTAB nDestTab)
Definition: table2.cxx:3976
bool Intersects(const ScRange &rRange) const
Definition: address.hxx:748
SCCOL size() const
ScSortParam aSortParam
Definition: table.hxx:212
ScTokenArray * GetCode()
sal_uIntPtr sal_uLong
ScSortInfoArray(sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2)
Definition: table3.cxx:275
CellType GetCellType(const ScAddress &rPos) const
Definition: table.hxx:460
ocSubTotal
ocOpen
sal_Int64 n
QueryItemsType & GetQueryItems()
Definition: queryentry.hxx:75
void SetStateOnPercent(sal_uLong nVal)
Definition: progress.hxx:96
void DetachFormulaCells(sc::EndListeningContext &rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: table2.cxx:1273
SC_DLLPUBLIC bool RemoveEntryByField(SCCOLROW nField)
Definition: queryparam.cxx:172
sal_Int32 GetMaxNumberStringLen(sal_uInt16 &nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd) const
Definition: table3.cxx:3052
const SfxItemSet & GetItemSet() const
const ContentProperties & rData
size_t size() const
Definition: userlist.cxx:345
SCCOLROW nField
Definition: queryentry.hxx:61
ScAddress aEnd
Definition: address.hxx:500
void SetAbsRow(SCROW nVal)
Definition: refdata.cxx:76
bool bDoSort
presort
SCSIZE Query(const ScQueryParam &rQueryParam, bool bKeepSub)
Definition: table3.cxx:2562
bool bPagebreak
page break at change of group
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
static void DecoladeRow(ScSortInfoArray *, SCROW nRow1, SCROW nRow2)
Definition: table3.cxx:1768
mdds::mtv::soa::multi_type_vector< BCBlkFunc > BroadcasterStoreType
std::shared_ptr< T > make_shared(Args &&...args)
void GetFilteredFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam &rParam, ScFilterEntries &rFilterEntries, bool bFiltering)
Definition: table3.cxx:2973
void Remove(const SfxPoolItem &)
sal_Int32 ICompare(const OUString &rSubStr1, const OUString &rSubStr2) const
Definition: userlist.cxx:174
std::vector< SCCOLROW > maOrderIndices
index of last non-empty cell position.
Definition: table3.cxx:267
bool anyExtrasWanted() const
Definition: sortparam.hxx:56
bool HasData(SCCOL nCol, SCROW nRow) const
Definition: table2.cxx:1973
void RemoveSubTotals(ScSubTotalParam &rParam)
Definition: table3.cxx:1974
SCCOLROW GetLast() const
Definition: table3.cxx:380
OUString GetInputString(SCCOL nCol, SCROW nRow, const svl::SharedString **pShared=nullptr) const
Definition: table2.cxx:1760
void UpdateSelectionFunction(ScFunctionData &rData, const ScMarkData &rMark)
Definition: table3.cxx:3061
DataType::const_iterator const_iterator
Definition: reordermap.hxx:23
bool HasRowHeader(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const
Definition: table3.cxx:2926
bool mbCellDrawObjects
If TRUE, consider the presence of draw objects anchored to the cell.
Definition: sortparam.hxx:48
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6075
void RemoveRowBreak(SCROW nRow, bool bPage, bool bManual)
Definition: table5.cxx:408
void GetMarkArea(ScRange &rRange) const
Definition: markdata.cxx:111
void ParseFormula(const CellStoreType &rStore, Func &rFunc)
Definition: mtvcellfunc.hxx:63
void SetRowBreak(SCROW nRow, bool bPage, bool bManual)
Definition: table5.cxx:438
void AttachFormulaCells(sc::StartListeningContext &rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: table2.cxx:1265
std::unique_ptr< ScSortInfo[]> const & GetFirstArray() const
Call this only during normal sorting, not from reordering.
Definition: table3.cxx:306
static SC_DLLPUBLIC const LocaleDataWrapper & getLocaleData()
Definition: global.cxx:1004
const TabsType & getAllPositions() const
Row positions in each column may contain duplicates.
Stores individual user-defined sort list.
Definition: userlist.hxx:32
int n2
void StartListeningFormulaCells(sc::StartListeningContext &rStartCxt, sc::EndListeningContext &rEndCxt, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1500
void Reorder(const sc::ReorderParam &rParam)
Definition: table3.cxx:1865
const EditTextObject * mpEditText
Definition: cellvalue.hxx:109
ScRefCellValue GetCellValue(SCROW nRow) const
Definition: column.cxx:734
enumrange< T >::Iterator begin(enumrange< T >)
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:878
ScRange maSortRange
This sort range already takes into account the presence or absence of header row / column i...
Definition: sortparam.hxx:151
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:23
Additional class containing cell annotation data.
Definition: postit.hxx:161
bool IsMultiMarked() const
Definition: markdata.hxx:82
FormulaError GetErrCode()
bool bNaturalSort
Definition: sortparam.hxx:114
int nCount
void SetOrderIndices(std::vector< SCCOLROW > &&rIndices)
Definition: table3.cxx:344
SC_DLLPUBLIC SCSIZE GetEntryCount() const
Definition: queryparam.cxx:111
void SortReorderAreaExtrasByColumn(const ScSortInfoArray *pArray, SCROW nDataRow1, SCROW nDataRow2, const ScDataAreaExtras &rDataAreaExtras, ScProgress *pProgress)
Definition: table3.cxx:923
SC_DLLPUBLIC const ScQueryEntry & GetEntry(SCSIZE n) const
Definition: queryparam.cxx:116
void set(const ScDocument &rDoc, SCTAB nTab, SCCOL nCol, SCROW nRow, bool bVal)
bool GetDataEntries(SCCOL nCol, SCROW nRow, std::set< ScTypedStrData > &rStrings)
Definition: table3.cxx:2997
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:110
void FillInExcelSyntax(svl::SharedStringPool &rPool, const OUString &aCellStr, SCSIZE nIndex, SvNumberFormatter *pFormatter)
Definition: queryparam.cxx:204
void SetRow(SCROW nRowP)
Definition: address.hxx:274
virtual void Query(QueryBase &rQuery) const
short CompareCell(sal_uInt16 nSort, ScRefCellValue &rCell1, SCCOL nCell1Col, SCROW nCell1Row, ScRefCellValue &rCell2, SCCOL nCell2Col, SCROW nCell2Row) const
Definition: table3.cxx:1523
bool SetRowHidden(SCROW nStartRow, SCROW nEndRow, bool bHidden)
Definition: table5.cxx:576
void EndListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:61
ScAddress aPos
std::vector< Row > RowsType
Definition: table3.cxx:258
void DoAutoOutline(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow)
Definition: table2.cxx:3904
void SetPattern(const ScAddress &rPos, const ScPatternAttr &rAttr)
Definition: table2.cxx:3047
void SetNeedNumberFormat(bool bVal)
ScBroadcastAreaSlotMachine * GetBASM() const
Definition: document.hxx:2160
void SetCol(SCCOL nColP)
Definition: address.hxx:278
RowsType * GetDataRows()
Definition: table3.cxx:391
Listeners aListeners
std::unique_ptr< ScBitMaskCompressedArray< SCCOL, CRFlags > > mpColFlags
Definition: table.hxx:184
bool mbCellNotes
If TRUE, consider the presence of cell notes besides data.
Definition: sortparam.hxx:46
void PutInOrder(T &nStart, T &nEnd)
Definition: address.hxx:961
ocSep
bool IsColValid(const SCCOL nScCol) const
Definition: table.hxx:320
void AdjustReferenceOnMovedOriginIfOtherSheet(const ScAddress &rOldPos, const ScAddress &rNewPos)
Adjust all internal references on base position change if they point to a sheet other than the one of...
Definition: token.cxx:4509
DocumentType eType
SCCOLROW mnLastIndex
Definition: table3.cxx:265
void executeColumnAction(ScDocument &rDoc, ColumnAction &ac) const
SCCOLROW GetStart() const
Definition: table3.cxx:379
OUString sPrefix
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
void ApplyStyle(SCCOL nCol, SCROW nRow, const ScStyleSheet *rStyle)
Definition: table2.cxx:2868
static bool joinFormulaCellAbove(const CellStoreType::position_type &aPos)
Merge with an existing formula group (if any) located immediately above if the cell at specified posi...
SCSIZE GetEmptyLinesInBlock(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScDirection eDir) const
Definition: table1.cxx:1119
const OUString & getNumDecimalSep() const
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1064
void SetDrawPageSize(bool bResetStreamValid=true, bool bUpdateNoteCaptionPos=true, const ScObjectHandling eObjectHandling=ScObjectHandling::RecalcPosMode)
Definition: table2.cxx:4056
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:877
const ScPostIt * mpNote
Definition: table3.cxx:241
bool ColHidden(SCCOL nCol, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: table5.cxx:559
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:442
SvNumFormatType GetType() const
sal_uInt16 ClearItem(sal_uInt16 nWhich=0)
void setSkipRange(const ScRange &rRange)
Set of column block positions only for one table.
bool CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam &rQueryParam)
Definition: table3.cxx:2743
ScDocument & GetDoc()
Definition: table.hxx:281
void Swap(SCCOLROW nInd1, SCCOLROW nInd2)
Call this only during normal sorting, not from reordering.
Definition: table3.cxx:322
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1045
bool IsMarked() const
Definition: markdata.hxx:81
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
SCCOL nSubTotals[MAXSUBTOTAL]
number of SubTotals
int i
const_iterator find(DataType::key_type key) const
Definition: reordermap.hxx:31
CollatorWrapper * pSortCollator
Definition: table.hxx:213
void swapRanges(ScRangeList &rRanges)
void SetUpdateRefs(bool b)
Definition: table3.cxx:299
const svl::SharedString * mpString
Definition: cellvalue.hxx:108
sal_Int16 SCCOL
Definition: types.hxx:21
Struct to hold non-data extended area, used with ScDocument::ShrinkToUsedDataArea().
Definition: sortparam.hxx:43
void SetAbsCol(SCCOL nVal)
Definition: refdata.cxx:59
bool TestRemoveSubTotals(const ScSubTotalParam &rParam)
Definition: table3.cxx:1940
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1013
const sc::CellTextAttr * mpAttr
Definition: table3.cxx:240
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:879
ScSingleRefData Ref1
Definition: refdata.hxx:124
const SCSIZE SCSIZE_MAX
Definition: address.hxx:59
const SvxPageUsage aArr[]
bool InsertRow(SCCOL nStartCol, SCTAB nStartTab, SCCOL nEndCol, SCTAB nEndTab, SCROW nStartRow, SCSIZE nSize, ScDocument *pRefUndoDoc=nullptr, const ScMarkData *pTabMark=nullptr)
Definition: document.cxx:1240
ScSortInfoArray(const ScSortInfoArray &)=delete
void DBShowRows(SCROW nRow1, SCROW nRow2, bool bShow)
Definition: table2.cxx:3593
size_t size() const
Definition: rangelst.hxx:89
ScSingleRefData Ref2
Definition: refdata.hxx:125
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
void Resize(size_t nNew)
Definition: queryparam.cxx:196
float u
Structure that stores segments of boolean flags per column, and perform custom action on those segmen...
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
static SC_DLLPUBLIC ScUserList * GetUserList()
Definition: global.cxx:274
constexpr TypedWhichId< SfxUInt32Item > ATTR_VALUE_FORMAT(146)
SvNumFormatType
std::unique_ptr< ScSubTotalFunc[]> pFunctions[MAXSUBTOTAL]
array of associated functions
BroadcastAreaSlots and their management, once per document.
Definition: bcaslot.hxx:245
ScColContainer aCol
Definition: table.hxx:158
static short Compare(const OUString &sInput1, const OUString &sInput2, const bool bCaseSens, const ScUserListData *pData, const CollatorWrapper *pCW)
Naturally compares two given strings.
Definition: table3.cxx:164
bool CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam &rQueryParam)
Definition: table3.cxx:2665
bool bCaseSens
Definition: sortparam.hxx:113
void DBShowRow(SCROW nRow, bool bShow)
Definition: table2.cxx:3567
bool mbKeepQuery
Definition: table3.cxx:268
bool DoSubTotals(ScSubTotalParam &rParam)
Definition: table3.cxx:2053
bool hasNumeric() const
Definition: cellvalue.cxx:622
ScRefCellValue maCell
Definition: table3.cxx:239
RowsType & InitDataRows(size_t nRowSize, size_t nColSize)
Definition: table3.cxx:384
sal_Int32 GetMaxStringLen(SCCOL nCol, SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet) const
Definition: table3.cxx:3043
void SetAbsTab(SCTAB nVal)
Definition: refdata.cxx:93
std::vector< Cell > maCells
Definition: table3.cxx:250
static bool SplitString(const OUString &sWhole, OUString &sPrefix, OUString &sSuffix, double &fNum)
Splits a given string into three parts: the prefix, number string, and the suffix.
Definition: table3.cxx:104
void CollectFormulaCells(std::vector< ScFormulaCell * > &rCells, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1284
svl::SharedString maString
Definition: queryentry.hxx:49
void SortReorderByRow(ScSortInfoArray *pArray, SCCOL nCol1, SCCOL nCol2, ScProgress *pProgress, bool bOnlyDataAreaExtras)
Definition: table3.cxx:1085
ScSortInfo & Get(sal_uInt16 nSort, SCCOLROW nInd)
Call this only during normal sorting, not from reordering.
Definition: table3.cxx:314
Used to collect positions of formula cells that belong to a formula group.
ScDataAreaExtras aDataAreaExtras
Definition: sortparam.hxx:109
SCCOL Col() const
Definition: address.hxx:266
bool SetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString &rString, const ScSetStringParam *pParam=nullptr)
Definition: table2.cxx:1621
bool RefVisible(const ScFormulaCell *pCell)
Definition: table2.cxx:4027
mdds::mtv::soa::multi_type_vector< CTAttrFunc > CellTextAttrStoreType
void SetKeepQuery(bool b)
Definition: table3.cxx:295
static void lcl_RemoveNumberFormat(ScTable *pTab, SCCOL nCol, SCROW nRow)
Definition: table3.cxx:2000
std::vector< SCCOLROW > maOrderIndices
List of original column / row positions after reordering.
Definition: sortparam.hxx:157
OUString GetString(SCCOL nCol, SCROW nRow, const ScInterpreterContext *pContext=nullptr) const
Definition: table2.cxx:1744
virtual formula::FormulaToken * AddOpCode(OpCode eCode) override
Definition: token.cxx:2264
CellType meType
Definition: cellvalue.hxx:105
void ReorderByRow(const std::vector< SCCOLROW > &rIndices)
Definition: table3.cxx:353
void SetState(sal_uLong nVal, sal_uLong nNewRange=0)
Definition: progress.hxx:78
bool RowHidden(SCROW nRow, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: table5.cxx:484
bool ValidQuery(SCROW nRow, const ScRefCellValue *pCell=nullptr, sc::TableColumnBlockPositionSet *pBlockPos=nullptr)
bool mbCellFormats
If TRUE, consider the presence of cell formats.
Definition: sortparam.hxx:50
sal_Int32 SCROW
Definition: types.hxx:17
To calculate a single subtotal function.
Definition: subtotal.hxx:60
mdds::mtv::soa::multi_type_vector< CellFunc, CellStoreTrait > CellStoreType
ScPostIt * GetCellNote(SCROW nRow)
Definition: column2.cxx:1990
void GetFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, ScFilterEntries &rFilterEntries, bool bFiltering=false)
Definition: table3.cxx:2963
bool CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam &rQueryParam)
Definition: table3.cxx:2849
void TopTenQuery(ScQueryParam &)
Definition: table3.cxx:2315
bool IsSubTotal() const
std::vector< SdrObject * > maDrawObjects
Definition: table3.cxx:242
bool bHasHeader
Definition: sortparam.hxx:111
static CollatorWrapper & GetCaseCollator()
case-sensitive collator
Definition: global.cxx:1055
static SC_DLLPUBLIC CollatorWrapper & GetCollator()
case-insensitive collator
Definition: global.cxx:1044
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
std::unique_ptr< ScSortInfoArray > CreateSortInfoArray(const sc::ReorderParam &rParam)
Definition: table3.cxx:463
void UnshareFormulaCells(SCTAB nTab, SCCOL nCol, std::vector< SCROW > &rRows)
Make specified formula cells non-grouped.
Definition: document10.cxx:351
CellType
Definition: global.hxx:268
virtual void Notify(const SfxHint &rHint)
short Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
Definition: table3.cxx:1729
sal_uLong GetCellCount() const
Definition: table3.cxx:3002
sal_uInt16 GetSortKeyCount() const
Definition: sortparam.hxx:139
ScColumnsRange GetColumnsRange(SCCOL begin, SCCOL end) const
Definition: table1.cxx:2614
constexpr sal_Int32 kSortCellsChunk
Definition: table3.cxx:400
OUString GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: documen3.cxx:1482
int uniform_int_distribution(int a, int b)
bool bIncludePattern
sort formats
#define SC_COLLATOR_IGNORES
Definition: global.hxx:51
virtual std::unique_ptr< EditTextObject > Clone() const =0
sal_uInt16 GetUsedSorts() const
Definition: table3.cxx:377
ScRangeList GetMarkedRangesForTab(SCTAB nTab) const
Get marked ranges with sheet-tab set to nTab.
Definition: markdata.cxx:471
const T & Put(std::unique_ptr< T > xItem, sal_uInt16 nWhich=0)
void SortReorderAreaExtrasByRow(ScSortInfoArray *pArray, SCCOL nDataCol1, SCCOL nDataCol2, const ScDataAreaExtras &rDataAreaExtras, ScProgress *pProgress)
Definition: table3.cxx:898
std::vector< std::unique_ptr< ScSortInfo[]> > mvppInfo
row-wise data table for sort by row operation.
Definition: table3.cxx:263
void SortReorderByRowRefUpdate(ScSortInfoArray *pArray, SCCOL nCol1, SCCOL nCol2, ScProgress *pProgress)
Definition: table3.cxx:1247
OUString GetUpperCellString(SCCOL nCol, SCROW nRow)
Definition: table2.cxx:4049
bool bGlobalKeepQuery
Definition: table.hxx:242
Reference< XComponentContext > getProcessComponentContext()
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:398
SvtBroadcaster * GetBroadcaster(SCCOL nCol, SCROW nRow)
Definition: table1.cxx:2508
void Sort(const ScSortParam &rSortParam, bool bKeepQuery, bool bUpdateRefs, ScProgress *pProgress, sc::ReorderParam *pUndo)
Sort a range of data.
Definition: table3.cxx:1779
double getValue()
Definition: cellvalue.cxx:632
ScQueryConnect eConnect
Definition: queryentry.hxx:63
OUString aCollatorAlgorithm
Definition: sortparam.hxx:123
SC_DLLPUBLIC ScStyleSheetPool * GetStyleSheetPool() const
Definition: document.cxx:6080
std::unique_ptr< RowsType > mpRows
Definition: table3.cxx:261
sal_uLong GetCodeCount() const
Definition: table3.cxx:3032
css::i18n::ParseResult parsePredefinedToken(sal_Int32 nTokenType, const OUString &rStr, sal_Int32 nPos, sal_Int32 nStartCharFlags, const OUString &userDefinedCharactersStart, sal_Int32 nContCharFlags, const OUString &userDefinedCharactersCont) const
Complex reference (a range) into the sheet.
Definition: refdata.hxx:122
std::vector< Item > QueryItemsType
Definition: queryentry.hxx:58
bool RowFiltered(SCROW nRow, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: table5.cxx:823
void RegroupFormulaCells(SCCOL nCol)
Definition: table7.cxx:286
void CopyAllBroadcasters(const SvtListener &r)
static TranslateId lcl_GetSubTotalStrId(int id)
Definition: table3.cxx:2027
bool getError() const
Definition: subtotal.hxx:69
std::pair< CellStoreType::const_iterator, size_t > FindFormula(const CellStoreType &rStore, SCROW nRow1, SCROW nRow2, Func &rFunc)
#define SAL_WARN(area, stream)
const ScSortInfoArray & operator=(const ScSortInfoArray &)=delete
void GetMultiMarkArea(ScRange &rRange) const
Definition: markdata.cxx:116
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:35
SCCOL ClampToAllocatedColumns(SCCOL nCol) const
Definition: table.hxx:1095
ScDocument & rDocument
Definition: table.hxx:206
void QuickSort(ScSortInfoArray *, SCCOLROW nLo, SCCOLROW nHi)
Definition: table3.cxx:1687
std::vector< sc::AreaListener > GetAllListeners(const ScRange &rRange, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup=sc::ListenerGroupType::Both)
Definition: bcaslot.cxx:1166
ScSubTotalFunc
Definition: global.hxx:834
const sc::CellTextAttr * GetCellTextAttr(SCROW nRow) const
Definition: column.cxx:795
bool IsSorted(SCCOLROW nStart, SCCOLROW nEnd) const
Definition: table3.cxx:1758
def label(st)
std::unique_ptr< SCCOL[]> pSubTotals[MAXSUBTOTAL]
array of columns to be calculated
ScDataAreaExtras maDataAreaExtras
Definition: sortparam.hxx:152
bool IsUpdateRefs() const
Definition: table3.cxx:301
std::unique_ptr< ScFlatBoolRowSegments > mpHiddenRows
Definition: table.hxx:187
const SCTAB SCTAB_MAX
Definition: address.hxx:57
virtual SfxStyleSheetBase * Find(const OUString &, SfxStyleFamily eFam, SfxStyleSearchBits n=SfxStyleSearchBits::All)
ScQueryOp eOp
Definition: queryentry.hxx:62
virtual void execute(SCROW nRow1, SCROW nRow2, bool bVal)=0
struct _ADOIndex Index
aStr
ocClose
Each instance of this struct represents a single filtering criteria.
Definition: queryentry.hxx:33
const ScPatternAttr * mpPattern
Definition: table3.cxx:243
bool IsSortCollatorGlobal() const
Definition: table3.cxx:622
virtual void startColumn(ScColumn *pCol)=0
void SplitFormulaGroups(SCCOL nCol, std::vector< SCROW > &rRows)
Definition: table7.cxx:270
const_iterator end() const
Definition: reordermap.hxx:26
sal_uInt16 nPos
sal_Int16 SCTAB
Definition: types.hxx:22
ScRefCellValue GetCellValue(SCCOL nCol, sc::ColumnBlockPosition &rBlockPos, SCROW nRow)
Definition: table2.cxx:1939
bool IsKeepQuery() const
Definition: table3.cxx:297
const SCSIZE MAXSUBTOTAL
Definition: global.hxx:81
SCSIZE GetPatternCount() const
Definition: column2.cxx:3658
void SetRowFiltered(SCROW nStartRow, SCROW nEndRow, bool bFiltered)
Definition: table5.cxx:903
FormulaToken * AddDouble(double fVal)