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 if (!rCell1.isEmpty())
1535 {
1536 if (!rCell2.isEmpty())
1537 {
1538 bool bErr1 = false;
1539 bool bStr1 = ( eType1 != CELLTYPE_VALUE );
1540 if (eType1 == CELLTYPE_FORMULA)
1541 {
1542 if (rCell1.getFormula()->GetErrCode() != FormulaError::NONE)
1543 {
1544 bErr1 = true;
1545 bStr1 = false;
1546 }
1547 else if (rCell1.getFormula()->IsValue())
1548 {
1549 bStr1 = false;
1550 }
1551 }
1552
1553 bool bErr2 = false;
1554 bool bStr2 = ( eType2 != CELLTYPE_VALUE );
1555 if (eType2 == CELLTYPE_FORMULA)
1556 {
1557 if (rCell2.getFormula()->GetErrCode() != FormulaError::NONE)
1558 {
1559 bErr2 = true;
1560 bStr2 = false;
1561 }
1562 else if (rCell2.getFormula()->IsValue())
1563 {
1564 bStr2 = false;
1565 }
1566 }
1567
1568 if ( bStr1 && bStr2 ) // only compare strings as strings!
1569 {
1570 OUString aStr1;
1571 OUString aStr2;
1572 if (eType1 == CELLTYPE_STRING)
1573 aStr1 = rCell1.getSharedString()->getString();
1574 else
1575 aStr1 = GetString(nCell1Col, nCell1Row);
1576 if (eType2 == CELLTYPE_STRING)
1577 aStr2 = rCell2.getSharedString()->getString();
1578 else
1579 aStr2 = GetString(nCell2Col, nCell2Row);
1580
1581 bool bUserDef = aSortParam.bUserDef; // custom sort order
1582 bool bNaturalSort = aSortParam.bNaturalSort; // natural sort
1583 bool bCaseSens = aSortParam.bCaseSens; // case sensitivity
1584
1586 if (bUserDef && pList && pList->size() > aSortParam.nUserIndex )
1587 {
1588 const ScUserListData& rData = (*pList)[aSortParam.nUserIndex];
1589
1590 if ( bNaturalSort )
1591 nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, &rData, pSortCollator );
1592 else
1593 {
1594 if ( bCaseSens )
1595 nRes = sal::static_int_cast<short>( rData.Compare(aStr1, aStr2) );
1596 else
1597 nRes = sal::static_int_cast<short>( rData.ICompare(aStr1, aStr2) );
1598 }
1599
1600 }
1601 if (!bUserDef)
1602 {
1603 if ( bNaturalSort )
1604 nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, nullptr, pSortCollator );
1605 else
1606 nRes = static_cast<short>( pSortCollator->compareString( aStr1, aStr2 ) );
1607 }
1608 }
1609 else if ( bStr1 ) // String <-> Number or Error
1610 {
1611 if (bErr2)
1612 nRes = -1; // String in front of Error
1613 else
1614 nRes = 1; // Number in front of String
1615 }
1616 else if ( bStr2 ) // Number or Error <-> String
1617 {
1618 if (bErr1)
1619 nRes = 1; // String in front of Error
1620 else
1621 nRes = -1; // Number in front of String
1622 }
1623 else if (bErr1 && bErr2)
1624 {
1625 // nothing, two Errors are equal
1626 }
1627 else if (bErr1) // Error <-> Number
1628 {
1629 nRes = 1; // Number in front of Error
1630 }
1631 else if (bErr2) // Number <-> Error
1632 {
1633 nRes = -1; // Number in front of Error
1634 }
1635 else // Mixed numbers
1636 {
1637 double nVal1 = rCell1.getValue();
1638 double nVal2 = rCell2.getValue();
1639 if (nVal1 < nVal2)
1640 nRes = -1;
1641 else if (nVal1 > nVal2)
1642 nRes = 1;
1643 }
1644 if ( !aSortParam.maKeyState[nSort].bAscending )
1645 nRes = -nRes;
1646 }
1647 else
1648 nRes = -1;
1649 }
1650 else
1651 {
1652 if (!rCell2.isEmpty())
1653 nRes = 1;
1654 else
1655 nRes = 0; // both empty
1656 }
1657 return nRes;
1658}
1659
1660short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nIndex2 ) const
1661{
1662 short nRes;
1663 sal_uInt16 nSort = 0;
1664 do
1665 {
1666 ScSortInfo& rInfo1 = pArray->Get( nSort, nIndex1 );
1667 ScSortInfo& rInfo2 = pArray->Get( nSort, nIndex2 );
1668 if ( aSortParam.bByRow )
1669 nRes = CompareCell( nSort,
1670 rInfo1.maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), rInfo1.nOrg,
1671 rInfo2.maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), rInfo2.nOrg );
1672 else
1673 nRes = CompareCell( nSort,
1674 rInfo1.maCell, static_cast<SCCOL>(rInfo1.nOrg), aSortParam.maKeyState[nSort].nField,
1675 rInfo2.maCell, static_cast<SCCOL>(rInfo2.nOrg), aSortParam.maKeyState[nSort].nField );
1676 } while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() );
1677 if( nRes == 0 )
1678 {
1679 ScSortInfo& rInfo1 = pArray->Get( 0, nIndex1 );
1680 ScSortInfo& rInfo2 = pArray->Get( 0, nIndex2 );
1681 if( rInfo1.nOrg < rInfo2.nOrg )
1682 nRes = -1;
1683 else if( rInfo1.nOrg > rInfo2.nOrg )
1684 nRes = 1;
1685 }
1686 return nRes;
1687}
1688
1690{
1691 if ((nHi - nLo) == 1)
1692 {
1693 if (Compare(pArray, nLo, nHi) > 0)
1694 pArray->Swap( nLo, nHi );
1695 }
1696 else
1697 {
1698 SCCOLROW ni = nLo;
1699 SCCOLROW nj = nHi;
1700 do
1701 {
1702 while ((ni <= nHi) && (Compare(pArray, ni, nLo)) < 0)
1703 ni++;
1704 while ((nj >= nLo) && (Compare(pArray, nLo, nj)) < 0)
1705 nj--;
1706 if (ni <= nj)
1707 {
1708 if (ni != nj)
1709 pArray->Swap( ni, nj );
1710 ni++;
1711 nj--;
1712 }
1713 } while (ni < nj);
1714 if ((nj - nLo) < (nHi - ni))
1715 {
1716 if (nLo < nj)
1717 QuickSort(pArray, nLo, nj);
1718 if (ni < nHi)
1719 QuickSort(pArray, ni, nHi);
1720 }
1721 else
1722 {
1723 if (ni < nHi)
1724 QuickSort(pArray, ni, nHi);
1725 if (nLo < nj)
1726 QuickSort(pArray, nLo, nj);
1727 }
1728 }
1729}
1730
1731short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
1732{
1733 short nRes;
1734 sal_uInt16 nSort = 0;
1735 const sal_uInt32 nMaxSorts = aSortParam.GetSortKeyCount();
1736 if (aSortParam.bByRow)
1737 {
1738 do
1739 {
1740 SCCOL nCol = static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField);
1741 nRes = 0;
1742 if(nCol < GetAllocatedColumnsCount())
1743 {
1744 ScRefCellValue aCell1 = aCol[nCol].GetCellValue(nIndex1);
1745 ScRefCellValue aCell2 = aCol[nCol].GetCellValue(nIndex2);
1746 nRes = CompareCell(nSort, aCell1, nCol, nIndex1, aCell2, nCol, nIndex2);
1747 }
1748 } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
1749 }
1750 else
1751 {
1752 do
1753 {
1754 SCROW nRow = aSortParam.maKeyState[nSort].nField;
1755 ScRefCellValue aCell1;
1756 ScRefCellValue aCell2;
1757 if(nIndex1 < GetAllocatedColumnsCount())
1758 aCell1 = aCol[nIndex1].GetCellValue(nRow);
1759 if(nIndex2 < GetAllocatedColumnsCount())
1760 aCell2 = aCol[nIndex2].GetCellValue(nRow);
1761 nRes = CompareCell( nSort, aCell1, static_cast<SCCOL>(nIndex1),
1762 nRow, aCell2, static_cast<SCCOL>(nIndex2), nRow );
1763 } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
1764 }
1765 return nRes;
1766}
1767
1768bool ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) const // over aSortParam
1769{
1770 for (SCCOLROW i=nStart; i<nEnd; i++)
1771 {
1772 if (Compare( i, i+1 ) > 0)
1773 return false;
1774 }
1775 return true;
1776}
1777
1779{
1780 SCROW nRow;
1781 int nMax = nRow2 - nRow1;
1782 for (SCROW i = nRow1; (i + 4) <= nRow2; i += 4)
1783 {
1785 pArray->Swap(i, nRow1 + nRow);
1786 }
1787}
1788
1790 const ScSortParam& rSortParam, bool bKeepQuery, bool bUpdateRefs,
1791 ScProgress* pProgress, sc::ReorderParam* pUndo )
1792{
1793 sc::DelayDeletingBroadcasters delayDeletingBroadcasters(GetDoc());
1794 InitSortCollator( rSortParam );
1795 bGlobalKeepQuery = bKeepQuery;
1796
1797 if (pUndo)
1798 {
1799 // Copy over the basic sort parameters.
1800 pUndo->maDataAreaExtras = rSortParam.aDataAreaExtras;
1801 pUndo->mbByRow = rSortParam.bByRow;
1802 pUndo->mbHiddenFiltered = bKeepQuery;
1803 pUndo->mbUpdateRefs = bUpdateRefs;
1804 pUndo->mbHasHeaders = rSortParam.bHasHeader;
1805 }
1806
1807 // It is assumed that the data area has already been trimmed as necessary.
1808
1809 aSortParam = rSortParam; // must be assigned before calling IsSorted()
1810 if (rSortParam.bByRow)
1811 {
1812 const SCROW nLastRow = rSortParam.nRow2;
1813 const SCROW nRow1 = (rSortParam.bHasHeader ? rSortParam.nRow1 + 1 : rSortParam.nRow1);
1814 if (nRow1 < nLastRow && !IsSorted(nRow1, nLastRow))
1815 {
1816 if(pProgress)
1817 pProgress->SetState( 0, nLastRow-nRow1 );
1818
1819 std::unique_ptr<ScSortInfoArray> pArray( CreateSortInfoArray(
1820 aSortParam, nRow1, nLastRow, bKeepQuery, bUpdateRefs));
1821
1822 if ( nLastRow - nRow1 > 255 )
1823 DecoladeRow(pArray.get(), nRow1, nLastRow);
1824
1825 QuickSort(pArray.get(), nRow1, nLastRow);
1826 if (pArray->IsUpdateRefs())
1827 SortReorderByRowRefUpdate(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress);
1828 else
1829 {
1830 SortReorderByRow(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress, false);
1831 if (rSortParam.aDataAreaExtras.anyExtrasWanted())
1833 rSortParam.aDataAreaExtras, pProgress);
1834 }
1835
1836 if (pUndo)
1837 {
1838 // Stored is the first data row without header row.
1839 pUndo->maSortRange = ScRange(rSortParam.nCol1, nRow1, nTab, rSortParam.nCol2, nLastRow, nTab);
1840 pUndo->maDataAreaExtras.mnStartRow = nRow1;
1841 pUndo->maOrderIndices = pArray->GetOrderIndices();
1842 }
1843 }
1844 }
1845 else
1846 {
1847 const SCCOL nLastCol = rSortParam.nCol2;
1848 const SCCOL nCol1 = (rSortParam.bHasHeader ? rSortParam.nCol1 + 1 : rSortParam.nCol1);
1849 if (nCol1 < nLastCol && !IsSorted(nCol1, nLastCol))
1850 {
1851 if(pProgress)
1852 pProgress->SetState( 0, nLastCol-nCol1 );
1853
1854 std::unique_ptr<ScSortInfoArray> pArray( CreateSortInfoArray(
1855 aSortParam, nCol1, nLastCol, bKeepQuery, bUpdateRefs));
1856
1857 QuickSort(pArray.get(), nCol1, nLastCol);
1858 SortReorderByColumn(pArray.get(), rSortParam.nRow1, rSortParam.nRow2,
1859 rSortParam.aDataAreaExtras.mbCellFormats, pProgress);
1860 if (rSortParam.aDataAreaExtras.anyExtrasWanted() && !pArray->IsUpdateRefs())
1861 SortReorderAreaExtrasByColumn( pArray.get(),
1862 rSortParam.nRow1, rSortParam.nRow2, rSortParam.aDataAreaExtras, pProgress);
1863
1864 if (pUndo)
1865 {
1866 // Stored is the first data column without header column.
1867 pUndo->maSortRange = ScRange(nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab);
1868 pUndo->maDataAreaExtras.mnStartCol = nCol1;
1869 pUndo->maOrderIndices = pArray->GetOrderIndices();
1870 }
1871 }
1872 }
1874}
1875
1877{
1878 if (rParam.maOrderIndices.empty())
1879 return;
1880
1881 std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(rParam));
1882 if (!pArray)
1883 return;
1884
1885 if (rParam.mbByRow)
1886 {
1887 // Re-play sorting from the known sort indices.
1888 pArray->ReorderByRow(rParam.maOrderIndices);
1889 if (pArray->IsUpdateRefs())
1891 pArray.get(), rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr);
1892 else
1893 {
1894 SortReorderByRow( pArray.get(),
1895 rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), nullptr, false);
1896 if (rParam.maDataAreaExtras.anyExtrasWanted())
1897 SortReorderAreaExtrasByRow( pArray.get(),
1898 rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(),
1899 rParam.maDataAreaExtras, nullptr);
1900 }
1901 }
1902 else
1903 {
1904 // Ordering by column is much simpler. Just set the order indices and we are done.
1905 pArray->SetOrderIndices(std::vector(rParam.maOrderIndices));
1907 pArray.get(), rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(),
1908 rParam.maDataAreaExtras.mbCellFormats, nullptr);
1909 if (rParam.maDataAreaExtras.anyExtrasWanted() && !pArray->IsUpdateRefs())
1910 SortReorderAreaExtrasByColumn( pArray.get(),
1911 rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(),
1912 rParam.maDataAreaExtras, nullptr);
1913 }
1914}
1915
1916namespace {
1917
1918class SubTotalRowFinder
1919{
1920 const ScTable& mrTab;
1921 const ScSubTotalParam& mrParam;
1922
1923public:
1924 SubTotalRowFinder(const ScTable& rTab, const ScSubTotalParam& rParam) :
1925 mrTab(rTab), mrParam(rParam) {}
1926
1927 bool operator() (size_t nRow, const ScFormulaCell* pCell)
1928 {
1929 if (!pCell->IsSubTotal())
1930 return false;
1931
1932 SCCOL nStartCol = mrParam.nCol1;
1933 SCCOL nEndCol = mrParam.nCol2;
1934
1935 for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(0, nStartCol - 1))
1936 {
1937 if (mrTab.HasData(nCol, nRow))
1938 return true;
1939 }
1940 for (SCCOL nCol : mrTab.GetAllocatedColumnsRange(nEndCol + 1, mrTab.GetDoc().MaxCol()))
1941 {
1942 if (mrTab.HasData(nCol, nRow))
1943 return true;
1944 }
1945 return false;
1946 }
1947};
1948
1949}
1950
1952{
1953 SCCOL nStartCol = rParam.nCol1;
1954 SCROW nStartRow = rParam.nRow1 + 1; // Header
1955 SCCOL nEndCol = ClampToAllocatedColumns(rParam.nCol2);
1956 SCROW nEndRow = rParam.nRow2;
1957
1958 for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
1959 {
1960 const sc::CellStoreType& rCells = aCol[nCol].maCells;
1961 SubTotalRowFinder aFunc(*this, rParam);
1962 std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
1963 sc::FindFormula(rCells, nStartRow, nEndRow, aFunc);
1964 if (aPos.first != rCells.end())
1965 return true;
1966 }
1967 return false;
1968}
1969
1970namespace {
1971
1972struct RemoveSubTotalsHandler
1973{
1974 std::set<SCROW> aRemoved;
1975
1976 void operator() (size_t nRow, const ScFormulaCell* p)
1977 {
1978 if (p->IsSubTotal())
1979 aRemoved.insert(nRow);
1980 }
1981};
1982
1983}
1984
1986{
1987 SCCOL nStartCol = rParam.nCol1;
1988 SCROW nStartRow = rParam.nRow1 + 1; // Header
1989 SCCOL nEndCol = ClampToAllocatedColumns(rParam.nCol2);
1990 SCROW nEndRow = rParam.nRow2; // will change
1991
1992 RemoveSubTotalsHandler aFunc;
1993 for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
1994 {
1995 const sc::CellStoreType& rCells = aCol[nCol].maCells;
1996 sc::ParseFormula(rCells.begin(), rCells, nStartRow, nEndRow, aFunc);
1997 }
1998
1999 auto& aRows = aFunc.aRemoved;
2000
2001 std::for_each(aRows.rbegin(), aRows.rend(), [this](const SCROW nRow) {
2002 RemoveRowBreak(nRow+1, false, true);
2003 rDocument.DeleteRow(0, nTab, rDocument.MaxCol(), nTab, nRow, 1);
2004 });
2005
2006 rParam.nRow2 -= aRows.size();
2007}
2008
2009// Delete hard number formats (for result formulas)
2010
2011static void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow )
2012{
2013 const ScPatternAttr* pPattern = pTab->GetPattern( nCol, nRow );
2014 if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, false )
2015 == SfxItemState::SET )
2016 {
2017 auto pNewPattern = std::make_unique<ScPatternAttr>( *pPattern );
2018 SfxItemSet& rSet = pNewPattern->GetItemSet();
2021 pTab->SetPattern( nCol, nRow, std::move(pNewPattern) );
2022 }
2023}
2024
2025namespace {
2026
2027struct RowEntry
2028{
2029 sal_uInt16 nGroupNo;
2030 SCROW nSubStartRow;
2031 SCROW nDestRow;
2032 SCROW nFuncStart;
2033 SCROW nFuncEnd;
2034};
2035
2036}
2037
2039{
2040 switch ( id )
2041 {
2042 case SUBTOTAL_FUNC_AVE: return STR_FUN_TEXT_AVG;
2043 case SUBTOTAL_FUNC_CNT:
2044 case SUBTOTAL_FUNC_CNT2: return STR_FUN_TEXT_COUNT;
2045 case SUBTOTAL_FUNC_MAX: return STR_FUN_TEXT_MAX;
2046 case SUBTOTAL_FUNC_MIN: return STR_FUN_TEXT_MIN;
2047 case SUBTOTAL_FUNC_PROD: return STR_FUN_TEXT_PRODUCT;
2048 case SUBTOTAL_FUNC_STD:
2049 case SUBTOTAL_FUNC_STDP: return STR_FUN_TEXT_STDDEV;
2050 case SUBTOTAL_FUNC_SUM: return STR_FUN_TEXT_SUM;
2051 case SUBTOTAL_FUNC_VAR:
2052 case SUBTOTAL_FUNC_VARP: return STR_FUN_TEXT_VAR;
2053 default:
2054 {
2055 return STR_EMPTYDATA;
2056 // added to avoid warnings
2057 }
2058 }
2059}
2060
2061// Gets the string used for "Grand" results
2063{
2064 switch ( id )
2065 {
2066 case SUBTOTAL_FUNC_AVE: return STR_TABLE_GRAND_AVG;
2067 case SUBTOTAL_FUNC_CNT:
2068 case SUBTOTAL_FUNC_CNT2: return STR_TABLE_GRAND_COUNT;
2069 case SUBTOTAL_FUNC_MAX: return STR_TABLE_GRAND_MAX;
2070 case SUBTOTAL_FUNC_MIN: return STR_TABLE_GRAND_MIN;
2071 case SUBTOTAL_FUNC_PROD: return STR_TABLE_GRAND_PRODUCT;
2072 case SUBTOTAL_FUNC_STD:
2073 case SUBTOTAL_FUNC_STDP: return STR_TABLE_GRAND_STDDEV;
2074 case SUBTOTAL_FUNC_SUM: return STR_TABLE_GRAND_SUM;
2075 case SUBTOTAL_FUNC_VAR:
2076 case SUBTOTAL_FUNC_VARP: return STR_TABLE_GRAND_VAR;
2077 default:
2078 {
2079 return STR_EMPTYDATA;
2080 // added to avoid warnings
2081 }
2082 }
2083}
2084
2085// new intermediate results
2086// rParam.nRow2 is changed!
2087
2089{
2090 SCCOL nStartCol = rParam.nCol1;
2091 SCROW nStartRow = rParam.nRow1 + 1; // Header
2092 SCCOL nEndCol = rParam.nCol2;
2093 SCROW nEndRow = rParam.nRow2; // will change
2094 sal_uInt16 i;
2095
2096 // Remove empty rows at the end
2097 // so that all exceeding (rDocument.MaxRow()) can be found by InsertRow (#35180#)
2098 // If sorted, all empty rows are at the end.
2099 SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM );
2100 nEndRow -= nEmpty;
2101
2102 sal_uInt16 nLevelCount = 0; // Number of levels
2103 bool bDoThis = true;
2104 for (i=0; i<MAXSUBTOTAL && bDoThis; i++)
2105 if (rParam.bGroupActive[i])
2106 nLevelCount = i+1;
2107 else
2108 bDoThis = false;
2109
2110 if (nLevelCount==0) // do nothing
2111 return true;
2112
2113 SCCOL* nGroupCol = rParam.nField; // columns which will be used when grouping
2114
2115 // With (blank) as a separate category, subtotal rows from
2116 // the other columns must always be tested
2117 // (previously only when a column occurred more than once)
2118 bool bTestPrevSub = ( nLevelCount > 1 );
2119
2120 OUString aSubString;
2121
2122 bool bIgnoreCase = !rParam.bCaseSens;
2123
2124 OUString aCompString[MAXSUBTOTAL];
2125
2126 //TODO: sort?
2127
2128 ScStyleSheet* pStyle = static_cast<ScStyleSheet*>(rDocument.GetStyleSheetPool()->Find(
2129 ScResId(STR_STYLENAME_RESULT), SfxStyleFamily::Para ));
2130
2131 bool bSpaceLeft = true; // Success when inserting?
2132
2133 // For performance reasons collect formula entries so their
2134 // references don't have to be tested for updates each time a new row is
2135 // inserted
2136 RowEntry aRowEntry;
2137 ::std::vector< RowEntry > aRowVector;
2138
2139 for (sal_uInt16 nLevel=0; nLevel<nLevelCount && bSpaceLeft; nLevel++)
2140 {
2141 aRowEntry.nGroupNo = nLevelCount - nLevel - 1;
2142
2143 // how many results per level
2144 SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo];
2145 // result functions
2146 ScSubTotalFunc* pResFunc = rParam.pFunctions[aRowEntry.nGroupNo].get();
2147
2148 if (nResCount > 0) // otherwise only sort
2149 {
2150 for (i=0; i<=aRowEntry.nGroupNo; i++)
2151 {
2152 aSubString = GetString( nGroupCol[i], nStartRow );
2153 if ( bIgnoreCase )
2154 aCompString[i] = ScGlobal::getCharClass().uppercase( aSubString );
2155 else
2156 aCompString[i] = aSubString;
2157 } // aSubString stays on the last
2158
2159 bool bBlockVis = false; // group visible?
2160 aRowEntry.nSubStartRow = nStartRow;
2161 for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++)
2162 {
2163 bool bChanged;
2164 if (nRow>nEndRow)
2165 bChanged = true;
2166 else
2167 {
2168 bChanged = false;
2169 OUString aString;
2170 for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++)
2171 {
2172 aString = GetString( nGroupCol[i], nRow );
2173 if (bIgnoreCase)
2174 aString = ScGlobal::getCharClass().uppercase(aString);
2175 // when sorting, blanks are separate group
2176 // otherwise blank cells are allowed below
2177 bChanged = ( ( !aString.isEmpty() || rParam.bDoSort ) &&
2178 aString != aCompString[i] );
2179 }
2180 if ( bChanged && bTestPrevSub )
2181 {
2182 // No group change on rows that will contain subtotal formulas
2183 bChanged = std::none_of(aRowVector.begin(), aRowVector.end(),
2184 [&nRow](const RowEntry& rEntry) { return rEntry.nDestRow == nRow; });
2185 }
2186 }
2187 if ( bChanged )
2188 {
2189 aRowEntry.nDestRow = nRow;
2190 aRowEntry.nFuncStart = aRowEntry.nSubStartRow;
2191 aRowEntry.nFuncEnd = nRow-1;
2192
2193 bSpaceLeft = rDocument.InsertRow( 0, nTab, rDocument.MaxCol(), nTab,
2194 aRowEntry.nDestRow, 1 );
2195 DBShowRow( aRowEntry.nDestRow, bBlockVis );
2196 if ( rParam.bPagebreak && nRow < rDocument.MaxRow() &&
2197 aRowEntry.nSubStartRow != nStartRow && nLevel == 0)
2198 SetRowBreak(aRowEntry.nSubStartRow, false, true);
2199
2200 if (bSpaceLeft)
2201 {
2202 for ( auto& rRowEntry : aRowVector)
2203 {
2204 if ( aRowEntry.nDestRow <= rRowEntry.nSubStartRow )
2205 ++rRowEntry.nSubStartRow;
2206 if ( aRowEntry.nDestRow <= rRowEntry.nDestRow )
2207 ++rRowEntry.nDestRow;
2208 if ( aRowEntry.nDestRow <= rRowEntry.nFuncStart )
2209 ++rRowEntry.nFuncStart;
2210 if ( aRowEntry.nDestRow <= rRowEntry.nFuncEnd )
2211 ++rRowEntry.nFuncEnd;
2212 }
2213 // collect formula positions
2214 aRowVector.push_back( aRowEntry );
2215
2216 OUString aOutString = aSubString;
2217 if (aOutString.isEmpty())
2218 aOutString = ScResId( STR_EMPTYDATA );
2219 aOutString += " ";
2220 TranslateId pStrId = STR_TABLE_ERGEBNIS;
2221 if ( nResCount == 1 )
2222 pStrId = lcl_GetSubTotalStrId(pResFunc[0]);
2223 aOutString += ScResId(pStrId);
2224 SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString );
2225 ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle );
2226
2227 ++nRow;
2228 ++nEndRow;
2229 aRowEntry.nSubStartRow = nRow;
2230 for (i=0; i<=aRowEntry.nGroupNo; i++)
2231 {
2232 aSubString = GetString( nGroupCol[i], nRow );
2233 if ( bIgnoreCase )
2234 aCompString[i] = ScGlobal::getCharClass().uppercase( aSubString );
2235 else
2236 aCompString[i] = aSubString;
2237 }
2238 }
2239 }
2240 bBlockVis = !RowFiltered(nRow);
2241 }
2242 }
2243 }
2244
2245 if (!aRowVector.empty())
2246 {
2247 // generate global total
2248 SCROW nGlobalStartRow = aRowVector[0].nSubStartRow;
2249 SCROW nGlobalStartFunc = aRowVector[0].nFuncStart;
2250 SCROW nGlobalEndRow = 0;
2251 SCROW nGlobalEndFunc = 0;
2252 for (const auto& rRowEntry : aRowVector)
2253 {
2254 nGlobalEndRow = (nGlobalEndRow < rRowEntry.nDestRow) ? rRowEntry.nDestRow : nGlobalEndRow;
2255 nGlobalEndFunc = (nGlobalEndFunc < rRowEntry.nFuncEnd) ? rRowEntry.nFuncEnd : nGlobalEndRow;
2256 }
2257
2258 for (sal_uInt16 nLevel = 0; nLevel<nLevelCount; nLevel++)
2259 {
2260 const sal_uInt16 nGroupNo = nLevelCount - nLevel - 1;
2261 const ScSubTotalFunc* pResFunc = rParam.pFunctions[nGroupNo].get();
2262 if (!pResFunc)
2263 {
2264 // No subtotal function given for this group => no formula or
2265 // label and do not insert a row.
2266 continue;
2267 }
2268
2269 // increment end row
2270 nGlobalEndRow++;
2271
2272 // add row entry for formula
2273 aRowEntry.nGroupNo = nGroupNo;
2274 aRowEntry.nSubStartRow = nGlobalStartRow;
2275 aRowEntry.nFuncStart = nGlobalStartFunc;
2276 aRowEntry.nDestRow = nGlobalEndRow;
2277 aRowEntry.nFuncEnd = nGlobalEndFunc;
2278
2279 // increment row
2280 nGlobalEndFunc++;
2281
2282 bSpaceLeft = rDocument.InsertRow(0, nTab, rDocument.MaxCol(), nTab, aRowEntry.nDestRow, 1);
2283
2284 if (bSpaceLeft)
2285 {
2286 aRowVector.push_back(aRowEntry);
2287 nEndRow++;
2288 DBShowRow(aRowEntry.nDestRow, true);
2289
2290 // insert label
2291 OUString label = ScResId(lcl_GetGrandSubTotalStrId(pResFunc[0]));
2292 SetString(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, label);
2293 ApplyStyle(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle);
2294 }
2295 }
2296 }
2297
2298 // now insert the formulas
2299 ScComplexRefData aRef;
2300 aRef.InitFlags();
2301 aRef.Ref1.SetAbsTab(nTab);
2302 aRef.Ref2.SetAbsTab(nTab);
2303 for (const auto& rRowEntry : aRowVector)
2304 {
2305 SCCOL nResCount = rParam.nSubTotals[rRowEntry.nGroupNo];
2306 SCCOL* nResCols = rParam.pSubTotals[rRowEntry.nGroupNo].get();
2307 ScSubTotalFunc* pResFunc = rParam.pFunctions[rRowEntry.nGroupNo].get();
2308 for ( SCCOL nResult=0; nResult < nResCount; ++nResult )
2309 {
2310 aRef.Ref1.SetAbsCol(nResCols[nResult]);
2311 aRef.Ref1.SetAbsRow(rRowEntry.nFuncStart);
2312 aRef.Ref2.SetAbsCol(nResCols[nResult]);
2313 aRef.Ref2.SetAbsRow(rRowEntry.nFuncEnd);
2314
2316 aArr.AddOpCode( ocSubTotal );
2317 aArr.AddOpCode( ocOpen );
2318 aArr.AddDouble( static_cast<double>(pResFunc[nResult]) );
2319 aArr.AddOpCode( ocSep );
2320 aArr.AddDoubleReference( aRef );
2321 aArr.AddOpCode( ocClose );
2322 aArr.AddOpCode( ocStop );
2323 ScFormulaCell* pCell = new ScFormulaCell(
2324 rDocument, ScAddress(nResCols[nResult], rRowEntry.nDestRow, nTab), aArr);
2325 if ( rParam.bIncludePattern )
2326 pCell->SetNeedNumberFormat(true);
2327
2328 SetFormulaCell(nResCols[nResult], rRowEntry.nDestRow, pCell);
2329 if ( nResCols[nResult] != nGroupCol[rRowEntry.nGroupNo] )
2330 {
2331 ApplyStyle( nResCols[nResult], rRowEntry.nDestRow, pStyle );
2332
2333 lcl_RemoveNumberFormat( this, nResCols[nResult], rRowEntry.nDestRow );
2334 }
2335 }
2336
2337 }
2338
2339 //TODO: according to setting, shift intermediate-sum rows up?
2340
2341 //TODO: create Outlines directly?
2342
2343 if (bSpaceLeft)
2344 DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
2345
2346 rParam.nRow2 = nEndRow; // new end
2347 return bSpaceLeft;
2348}
2349
2351{
2352 bool bSortCollatorInitialized = false;
2353 SCSIZE nEntryCount = rParam.GetEntryCount();
2354 SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1);
2355 SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1);
2356 for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ )
2357 {
2358 ScQueryEntry& rEntry = rParam.GetEntry(i);
2360
2361 for (ScQueryEntry::Item& rItem : rItems)
2362 {
2363 switch (rEntry.eOp)
2364 {
2365 case SC_TOPVAL:
2366 case SC_BOTVAL:
2367 case SC_TOPPERC:
2368 case SC_BOTPERC:
2369 {
2370 ScSortParam aLocalSortParam(rParam, static_cast<SCCOL>(rEntry.nField));
2371 aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare
2372 if (!bSortCollatorInitialized)
2373 {
2374 bSortCollatorInitialized = true;
2375 InitSortCollator(aLocalSortParam);
2376 }
2377 std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nRow1, rParam.nRow2, bGlobalKeepQuery, false));
2378 DecoladeRow(pArray.get(), nRow1, rParam.nRow2);
2379 QuickSort(pArray.get(), nRow1, rParam.nRow2);
2380 std::unique_ptr<ScSortInfo[]> const& ppInfo = pArray->GetFirstArray();
2381 SCSIZE nValidCount = nCount;
2382 // Don't count note or blank cells, they are sorted to the end
2383 while (nValidCount > 0 && ppInfo[nValidCount - 1].maCell.isEmpty())
2384 nValidCount--;
2385 // Don't count Strings, they are between Value and blank
2386 while (nValidCount > 0 && ppInfo[nValidCount - 1].maCell.hasString())
2387 nValidCount--;
2388 if (nValidCount > 0)
2389 {
2390 if (rItem.meType == ScQueryEntry::ByString)
2391 { // by string ain't going to work
2392 rItem.meType = ScQueryEntry::ByValue;
2393 rItem.mfVal = 10; // 10 and 10% respectively
2394 }
2395 SCSIZE nVal = (rItem.mfVal >= 1 ? static_cast<SCSIZE>(rItem.mfVal) : 1);
2396 SCSIZE nOffset = 0;
2397 switch (rEntry.eOp)
2398 {
2399 case SC_TOPVAL:
2400 {
2401 rEntry.eOp = SC_GREATER_EQUAL;
2402 if (nVal > nValidCount)
2403 nVal = nValidCount;
2404 nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount
2405 }
2406 break;
2407 case SC_BOTVAL:
2408 {
2409 rEntry.eOp = SC_LESS_EQUAL;
2410 if (nVal > nValidCount)
2411 nVal = nValidCount;
2412 nOffset = nVal - 1; // 1 <= nVal <= nValidCount
2413 }
2414 break;
2415 case SC_TOPPERC:
2416 {
2417 rEntry.eOp = SC_GREATER_EQUAL;
2418 if (nVal > 100)
2419 nVal = 100;
2420 nOffset = nValidCount - (nValidCount * nVal / 100);
2421 if (nOffset >= nValidCount)
2422 nOffset = nValidCount - 1;
2423 }
2424 break;
2425 case SC_BOTPERC:
2426 {
2427 rEntry.eOp = SC_LESS_EQUAL;
2428 if (nVal > 100)
2429 nVal = 100;
2430 nOffset = (nValidCount * nVal / 100);
2431 if (nOffset >= nValidCount)
2432 nOffset = nValidCount - 1;
2433 }
2434 break;
2435 default:
2436 {
2437 // added to avoid warnings
2438 }
2439 }
2440 ScRefCellValue aCell = ppInfo[nOffset].maCell;
2441 if (aCell.hasNumeric())
2442 rItem.mfVal = aCell.getValue();
2443 else
2444 {
2445 OSL_FAIL("TopTenQuery: pCell no ValueData");
2446 rEntry.eOp = SC_GREATER_EQUAL;
2447 rItem.mfVal = 0;
2448 }
2449 }
2450 else
2451 {
2452 rEntry.eOp = SC_GREATER_EQUAL;
2453 rItem.meType = ScQueryEntry::ByValue;
2454 rItem.mfVal = 0;
2455 }
2456 }
2457 break;
2458 default:
2459 {
2460 // added to avoid warnings
2461 }
2462 }
2463 }
2464 }
2465 if ( bSortCollatorInitialized )
2467}
2468
2469namespace {
2470
2471bool CanOptimizeQueryStringToNumber( const SvNumberFormatter* pFormatter, sal_uInt32 nFormatIndex, bool& bDateFormat )
2472{
2473 // tdf#105629: ScQueryEntry::ByValue queries are faster than ScQueryEntry::ByString.
2474 // The problem with this optimization is that the autofilter dialog apparently converts
2475 // the value to text and then converts that back to a number for filtering.
2476 // If that leads to any change of value (such as when time is rounded to seconds),
2477 // even matching values will be filtered out. Therefore query by value only for formats
2478 // where no such change should occur.
2479 if(const SvNumberformat* pEntry = pFormatter->GetEntry(nFormatIndex))
2480 {
2481 switch(pEntry->GetType())
2482 {
2483 case SvNumFormatType::NUMBER:
2484 case SvNumFormatType::FRACTION:
2485 case SvNumFormatType::SCIENTIFIC:
2486 return true;
2487 case SvNumFormatType::DATE:
2488 case SvNumFormatType::DATETIME:
2489 bDateFormat = true;
2490 break;
2491 default:
2492 break;
2493 }
2494 }
2495 return false;
2496}
2497
2498class PrepareQueryItem
2499{
2500 const ScDocument& mrDoc;
2501 const bool mbRoundForFilter;
2502public:
2503 explicit PrepareQueryItem(const ScDocument& rDoc, bool bRoundForFilter) :
2504 mrDoc(rDoc), mbRoundForFilter(bRoundForFilter) {}
2505
2506 void operator() (ScQueryEntry::Item& rItem)
2507 {
2508 rItem.mbRoundForFilter = mbRoundForFilter;
2509
2511 return;
2512
2513 sal_uInt32 nIndex = 0;
2514 bool bNumber = mrDoc.GetFormatTable()->
2515 IsNumberFormat(rItem.maString.getString(), nIndex, rItem.mfVal);
2516
2517 // Advanced Filter creates only ByString queries that need to be
2518 // converted to ByValue if appropriate. rItem.mfVal now holds the value
2519 // if bNumber==true.
2520
2521 if (rItem.meType == ScQueryEntry::ByString)
2522 {
2523 bool bDateFormat = false;
2524 if (bNumber && CanOptimizeQueryStringToNumber( mrDoc.GetFormatTable(), nIndex, bDateFormat ))
2526 if (!bDateFormat)
2527 return;
2528 }
2529
2530 // Double-check if the query by date is really appropriate.
2531
2532 if (bNumber && ((nIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0))
2533 {
2534 const SvNumberformat* pEntry = mrDoc.GetFormatTable()->GetEntry(nIndex);
2535 if (pEntry)
2536 {
2537 SvNumFormatType nNumFmtType = pEntry->GetType();
2538 if (!(nNumFmtType & SvNumFormatType::DATE) || (nNumFmtType & SvNumFormatType::TIME))
2539 rItem.meType = ScQueryEntry::ByValue; // not a date only
2540 else
2541 rItem.meType = ScQueryEntry::ByDate; // date only
2542 }
2543 else
2544 rItem.meType = ScQueryEntry::ByValue; // what the ... not a date
2545 }
2546 else
2547 rItem.meType = ScQueryEntry::ByValue; // not a date
2548 }
2549};
2550
2551void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam, bool bRoundForFilter )
2552{
2553 bool bTopTen = false;
2554 SCSIZE nEntryCount = rParam.GetEntryCount();
2555
2556 for ( SCSIZE i = 0; i < nEntryCount; ++i )
2557 {
2558 ScQueryEntry& rEntry = rParam.GetEntry(i);
2559 if (!rEntry.bDoQuery)
2560 continue;
2561
2563 std::for_each(rItems.begin(), rItems.end(), PrepareQueryItem(*pDoc, bRoundForFilter));
2564
2565 if ( !bTopTen )
2566 {
2567 switch ( rEntry.eOp )
2568 {
2569 case SC_TOPVAL:
2570 case SC_BOTVAL:
2571 case SC_TOPPERC:
2572 case SC_BOTPERC:
2573 {
2574 bTopTen = true;
2575 }
2576 break;
2577 default:
2578 {
2579 }
2580 }
2581 }
2582 }
2583
2584 if ( bTopTen )
2585 {
2586 pTab->TopTenQuery( rParam );
2587 }
2588}
2589
2590}
2591
2593{
2594 lcl_PrepareQuery(&rDocument, this, rQueryParam, false);
2595}
2596
2597SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub)
2598{
2599 ScQueryParam aParam( rParamOrg );
2600 typedef std::unordered_set<OUString> StrSetType;
2601 StrSetType aStrSet;
2602
2603 bool bStarted = false;
2604 bool bOldResult = true;
2605 SCROW nOldStart = 0;
2606 SCROW nOldEnd = 0;
2607
2608 SCSIZE nCount = 0;
2609 SCROW nOutRow = 0;
2610 SCROW nHeader = aParam.bHasHeader ? 1 : 0;
2611
2612 lcl_PrepareQuery(&rDocument, this, aParam, true);
2613
2614 if (!aParam.bInplace)
2615 {
2616 nOutRow = aParam.nDestRow + nHeader;
2617 if (nHeader > 0)
2618 CopyData( aParam.nCol1, aParam.nRow1, aParam.nCol2, aParam.nRow1,
2619 aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
2620 }
2621
2622 sc::TableColumnBlockPositionSet blockPos( GetDoc(), nTab ); // cache mdds access
2623 ScQueryEvaluator queryEvaluator(GetDoc(), *this, aParam);
2624
2625 SCROW nRealRow2 = aParam.nRow2;
2626 for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j)
2627 {
2628 bool bResult; // Filter result
2629 bool bValid = queryEvaluator.ValidQuery(j, nullptr, &blockPos);
2630 if (!bValid && bKeepSub) // Keep subtotals
2631 {
2632 for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
2633 {
2634 ScRefCellValue aCell = GetCellValue(nCol, j);
2635 if (aCell.getType() != CELLTYPE_FORMULA)
2636 continue;
2637
2638 if (!aCell.getFormula()->IsSubTotal())
2639 continue;
2640
2641 if (RefVisible(aCell.getFormula()))
2642 bValid = true;
2643 }
2644 }
2645 if (bValid)
2646 {
2647 if (aParam.bDuplicate)
2648 bResult = true;
2649 else
2650 {
2651 OUStringBuffer aStr;
2652 for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++)
2653 {
2654 OUString aCellStr = GetString(k, j);
2655 aStr.append(aCellStr + u"\x0001");
2656 }
2657
2658 bResult = aStrSet.insert(aStr.makeStringAndClear()).second; // unique if inserted.
2659 }
2660 }
2661 else
2662 bResult = false;
2663
2664 if (aParam.bInplace)
2665 {
2666 if (bResult == bOldResult && bStarted)
2667 nOldEnd = j;
2668 else
2669 {
2670 if (bStarted)
2671 DBShowRows(nOldStart,nOldEnd, bOldResult);
2672 nOldStart = nOldEnd = j;
2673 bOldResult = bResult;
2674 }
2675 bStarted = true;
2676 }
2677 else
2678 {
2679 if (bResult)
2680 {
2681 CopyData( aParam.nCol1,j, aParam.nCol2,j, aParam.nDestCol,nOutRow,aParam.nDestTab );
2682 if( nTab == aParam.nDestTab ) // copy to self, changes may invalidate caching position hints
2683 blockPos.invalidate();
2684 ++nOutRow;
2685 }
2686 }
2687 if (bResult)
2688 ++nCount;
2689 }
2690
2691 if (aParam.bInplace && bStarted)
2692 DBShowRows(nOldStart,nOldEnd, bOldResult);
2693
2694 if (aParam.bInplace)
2696
2697 return nCount;
2698}
2699
2700bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2701{
2702 bool bValid = true;
2703 std::unique_ptr<SCCOL[]> pFields(new SCCOL[nCol2-nCol1+1]);
2704 OUString aCellStr;
2705 SCCOL nCol = nCol1;
2706 OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2707 SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2708 SCROW nDBRow1 = rQueryParam.nRow1;
2709 SCCOL nDBCol2 = rQueryParam.nCol2;
2710 // First row must be column headers
2711 while (bValid && (nCol <= nCol2))
2712 {
2713 OUString aQueryStr = GetUpperCellString(nCol, nRow1);
2714 bool bFound = false;
2715 SCCOL i = rQueryParam.nCol1;
2716 while (!bFound && (i <= nDBCol2))
2717 {
2718 if ( nTab == nDBTab )
2719 aCellStr = GetUpperCellString(i, nDBRow1);
2720 else
2721 aCellStr = rDocument.GetUpperCellString(i, nDBRow1, nDBTab);
2722 bFound = (aCellStr == aQueryStr);
2723 if (!bFound) i++;
2724 }
2725 if (bFound)
2726 pFields[nCol - nCol1] = i;
2727 else
2728 bValid = false;
2729 nCol++;
2730 }
2731 if (bValid)
2732 {
2733 sal_uLong nVisible = 0;
2734 for ( nCol=nCol1; nCol<=ClampToAllocatedColumns(nCol2); nCol++ )
2735 nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
2736
2737 if ( nVisible > SCSIZE_MAX / sizeof(void*) )
2738 {
2739 OSL_FAIL("too many filter criteria");
2740 nVisible = 0;
2741 }
2742
2743 SCSIZE nNewEntries = nVisible;
2744 rQueryParam.Resize( nNewEntries );
2745
2746 SCSIZE nIndex = 0;
2747 SCROW nRow = nRow1 + 1;
2749 while (nRow <= nRow2)
2750 {
2751 nCol = nCol1;
2752 while (nCol <= nCol2)
2753 {
2754 aCellStr = GetInputString( nCol, nRow );
2755 if (!aCellStr.isEmpty())
2756 {
2757 if (nIndex < nNewEntries)
2758 {
2759 rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1];
2760 rQueryParam.FillInExcelSyntax(rPool, aCellStr, nIndex, nullptr);
2761 nIndex++;
2762 if (nIndex < nNewEntries)
2763 rQueryParam.GetEntry(nIndex).eConnect = SC_AND;
2764 }
2765 else
2766 bValid = false;
2767 }
2768 nCol++;
2769 }
2770 nRow++;
2771 if (nIndex < nNewEntries)
2772 rQueryParam.GetEntry(nIndex).eConnect = SC_OR;
2773 }
2774 }
2775 return bValid;
2776}
2777
2778bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2779{
2780 // A valid StarQuery must be at least 4 columns wide. To be precise it
2781 // should be exactly 4 columns ...
2782 // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
2783 // column Excel style query range immediately left to itself would result
2784 // in a circular reference when the field name or operator or value (first
2785 // to third query range column) is obtained (#i58354#). Furthermore, if the
2786 // range wasn't sufficiently specified data changes wouldn't flag formula
2787 // cells for recalculation.
2788 if (nCol2 - nCol1 < 3)
2789 return false;
2790
2791 bool bValid;
2792 OUString aCellStr;
2793 SCSIZE nIndex = 0;
2794 SCROW nRow = nRow1;
2795 OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2796 SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2797 SCROW nDBRow1 = rQueryParam.nRow1;
2798 SCCOL nDBCol2 = rQueryParam.nCol2;
2799
2800 SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1);
2801 rQueryParam.Resize( nNewEntries );
2803
2804 do
2805 {
2806 ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex);
2807
2808 bValid = false;
2809 // First column AND/OR
2810 if (nIndex > 0)
2811 {
2812 aCellStr = GetUpperCellString(nCol1, nRow);
2813 if ( aCellStr == ScResId(STR_TABLE_AND) )
2814 {
2815 rEntry.eConnect = SC_AND;
2816 bValid = true;
2817 }
2818 else if ( aCellStr == ScResId(STR_TABLE_OR) )
2819 {
2820 rEntry.eConnect = SC_OR;
2821 bValid = true;
2822 }
2823 }
2824 // Second column field name
2825 if ((nIndex < 1) || bValid)
2826 {
2827 bool bFound = false;
2828 aCellStr = GetUpperCellString(nCol1 + 1, nRow);
2829 for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++)
2830 {
2831 OUString aFieldStr;
2832 if ( nTab == nDBTab )
2833 aFieldStr = GetUpperCellString(i, nDBRow1);
2834 else
2835 aFieldStr = rDocument.GetUpperCellString(i, nDBRow1, nDBTab);
2836 bFound = (aCellStr == aFieldStr);
2837 if (bFound)
2838 {
2839 rEntry.nField = i;
2840 bValid = true;
2841 }
2842 else
2843 bValid = false;
2844 }
2845 }
2846 // Third column operator =<>...
2847 if (bValid)
2848 {
2849 aCellStr = GetUpperCellString(nCol1 + 2, nRow);
2850 if (aCellStr.startsWith("<"))
2851 {
2852 if (aCellStr[1] == '>')
2853 rEntry.eOp = SC_NOT_EQUAL;
2854 else if (aCellStr[1] == '=')
2855 rEntry.eOp = SC_LESS_EQUAL;
2856 else
2857 rEntry.eOp = SC_LESS;
2858 }
2859 else if (aCellStr.startsWith(">"))
2860 {
2861 if (aCellStr[1] == '=')
2862 rEntry.eOp = SC_GREATER_EQUAL;
2863 else
2864 rEntry.eOp = SC_GREATER;
2865 }
2866 else if (aCellStr.startsWith("="))
2867 rEntry.eOp = SC_EQUAL;
2868
2869 }
2870 // Fourth column values
2871 if (bValid)
2872 {
2873 OUString aStr = GetString(nCol1 + 3, nRow);
2874 rEntry.GetQueryItem().maString = rPool.intern(aStr);
2875 rEntry.bDoQuery = true;
2876 }
2877 nIndex++;
2878 nRow++;
2879 }
2880 while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ );
2881 return bValid;
2882}
2883
2884bool ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2885{
2886 SCSIZE i, nCount;
2887 PutInOrder(nCol1, nCol2);
2888 PutInOrder(nRow1, nRow2);
2889
2890 nCount = rQueryParam.GetEntryCount();
2891 for (i=0; i < nCount; i++)
2892 rQueryParam.GetEntry(i).Clear();
2893
2894 // Standard query table
2895 bool bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2896 // Excel Query table
2897 if (!bValid)
2898 bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2899
2901 nCount = rQueryParam.GetEntryCount();
2902 if (bValid)
2903 {
2904 // query type must be set
2905 for (i=0; i < nCount; i++)
2906 {
2907 ScQueryEntry::Item& rItem = rQueryParam.GetEntry(i).GetQueryItem();
2908 sal_uInt32 nIndex = 0;
2909 bool bNumber = pFormatter->IsNumberFormat(
2910 rItem.maString.getString(), nIndex, rItem.mfVal);
2911 bool bDateFormat = false;
2912 rItem.meType = bNumber && CanOptimizeQueryStringToNumber( pFormatter, nIndex, bDateFormat )
2914 }
2915 }
2916 else
2917 {
2918 for (i=0; i < nCount; i++)
2919 rQueryParam.GetEntry(i).Clear();
2920 }
2921 return bValid;
2922}
2923
2924bool ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const
2925{
2926 if (nStartRow == nEndRow)
2927 // Assume only data.
2928 /* XXX NOTE: previous behavior still checked this one row and could
2929 * evaluate it has header row, but that doesn't make much sense. */
2930 return false;
2931
2932 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2933 {
2934 CellType eType = GetCellType( nCol, nStartRow );
2935 // Any non-text cell in first row => not headers.
2937 return false;
2938 }
2939
2940 // First row all text cells, any non-text cell in second row => headers.
2941 SCROW nTestRow = nStartRow + 1;
2942 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2943 {
2944 CellType eType = GetCellType( nCol, nTestRow );
2946 return true;
2947 }
2948
2949 // Also second row all text cells => first row not headers.
2950 return false;
2951}
2952
2953bool ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const
2954{
2955 if (nStartCol == nEndCol)
2956 // Assume only data.
2957 /* XXX NOTE: previous behavior still checked this one column and could
2958 * evaluate it has header column, but that doesn't make much sense. */
2959 return false;
2960
2961 for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
2962 {
2963 CellType eType = GetCellType( nStartCol, nRow );
2964 // Any non-text cell in first column => not headers.
2966 return false;
2967 }
2968
2969 // First column all text cells, any non-text cell in second column => headers.
2970 SCCOL nTestCol = nStartCol + 1;
2971 for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
2972 {
2973 CellType eType = GetCellType( nRow, nTestCol );
2975 return true;
2976 }
2977
2978 // Also second column all text cells => first column not headers.
2979 return false;
2980}
2981
2982void ScTable::GetFilterEntries( SCCOL nCol, SCROW nRow1, SCROW nRow2, ScFilterEntries& rFilterEntries, bool bFiltering )
2983{
2984 if (nCol >= aCol.size())
2985 return;
2986
2988 aCol[nCol].InitBlockPosition(aBlockPos);
2989 aCol[nCol].GetFilterEntries(aBlockPos, nRow1, nRow2, rFilterEntries, bFiltering, false /*bFilteredRow*/);
2990}
2991
2993 SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, ScFilterEntries& rFilterEntries, bool bFiltering )
2994{
2995 if (nCol >= aCol.size())
2996 return;
2997
2999 aCol[nCol].InitBlockPosition(aBlockPos);
3000
3001 // remove the entry for this column from the query parameter
3002 ScQueryParam aParam( rParam );
3003 aParam.RemoveEntryByField(nCol);
3004
3005 lcl_PrepareQuery(&rDocument, this, aParam, true);
3006 ScQueryEvaluator queryEvaluator(GetDoc(), *this, aParam);
3007 for ( SCROW j = nRow1; j <= nRow2; ++j )
3008 {
3009 if (queryEvaluator.ValidQuery(j))
3010 {
3011 aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries, bFiltering, false/*bFilteredRow*/);
3012 }
3013 else
3014 {
3015 aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries, bFiltering, true/*bFilteredRow*/);
3016 }
3017 }
3018}
3019
3020bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, std::set<ScTypedStrData>& rStrings)
3021{
3022 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
3023 return false;
3024 return aCol[nCol].GetDataEntries( nRow, rStrings);
3025}
3026
3027sal_uInt64 ScTable::GetCellCount() const
3028{
3029 sal_uInt64 nCellCount = 0;
3030
3031 for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3032 nCellCount += aCol[nCol].GetCellCount();
3033
3034 return nCellCount;
3035}
3036
3038{
3039 sal_uInt64 nCellCount = 0;
3040
3041 for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3042 nCellCount += aCol[nCol].GetWeightedCount();
3043
3044 return nCellCount;
3045}
3046
3047sal_uInt64 ScTable::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
3048{
3049 sal_uInt64 nCellCount = 0;
3050
3051 for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3052 nCellCount += aCol[nCol].GetWeightedCount(nStartRow, nEndRow);
3053
3054 return nCellCount;
3055}
3056
3057sal_uInt64 ScTable::GetCodeCount() const
3058{
3059 sal_uInt64 nCodeCount = 0;
3060
3061 for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3062 if ( aCol[nCol].GetCellCount() )
3063 nCodeCount += aCol[nCol].GetCodeCount();
3064
3065 return nCodeCount;
3066}
3067
3068sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart,
3069 SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
3070{
3071 if ( IsColValid( nCol ) )
3072 return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet );
3073 else
3074 return 0;
3075}
3076
3078 sal_uInt16& nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const
3079{
3080 if ( IsColValid( nCol ) )
3081 return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd );
3082 else
3083 return 0;
3084}
3085
3087{
3088 ScRangeList aRanges = rMark.GetMarkedRangesForTab( nTab );
3089 ScRange aMarkArea( ScAddress::UNINITIALIZED );
3090 if (rMark.IsMultiMarked())
3091 aMarkArea = rMark.GetMultiMarkArea();
3092 else if (rMark.IsMarked())
3093 aMarkArea = rMark.GetMarkArea();
3094 else
3095 {
3096 assert(!"ScTable::UpdateSelectionFunction - called without anything marked");
3097 aMarkArea.aStart.SetCol(0);
3098 aMarkArea.aEnd.SetCol(rDocument.MaxCol());
3099 }
3100 const SCCOL nStartCol = aMarkArea.aStart.Col();
3101 const SCCOL nEndCol = ClampToAllocatedColumns(aMarkArea.aEnd.Col());
3102 for (SCCOL nCol = nStartCol; nCol <= nEndCol && !rData.getError(); ++nCol)
3103 {
3104 if (mpColFlags && ColHidden(nCol))
3105 continue;
3106
3107 aCol[nCol].UpdateSelectionFunction(aRanges, rData, *mpHiddenRows);
3108 }
3109}
3110
3111/* 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:1395
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.hxx:964
ScPostIt * GetCellNote(SCROW nRow)
Definition: column2.cxx:2184
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:1611
const sc::CellTextAttr * GetCellTextAttr(SCROW nRow) const
Definition: column.cxx:692
SCSIZE GetPatternCount() const
Definition: column.hxx:904
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:6187
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:1487
ScBroadcastAreaSlotMachine * GetBASM() const
Definition: document.hxx:2232
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1083
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:6192
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:603
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:1250
std::map< SCROW, std::vector< SdrObject * > > GetObjectsAnchoredToRange(SCTAB nTab, SCCOL nCol, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:2522
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:1093
static SC_DLLPUBLIC const LocaleDataWrapper & getLocaleData()
Definition: global.cxx:1053
static CollatorWrapper & GetCaseCollator()
case-sensitive collator
Definition: global.cxx:1104
static SC_DLLPUBLIC ScUserList * GetUserList()
Definition: global.cxx:288
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1062
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:155
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:2700
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:1789
bool ValidCol(SCCOL nCol) const
Definition: table.hxx:353
ScRefCellValue GetCellValue(SCCOL nCol, sc::ColumnBlockPosition &rBlockPos, SCROW nRow)
Definition: table2.cxx:2029
static void DecoladeRow(ScSortInfoArray *, SCROW nRow1, SCROW nRow2)
Definition: table3.cxx:1778
void PrepareQuery(ScQueryParam &rQueryParam)
Definition: table3.cxx:2592
ScColumnsRange GetAllocatedColumnsRange(SCCOL begin, SCCOL end) const
Definition: table1.cxx:2710
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:2953
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:963
void DoAutoOutline(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow)
Definition: table2.cxx:4069
CollatorWrapper * pSortCollator
Definition: table.hxx:223
void UpdateSelectionFunction(ScFunctionData &rData, const ScMarkData &rMark)
Definition: table3.cxx:3086
void DetachFormulaCells(sc::EndListeningContext &rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: table2.cxx:1279
ScFormulaCell * SetFormulaCell(SCCOL nCol, SCROW nRow, ScFormulaCell *pCell)
Takes ownership of pCell.
Definition: table2.cxx:1735
ScColContainer aCol
Definition: table.hxx:162
bool CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam &rQueryParam)
Definition: table3.cxx:2778
OUString GetString(SCCOL nCol, SCROW nRow, const ScInterpreterContext *pContext=nullptr) const
Definition: table2.cxx:1774
bool HasData(SCCOL nCol, SCROW nRow) const
Definition: table2.cxx:2063
ScColumn & CreateColumnIfNotExists(const SCCOL nScCol)
Definition: table.hxx:300
void QuickSort(ScSortInfoArray *, SCCOLROW nLo, SCCOLROW nHi)
Definition: table3.cxx:1689
bool IsColValid(const SCCOL nScCol) const
Definition: table.hxx:341
std::unique_ptr< ScBitMaskCompressedArray< SCCOL, CRFlags > > mpColFlags
Definition: table.hxx:194
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:3020
sal_uInt64 GetWeightedCount() const
Definition: table3.cxx:3037
bool SetRowHidden(SCROW nStartRow, SCROW nEndRow, bool bHidden)
Definition: table5.cxx:572
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:555
bool HasColHeader(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const
Definition: table3.cxx:2924
SCTAB nTab
Definition: table.hxx:215
sal_uInt64 GetCodeCount() const
Definition: table3.cxx:3057
short Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
Definition: table3.cxx:1731
void DestroySortCollator()
Definition: table3.cxx:644
void AttachFormulaCells(sc::StartListeningContext &rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: table2.cxx:1271
void GetFilteredFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam &rParam, ScFilterEntries &rFilterEntries, bool bFiltering)
Definition: table3.cxx:2992
bool IsSorted(SCCOLROW nStart, SCCOLROW nEnd) const
Definition: table3.cxx:1768
OUString GetInputString(SCCOL nCol, SCROW nRow, bool bForceSystemLocale=false) const
Definition: table2.cxx:1790
bool IsSortCollatorGlobal() const
Definition: table3.cxx:622
bool DoSubTotals(ScSubTotalParam &rParam)
Definition: table3.cxx:2088
void DBShowRows(SCROW nRow1, SCROW nRow2, bool bShow)
Definition: table2.cxx:3756
bool bGlobalKeepQuery
Definition: table.hxx:253
bool SetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString &rString, const ScSetStringParam *pParam=nullptr)
Definition: table2.cxx:1651
bool RowHidden(SCROW nRow, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: table5.cxx:480
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:434
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:1200
SCCOL GetAllocatedColumnsCount() const
Definition: table.hxx:1151
void SplitFormulaGroups(SCCOL nCol, std::vector< SCROW > &rRows)
Definition: table7.cxx:270
bool CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam &rQueryParam)
Definition: table3.cxx:2884
std::unique_ptr< ScFlatBoolRowSegments > mpHiddenRows
Definition: table.hxx:197
SCTAB GetTab() const
Definition: table.hxx:296
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:883
CellType GetCellType(const ScAddress &rPos) const
Definition: table.hxx:484
void RemoveSubTotals(ScSubTotalParam &rParam)
Definition: table3.cxx:1985
sal_Int32 GetMaxStringLen(SCCOL nCol, SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet) const
Definition: table3.cxx:3068
SvtBroadcaster * GetBroadcaster(SCCOL nCol, SCROW nRow)
Definition: table1.cxx:2577
const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow) const
Definition: table2.cxx:2281
ScSortParam aSortParam
Definition: table.hxx:222
sal_Int32 GetMaxNumberStringLen(sal_uInt16 &nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd) const
Definition: table3.cxx:3077
SCCOL ClampToAllocatedColumns(SCCOL nCol) const
Definition: table.hxx:1150
sal_uInt64 GetCellCount() const
Definition: table3.cxx:3027
ScDocument & rDocument
Definition: table.hxx:216
void RegroupFormulaCells(SCCOL nCol)
Definition: table7.cxx:286
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:2982
void Reorder(const sc::ReorderParam &rParam)
Definition: table3.cxx:1876
ScDocument & GetDoc()
Definition: table.hxx:294
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:2350
SCSIZE Query(const ScQueryParam &rQueryParam, bool bKeepSub)
Definition: table3.cxx:2597
bool TestRemoveSubTotals(const ScSubTotalParam &rParam)
Definition: table3.cxx:1951
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:4511
void AdjustReferenceOnMovedOrigin(const ScAddress &rOldPos, const ScAddress &rNewPos)
Adjust all internal references on base position change.
Definition: token.cxx:4473
Stores individual user-defined sort list.
Definition: userlist.hxx:33
sal_Int32 Compare(const OUString &rSubStr1, const OUString &rSubStr2) const
Definition: userlist.cxx:149
sal_Int32 ICompare(const OUString &rSubStr1, const OUString &rSubStr2) const
Definition: userlist.cxx:175
Collection of user-defined sort lists.
Definition: userlist.hxx:67
size_t size() const
Definition: userlist.cxx:346
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
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:855
@ SC_AND
Definition: global.hxx:854
CellType
Definition: global.hxx:271
@ CELLTYPE_EDIT
Definition: global.hxx:276
@ CELLTYPE_STRING
Definition: global.hxx:274
@ CELLTYPE_FORMULA
Definition: global.hxx:275
@ CELLTYPE_VALUE
Definition: global.hxx:273
ScSubTotalFunc
Definition: global.hxx:859
@ SUBTOTAL_FUNC_STDP
Definition: global.hxx:868
@ SUBTOTAL_FUNC_MAX
Definition: global.hxx:864
@ SUBTOTAL_FUNC_CNT2
Definition: global.hxx:863
@ SUBTOTAL_FUNC_AVE
Definition: global.hxx:861
@ SUBTOTAL_FUNC_VARP
Definition: global.hxx:871
@ SUBTOTAL_FUNC_VAR
Definition: global.hxx:870
@ SUBTOTAL_FUNC_SUM
Definition: global.hxx:869
@ SUBTOTAL_FUNC_STD
Definition: global.hxx:867
@ SUBTOTAL_FUNC_MIN
Definition: global.hxx:865
@ SUBTOTAL_FUNC_CNT
Definition: global.hxx:862
@ SUBTOTAL_FUNC_PROD
Definition: global.hxx:866
@ DIR_BOTTOM
Definition: global.hxx:343
@ SC_LESS_EQUAL
Definition: global.hxx:837
@ SC_LESS
Definition: global.hxx:835
@ SC_GREATER_EQUAL
Definition: global.hxx:838
@ SC_TOPPERC
Definition: global.hxx:842
@ SC_TOPVAL
Definition: global.hxx:840
@ SC_GREATER
Definition: global.hxx:836
@ SC_EQUAL
Definition: global.hxx:834
@ SC_BOTPERC
Definition: global.hxx:843
@ SC_NOT_EQUAL
Definition: global.hxx:839
@ SC_BOTVAL
Definition: global.hxx:841
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:919
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:44
bool mbCellDrawObjects
If TRUE, consider the presence of draw objects anchored to the cell.
Definition: sortparam.hxx:48
bool mbCellFormats
If TRUE, consider the presence of cell formats.
Definition: sortparam.hxx:50
bool mbCellNotes
If TRUE, consider the presence of cell notes besides data.
Definition: sortparam.hxx:46
bool anyExtrasWanted() const
Definition: sortparam.hxx:56
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:114
::std::vector< ScSortKeyState > maKeyState
Definition: sortparam.hxx:121
OUString aCollatorAlgorithm
Definition: sortparam.hxx:123
bool bHasHeader
Definition: sortparam.hxx:111
ScDataAreaExtras aDataAreaExtras
Definition: sortparam.hxx:109
css::lang::Locale aCollatorLocale
Definition: sortparam.hxx:122
sal_uInt16 nUserIndex
Definition: sortparam.hxx:110
sal_uInt16 GetSortKeyCount() const
Definition: sortparam.hxx:139
bool bCaseSens
Definition: sortparam.hxx:113
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:152
std::vector< SCCOLROW > maOrderIndices
List of original column / row positions after reordering.
Definition: sortparam.hxx:157
ScRange maSortRange
This sort range already takes into account the presence or absence of header row / column i....
Definition: sortparam.hxx:151
static void lcl_RemoveNumberFormat(ScTable *pTab, SCCOL nCol, SCROW nRow)
Definition: table3.cxx:2011
static TranslateId lcl_GetGrandSubTotalStrId(int id)
Definition: table3.cxx:2062
constexpr sal_Int32 kSortCellsChunk
Definition: table3.cxx:398
static TranslateId lcl_GetSubTotalStrId(int id)
Definition: table3.cxx:2038
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