LibreOffice Module sc (master)  1
queryparam.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 <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:
39  explicit FindByField(SCCOLROW nField) : mnField(nField) {}
40  bool operator() (const std::unique_ptr<ScQueryEntry>& rpEntry) const
41  {
42  return rpEntry->bDoQuery && rpEntry->nField == mnField;
43  }
44 };
45 
46 struct FindUnused
47 {
48  bool operator() (const std::unique_ptr<ScQueryEntry>& rpEntry) const
49  {
50  return !rpEntry->bDoQuery;
51  }
52 };
53 
54 }
55 
57 {
58  return m_Entries.begin();
59 }
60 
62 {
63  return m_Entries.end();
64 }
65 
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 
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 
90 {
91  if (this != &r)
92  {
95  bByRow = r.bByRow;
96  bInplace = r.bInplace;
97  bCaseSens = r.bCaseSens;
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 
111 {
112 }
113 
115 {
116  return true;
117 }
118 
120 {
121  return m_Entries.size();
122 }
123 
125 {
126  return *m_Entries[n];
127 }
128 
130 {
131  return *m_Entries[n];
132 }
133 
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 
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 
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 
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 
200 {
201  while( RemoveEntryByField( nField ) ) {}
202 }
203 
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 
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())
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);
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 
298  nCol1(0),nRow1(0),nCol2(0),nRow2(0),nTab(0)
299 {
300 }
301 
303 {
304 }
305 
309  bDestPers(true),
310  nDestTab(0),
311  nDestCol(0),
312  nDestRow(0)
313 {
314  Clear();
315 }
316 
317 ScQueryParam::ScQueryParam( const ScQueryParam& ) = default;
318 
320  ScQueryParamBase(r),
322  bDestPers(true),
323  nDestTab(0),
324  nDestCol(0),
325  nDestRow(0)
326 {
327 }
328 
330 {
331 }
332 
334 {
335  nCol1=nCol2 = 0;
336  nRow1=nRow2 = 0;
337  nTab = SCTAB_MAX;
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 
351 {
352  bDestPers = true;
353  nDestTab = 0;
354  nDestCol = 0;
355  nDestRow = 0;
356 }
357 
359 
360 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 
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 
425  mnField(-1),
426  mbSkipString(true),
427  meType(eType)
428 {
429 }
430 
432 {
433 }
434 
438 {
439 }
440 
442 {
443 }
444 
446 {
447  return nCol1 <= mnField && mnField <= nCol2;
448 }
449 
452 {
453 }
454 
456 {
457  SCSIZE nC, nR;
458  mpMatrix->GetDimensions(nC, nR);
459  return 0 <= mnField && mnField <= static_cast<SCCOL>(nC);
460 }
461 
463 {
464 }
465 
466 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OUString getString() const
SharedString intern(const OUString &rStr)
ScQueryEntry * FindEntryByField(SCCOLROW nField, bool bNew)
Definition: queryparam.cxx:149
static SharedString getEmptyString()
virtual ~ScDBQueryParamInternal() override
Definition: queryparam.cxx:441
sal_Int64 n
virtual ~ScDBQueryParamMatrix() override
Definition: queryparam.cxx:462
SC_DLLPUBLIC bool RemoveEntryByField(SCCOLROW nField)
Definition: queryparam.cxx:180
void ClearDestParams()
Definition: queryparam.cxx:350
const_iterator end() const
Definition: queryparam.cxx:61
const Item & GetQueryItem() const
Definition: queryentry.cxx:118
virtual ~ScQueryParamBase()
Definition: queryparam.cxx:110
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:45
sal_Int32 SCCOLROW
a type capable of holding either SCCOL or SCROW
Definition: types.hxx:24
ScMatrixRef mpMatrix
Definition: queryparam.hxx:198
bool operator==(const ScQueryParam &rOther) const
Definition: queryparam.cxx:360
SC_DLLPUBLIC SCSIZE GetEntryCount() const
Definition: queryparam.cxx:119
SC_DLLPUBLIC const ScQueryEntry & GetEntry(SCSIZE n) const
Definition: queryparam.cxx:124
void FillInExcelSyntax(svl::SharedStringPool &rPool, const OUString &aCellStr, SCSIZE nIndex, SvNumberFormatter *pFormatter)
Definition: queryparam.cxx:223
EntriesType::const_iterator const_iterator
Definition: queryparam.hxx:72
SC_DLLPUBLIC void RemoveAllEntriesByField(SCCOLROW nField)
Definition: queryparam.cxx:199
EntriesType m_Entries
Definition: queryparam.hxx:82
const_iterator begin() const
Definition: queryparam.cxx:56
virtual ~ScQueryParam() override
Definition: queryparam.cxx:329
virtual bool IsValidFieldIndex() const override
Definition: queryparam.cxx:455
int i
bool isEmpty() const
sal_Int16 SCCOL
Definition: types.hxx:22
void Resize(size_t nNew)
Definition: queryparam.cxx:204
bool IsNumberFormat(const OUString &sString, sal_uInt32 &F_Index, double &fOutNumber, SvNumInputOptions eInputOptions=SvNumInputOptions::NONE)
bool mbRangeLookup
for spreadsheet functions like MATCH, LOOKUP, HLOOKUP, VLOOKUP
Definition: queryparam.hxx:50
virtual ~ScDBQueryParamBase() override
Definition: queryparam.cxx:431
svl::SharedString maString
Definition: queryentry.hxx:41
ScQueryParamBase & operator=(const ScQueryParamBase &r)
Definition: queryparam.cxx:89
ScDBQueryParamBase()=delete
sal_Int32 SCROW
Definition: types.hxx:18
SC_DLLPUBLIC ScQueryEntry & AppendEntry()
Definition: queryparam.cxx:134
virtual bool IsValidFieldIndex() const
Definition: queryparam.cxx:114
void MoveToDest()
Definition: queryparam.cxx:398
ScXMLEditAttributeMap::Entry const aEntries[]
ScQueryParam & operator=(const ScQueryParam &)
const SCTAB SCTAB_MAX
Definition: address.hxx:58
ScQueryOp eOp
Definition: queryentry.hxx:52
RedlineType meType
Each instance of this struct represents a single filtering criteria.
Definition: queryentry.hxx:33
utl::SearchParam::SearchType eSearchType
Definition: queryparam.hxx:44
sal_Int16 SCTAB
Definition: types.hxx:23
virtual bool IsValidFieldIndex() const override
Definition: queryparam.cxx:445
std::vector< ScQueryEntry * > FindAllEntriesByField(SCCOLROW nField)
Definition: queryparam.cxx:167
virtual ~ScQueryParamTable()
Definition: queryparam.cxx:302