fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / tool / compare.cxx
blobb8836056a6aabf64f8eb4491a48698732bf09125
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "compare.hxx"
22 #include "document.hxx"
23 #include "docoptio.hxx"
25 #include <unotools/textsearch.hxx>
27 namespace sc {
29 Compare::Cell::Cell() :
30 mfValue(0.0), mbValue(false), mbEmpty(false) {}
32 Compare::Compare() :
33 meOp(SC_EQUAL), mbIgnoreCase(true) {}
35 CompareOptions::CompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ) :
36 aQueryEntry(rEntry),
37 bRegEx(bReg),
38 bMatchWholeCell(pDoc->GetDocOptions().IsMatchWholeCell())
40 bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL));
41 // Interpreter functions usually are case insensitive, except the simple
42 // comparison operators, for which these options aren't used. Override in
43 // struct if needed.
46 double CompareFunc( const Compare& rComp, CompareOptions* pOptions )
48 const Compare::Cell& rCell1 = rComp.maCells[0];
49 const Compare::Cell& rCell2 = rComp.maCells[1];
51 // Keep DoubleError if encountered
52 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
53 if (!rCell1.mbEmpty && rCell1.mbValue && !rtl::math::isFinite(rCell1.mfValue))
54 return rCell1.mfValue;
55 if (!rCell2.mbEmpty && rCell2.mbValue && !rtl::math::isFinite(rCell2.mfValue))
56 return rCell2.mfValue;
58 size_t nStringQuery = 0; // 0:=no, 1:=0, 2:=1
59 double fRes = 0;
60 if (rCell1.mbEmpty)
62 if (rCell2.mbEmpty)
63 ; // empty cell == empty cell, fRes 0
64 else if (rCell2.mbValue)
66 if (rCell2.mfValue != 0.0)
68 if (rCell2.mfValue < 0.0)
69 fRes = 1; // empty cell > -x
70 else
71 fRes = -1; // empty cell < x
73 // else: empty cell == 0.0
75 else
77 if (!rCell2.maStr.isEmpty())
78 fRes = -1; // empty cell < "..."
79 // else: empty cell == ""
82 else if (rCell2.mbEmpty)
84 if (rCell1.mbValue)
86 if (rCell1.mfValue != 0.0)
88 if (rCell1.mfValue < 0.0)
89 fRes = -1; // -x < empty cell
90 else
91 fRes = 1; // x > empty cell
93 // else: empty cell == 0.0
95 else
97 if (!rCell1.maStr.isEmpty())
98 fRes = 1; // "..." > empty cell
99 // else: "" == empty cell
102 else if (rCell1.mbValue)
104 if (rCell2.mbValue)
106 if (!rtl::math::approxEqual(rCell1.mfValue, rCell2.mfValue))
108 if (rCell1.mfValue - rCell2.mfValue < 0)
109 fRes = -1;
110 else
111 fRes = 1;
114 else
116 fRes = -1; // number is less than string
117 nStringQuery = 2; // 1+1
120 else if (rCell2.mbValue)
122 fRes = 1; // string is greater than number
123 nStringQuery = 1; // 0+1
125 else
127 // Both strings.
128 if (pOptions)
130 // All similar to ScTable::ValidQuery(), *rComp.pVal[1] actually
131 // is/must be identical to *rEntry.pStr, which is essential for
132 // regex to work through GetSearchTextPtr().
133 ScQueryEntry& rEntry = pOptions->aQueryEntry;
134 OSL_ENSURE(rEntry.GetQueryItem().maString == rCell2.maStr, "ScInterpreter::CompareFunc: broken options");
135 if (pOptions->bRegEx)
137 sal_Int32 nStart = 0;
138 sal_Int32 nStop = rCell1.maStr.getLength();
139 bool bMatch = rEntry.GetSearchTextPtr(
140 !rComp.mbIgnoreCase)->SearchForward(
141 rCell1.maStr.getString(), &nStart, &nStop);
142 if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rCell1.maStr.getLength()))
143 bMatch = false; // RegEx must match entire string.
144 fRes = (bMatch ? 0 : 1);
146 else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
148 ::utl::TransliterationWrapper* pTransliteration =
149 (rComp.mbIgnoreCase ? ScGlobal::GetpTransliteration() :
150 ScGlobal::GetCaseTransliteration());
151 bool bMatch = false;
152 if (pOptions->bMatchWholeCell)
154 if (rComp.mbIgnoreCase)
155 bMatch = rCell1.maStr.getDataIgnoreCase() == rCell2.maStr.getDataIgnoreCase();
156 else
157 bMatch = rCell1.maStr.getData() == rCell2.maStr.getData();
159 else
161 OUString aCell( pTransliteration->transliterate(
162 rCell1.maStr.getString(), ScGlobal::eLnge, 0,
163 rCell1.maStr.getLength(), NULL));
164 OUString aQuer( pTransliteration->transliterate(
165 rCell2.maStr.getString(), ScGlobal::eLnge, 0,
166 rCell2.maStr.getLength(), NULL));
167 bMatch = (aCell.indexOf( aQuer ) != -1);
169 fRes = (bMatch ? 0 : 1);
171 else if (rComp.mbIgnoreCase)
172 fRes = (double) ScGlobal::GetCollator()->compareString(
173 rCell1.maStr.getString(), rCell2.maStr.getString());
174 else
175 fRes = (double) ScGlobal::GetCaseCollator()->compareString(
176 rCell1.maStr.getString(), rCell2.maStr.getString());
178 else if (rComp.meOp == SC_EQUAL || rComp.meOp == SC_NOT_EQUAL)
180 if (rComp.mbIgnoreCase)
181 fRes = (rCell1.maStr.getDataIgnoreCase() == rCell2.maStr.getDataIgnoreCase()) ? 0 : 1;
182 else
183 fRes = (rCell1.maStr.getData() == rCell2.maStr.getData()) ? 0 : 1;
185 else if (rComp.mbIgnoreCase)
186 fRes = (double) ScGlobal::GetCollator()->compareString(
187 rCell1.maStr.getString(), rCell2.maStr.getString());
188 else
189 fRes = (double) ScGlobal::GetCaseCollator()->compareString(
190 rCell1.maStr.getString(), rCell2.maStr.getString());
193 if (nStringQuery && pOptions)
195 const ScQueryEntry& rEntry = pOptions->aQueryEntry;
196 const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
197 if (!rItems.empty())
199 const ScQueryEntry::Item& rItem = rItems[0];
200 if (rItem.meType != ScQueryEntry::ByString && !rItem.maString.isEmpty() &&
201 (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL))
203 // As in ScTable::ValidQuery() match a numeric string for a
204 // number query that originated from a string, e.g. in SUMIF
205 // and COUNTIF. Transliteration is not needed here.
206 bool bEqual = false;
207 if (nStringQuery == 1)
208 bEqual = rCell1.maStr == rItem.maString;
209 else
210 bEqual = rCell2.maStr == rItem.maString;
212 // match => fRes=0, else fRes=1
213 fRes = double((rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual);
218 return fRes;
221 double CompareFunc( const Compare::Cell& rCell1, double fCell2, CompareOptions* pOptions )
223 // Keep DoubleError if encountered
224 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
225 if (!rCell1.mbEmpty && rCell1.mbValue && !rtl::math::isFinite(rCell1.mfValue))
226 return rCell1.mfValue;
227 if (!rtl::math::isFinite(fCell2))
228 return fCell2;
230 bool bStringQuery = false;
231 double fRes = 0;
232 if (rCell1.mbEmpty)
234 if (fCell2 != 0.0)
236 if (fCell2 < 0.0)
237 fRes = 1; // empty cell > -x
238 else
239 fRes = -1; // empty cell < x
241 // else: empty cell == 0.0
243 else if (rCell1.mbValue)
245 if (!rtl::math::approxEqual(rCell1.mfValue, fCell2))
247 if (rCell1.mfValue - fCell2 < 0)
248 fRes = -1;
249 else
250 fRes = 1;
253 else
255 fRes = 1; // string is greater than number
256 bStringQuery = true;
259 if (bStringQuery && pOptions)
261 const ScQueryEntry& rEntry = pOptions->aQueryEntry;
262 const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
263 if (!rItems.empty())
265 const ScQueryEntry::Item& rItem = rItems[0];
266 if (rItem.meType != ScQueryEntry::ByString && !rItem.maString.isEmpty() &&
267 (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL))
269 // As in ScTable::ValidQuery() match a numeric string for a
270 // number query that originated from a string, e.g. in SUMIF
271 // and COUNTIF. Transliteration is not needed here.
272 bool bEqual = rCell1.maStr == rItem.maString;
274 // match => fRes=0, else fRes=1
275 fRes = double((rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual);
280 return fRes;
283 double CompareFunc( double fCell1, double fCell2 )
285 // Keep DoubleError if encountered
286 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
287 if (!rtl::math::isFinite(fCell1))
288 return fCell1;
289 if (!rtl::math::isFinite(fCell2))
290 return fCell2;
292 double fRes = 0.0;
294 if (!rtl::math::approxEqual(fCell1, fCell2))
296 if (fCell1 - fCell2 < 0.0)
297 fRes = -1;
298 else
299 fRes = 1;
302 return fRes;
305 double CompareEmptyToNumericFunc( double fCell2 )
307 // Keep DoubleError if encountered
308 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
309 if (!rtl::math::isFinite(fCell2))
310 return fCell2;
312 double fRes = 0;
313 if (fCell2 != 0.0)
315 if (fCell2 < 0.0)
316 fRes = 1; // empty cell > -x
317 else
318 fRes = -1; // empty cell < x
320 // else: empty cell == 0.0
322 return fRes;
327 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */