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