LibreOffice Module sc (master) 1
rangecache.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
20#include <rangecache.hxx>
21#include <cellvalue.hxx>
22#include <document.hxx>
23#include <brdcst.hxx>
24#include <queryevaluator.hxx>
25#include <queryparam.hxx>
26
27#include <sal/log.hxx>
28#include <svl/numformat.hxx>
30
32{
33 assert(op == SC_GREATER || op == SC_GREATER_EQUAL || op == SC_LESS || op == SC_LESS_EQUAL
34 || op == SC_EQUAL);
35 // We want all matching values to start in the sort order,
36 // since the data is searched from start until the last matching one.
37 return op == SC_GREATER || op == SC_GREATER_EQUAL;
38}
39
41{
42 assert(param.GetEntry(0).bDoQuery && !param.GetEntry(1).bDoQuery
43 && param.GetEntry(0).GetQueryItems().size() == 1);
50}
51
53 const ScQueryParam& param, ScInterpreterContext* context,
54 bool invalid)
55 : maRange(rRange)
56 , mpDoc(pDoc)
57 , mValid(false)
58 , mValueType(toValueType(param))
59{
60 assert(maRange.aStart.Col() == maRange.aEnd.Col());
61 assert(maRange.aStart.Tab() == maRange.aEnd.Tab());
62 SCTAB nTab = maRange.aStart.Tab();
63 SCTAB nCol = maRange.aStart.Col();
64 assert(param.GetEntry(0).bDoQuery && !param.GetEntry(1).bDoQuery
65 && param.GetEntry(0).GetQueryItems().size() == 1);
66 const ScQueryEntry& entry = param.GetEntry(0);
67 const ScQueryEntry::Item& item = entry.GetQueryItem();
68 mQueryOp = entry.eOp;
69 mQueryType = item.meType;
70
71 if (invalid)
72 return; // leave empty
73
74 SCROW startRow = maRange.aStart.Row();
75 SCROW endRow = maRange.aEnd.Row();
76 SCCOL startCol = maRange.aStart.Col();
77 SCCOL endCol = maRange.aEnd.Col();
78 if (!item.mbMatchEmpty)
79 if (!pDoc->ShrinkToDataArea(nTab, startCol, startRow, endCol, endRow))
80 return; // no data cells, no need for a cache
81
83 {
84 struct RowData
85 {
86 SCROW row;
87 double value;
88 };
89 std::vector<RowData> rowData;
90 for (SCROW nRow = startRow; nRow <= endRow; ++nRow)
91 {
92 ScRefCellValue cell(pDoc->GetRefCellValue(ScAddress(nCol, nRow, nTab)));
94 rowData.push_back(RowData{ nRow, cell.getValue() });
96 {
97 // Make sure that other possibilities in the generic handling
98 // in ScQueryEvaluator::processEntry() do not alter the results.
99 // (ByTextColor/ByBackgroundColor are blocked by CanBeUsedForSorterCache(),
100 // but isQueryByString() is possible if the cell content is a string.
101 // And including strings here would be tricky, as the string comparison
102 // may possibly(?) be different than a numeric one. So check if the string
103 // may possibly match a number, by converting it to one. If it can't match,
104 // then it's fine to ignore it (and it can happen e.g. if the query uses
105 // the whole column which includes a textual header). But if it can possibly
106 // match, then bail out and leave it to the unoptimized case.
107 // TODO Maybe it would actually work to use the numeric value obtained here?
109 return; // substring matching cannot be sorted
110 sal_uInt32 format = 0;
111 double value;
112 if (context->GetFormatTable()->IsNumberFormat(cell.getString(pDoc), format, value))
113 return;
114 }
115 }
116 std::stable_sort(rowData.begin(), rowData.end(),
117 [](const RowData& d1, const RowData& d2) { return d1.value < d2.value; });
118 if (needsDescending(entry.eOp))
119 for (auto it = rowData.rbegin(); it != rowData.rend(); ++it)
120 mSortedRows.emplace_back(it->row);
121 else
122 for (const RowData& d : rowData)
123 mSortedRows.emplace_back(d.row);
124 }
125 else
126 {
127 struct RowData
128 {
129 SCROW row;
130 OUString string;
131 };
132 std::vector<RowData> rowData;
133 // Try to reuse as much ScQueryEvaluator code as possible, this should
134 // basically do the same comparisons.
135 assert(pDoc->FetchTable(nTab) != nullptr);
136 ScQueryEvaluator evaluator(*pDoc, *pDoc->FetchTable(nTab), param, context);
137 for (SCROW nRow = startRow; nRow <= endRow; ++nRow)
138 {
139 ScRefCellValue cell(pDoc->GetRefCellValue(ScAddress(nCol, nRow, nTab)));
140 // This should be used only with ScQueryEntry::ByString, and that
141 // means that ScQueryEvaluator::isQueryByString() should be the only
142 // possibility in the generic handling in ScQueryEvaluator::processEntry()
143 // (ByTextColor/ByBackgroundColor are blocked by CanBeUsedForSorterCache(),
144 // and isQueryByValue() is blocked by ScQueryEntry::ByString).
148 {
149 const svl::SharedString* sharedString = nullptr;
150 OUString string = evaluator.getCellString(cell, nRow, nCol, &sharedString);
151 if (sharedString)
152 string = sharedString->getString();
153 rowData.push_back(RowData{ nRow, string });
154 }
155 }
156 CollatorWrapper& collator
158 std::stable_sort(rowData.begin(), rowData.end(),
159 [&collator](const RowData& d1, const RowData& d2) {
160 return collator.compareString(d1.string, d2.string) < 0;
161 });
162 if (needsDescending(entry.eOp))
163 for (auto it = rowData.rbegin(); it != rowData.rend(); ++it)
164 mSortedRows.emplace_back(it->row);
165 else
166 for (const RowData& d : rowData)
167 mSortedRows.emplace_back(d.row);
168 }
169
170 mRowToIndex.resize(maRange.aEnd.Row() - maRange.aStart.Row() + 1, mSortedRows.max_size());
171 for (size_t i = 0; i < mSortedRows.size(); ++i)
173 mValid = true;
174}
175
177{
178 if (!mpDoc->IsInDtorClear())
179 {
180 if (rHint.GetId() == SfxHintId::ScDataChanged || rHint.GetId() == SfxHintId::ScAreaChanged)
181 {
183 // this ScSortedRangeCache is deleted by RemoveSortedRangeCache
184 }
185 }
186}
187
189 const ScQueryParam& param)
190{
191 assert(param.GetEntry(0).bDoQuery && !param.GetEntry(1).bDoQuery
192 && param.GetEntry(0).GetQueryItems().size() == 1);
193 const ScQueryEntry& entry = param.GetEntry(0);
194 const ScQueryEntry::Item& item = entry.GetQueryItem();
195 return { range, toValueType(param), entry.eOp, item.meType };
196}
197
198/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
double d
B2DRange maRange
SCTAB Tab() const
Definition: address.hxx:283
SCROW Row() const
Definition: address.hxx:274
SCCOL Col() const
Definition: address.hxx:279
ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2545
bool ShrinkToDataArea(SCTAB nTab, SCCOL &rStartCol, SCROW &rStartRow, SCCOL &rEndCol, SCROW &rEndRow) const
Shrink a range to only include data area.
Definition: document.cxx:1044
void RemoveSortedRangeCache(ScSortedRangeCache &rCache)
Definition: documen2.cxx:1270
bool IsInDtorClear() const
Definition: document.hxx:2448
ScRefCellValue GetRefCellValue(const ScAddress &rPos)
Definition: documen2.cxx:587
static SC_DLLPUBLIC CollatorWrapper & GetCollator()
case-insensitive collator
Definition: global.cxx:1093
OUString getCellString(const ScRefCellValue &rCell, SCROW nRow, SCCOL nCol, const svl::SharedString **sharedString)
bool isMatchWholeCell(ScQueryOp eOp) const
static bool isQueryByValue(ScQueryOp eOp, ScQueryEntry::QueryType eType, const ScRefCellValue &rCell)
static bool isQueryByString(ScQueryOp eOp, ScQueryEntry::QueryType eType, const ScRefCellValue &rCell)
ScAddress aEnd
Definition: address.hxx:498
ScAddress aStart
Definition: address.hxx:497
std::vector< SCROW > mSortedRows
Definition: rangecache.hxx:105
std::vector< size_t > mRowToIndex
Definition: rangecache.hxx:106
virtual void Notify(const SfxHint &rHint) override
Remove from document structure and delete (!) cache on modify hint.
Definition: rangecache.cxx:176
ScQueryEntry::QueryType mQueryType
Definition: rangecache.hxx:112
ScSortedRangeCache(ScDocument *pDoc, const ScRange &rRange, const ScQueryParam &param, ScInterpreterContext *context, bool invalid=false)
MUST be new'd because Notify() deletes.
Definition: rangecache.cxx:52
static HashKey makeHashKey(const ScRange &range, const ScQueryParam &param)
Definition: rangecache.cxx:188
ValueType mValueType
Definition: rangecache.hxx:110
ScDocument * mpDoc
Definition: rangecache.hxx:108
SfxHintId GetId() const
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
const OUString & getString() const
ScQueryOp
Definition: global.hxx:833
@ SC_LESS_EQUAL
Definition: global.hxx:837
@ SC_LESS
Definition: global.hxx:835
@ SC_GREATER_EQUAL
Definition: global.hxx:838
@ SC_GREATER
Definition: global.hxx:836
@ SC_EQUAL
Definition: global.hxx:834
int i
bool mValid
Definition: queryiter.cxx:1153
static ScSortedRangeCache::ValueType toValueType(const ScQueryParam &param)
Definition: rangecache.cxx:40
static bool needsDescending(ScQueryOp op)
Definition: rangecache.cxx:31
SvNumberFormatter * GetFormatTable() const
Each instance of this struct represents a single filtering criteria.
Definition: queryentry.hxx:34
const Item & GetQueryItem() const
Definition: queryentry.hxx:85
ScQueryOp eOp
Definition: queryentry.hxx:62
QueryItemsType & GetQueryItems()
Definition: queryentry.hxx:75
SC_DLLPUBLIC const ScQueryEntry & GetEntry(SCSIZE n) const
Definition: queryparam.cxx:116
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
OUString getString(const ScDocument *pDoc) const
Retrieve string value.
Definition: cellvalue.cxx:657
double getValue()
Definition: cellvalue.cxx:629
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17