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// new intermediate results
2062// rParam.nRow2 is changed!
2063
2065{
2066 SCCOL nStartCol = rParam.nCol1;
2067 SCROW nStartRow = rParam.nRow1 + 1; // Header
2068 SCCOL nEndCol = rParam.nCol2;
2069 SCROW nEndRow = rParam.nRow2; // will change
2070 sal_uInt16 i;
2071
2072 // Remove empty rows at the end
2073 // so that all exceeding (rDocument.MaxRow()) can be found by InsertRow (#35180#)
2074 // If sorted, all empty rows are at the end.
2075 SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM );
2076 nEndRow -= nEmpty;
2077
2078 sal_uInt16 nLevelCount = 0; // Number of levels
2079 bool bDoThis = true;
2080 for (i=0; i<MAXSUBTOTAL && bDoThis; i++)
2081 if (rParam.bGroupActive[i])
2082 nLevelCount = i+1;
2083 else
2084 bDoThis = false;
2085
2086 if (nLevelCount==0) // do nothing
2087 return true;
2088
2089 SCCOL* nGroupCol = rParam.nField; // columns which will be used when grouping
2090
2091 // With (blank) as a separate category, subtotal rows from
2092 // the other columns must always be tested
2093 // (previously only when a column occurred more than once)
2094 bool bTestPrevSub = ( nLevelCount > 1 );
2095
2096 OUString aSubString;
2097
2098 bool bIgnoreCase = !rParam.bCaseSens;
2099
2100 OUString aCompString[MAXSUBTOTAL];
2101
2102 //TODO: sort?
2103
2104 ScStyleSheet* pStyle = static_cast<ScStyleSheet*>(rDocument.GetStyleSheetPool()->Find(
2105 ScResId(STR_STYLENAME_RESULT), SfxStyleFamily::Para ));
2106
2107 bool bSpaceLeft = true; // Success when inserting?
2108
2109 // For performance reasons collect formula entries so their
2110 // references don't have to be tested for updates each time a new row is
2111 // inserted
2112 RowEntry aRowEntry;
2113 ::std::vector< RowEntry > aRowVector;
2114
2115 for (sal_uInt16 nLevel=0; nLevel<nLevelCount && bSpaceLeft; nLevel++)
2116 {
2117 aRowEntry.nGroupNo = nLevelCount - nLevel - 1;
2118
2119 // how many results per level
2120 SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo];
2121 // result functions
2122 ScSubTotalFunc* pResFunc = rParam.pFunctions[aRowEntry.nGroupNo].get();
2123
2124 if (nResCount > 0) // otherwise only sort
2125 {
2126 for (i=0; i<=aRowEntry.nGroupNo; i++)
2127 {
2128 aSubString = GetString( nGroupCol[i], nStartRow );
2129 if ( bIgnoreCase )
2130 aCompString[i] = ScGlobal::getCharClass().uppercase( aSubString );
2131 else
2132 aCompString[i] = aSubString;
2133 } // aSubString stays on the last
2134
2135 bool bBlockVis = false; // group visible?
2136 aRowEntry.nSubStartRow = nStartRow;
2137 for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++)
2138 {
2139 bool bChanged;
2140 if (nRow>nEndRow)
2141 bChanged = true;
2142 else
2143 {
2144 bChanged = false;
2145 OUString aString;
2146 for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++)
2147 {
2148 aString = GetString( nGroupCol[i], nRow );
2149 if (bIgnoreCase)
2150 aString = ScGlobal::getCharClass().uppercase(aString);
2151 // when sorting, blanks are separate group
2152 // otherwise blank cells are allowed below
2153 bChanged = ( ( !aString.isEmpty() || rParam.bDoSort ) &&
2154 aString != aCompString[i] );
2155 }
2156 if ( bChanged && bTestPrevSub )
2157 {
2158 // No group change on rows that will contain subtotal formulas
2159 bChanged = std::none_of(aRowVector.begin(), aRowVector.end(),
2160 [&nRow](const RowEntry& rEntry) { return rEntry.nDestRow == nRow; });
2161 }
2162 }
2163 if ( bChanged )
2164 {
2165 aRowEntry.nDestRow = nRow;
2166 aRowEntry.nFuncStart = aRowEntry.nSubStartRow;
2167 aRowEntry.nFuncEnd = nRow-1;
2168
2169 bSpaceLeft = rDocument.InsertRow( 0, nTab, rDocument.MaxCol(), nTab,
2170 aRowEntry.nDestRow, 1 );
2171 DBShowRow( aRowEntry.nDestRow, bBlockVis );
2172 if ( rParam.bPagebreak && nRow < rDocument.MaxRow() &&
2173 aRowEntry.nSubStartRow != nStartRow && nLevel == 0)
2174 SetRowBreak(aRowEntry.nSubStartRow, false, true);
2175
2176 if (bSpaceLeft)
2177 {
2178 for ( auto& rRowEntry : aRowVector)
2179 {
2180 if ( aRowEntry.nDestRow <= rRowEntry.nSubStartRow )
2181 ++rRowEntry.nSubStartRow;
2182 if ( aRowEntry.nDestRow <= rRowEntry.nDestRow )
2183 ++rRowEntry.nDestRow;
2184 if ( aRowEntry.nDestRow <= rRowEntry.nFuncStart )
2185 ++rRowEntry.nFuncStart;
2186 if ( aRowEntry.nDestRow <= rRowEntry.nFuncEnd )
2187 ++rRowEntry.nFuncEnd;
2188 }
2189 // collect formula positions
2190 aRowVector.push_back( aRowEntry );
2191
2192 OUString aOutString = aSubString;
2193 if (aOutString.isEmpty())
2194 aOutString = ScResId( STR_EMPTYDATA );
2195 aOutString += " ";
2196 TranslateId pStrId = STR_TABLE_ERGEBNIS;
2197 if ( nResCount == 1 )
2198 pStrId = lcl_GetSubTotalStrId(pResFunc[0]);
2199 aOutString += ScResId(pStrId);
2200 SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString );
2201 ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle );
2202
2203 ++nRow;
2204 ++nEndRow;
2205 aRowEntry.nSubStartRow = nRow;
2206 for (i=0; i<=aRowEntry.nGroupNo; i++)
2207 {
2208 aSubString = GetString( nGroupCol[i], nRow );
2209 if ( bIgnoreCase )
2210 aCompString[i] = ScGlobal::getCharClass().uppercase( aSubString );
2211 else
2212 aCompString[i] = aSubString;
2213 }
2214 }
2215 }
2216 bBlockVis = !RowFiltered(nRow);
2217 }
2218 }
2219 }
2220
2221 if (!aRowVector.empty())
2222 {
2223 // generate global total
2224 SCROW nGlobalStartRow = aRowVector[0].nSubStartRow;
2225 SCROW nGlobalStartFunc = aRowVector[0].nFuncStart;
2226 SCROW nGlobalEndRow = 0;
2227 SCROW nGlobalEndFunc = 0;
2228 for (const auto& rRowEntry : aRowVector)
2229 {
2230 nGlobalEndRow = (nGlobalEndRow < rRowEntry.nDestRow) ? rRowEntry.nDestRow : nGlobalEndRow;
2231 nGlobalEndFunc = (nGlobalEndFunc < rRowEntry.nFuncEnd) ? rRowEntry.nFuncEnd : nGlobalEndRow;
2232 }
2233
2234 for (sal_uInt16 nLevel = 0; nLevel<nLevelCount; nLevel++)
2235 {
2236 const sal_uInt16 nGroupNo = nLevelCount - nLevel - 1;
2237 const ScSubTotalFunc* pResFunc = rParam.pFunctions[nGroupNo].get();
2238 if (!pResFunc)
2239 {
2240 // No subtotal function given for this group => no formula or
2241 // label and do not insert a row.
2242 continue;
2243 }
2244
2245 // increment end row
2246 nGlobalEndRow++;
2247
2248 // add row entry for formula
2249 aRowEntry.nGroupNo = nGroupNo;
2250 aRowEntry.nSubStartRow = nGlobalStartRow;
2251 aRowEntry.nFuncStart = nGlobalStartFunc;
2252 aRowEntry.nDestRow = nGlobalEndRow;
2253 aRowEntry.nFuncEnd = nGlobalEndFunc;
2254
2255 // increment row
2256 nGlobalEndFunc++;
2257
2258 bSpaceLeft = rDocument.InsertRow(0, nTab, rDocument.MaxCol(), nTab, aRowEntry.nDestRow, 1);
2259
2260 if (bSpaceLeft)
2261 {
2262 aRowVector.push_back(aRowEntry);
2263 nEndRow++;
2264 DBShowRow(aRowEntry.nDestRow, true);
2265
2266 // insert label
2267 OUString label = ScResId(STR_TABLE_GRAND) + " " + ScResId(lcl_GetSubTotalStrId(pResFunc[0]));
2268 SetString(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, label);
2269 ApplyStyle(nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, pStyle);
2270 }
2271 }
2272 }
2273
2274 // now insert the formulas
2275 ScComplexRefData aRef;
2276 aRef.InitFlags();
2277 aRef.Ref1.SetAbsTab(nTab);
2278 aRef.Ref2.SetAbsTab(nTab);
2279 for (const auto& rRowEntry : aRowVector)
2280 {
2281 SCCOL nResCount = rParam.nSubTotals[rRowEntry.nGroupNo];
2282 SCCOL* nResCols = rParam.pSubTotals[rRowEntry.nGroupNo].get();
2283 ScSubTotalFunc* pResFunc = rParam.pFunctions[rRowEntry.nGroupNo].get();
2284 for ( SCCOL nResult=0; nResult < nResCount; ++nResult )
2285 {
2286 aRef.Ref1.SetAbsCol(nResCols[nResult]);
2287 aRef.Ref1.SetAbsRow(rRowEntry.nFuncStart);
2288 aRef.Ref2.SetAbsCol(nResCols[nResult]);
2289 aRef.Ref2.SetAbsRow(rRowEntry.nFuncEnd);
2290
2292 aArr.AddOpCode( ocSubTotal );
2293 aArr.AddOpCode( ocOpen );
2294 aArr.AddDouble( static_cast<double>(pResFunc[nResult]) );
2295 aArr.AddOpCode( ocSep );
2296 aArr.AddDoubleReference( aRef );
2297 aArr.AddOpCode( ocClose );
2298 aArr.AddOpCode( ocStop );
2299 ScFormulaCell* pCell = new ScFormulaCell(
2300 rDocument, ScAddress(nResCols[nResult], rRowEntry.nDestRow, nTab), aArr);
2301 if ( rParam.bIncludePattern )
2302 pCell->SetNeedNumberFormat(true);
2303
2304 SetFormulaCell(nResCols[nResult], rRowEntry.nDestRow, pCell);
2305 if ( nResCols[nResult] != nGroupCol[rRowEntry.nGroupNo] )
2306 {
2307 ApplyStyle( nResCols[nResult], rRowEntry.nDestRow, pStyle );
2308
2309 lcl_RemoveNumberFormat( this, nResCols[nResult], rRowEntry.nDestRow );
2310 }
2311 }
2312
2313 }
2314
2315 //TODO: according to setting, shift intermediate-sum rows up?
2316
2317 //TODO: create Outlines directly?
2318
2319 if (bSpaceLeft)
2320 DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
2321
2322 rParam.nRow2 = nEndRow; // new end
2323 return bSpaceLeft;
2324}
2325
2327{
2328 bool bSortCollatorInitialized = false;
2329 SCSIZE nEntryCount = rParam.GetEntryCount();
2330 SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1);
2331 SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1);
2332 for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ )
2333 {
2334 ScQueryEntry& rEntry = rParam.GetEntry(i);
2336
2337 for (ScQueryEntry::Item& rItem : rItems)
2338 {
2339 switch (rEntry.eOp)
2340 {
2341 case SC_TOPVAL:
2342 case SC_BOTVAL:
2343 case SC_TOPPERC:
2344 case SC_BOTPERC:
2345 {
2346 ScSortParam aLocalSortParam(rParam, static_cast<SCCOL>(rEntry.nField));
2347 aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare
2348 if (!bSortCollatorInitialized)
2349 {
2350 bSortCollatorInitialized = true;
2351 InitSortCollator(aLocalSortParam);
2352 }
2353 std::unique_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nRow1, rParam.nRow2, bGlobalKeepQuery, false));
2354 DecoladeRow(pArray.get(), nRow1, rParam.nRow2);
2355 QuickSort(pArray.get(), nRow1, rParam.nRow2);
2356 std::unique_ptr<ScSortInfo[]> const& ppInfo = pArray->GetFirstArray();
2357 SCSIZE nValidCount = nCount;
2358 // Don't count note or blank cells, they are sorted to the end
2359 while (nValidCount > 0 && ppInfo[nValidCount - 1].maCell.isEmpty())
2360 nValidCount--;
2361 // Don't count Strings, they are between Value and blank
2362 while (nValidCount > 0 && ppInfo[nValidCount - 1].maCell.hasString())
2363 nValidCount--;
2364 if (nValidCount > 0)
2365 {
2366 if (rItem.meType == ScQueryEntry::ByString)
2367 { // by string ain't going to work
2368 rItem.meType = ScQueryEntry::ByValue;
2369 rItem.mfVal = 10; // 10 and 10% respectively
2370 }
2371 SCSIZE nVal = (rItem.mfVal >= 1 ? static_cast<SCSIZE>(rItem.mfVal) : 1);
2372 SCSIZE nOffset = 0;
2373 switch (rEntry.eOp)
2374 {
2375 case SC_TOPVAL:
2376 {
2377 rEntry.eOp = SC_GREATER_EQUAL;
2378 if (nVal > nValidCount)
2379 nVal = nValidCount;
2380 nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount
2381 }
2382 break;
2383 case SC_BOTVAL:
2384 {
2385 rEntry.eOp = SC_LESS_EQUAL;
2386 if (nVal > nValidCount)
2387 nVal = nValidCount;
2388 nOffset = nVal - 1; // 1 <= nVal <= nValidCount
2389 }
2390 break;
2391 case SC_TOPPERC:
2392 {
2393 rEntry.eOp = SC_GREATER_EQUAL;
2394 if (nVal > 100)
2395 nVal = 100;
2396 nOffset = nValidCount - (nValidCount * nVal / 100);
2397 if (nOffset >= nValidCount)
2398 nOffset = nValidCount - 1;
2399 }
2400 break;
2401 case SC_BOTPERC:
2402 {
2403 rEntry.eOp = SC_LESS_EQUAL;
2404 if (nVal > 100)
2405 nVal = 100;
2406 nOffset = (nValidCount * nVal / 100);
2407 if (nOffset >= nValidCount)
2408 nOffset = nValidCount - 1;
2409 }
2410 break;
2411 default:
2412 {
2413 // added to avoid warnings
2414 }
2415 }
2416 ScRefCellValue aCell = ppInfo[nOffset].maCell;
2417 if (aCell.hasNumeric())
2418 rItem.mfVal = aCell.getValue();
2419 else
2420 {
2421 OSL_FAIL("TopTenQuery: pCell no ValueData");
2422 rEntry.eOp = SC_GREATER_EQUAL;
2423 rItem.mfVal = 0;
2424 }
2425 }
2426 else
2427 {
2428 rEntry.eOp = SC_GREATER_EQUAL;
2429 rItem.meType = ScQueryEntry::ByValue;
2430 rItem.mfVal = 0;
2431 }
2432 }
2433 break;
2434 default:
2435 {
2436 // added to avoid warnings
2437 }
2438 }
2439 }
2440 }
2441 if ( bSortCollatorInitialized )
2443}
2444
2445namespace {
2446
2447bool CanOptimizeQueryStringToNumber( const SvNumberFormatter* pFormatter, sal_uInt32 nFormatIndex, bool& bDateFormat )
2448{
2449 // tdf#105629: ScQueryEntry::ByValue queries are faster than ScQueryEntry::ByString.
2450 // The problem with this optimization is that the autofilter dialog apparently converts
2451 // the value to text and then converts that back to a number for filtering.
2452 // If that leads to any change of value (such as when time is rounded to seconds),
2453 // even matching values will be filtered out. Therefore query by value only for formats
2454 // where no such change should occur.
2455 if(const SvNumberformat* pEntry = pFormatter->GetEntry(nFormatIndex))
2456 {
2457 switch(pEntry->GetType())
2458 {
2459 case SvNumFormatType::NUMBER:
2460 case SvNumFormatType::FRACTION:
2461 case SvNumFormatType::SCIENTIFIC:
2462 return true;
2463 case SvNumFormatType::DATE:
2464 case SvNumFormatType::DATETIME:
2465 bDateFormat = true;
2466 break;
2467 default:
2468 break;
2469 }
2470 }
2471 return false;
2472}
2473
2474class PrepareQueryItem
2475{
2476 const ScDocument& mrDoc;
2477 const bool mbRoundForFilter;
2478public:
2479 explicit PrepareQueryItem(const ScDocument& rDoc, bool bRoundForFilter) :
2480 mrDoc(rDoc), mbRoundForFilter(bRoundForFilter) {}
2481
2482 void operator() (ScQueryEntry::Item& rItem)
2483 {
2484 rItem.mbRoundForFilter = mbRoundForFilter;
2485
2487 return;
2488
2489 sal_uInt32 nIndex = 0;
2490 bool bNumber = mrDoc.GetFormatTable()->
2491 IsNumberFormat(rItem.maString.getString(), nIndex, rItem.mfVal);
2492
2493 // Advanced Filter creates only ByString queries that need to be
2494 // converted to ByValue if appropriate. rItem.mfVal now holds the value
2495 // if bNumber==true.
2496
2497 if (rItem.meType == ScQueryEntry::ByString)
2498 {
2499 bool bDateFormat = false;
2500 if (bNumber && CanOptimizeQueryStringToNumber( mrDoc.GetFormatTable(), nIndex, bDateFormat ))
2502 if (!bDateFormat)
2503 return;
2504 }
2505
2506 // Double-check if the query by date is really appropriate.
2507
2508 if (bNumber && ((nIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0))
2509 {
2510 const SvNumberformat* pEntry = mrDoc.GetFormatTable()->GetEntry(nIndex);
2511 if (pEntry)
2512 {
2513 SvNumFormatType nNumFmtType = pEntry->GetType();
2514 if (!(nNumFmtType & SvNumFormatType::DATE) || (nNumFmtType & SvNumFormatType::TIME))
2515 rItem.meType = ScQueryEntry::ByValue; // not a date only
2516 else
2517 rItem.meType = ScQueryEntry::ByDate; // date only
2518 }
2519 else
2520 rItem.meType = ScQueryEntry::ByValue; // what the ... not a date
2521 }
2522 else
2523 rItem.meType = ScQueryEntry::ByValue; // not a date
2524 }
2525};
2526
2527void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam, bool bRoundForFilter )
2528{
2529 bool bTopTen = false;
2530 SCSIZE nEntryCount = rParam.GetEntryCount();
2531
2532 for ( SCSIZE i = 0; i < nEntryCount; ++i )
2533 {
2534 ScQueryEntry& rEntry = rParam.GetEntry(i);
2535 if (!rEntry.bDoQuery)
2536 continue;
2537
2539 std::for_each(rItems.begin(), rItems.end(), PrepareQueryItem(*pDoc, bRoundForFilter));
2540
2541 if ( !bTopTen )
2542 {
2543 switch ( rEntry.eOp )
2544 {
2545 case SC_TOPVAL:
2546 case SC_BOTVAL:
2547 case SC_TOPPERC:
2548 case SC_BOTPERC:
2549 {
2550 bTopTen = true;
2551 }
2552 break;
2553 default:
2554 {
2555 }
2556 }
2557 }
2558 }
2559
2560 if ( bTopTen )
2561 {
2562 pTab->TopTenQuery( rParam );
2563 }
2564}
2565
2566}
2567
2569{
2570 lcl_PrepareQuery(&rDocument, this, rQueryParam, false);
2571}
2572
2573SCSIZE ScTable::Query(const ScQueryParam& rParamOrg, bool bKeepSub)
2574{
2575 ScQueryParam aParam( rParamOrg );
2576 typedef std::unordered_set<OUString> StrSetType;
2577 StrSetType aStrSet;
2578
2579 bool bStarted = false;
2580 bool bOldResult = true;
2581 SCROW nOldStart = 0;
2582 SCROW nOldEnd = 0;
2583
2584 SCSIZE nCount = 0;
2585 SCROW nOutRow = 0;
2586 SCROW nHeader = aParam.bHasHeader ? 1 : 0;
2587
2588 lcl_PrepareQuery(&rDocument, this, aParam, true);
2589
2590 if (!aParam.bInplace)
2591 {
2592 nOutRow = aParam.nDestRow + nHeader;
2593 if (nHeader > 0)
2594 CopyData( aParam.nCol1, aParam.nRow1, aParam.nCol2, aParam.nRow1,
2595 aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
2596 }
2597
2598 sc::TableColumnBlockPositionSet blockPos( GetDoc(), nTab ); // cache mdds access
2599 ScQueryEvaluator queryEvaluator(GetDoc(), *this, aParam);
2600
2601 SCROW nRealRow2 = aParam.nRow2;
2602 for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j)
2603 {
2604 bool bResult; // Filter result
2605 bool bValid = queryEvaluator.ValidQuery(j, nullptr, &blockPos);
2606 if (!bValid && bKeepSub) // Keep subtotals
2607 {
2608 for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
2609 {
2610 ScRefCellValue aCell = GetCellValue(nCol, j);
2611 if (aCell.getType() != CELLTYPE_FORMULA)
2612 continue;
2613
2614 if (!aCell.getFormula()->IsSubTotal())
2615 continue;
2616
2617 if (RefVisible(aCell.getFormula()))
2618 bValid = true;
2619 }
2620 }
2621 if (bValid)
2622 {
2623 if (aParam.bDuplicate)
2624 bResult = true;
2625 else
2626 {
2627 OUStringBuffer aStr;
2628 for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++)
2629 {
2630 OUString aCellStr = GetString(k, j);
2631 aStr.append(aCellStr + u"\x0001");
2632 }
2633
2634 bResult = aStrSet.insert(aStr.makeStringAndClear()).second; // unique if inserted.
2635 }
2636 }
2637 else
2638 bResult = false;
2639
2640 if (aParam.bInplace)
2641 {
2642 if (bResult == bOldResult && bStarted)
2643 nOldEnd = j;
2644 else
2645 {
2646 if (bStarted)
2647 DBShowRows(nOldStart,nOldEnd, bOldResult);
2648 nOldStart = nOldEnd = j;
2649 bOldResult = bResult;
2650 }
2651 bStarted = true;
2652 }
2653 else
2654 {
2655 if (bResult)
2656 {
2657 CopyData( aParam.nCol1,j, aParam.nCol2,j, aParam.nDestCol,nOutRow,aParam.nDestTab );
2658 if( nTab == aParam.nDestTab ) // copy to self, changes may invalidate caching position hints
2659 blockPos.invalidate();
2660 ++nOutRow;
2661 }
2662 }
2663 if (bResult)
2664 ++nCount;
2665 }
2666
2667 if (aParam.bInplace && bStarted)
2668 DBShowRows(nOldStart,nOldEnd, bOldResult);
2669
2670 if (aParam.bInplace)
2672
2673 return nCount;
2674}
2675
2676bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2677{
2678 bool bValid = true;
2679 std::unique_ptr<SCCOL[]> pFields(new SCCOL[nCol2-nCol1+1]);
2680 OUString aCellStr;
2681 SCCOL nCol = nCol1;
2682 OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2683 SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2684 SCROW nDBRow1 = rQueryParam.nRow1;
2685 SCCOL nDBCol2 = rQueryParam.nCol2;
2686 // First row must be column headers
2687 while (bValid && (nCol <= nCol2))
2688 {
2689 OUString aQueryStr = GetUpperCellString(nCol, nRow1);
2690 bool bFound = false;
2691 SCCOL i = rQueryParam.nCol1;
2692 while (!bFound && (i <= nDBCol2))
2693 {
2694 if ( nTab == nDBTab )
2695 aCellStr = GetUpperCellString(i, nDBRow1);
2696 else
2697 aCellStr = rDocument.GetUpperCellString(i, nDBRow1, nDBTab);
2698 bFound = (aCellStr == aQueryStr);
2699 if (!bFound) i++;
2700 }
2701 if (bFound)
2702 pFields[nCol - nCol1] = i;
2703 else
2704 bValid = false;
2705 nCol++;
2706 }
2707 if (bValid)
2708 {
2709 sal_uLong nVisible = 0;
2710 for ( nCol=nCol1; nCol<=ClampToAllocatedColumns(nCol2); nCol++ )
2711 nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
2712
2713 if ( nVisible > SCSIZE_MAX / sizeof(void*) )
2714 {
2715 OSL_FAIL("too many filter criteria");
2716 nVisible = 0;
2717 }
2718
2719 SCSIZE nNewEntries = nVisible;
2720 rQueryParam.Resize( nNewEntries );
2721
2722 SCSIZE nIndex = 0;
2723 SCROW nRow = nRow1 + 1;
2725 while (nRow <= nRow2)
2726 {
2727 nCol = nCol1;
2728 while (nCol <= nCol2)
2729 {
2730 aCellStr = GetInputString( nCol, nRow );
2731 if (!aCellStr.isEmpty())
2732 {
2733 if (nIndex < nNewEntries)
2734 {
2735 rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1];
2736 rQueryParam.FillInExcelSyntax(rPool, aCellStr, nIndex, nullptr);
2737 nIndex++;
2738 if (nIndex < nNewEntries)
2739 rQueryParam.GetEntry(nIndex).eConnect = SC_AND;
2740 }
2741 else
2742 bValid = false;
2743 }
2744 nCol++;
2745 }
2746 nRow++;
2747 if (nIndex < nNewEntries)
2748 rQueryParam.GetEntry(nIndex).eConnect = SC_OR;
2749 }
2750 }
2751 return bValid;
2752}
2753
2754bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2755{
2756 // A valid StarQuery must be at least 4 columns wide. To be precise it
2757 // should be exactly 4 columns ...
2758 // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
2759 // column Excel style query range immediately left to itself would result
2760 // in a circular reference when the field name or operator or value (first
2761 // to third query range column) is obtained (#i58354#). Furthermore, if the
2762 // range wasn't sufficiently specified data changes wouldn't flag formula
2763 // cells for recalculation.
2764 if (nCol2 - nCol1 < 3)
2765 return false;
2766
2767 bool bValid;
2768 OUString aCellStr;
2769 SCSIZE nIndex = 0;
2770 SCROW nRow = nRow1;
2771 OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2772 SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2773 SCROW nDBRow1 = rQueryParam.nRow1;
2774 SCCOL nDBCol2 = rQueryParam.nCol2;
2775
2776 SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1);
2777 rQueryParam.Resize( nNewEntries );
2779
2780 do
2781 {
2782 ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex);
2783
2784 bValid = false;
2785 // First column AND/OR
2786 if (nIndex > 0)
2787 {
2788 aCellStr = GetUpperCellString(nCol1, nRow);
2789 if ( aCellStr == ScResId(STR_TABLE_AND) )
2790 {
2791 rEntry.eConnect = SC_AND;
2792 bValid = true;
2793 }
2794 else if ( aCellStr == ScResId(STR_TABLE_OR) )
2795 {
2796 rEntry.eConnect = SC_OR;
2797 bValid = true;
2798 }
2799 }
2800 // Second column field name
2801 if ((nIndex < 1) || bValid)
2802 {
2803 bool bFound = false;
2804 aCellStr = GetUpperCellString(nCol1 + 1, nRow);
2805 for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++)
2806 {
2807 OUString aFieldStr;
2808 if ( nTab == nDBTab )
2809 aFieldStr = GetUpperCellString(i, nDBRow1);
2810 else
2811 aFieldStr = rDocument.GetUpperCellString(i, nDBRow1, nDBTab);
2812 bFound = (aCellStr == aFieldStr);
2813 if (bFound)
2814 {
2815 rEntry.nField = i;
2816 bValid = true;
2817 }
2818 else
2819 bValid = false;
2820 }
2821 }
2822 // Third column operator =<>...
2823 if (bValid)
2824 {
2825 aCellStr = GetUpperCellString(nCol1 + 2, nRow);
2826 if (aCellStr.startsWith("<"))
2827 {
2828 if (aCellStr[1] == '>')
2829 rEntry.eOp = SC_NOT_EQUAL;
2830 else if (aCellStr[1] == '=')
2831 rEntry.eOp = SC_LESS_EQUAL;
2832 else
2833 rEntry.eOp = SC_LESS;
2834 }
2835 else if (aCellStr.startsWith(">"))
2836 {
2837 if (aCellStr[1] == '=')
2838 rEntry.eOp = SC_GREATER_EQUAL;
2839 else
2840 rEntry.eOp = SC_GREATER;
2841 }
2842 else if (aCellStr.startsWith("="))
2843 rEntry.eOp = SC_EQUAL;
2844
2845 }
2846 // Fourth column values
2847 if (bValid)
2848 {
2849 OUString aStr = GetString(nCol1 + 3, nRow);
2850 rEntry.GetQueryItem().maString = rPool.intern(aStr);
2851 rEntry.bDoQuery = true;
2852 }
2853 nIndex++;
2854 nRow++;
2855 }
2856 while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ );
2857 return bValid;
2858}
2859
2860bool ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2861{
2862 SCSIZE i, nCount;
2863 PutInOrder(nCol1, nCol2);
2864 PutInOrder(nRow1, nRow2);
2865
2866 nCount = rQueryParam.GetEntryCount();
2867 for (i=0; i < nCount; i++)
2868 rQueryParam.GetEntry(i).Clear();
2869
2870 // Standard query table
2871 bool bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2872 // Excel Query table
2873 if (!bValid)
2874 bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2875
2877 nCount = rQueryParam.GetEntryCount();
2878 if (bValid)
2879 {
2880 // query type must be set
2881 for (i=0; i < nCount; i++)
2882 {
2883 ScQueryEntry::Item& rItem = rQueryParam.GetEntry(i).GetQueryItem();
2884 sal_uInt32 nIndex = 0;
2885 bool bNumber = pFormatter->IsNumberFormat(
2886 rItem.maString.getString(), nIndex, rItem.mfVal);
2887 bool bDateFormat = false;
2888 rItem.meType = bNumber && CanOptimizeQueryStringToNumber( pFormatter, nIndex, bDateFormat )
2890 }
2891 }
2892 else
2893 {
2894 for (i=0; i < nCount; i++)
2895 rQueryParam.GetEntry(i).Clear();
2896 }
2897 return bValid;
2898}
2899
2900bool ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow) const
2901{
2902 if (nStartRow == nEndRow)
2903 // Assume only data.
2904 /* XXX NOTE: previous behavior still checked this one row and could
2905 * evaluate it has header row, but that doesn't make much sense. */
2906 return false;
2907
2908 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2909 {
2910 CellType eType = GetCellType( nCol, nStartRow );
2911 // Any non-text cell in first row => not headers.
2913 return false;
2914 }
2915
2916 // First row all text cells, any non-text cell in second row => headers.
2917 SCROW nTestRow = nStartRow + 1;
2918 for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2919 {
2920 CellType eType = GetCellType( nCol, nTestRow );
2922 return true;
2923 }
2924
2925 // Also second row all text cells => first row not headers.
2926 return false;
2927}
2928
2929bool ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const
2930{
2931 if (nStartCol == nEndCol)
2932 // Assume only data.
2933 /* XXX NOTE: previous behavior still checked this one column and could
2934 * evaluate it has header column, but that doesn't make much sense. */
2935 return false;
2936
2937 for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
2938 {
2939 CellType eType = GetCellType( nStartCol, nRow );
2940 // Any non-text cell in first column => not headers.
2942 return false;
2943 }
2944
2945 // First column all text cells, any non-text cell in second column => headers.
2946 SCCOL nTestCol = nStartCol + 1;
2947 for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
2948 {
2949 CellType eType = GetCellType( nRow, nTestCol );
2951 return true;
2952 }
2953
2954 // Also second column all text cells => first column not headers.
2955 return false;
2956}
2957
2958void ScTable::GetFilterEntries( SCCOL nCol, SCROW nRow1, SCROW nRow2, ScFilterEntries& rFilterEntries, bool bFiltering )
2959{
2960 if (nCol >= aCol.size())
2961 return;
2962
2964 aCol[nCol].InitBlockPosition(aBlockPos);
2965 aCol[nCol].GetFilterEntries(aBlockPos, nRow1, nRow2, rFilterEntries, bFiltering, false /*bFilteredRow*/);
2966}
2967
2969 SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, ScFilterEntries& rFilterEntries, bool bFiltering )
2970{
2971 if (nCol >= aCol.size())
2972 return;
2973
2975 aCol[nCol].InitBlockPosition(aBlockPos);
2976
2977 // remove the entry for this column from the query parameter
2978 ScQueryParam aParam( rParam );
2979 aParam.RemoveEntryByField(nCol);
2980
2981 lcl_PrepareQuery(&rDocument, this, aParam, true);
2982 ScQueryEvaluator queryEvaluator(GetDoc(), *this, aParam);
2983 for ( SCROW j = nRow1; j <= nRow2; ++j )
2984 {
2985 if (queryEvaluator.ValidQuery(j))
2986 {
2987 aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries, bFiltering, false/*bFilteredRow*/);
2988 }
2989 else
2990 {
2991 aCol[nCol].GetFilterEntries(aBlockPos, j, j, rFilterEntries, bFiltering, true/*bFilteredRow*/);
2992 }
2993 }
2994}
2995
2996bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, std::set<ScTypedStrData>& rStrings)
2997{
2998 if (!ValidCol(nCol) || nCol >= GetAllocatedColumnsCount())
2999 return false;
3000 return aCol[nCol].GetDataEntries( nRow, rStrings);
3001}
3002
3003sal_uInt64 ScTable::GetCellCount() const
3004{
3005 sal_uInt64 nCellCount = 0;
3006
3007 for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3008 nCellCount += aCol[nCol].GetCellCount();
3009
3010 return nCellCount;
3011}
3012
3014{
3015 sal_uInt64 nCellCount = 0;
3016
3017 for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3018 nCellCount += aCol[nCol].GetWeightedCount();
3019
3020 return nCellCount;
3021}
3022
3023sal_uInt64 ScTable::GetWeightedCount(SCROW nStartRow, SCROW nEndRow) const
3024{
3025 sal_uInt64 nCellCount = 0;
3026
3027 for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3028 nCellCount += aCol[nCol].GetWeightedCount(nStartRow, nEndRow);
3029
3030 return nCellCount;
3031}
3032
3033sal_uInt64 ScTable::GetCodeCount() const
3034{
3035 sal_uInt64 nCodeCount = 0;
3036
3037 for ( SCCOL nCol=0; nCol < aCol.size(); nCol++ )
3038 if ( aCol[nCol].GetCellCount() )
3039 nCodeCount += aCol[nCol].GetCodeCount();
3040
3041 return nCodeCount;
3042}
3043
3044sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart,
3045 SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
3046{
3047 if ( IsColValid( nCol ) )
3048 return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet );
3049 else
3050 return 0;
3051}
3052
3054 sal_uInt16& nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const
3055{
3056 if ( IsColValid( nCol ) )
3057 return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd );
3058 else
3059 return 0;
3060}
3061
3063{
3064 ScRangeList aRanges = rMark.GetMarkedRangesForTab( nTab );
3065 ScRange aMarkArea( ScAddress::UNINITIALIZED );
3066 if (rMark.IsMultiMarked())
3067 aMarkArea = rMark.GetMultiMarkArea();
3068 else if (rMark.IsMarked())
3069 aMarkArea = rMark.GetMarkArea();
3070 else
3071 {
3072 assert(!"ScTable::UpdateSelectionFunction - called without anything marked");
3073 aMarkArea.aStart.SetCol(0);
3074 aMarkArea.aEnd.SetCol(rDocument.MaxCol());
3075 }
3076 const SCCOL nStartCol = aMarkArea.aStart.Col();
3077 const SCCOL nEndCol = ClampToAllocatedColumns(aMarkArea.aEnd.Col());
3078 for (SCCOL nCol = nStartCol; nCol <= nEndCol && !rData.getError(); ++nCol)
3079 {
3080 if (mpColFlags && ColHidden(nCol))
3081 continue;
3082
3083 aCol[nCol].UpdateSelectionFunction(aRanges, rData, *mpHiddenRows);
3084 }
3085}
3086
3087/* 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:246
std::vector< sc::AreaListener > GetAllListeners(const ScRange &rRange, sc::AreaOverlapType eType, sc::ListenerGroupType eGroup=sc::ListenerGroupType::Both)
Definition: bcaslot.cxx:1259
SCCOL size() const
void CollectFormulaCells(std::vector< ScFormulaCell * > &rCells, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1377
const ScPatternAttr * GetPattern(SCROW nRow) const
Definition: column.hxx:952
ScPostIt * GetCellNote(SCROW nRow)
Definition: column2.cxx:2174
void InitBlockPosition(sc::ColumnBlockPosition &rBlockPos)
Definition: column3.cxx:1122
ScRefCellValue GetCellValue(SCROW nRow) const
Definition: column.cxx:638
void StartListeningFormulaCells(sc::StartListeningContext &rStartCxt, sc::EndListeningContext &rEndCxt, SCROW nRow1, SCROW nRow2)
Definition: column4.cxx:1593
const sc::CellTextAttr * GetCellTextAttr(SCROW nRow) const
Definition: column.cxx:692
SCSIZE GetPatternCount() const
Definition: column.hxx:892
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:897
void EndListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:61
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:891
SC_DLLPUBLIC ScDocumentPool * GetPool()
Definition: document.cxx:6170
SC_DLLPUBLIC SCROW MaxRow() const
Definition: document.hxx:892
void UnshareFormulaCells(SCTAB nTab, SCCOL nCol, std::vector< SCROW > &rRows)
Make specified formula cells non-grouped.
Definition: document10.cxx:353
OUString GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: documen3.cxx:1487
ScBroadcastAreaSlotMachine * GetBASM() const
Definition: document.hxx:2226
SC_DLLPUBLIC ScDrawLayer * GetDrawLayer()
Definition: document.hxx:1082
void RegroupFormulaCells(SCTAB nTab, SCCOL nCol)
Definition: document10.cxx:362
void StartListeningArea(const ScRange &rRange, bool bGroupListening, SvtListener *pListener)
Definition: documen7.cxx:35
SC_DLLPUBLIC ScStyleSheetPool * GetStyleSheetPool() const
Definition: document.cxx:6175
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:592
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:1252
std::map< SCROW, std::vector< SdrObject * > > GetObjectsAnchoredToRange(SCTAB nTab, SCCOL nCol, SCROW nStartRow, SCROW nEndRow)
Definition: drwlayer.cxx:2492
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:2676
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:348
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:2568
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:2929
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:921
void DoAutoOutline(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow)
Definition: table2.cxx:4069
CollatorWrapper * pSortCollator
Definition: table.hxx:221
void UpdateSelectionFunction(ScFunctionData &rData, const ScMarkData &rMark)
Definition: table3.cxx:3062
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:160
bool CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam &rQueryParam)
Definition: table3.cxx:2754
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:295
void QuickSort(ScSortInfoArray *, SCCOLROW nLo, SCCOLROW nHi)
Definition: table3.cxx:1689
bool IsColValid(const SCCOL nScCol) const
Definition: table.hxx:336
std::unique_ptr< ScBitMaskCompressedArray< SCCOL, CRFlags > > mpColFlags
Definition: table.hxx:192
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:2996
sal_uInt64 GetWeightedCount() const
Definition: table3.cxx:3013
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:2900
SCTAB nTab
Definition: table.hxx:213
sal_uInt64 GetCodeCount() const
Definition: table3.cxx:3033
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:2968
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:2064
void DBShowRows(SCROW nRow1, SCROW nRow2, bool bShow)
Definition: table2.cxx:3756
bool bGlobalKeepQuery
Definition: table.hxx:251
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:1142
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:2860
std::unique_ptr< ScFlatBoolRowSegments > mpHiddenRows
Definition: table.hxx:195
SCTAB GetTab() const
Definition: table.hxx:291
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:841
CellType GetCellType(const ScAddress &rPos) const
Definition: table.hxx:477
void RemoveSubTotals(ScSubTotalParam &rParam)
Definition: table3.cxx:1985
sal_Int32 GetMaxStringLen(SCCOL nCol, SCROW nRowStart, SCROW nRowEnd, rtl_TextEncoding eCharSet) const
Definition: table3.cxx:3044
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:220
sal_Int32 GetMaxNumberStringLen(sal_uInt16 &nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd) const
Definition: table3.cxx:3053
SCCOL ClampToAllocatedColumns(SCCOL nCol) const
Definition: table.hxx:1141
sal_uInt64 GetCellCount() const
Definition: table3.cxx:3003
ScDocument & rDocument
Definition: table.hxx:214
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:2958
void Reorder(const sc::ReorderParam &rParam)
Definition: table3.cxx:1876
ScDocument & GetDoc()
Definition: table.hxx:289
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:2326
SCSIZE Query(const ScQueryParam &rQueryParam, bool bKeepSub)
Definition: table3.cxx:2573
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.
std::pair< CellStoreType::const_iterator, size_t > FindFormula(const CellStoreType &rStore, SCROW nRow1, SCROW nRow2, Func &rFunc)
mdds::mtv::soa::multi_type_vector< CNoteFunc > CellNoteStoreType
void ParseFormula(const CellStoreType &rStore, Func &rFunc)
Definition: mtvcellfunc.hxx:63
mdds::mtv::soa::multi_type_vector< BCBlkFunc > BroadcasterStoreType
mdds::mtv::soa::multi_type_vector< CellFunc, CellStoreTrait > CellStoreType
mdds::mtv::soa::multi_type_vector< CTAttrFunc > CellTextAttrStoreType
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:907
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
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