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 <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 ScQueryEntry& rpEntry) const
41  {
42  return rpEntry.bDoQuery && rpEntry.nField == mnField;
43  }
44 };
45 
46 struct FindUnused
47 {
48  bool operator() (const 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  m_Entries.resize(MAXQUERY);
76 }
77 
79  eSearchType(r.eSearchType), bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace),
80  bCaseSens(r.bCaseSens), bDuplicate(r.bDuplicate), mbRangeLookup(r.mbRangeLookup),
81  m_Entries(r.m_Entries)
82 {
83 }
84 
86 {
87  if (this != &r)
88  {
91  bByRow = r.bByRow;
92  bInplace = r.bInplace;
93  bCaseSens = r.bCaseSens;
96  m_Entries = r.m_Entries;
97  }
98  return *this;
99 }
100 
102 {
103 }
104 
106 {
107  return true;
108 }
109 
111 {
112  return m_Entries.size();
113 }
114 
116 {
117  return m_Entries[n];
118 }
119 
121 {
122  return m_Entries[n];
123 }
124 
126 {
127  // Find the first unused entry.
128  EntriesType::iterator itr = std::find_if(
129  m_Entries.begin(), m_Entries.end(), FindUnused());
130 
131  if (itr != m_Entries.end())
132  // Found!
133  return *itr;
134 
135  // Add a new entry to the end.
136  m_Entries.push_back(ScQueryEntry());
137  return m_Entries.back();
138 }
139 
141 {
142  EntriesType::iterator itr = std::find_if(
143  m_Entries.begin(), m_Entries.end(), FindByField(nField));
144 
145  if (itr != m_Entries.end())
146  {
147  // existing entry found!
148  return &*itr;
149  }
150 
151  if (!bNew)
152  // no existing entry found, and we are not creating a new one.
153  return nullptr;
154 
155  return &AppendEntry();
156 }
157 
158 std::vector<ScQueryEntry*> ScQueryParamBase::FindAllEntriesByField(SCCOLROW nField)
159 {
160  std::vector<ScQueryEntry*> aEntries;
161 
162  auto fFind = FindByField(nField);
163 
164  for (auto& rxEntry : m_Entries)
165  if (fFind(rxEntry))
166  aEntries.push_back(&rxEntry);
167 
168  return aEntries;
169 }
170 
172 {
173  EntriesType::iterator itr = std::find_if(
174  m_Entries.begin(), m_Entries.end(), FindByField(nField));
175  bool bRet = false;
176 
177  if (itr != m_Entries.end())
178  {
179  m_Entries.erase(itr);
180  if (m_Entries.size() < MAXQUERY)
181  // Make sure that we have at least MAXQUERY number of entries at
182  // all times.
183  m_Entries.resize(MAXQUERY);
184  bRet = true;
185  }
186 
187  return bRet;
188 }
189 
191 {
192  while( RemoveEntryByField( nField ) ) {}
193 }
194 
195 void ScQueryParamBase::Resize(size_t nNew)
196 {
197  if (nNew < MAXQUERY)
198  nNew = MAXQUERY; // never less than MAXQUERY
199 
200  m_Entries.resize(nNew);
201 }
202 
204  svl::SharedStringPool& rPool, const OUString& rCellStr, SCSIZE nIndex, SvNumberFormatter* pFormatter )
205 {
206  if (nIndex >= m_Entries.size())
207  Resize(nIndex+1);
208 
209  ScQueryEntry& rEntry = GetEntry(nIndex);
210  ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
211  bool bByEmpty = false;
212  bool bByNonEmpty = false;
213 
214  if (rCellStr.isEmpty())
216  else
217  {
218  rEntry.bDoQuery = true;
219  // Operatoren herausfiltern
220  if (rCellStr[0] == '<')
221  {
222  if (rCellStr.getLength() > 1 && rCellStr[1] == '>')
223  {
224  rItem.maString = rPool.intern(rCellStr.copy(2));
225  rEntry.eOp = SC_NOT_EQUAL;
226  if (rCellStr.getLength() == 2)
227  bByNonEmpty = true;
228  }
229  else if (rCellStr.getLength() > 1 && rCellStr[1] == '=')
230  {
231  rItem.maString = rPool.intern(rCellStr.copy(2));
232  rEntry.eOp = SC_LESS_EQUAL;
233  }
234  else
235  {
236  rItem.maString = rPool.intern(rCellStr.copy(1));
237  rEntry.eOp = SC_LESS;
238  }
239  }
240  else if (rCellStr[0]== '>')
241  {
242  if (rCellStr.getLength() > 1 && rCellStr[1] == '=')
243  {
244  rItem.maString = rPool.intern(rCellStr.copy(2));
245  rEntry.eOp = SC_GREATER_EQUAL;
246  }
247  else
248  {
249  rItem.maString = rPool.intern(rCellStr.copy(1));
250  rEntry.eOp = SC_GREATER;
251  }
252  }
253  else
254  {
255  if (rCellStr[0] == '=')
256  {
257  rItem.maString = rPool.intern(rCellStr.copy(1));
258  if (rCellStr.getLength() == 1)
259  bByEmpty = true;
260  }
261  else
262  rItem.maString = rPool.intern(rCellStr);
263  rEntry.eOp = SC_EQUAL;
264  }
265  }
266 
267  if (!pFormatter)
268  return;
269 
270  /* TODO: pFormatter currently is also used as a flag whether matching
271  * empty cells with an empty string is triggered from the interpreter.
272  * This could be handled independently if all queries should support
273  * it, needs to be evaluated if that actually is desired. */
274 
275  // Interpreter queries have only one query, also QueryByEmpty and
276  // QueryByNonEmpty rely on that.
277  if (nIndex != 0)
278  return;
279 
280  // (empty = empty) is a match, and (empty <> not-empty) also is a
281  // match. (empty = 0) is not a match.
282  rItem.mbMatchEmpty = ((rEntry.eOp == SC_EQUAL && rItem.maString.isEmpty())
283  || (rEntry.eOp == SC_NOT_EQUAL && !rItem.maString.isEmpty()));
284 
285  // SetQueryBy override item members with special values, so do this last.
286  if (bByEmpty)
287  rEntry.SetQueryByEmpty();
288  else if (bByNonEmpty)
289  rEntry.SetQueryByNonEmpty();
290  else
291  {
292  sal_uInt32 nFormat = 0;
293  bool bNumber = pFormatter->IsNumberFormat( rItem.maString.getString(), nFormat, rItem.mfVal);
295  }
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: */
void SetQueryByEmpty()
Definition: queryentry.cxx:77
OUString getString() const
SharedString intern(const OUString &rStr)
ScQueryEntry * FindEntryByField(SCCOLROW nField, bool bNew)
Definition: queryparam.cxx:140
const Item & GetQueryItem() const
Definition: queryentry.hxx:85
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:171
SCCOLROW nField
Definition: queryentry.hxx:61
static const SharedString & getEmptyString()
void ClearDestParams()
Definition: queryparam.cxx:349
const_iterator end() const
Definition: queryparam.cxx:61
virtual ~ScQueryParamBase()
Definition: queryparam.cxx:101
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:110
SC_DLLPUBLIC const ScQueryEntry & GetEntry(SCSIZE n) const
Definition: queryparam.cxx:115
void FillInExcelSyntax(svl::SharedStringPool &rPool, const OUString &aCellStr, SCSIZE nIndex, SvNumberFormatter *pFormatter)
Definition: queryparam.cxx:203
EntriesType::const_iterator const_iterator
Definition: queryparam.hxx:71
SC_DLLPUBLIC void RemoveAllEntriesByField(SCCOLROW nField)
Definition: queryparam.cxx:190
EntriesType m_Entries
Definition: queryparam.hxx:81
const_iterator begin() const
Definition: queryparam.cxx:56
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:195
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:85
ScDBQueryParamBase()=delete
sal_Int32 SCROW
Definition: types.hxx:17
SC_DLLPUBLIC ScQueryEntry & AppendEntry()
Definition: queryparam.cxx:125
virtual bool IsValidFieldIndex() const
Definition: queryparam.cxx:105
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:62
RedlineType meType
Each instance of this struct represents a single filtering criteria.
Definition: queryentry.hxx:33
void SetQueryByNonEmpty()
Definition: queryentry.cxx:99
utl::SearchParam::SearchType eSearchType
Definition: queryparam.hxx:43
sal_Int16 SCTAB
Definition: types.hxx:22
bool m_bDetectedRangeSegmentation false
virtual bool IsValidFieldIndex() const override
Definition: queryparam.cxx:442
std::vector< ScQueryEntry * > FindAllEntriesByField(SCCOLROW nField)
Definition: queryparam.cxx:158
virtual ~ScQueryParamTable()
Definition: queryparam.cxx:303