Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/inc/sortparam.hxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#pragma once
21
22
672k
#define DEFSORT 3
23
24
#include <vector>
25
26
#include "address.hxx"
27
#include <com/sun/star/lang/Locale.hpp>
28
#include <com/sun/star/sheet/SortNumberBehavior.hpp>
29
#include "scdllapi.h"
30
#include "celltextattr.hxx"
31
#include "cellvalue.hxx"
32
#include "patattr.hxx"
33
#include <tools/color.hxx>
34
35
struct ScSubTotalParam;
36
struct ScQueryParam;
37
class SdrObject;
38
class ScPostIt;
39
40
enum class SortOrderType
41
{
42
    Ordered,
43
    Random
44
};
45
46
/** Sort by which color */
47
enum class ScColorSortMode {
48
    None,
49
    TextColor,
50
    BackgroundColor
51
};
52
53
/** Sort key state defines one way how to sort the range.
54
 *
55
 * A range of values can be sorted in multiple way, each column a different way.
56
 *
57
 * For example: sort column A ascending and if the column when there are same values, define that those should be
58
 * sorted descending usign the column C.
59
 **/
60
struct ScSortKeyState
61
{
62
    SCCOLROW nField = 0;
63
    bool bDoSort = false;
64
    bool bAscending = true;
65
    ScColorSortMode aColorSortMode = ScColorSortMode::None;
66
    Color aColorSortColor;
67
};
68
69
/** Struct to hold non-data extended area, used with
70
    ScDocument::ShrinkToUsedDataArea().
71
*/
72
struct ScDataAreaExtras
73
{
74
    /// If TRUE, consider the presence of cell notes besides data.
75
    bool    mbCellNotes = false;
76
    /// If TRUE, consider the presence of draw objects anchored to the cell.
77
    bool    mbCellDrawObjects = false;
78
    /// If TRUE, consider the presence of cell formats.
79
    bool    mbCellFormats = false;
80
    SCCOL   mnStartCol = SCCOL_MAX;
81
    SCROW   mnStartRow = SCROW_MAX;
82
    SCCOL   mnEndCol = -1;
83
    SCROW   mnEndRow = -1;
84
85
0
    bool anyExtrasWanted() const { return mbCellNotes || mbCellDrawObjects || mbCellFormats; }
86
0
    void resetArea() { mnStartCol = SCCOL_MAX; mnStartRow = SCROW_MAX; mnEndCol = -1; mnEndRow = -1; }
87
88
    bool operator==( const ScDataAreaExtras& rOther ) const
89
0
    {
90
        // Ignore area range, this is used in ScSortParam::operator==().
91
0
        return mbCellNotes       == rOther.mbCellNotes
92
0
            && mbCellDrawObjects == rOther.mbCellDrawObjects
93
0
            && mbCellFormats     == rOther.mbCellFormats;
94
0
    }
95
96
    enum class Clip
97
    {
98
        None,
99
        Col,
100
        Row
101
    };
102
103
    /// Obtain the overall range if area extras are larger.
104
    void GetOverallRange( SCCOL& nCol1, SCROW& nRow1, SCCOL& nCol2, SCROW& nRow2, Clip eClip = Clip::None ) const
105
0
    {
106
0
        if (eClip != Clip::Col)
107
0
        {
108
0
            if (nCol1 > mnStartCol)
109
0
                nCol1 = mnStartCol;
110
0
            if (nCol2 < mnEndCol)
111
0
                nCol2 = mnEndCol;
112
0
        }
113
0
        if (eClip != Clip::Row)
114
0
        {
115
0
            if (nRow1 > mnStartRow)
116
0
                nRow1 = mnStartRow;
117
0
            if (nRow2 < mnEndRow)
118
0
                nRow2 = mnEndRow;
119
0
        }
120
0
    }
121
122
    /// Set the overall range.
123
    void SetOverallRange( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
124
0
    {
125
0
        mnStartCol = nCol1;
126
0
        mnStartRow = nRow1;
127
0
        mnEndCol   = nCol2;
128
0
        mnEndRow   = nRow2;
129
0
    }
130
};
131
132
/** Specifies how numbers embedded in text are treated in text
133
    comparisons. The values correspond to the ODF attribute
134
    table:embedded-number-behavior (19.628, part 3 ODF 1.4).
135
*/
136
enum class ScSortNumberBehavior : sal_Int32
137
{
138
    ALPHA_NUMERIC = css::sheet::SortNumberBehavior::ALPHA_NUMERIC, // 0
139
    DOUBLE = css::sheet::SortNumberBehavior::DOUBLE, // 1
140
    INTEGER  = css::sheet::SortNumberBehavior::INTEGER, // 2
141
};
142
143
struct SC_DLLPUBLIC ScSortParam
144
{
145
    SCCOL       nCol1;
146
    SCROW       nRow1;
147
    SCCOL       nCol2;
148
    SCROW       nRow2;
149
    SCTAB       nSourceTab;
150
    ScDataAreaExtras aDataAreaExtras;
151
    sal_uInt16  nUserIndex;
152
    bool        bHasHeader;
153
    bool        bByRow;
154
    bool        bCaseSens;
155
    ScSortNumberBehavior eSortNumberBehavior;
156
    bool        bUserDef;
157
    bool        bInplace;
158
    SCTAB       nDestTab;
159
    SCCOL       nDestCol;
160
    SCROW       nDestRow;
161
    std::vector<ScSortKeyState> maKeyState;
162
    css::lang::Locale aCollatorLocale;
163
    OUString    aCollatorAlgorithm;
164
    sal_uInt16  nCompatHeader;
165
    SortOrderType meSortOrderType = SortOrderType::Ordered;
166
167
    ScSortParam();
168
    ScSortParam( const ScSortParam& r );
169
    /// SubTotals sort
170
    ScSortParam( const ScSubTotalParam& rSub, const ScSortParam& rOld );
171
    /// TopTen sort
172
    ScSortParam( const ScQueryParam&, SCCOL nCol );
173
    ~ScSortParam();
174
175
    ScSortParam&    operator=  ( const ScSortParam& r );
176
    bool            operator== ( const ScSortParam& rOther ) const;
177
    void            Clear       ();
178
    void            MoveToDest();
179
180
0
    sal_uInt16 GetSortKeyCount() const { return maKeyState.size(); }
181
};
182
183
struct ScSortInfo final
184
{
185
    ScRefCellValue maCell;
186
    SCCOLROW       nOrg;
187
};
188
189
class ScSortInfoArray
190
{
191
public:
192
193
    struct Cell
194
    {
195
        ScRefCellValue maCell;
196
        const sc::CellTextAttr* mpAttr;
197
        const ScPostIt* mpNote;
198
        std::vector<SdrObject*> maDrawObjects;
199
        CellAttributeHolder maPattern;
200
201
0
        Cell() : mpAttr(nullptr), mpNote(nullptr),  maPattern() {}
202
    };
203
204
    struct Row
205
    {
206
        std::vector<Cell> maCells;
207
208
        bool mbHidden:1;
209
        bool mbFiltered:1;
210
211
0
        explicit Row( size_t nColSize ) : maCells(nColSize, Cell()), mbHidden(false), mbFiltered(false) {}
212
    };
213
214
    typedef std::vector<Row> RowsType;
215
216
private:
217
    std::unique_ptr<RowsType> mpRows; /// row-wise data table for sort by row operation.
218
219
    std::vector<std::unique_ptr<ScSortInfo[]>> mvppInfo;
220
    SCCOLROW        nStart;
221
    SCCOLROW        mnLastIndex; /// index of last non-empty cell position.
222
223
    std::vector<SCCOLROW> maOrderIndices;
224
    bool mbKeepQuery;
225
    bool mbUpdateRefs;
226
227
public:
228
    ScSortInfoArray(const ScSortInfoArray&) = delete;
229
    const ScSortInfoArray& operator=(const ScSortInfoArray&) = delete;
230
231
    ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
232
0
        mvppInfo(nSorts),
233
0
        nStart( nInd1 ),
234
0
        mnLastIndex(nInd2),
235
0
        mbKeepQuery(false),
236
0
        mbUpdateRefs(false)
237
0
    {
238
0
        SCSIZE nCount( nInd2 - nInd1 + 1 );
239
0
        if (nSorts)
240
0
        {
241
0
            for ( sal_uInt16 nSort = 0; nSort < nSorts; nSort++ )
242
0
            {
243
0
                mvppInfo[nSort].reset(new ScSortInfo[nCount]);
244
0
            }
245
0
        }
246
247
0
        for (size_t i = 0; i < nCount; ++i)
248
0
            maOrderIndices.push_back(i+nStart);
249
0
    }
250
251
0
    void SetKeepQuery( bool b ) { mbKeepQuery = b; }
252
253
0
    bool IsKeepQuery() const { return mbKeepQuery; }
254
255
0
    void SetUpdateRefs( bool b ) { mbUpdateRefs = b; }
256
257
0
    bool IsUpdateRefs() const { return mbUpdateRefs; }
258
259
    /**
260
     * Call this only during normal sorting, not from reordering.
261
     */
262
    std::unique_ptr<ScSortInfo[]> const & GetFirstArray() const
263
0
    {
264
0
        return mvppInfo[0];
265
0
    }
266
267
    /**
268
     * Call this only during normal sorting, not from reordering.
269
     */
270
    ScSortInfo & Get( sal_uInt16 nSort, SCCOLROW nInd )
271
0
    {
272
0
        return mvppInfo[nSort][ nInd - nStart ];
273
0
    }
274
275
    /**
276
     * Call this only during normal sorting, not from reordering.
277
     */
278
    void Swap( SCCOLROW nInd1, SCCOLROW nInd2 )
279
0
    {
280
0
        if (nInd1 == nInd2) // avoid self-move-assign
281
0
            return;
282
0
        SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart);
283
0
        SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart);
284
0
        for ( sal_uInt16 nSort = 0; nSort < static_cast<sal_uInt16>(mvppInfo.size()); nSort++ )
285
0
        {
286
0
            auto & ppInfo = mvppInfo[nSort];
287
0
            std::swap(ppInfo[n1], ppInfo[n2]);
288
0
        }
289
290
0
        std::swap(maOrderIndices[n1], maOrderIndices[n2]);
291
292
0
        if (mpRows)
293
0
        {
294
            // Swap rows in data table.
295
0
            RowsType& rRows = *mpRows;
296
0
            std::swap(rRows[n1], rRows[n2]);
297
0
        }
298
0
    }
