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 <memory>
21 #include <queryparam.hxx>
22 #include <queryentry.hxx>
23 #include <scmatrix.hxx>
24
25 #include <svl/sharedstringpool.hxx>
26 #include <svl/zforlist.hxx>
27 #include <osl/diagnose.h>
28
29 #include <algorithm>
30
31 namespace {
32
33 const size_t MAXQUERY = 8;
34
35 class FindByField
36 {
37 SCCOLROW mnField;
38 public:
FindByField(SCCOLROW nField)39 explicit FindByField(SCCOLROW nField) : mnField(nField) {}
operator ()(const std::unique_ptr<ScQueryEntry> & rpEntry) const40 bool operator() (const std::unique_ptr<ScQueryEntry>& rpEntry) const
41 {
42 return rpEntry->bDoQuery && rpEntry->nField == mnField;
43 }
44 };
45
46 struct FindUnused
47 {
operator ()__anon6890543f0111::FindUnused48 bool operator() (const std::unique_ptr<ScQueryEntry>& rpEntry) const
49 {
50 return !rpEntry->bDoQuery;
51 }
52 };
53
54 }
55
begin() const56 ScQueryParamBase::const_iterator ScQueryParamBase::begin() const
57 {
58 return m_Entries.begin();
59 }
60
end() const61 ScQueryParamBase::const_iterator ScQueryParamBase::end() const
62 {
63 return m_Entries.end();
64 }
65
ScQueryParamBase()66 ScQueryParamBase::ScQueryParamBase() :
67 eSearchType(utl::SearchParam::SearchType::Normal),
68 bHasHeader(true),
69 bByRow(true),
70 bInplace(true),
71 bCaseSens(false),
72 bDuplicate(false),
73 mbRangeLookup(false)
74 {
75 for (size_t i = 0; i < MAXQUERY; ++i)
76 m_Entries.push_back(std::make_unique<ScQueryEntry>());
77 }
78
ScQueryParamBase(const ScQueryParamBase & r)79 ScQueryParamBase::ScQueryParamBase(const ScQueryParamBase& r) :
80 eSearchType(r.eSearchType), bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace),
81 bCaseSens(r.bCaseSens), bDuplicate(r.bDuplicate), mbRangeLookup(r.mbRangeLookup)
82 {
83 for (auto const& it : r.m_Entries)
84 {
85 m_Entries.push_back(std::make_unique<ScQueryEntry>(*it));
86 }
87 }
88
operator =(const ScQueryParamBase & r)89 ScQueryParamBase& ScQueryParamBase::operator=(const ScQueryParamBase& r)
90 {
91 if (this != &r)
92 {
93 eSearchType = r.eSearchType;
94 bHasHeader = r.bHasHeader;
95 bByRow = r.bByRow;
96 bInplace = r.bInplace;
97 bCaseSens = r.bCaseSens;
98 bDuplicate = r.bDuplicate;
99 mbRangeLookup = r.mbRangeLookup;
100
101 m_Entries.clear();
102 for (auto const& it : r.m_Entries)
103 {
104 m_Entries.push_back(std::make_unique<ScQueryEntry>(*it));
105 }
106 }
107 return *this;
108 }
109
~ScQueryParamBase()110 ScQueryParamBase::~ScQueryParamBase()
111 {
112 }
113
IsValidFieldIndex() const114 bool ScQueryParamBase::IsValidFieldIndex() const
115 {
116 return true;
117 }
118
GetEntryCount() const119 SCSIZE ScQueryParamBase::GetEntryCount() const
120 {
121 return m_Entries.size();
122 }
123
GetEntry(SCSIZE n) const124 const ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n) const
125 {
126 return *m_Entries[n];
127 }
128
GetEntry(SCSIZE n)129 ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n)
130 {
131 return *m_Entries[n];
132 }
133
AppendEntry()134 ScQueryEntry& ScQueryParamBase::AppendEntry()
135 {
136 // Find the first unused entry.
137 EntriesType::iterator itr = std::find_if(
138 m_Entries.begin(), m_Entries.end(), FindUnused());
139
140 if (itr != m_Entries.end())
141 // Found!
142 return **itr;
143
144 // Add a new entry to the end.
145 m_Entries.push_back(std::make_unique<ScQueryEntry>());
146 return *m_Entries.back();
147 }
148
FindEntryByField(SCCOLROW nField,bool bNew)149 ScQueryEntry* ScQueryParamBase::FindEntryByField(SCCOLROW nField, bool bNew)
150 {
151 EntriesType::iterator itr = std::find_if(
152 m_Entries.begin(), m_Entries.end(), FindByField(nField));
153
154 if (itr != m_Entries.end())
155 {
156 // existing entry found!
157 return (*itr).get();
158 }
159
160 if (!bNew)
161 // no existing entry found, and we are not creating a new one.
162 return nullptr;
163
164 return &AppendEntry();
165 }
166
FindAllEntriesByField(SCCOLROW nField)167 std::vector<ScQueryEntry*> ScQueryParamBase::FindAllEntriesByField(SCCOLROW nField)
168 {
169 std::vector<ScQueryEntry*> aEntries;
170
171 auto fFind = FindByField(nField);
172
173 for (const auto& rxEntry : m_Entries)
174 if (fFind(rxEntry))
175 aEntries.push_back(rxEntry.get());
176
177 return aEntries;
178 }
179
RemoveEntryByField(SCCOLROW nField)180 bool ScQueryParamBase::RemoveEntryByField(SCCOLROW nField)
181 {
182 EntriesType::iterator itr = std::find_if(
183 m_Entries.begin(), m_Entries.end(), FindByField(nField));
184 bool bRet = false;
185
186 if (itr != m_Entries.end())
187 {
188 m_Entries.erase(itr);
189 if (m_Entries.size() < MAXQUERY)
190 // Make sure that we have at least MAXQUERY number of entries at
191 // all times.
192 m_Entries.push_back(std::make_unique<ScQueryEntry>());
193 bRet = true;
194 }
195
196 return bRet;
197 }
198
RemoveAllEntriesByField(SCCOLROW nField)199 void ScQueryParamBase::RemoveAllEntriesByField(SCCOLROW nField)
200 {
201 while( RemoveEntryByField( nField ) ) {}
202 }
203
Resize(size_t nNew)204 void ScQueryParamBase::Resize(size_t nNew)
205 {
206 if (nNew < MAXQUERY)
207 nNew = MAXQUERY; // never less than MAXQUERY
208
209 if (nNew < m_Entries.size())
210 {
211 size_t n = m_Entries.size() - nNew;
212 for (size_t i = 0; i < n; ++i)
213 m_Entries.pop_back();
214 }
215 else if (nNew > m_Entries.size())
216 {
217 size_t n = nNew - m_Entries.size();
218 for (size_t i = 0; i < n; ++i)
219 m_Entries.push_back(std::make_unique<ScQueryEntry>());
220 }
221 }
222
FillInExcelSyntax(svl::SharedStringPool & rPool,const OUString & rCellStr,SCSIZE nIndex,SvNumberFormatter * pFormatter)223 void ScQueryParamBase::FillInExcelSyntax(
224 svl::SharedStringPool& rPool, const OUString& rCellStr, SCSIZE nIndex, SvNumberFormatter* pFormatter )
225 {
226 if (nIndex >= m_Entries.size())
227 Resize(nIndex+1);
228
229 ScQueryEntry& rEntry = GetEntry(nIndex);
230 ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
231
232 if (rCellStr.isEmpty())
233 rItem.maString = svl::SharedString::getEmptyString();
234 else
235 {
236 rEntry.bDoQuery = true;
237 // Operatoren herausfiltern
238 if (rCellStr[0] == '<')
239 {
240 if (rCellStr.getLength() > 1 && rCellStr[1] == '>')
241 {
242 rItem.maString = rPool.intern(rCellStr.copy(2));
243 rEntry.eOp = SC_NOT_EQUAL;
244 }
245 else if (rCellStr.getLength() > 1 && rCellStr[1] == '=')
246 {
247 rItem.maString = rPool.intern(rCellStr.copy(2));
248 rEntry.eOp = SC_LESS_EQUAL;
249 }
250 else
251 {
252 rItem.maString = rPool.intern(rCellStr.copy(1));
253 rEntry.eOp = SC_LESS;
254 }
255 }
256 else if (rCellStr[0]== '>')
257 {
258 if (rCellStr.getLength() > 1 && rCellStr[1] == '=')
259 {
260 rItem.maString = rPool.intern(rCellStr.copy(2));
261 rEntry.eOp = SC_GREATER_EQUAL;
262 }
263 else
264 {
265 rItem.maString = rPool.intern(rCellStr.copy(1));
266 rEntry.eOp = SC_GREATER;
267 }
268 }
269 else
270 {
271 if (rCellStr[0] == '=')
272 rItem.maString = rPool.intern(rCellStr.copy(1));
273 else
274 rItem.maString = rPool.intern(rCellStr);
275 rEntry.eOp = SC_EQUAL;
276 }
277 }
278
279 if (!pFormatter)
280 return;
281
282 sal_uInt32 nFormat = 0;
283 bool bNumber = pFormatter->IsNumberFormat( rItem.maString.getString(), nFormat, rItem.mfVal);
284 rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
285
286 /* TODO: pFormatter currently is also used as a flag whether matching
287 * empty cells with an empty string is triggered from the interpreter.
288 * This could be handled independently if all queries should support
289 * it, needs to be evaluated if that actually is desired. */
290
291 // (empty = empty) is a match, and (empty <> not-empty) also is a
292 // match. (empty = 0) is not a match.
293 rItem.mbMatchEmpty = ((rEntry.eOp == SC_EQUAL && rItem.maString.isEmpty())
294 || (rEntry.eOp == SC_NOT_EQUAL && !rItem.maString.isEmpty()));
295 }
296
ScQueryParamTable()297 ScQueryParamTable::ScQueryParamTable() :
298 nCol1(0),nRow1(0),nCol2(0),nRow2(0),nTab(0)
299 {
300 }
301
~ScQueryParamTable()302 ScQueryParamTable::~ScQueryParamTable()
303 {
304 }
305
ScQueryParam()306 ScQueryParam::ScQueryParam() :
307 ScQueryParamBase(),
308 ScQueryParamTable(),
309 bDestPers(true),
310 nDestTab(0),
311 nDestCol(0),
312 nDestRow(0)
313 {
314 Clear();
315 }
316
317 ScQueryParam::ScQueryParam( const ScQueryParam& ) = default;
318
ScQueryParam(const ScDBQueryParamInternal & r)319 ScQueryParam::ScQueryParam( const ScDBQueryParamInternal& r ) :
320 ScQueryParamBase(r),
321 ScQueryParamTable(r),
322 bDestPers(true),
323 nDestTab(0),
324 nDestCol(0),
325 nDestRow(0)
326 {
327 }
328
~ScQueryParam()329 ScQueryParam::~ScQueryParam()
330 {
331 }
332
Clear()333 void ScQueryParam::Clear()
334 {
335 nCol1=nCol2 = 0;
336 nRow1=nRow2 = 0;
337 nTab = SCTAB_MAX;
338 eSearchType = utl::SearchParam::SearchType::Normal;
339 bHasHeader = bCaseSens = false;
340 bInplace = bByRow = bDuplicate = true;
341
342 for (auto & itr : m_Entries)
343 {
344 itr->Clear();
345 }
346
347 ClearDestParams();
348 }
349
ClearDestParams()350 void ScQueryParam::ClearDestParams()
351 {
352 bDestPers = true;
353 nDestTab = 0;
354 nDestCol = 0;
355 nDestRow = 0;
356 }
357
358 ScQueryParam& ScQueryParam::operator=( const ScQueryParam& ) = default;
359
operator ==(const ScQueryParam & rOther) const360 bool ScQueryParam::operator==( const ScQueryParam& rOther ) const
361 {
362 bool bEqual = false;
363
364 // Are the number of queries equal?
365 SCSIZE nUsed = 0;
366 SCSIZE nOtherUsed = 0;
367 SCSIZE nEntryCount = GetEntryCount();
368 SCSIZE nOtherEntryCount = rOther.GetEntryCount();
369
370 while (nUsed<nEntryCount && m_Entries[nUsed]->bDoQuery) ++nUsed;
371 while (nOtherUsed<nOtherEntryCount && rOther.m_Entries[nOtherUsed]->bDoQuery)
372 ++nOtherUsed;
373
374 if ( (nUsed == nOtherUsed)
375 && (nCol1 == rOther.nCol1)
376 && (nRow1 == rOther.nRow1)
377 && (nCol2 == rOther.nCol2)
378 && (nRow2 == rOther.nRow2)
379 && (nTab == rOther.nTab)
380 && (bHasHeader == rOther.bHasHeader)
381 && (bByRow == rOther.bByRow)
382 && (bInplace == rOther.bInplace)
383 && (bCaseSens == rOther.bCaseSens)
384 && (eSearchType == rOther.eSearchType)
385 && (bDuplicate == rOther.bDuplicate)
386 && (bDestPers == rOther.bDestPers)
387 && (nDestTab == rOther.nDestTab)
388 && (nDestCol == rOther.nDestCol)
389 && (nDestRow == rOther.nDestRow) )
390 {
391 bEqual = true;
392 for ( SCSIZE i=0; i<nUsed && bEqual; i++ )
393 bEqual = *m_Entries[i] == *rOther.m_Entries[i];
394 }
395 return bEqual;
396 }
397
MoveToDest()398 void ScQueryParam::MoveToDest()
399 {
400 if (!bInplace)
401 {
402 SCCOL nDifX = nDestCol - nCol1;
403 SCROW nDifY = nDestRow - nRow1;
404 SCTAB nDifZ = nDestTab - nTab;
405
406 nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nDifX );
407 nRow1 = sal::static_int_cast<SCROW>( nRow1 + nDifY );
408 nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nDifX );
409 nRow2 = sal::static_int_cast<SCROW>( nRow2 + nDifY );
410 nTab = sal::static_int_cast<SCTAB>( nTab + nDifZ );
411 size_t n = m_Entries.size();
412 for (size_t i=0; i<n; i++)
413 m_Entries[i]->nField += nDifX;
414
415 bInplace = true;
416 }
417 else
418 {
419 OSL_FAIL("MoveToDest, bInplace == TRUE");
420 }
421 }
422
ScDBQueryParamBase(DataType eType)423 ScDBQueryParamBase::ScDBQueryParamBase(DataType eType) :
424 ScQueryParamBase(),
425 mnField(-1),
426 mbSkipString(true),
427 meType(eType)
428 {
429 }
430
~ScDBQueryParamBase()431 ScDBQueryParamBase::~ScDBQueryParamBase()
432 {
433 }
434
ScDBQueryParamInternal()435 ScDBQueryParamInternal::ScDBQueryParamInternal() :
436 ScDBQueryParamBase(ScDBQueryParamBase::INTERNAL),
437 ScQueryParamTable()
438 {
439 }
440
~ScDBQueryParamInternal()441 ScDBQueryParamInternal::~ScDBQueryParamInternal()
442 {
443 }
444
IsValidFieldIndex() const445 bool ScDBQueryParamInternal::IsValidFieldIndex() const
446 {
447 return nCol1 <= mnField && mnField <= nCol2;
448 }
449
ScDBQueryParamMatrix()450 ScDBQueryParamMatrix::ScDBQueryParamMatrix() :
451 ScDBQueryParamBase(ScDBQueryParamBase::MATRIX)
452 {
453 }
454
IsValidFieldIndex() const455 bool ScDBQueryParamMatrix::IsValidFieldIndex() const
456 {
457 SCSIZE nC, nR;
458 mpMatrix->GetDimensions(nC, nR);
459 return 0 <= mnField && mnField <= static_cast<SCCOL>(nC);
460 }
461
~ScDBQueryParamMatrix()462 ScDBQueryParamMatrix::~ScDBQueryParamMatrix()
463 {
464 }
465
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
467