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