299
300
    void SetOrderIndices( std::vector<SCCOLROW>&& rIndices )
301
0
    {
302
0
        maOrderIndices = std::move(rIndices);
303
0
    }
304
305
    /**
306
     * @param rIndices indices are actual row positions on the sheet, not an
307
     *                 offset from the top row.
308
     */
309
    void ReorderByRow( const std::vector<SCCOLROW>& rIndices )
310
0
    {
311
0
        if (!mpRows)
312
0
            return;
313
314
0
        RowsType& rRows = *mpRows;
315
316
0
        std::vector<SCCOLROW> aOrderIndices2;
317
0
        aOrderIndices2.reserve(rIndices.size());
318
319
0
        RowsType aRows2;
320
0
        aRows2.reserve(rRows.size());
321
322
0
        for (const auto& rIndex : rIndices)
323
0
        {
324
0
            size_t nPos = rIndex - nStart; // switch to an offset to top row.
325
0
            aRows2.push_back(rRows[nPos]);
326
0
            aOrderIndices2.push_back(maOrderIndices[nPos]);
327
0
        }
328
329
0
        rRows.swap(aRows2);
330
0
        maOrderIndices.swap(aOrderIndices2);
331
0
    }
332
333
0
    sal_uInt16      GetUsedSorts() const { return mvppInfo.size(); }
