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