334
335
0
    SCCOLROW    GetStart() const { return nStart; }
336
0
    SCCOLROW GetLast() const { return mnLastIndex; }
337
338
0
    const std::vector<SCCOLROW>& GetOrderIndices() const { return maOrderIndices; }
339
340
    RowsType& InitDataRows( size_t nRowSize, size_t nColSize )
341
0
    {
342
0
        mpRows.reset(new RowsType);
343
0
        mpRows->resize(nRowSize, Row(nColSize));
344
0
        return *mpRows;
345
0
    }
346
347
    RowsType* GetDataRows()
348
0
    {
349
0
        return mpRows.get();
350
0
    }
351
};
352
353
namespace sc {
354
355
struct ReorderParam
356
{
357
    /**
358
     * This sort range already takes into account the presence or absence of
359
     * header row / column i.e. if a header row / column is present, it
360
     * excludes that row / column.
361
     */
362
    ScRange maSortRange;
363
    ScDataAreaExtras maDataAreaExtras;
364
365
    /**
366
     * List of original column / row positions after reordering.
367
     */
368
    std::vector<SCCOLROW> maOrderIndices;
369
    bool mbByRow;
370
    bool mbHiddenFiltered;
371
    bool mbUpdateRefs;
372
    bool mbHasHeaders;
373
    bool mbShuffle;
374
375
    /**
376
     * Reorder the position indices such that it can be used to undo the
377
     * original reordering.
378
     */
379
    void reverse();
380
381
    ReorderParam()
382
0
        : mbByRow(false)
383
0
        , mbHiddenFiltered(false)
384
0
        , mbUpdateRefs(false)
385
0
        , mbHasHeaders(false)
386
0
        , mbShuffle(false)
387
0
    {
388
0
    }
389
};
390
391
}
392
393
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */