Resolves: tdf#162093 TableRef item specifier may occur standalone
[LibreOffice.git] / sc / source / core / tool / queryparam.cxx
blobf270488c7e72ae9b8cac03e5f36d8e378ba3200b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <interpretercontext.hxx>
22 #include <queryparam.hxx>
23 #include <queryentry.hxx>
24 #include <scmatrix.hxx>
26 #include <svl/sharedstringpool.hxx>
27 #include <svl/numformat.hxx>
28 #include <o3tl/safeint.hxx>
29 #include <osl/diagnose.h>
31 #include <algorithm>
33 namespace {
35 const size_t MAXQUERY = 8;
37 class FindByField
39 SCCOLROW mnField;
40 public:
41 explicit FindByField(SCCOLROW nField) : mnField(nField) {}
42 bool operator() (const ScQueryEntry& rpEntry) const
44 return rpEntry.bDoQuery && rpEntry.nField == mnField;
48 struct FindUnused
50 bool operator() (const ScQueryEntry& rpEntry) const
52 return !rpEntry.bDoQuery;
58 ScQueryParamBase::const_iterator ScQueryParamBase::begin() const
60 return m_Entries.begin();
63 ScQueryParamBase::const_iterator ScQueryParamBase::end() const
65 return m_Entries.end();
68 ScQueryParamBase::ScQueryParamBase() :
69 eSearchType(utl::SearchParam::SearchType::Normal),
70 bHasHeader(true),
71 bByRow(true),
72 bInplace(true),
73 bCaseSens(false),
74 bDuplicate(false),
75 mbRangeLookup(false)
77 m_Entries.resize(MAXQUERY);
80 ScQueryParamBase::ScQueryParamBase(const ScQueryParamBase& r) :
81 eSearchType(r.eSearchType), bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace),
82 bCaseSens(r.bCaseSens), bDuplicate(r.bDuplicate), mbRangeLookup(r.mbRangeLookup),
83 m_Entries(r.m_Entries)
87 ScQueryParamBase& ScQueryParamBase::operator=(const ScQueryParamBase& r)
89 if (this != &r)
91 eSearchType = r.eSearchType;
92 bHasHeader = r.bHasHeader;
93 bByRow = r.bByRow;
94 bInplace = r.bInplace;
95 bCaseSens = r.bCaseSens;
96 bDuplicate = r.bDuplicate;
97 mbRangeLookup = r.mbRangeLookup;
98 m_Entries = r.m_Entries;
100 return *this;
103 ScQueryParamBase::~ScQueryParamBase()
107 bool ScQueryParamBase::IsValidFieldIndex() const
109 return true;
112 SCSIZE ScQueryParamBase::GetEntryCount() const
114 return m_Entries.size();
117 const ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n) const
119 return m_Entries[n];
122 ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n)
124 return m_Entries[n];
127 ScQueryEntry& ScQueryParamBase::AppendEntry()
129 // Find the first unused entry.
130 EntriesType::iterator itr = std::find_if(
131 m_Entries.begin(), m_Entries.end(), FindUnused());
133 if (itr != m_Entries.end())
134 // Found!
135 return *itr;
137 // Add a new entry to the end.
138 m_Entries.push_back(ScQueryEntry());
139 return m_Entries.back();
142 ScQueryEntry* ScQueryParamBase::FindEntryByField(SCCOLROW nField, bool bNew)
144 EntriesType::iterator itr = std::find_if(
145 m_Entries.begin(), m_Entries.end(), FindByField(nField));
147 if (itr != m_Entries.end())
149 // existing entry found!
150 return &*itr;
153 if (!bNew)
154 // no existing entry found, and we are not creating a new one.
155 return nullptr;
157 return &AppendEntry();
160 std::vector<ScQueryEntry*> ScQueryParamBase::FindAllEntriesByField(SCCOLROW nField)
162 std::vector<ScQueryEntry*> aEntries;
164 auto fFind = FindByField(nField);
166 for (auto& rxEntry : m_Entries)
167 if (fFind(rxEntry))
168 aEntries.push_back(&rxEntry);
170 return aEntries;
173 bool ScQueryParamBase::RemoveEntryByField(SCCOLROW nField)
175 EntriesType::iterator itr = std::find_if(
176 m_Entries.begin(), m_Entries.end(), FindByField(nField));
177 bool bRet = false;
179 if (itr != m_Entries.end())
181 m_Entries.erase(itr);
182 if (m_Entries.size() < MAXQUERY)
183 // Make sure that we have at least MAXQUERY number of entries at
184 // all times.
185 m_Entries.resize(MAXQUERY);
186 bRet = true;
189 return bRet;
192 void ScQueryParamBase::RemoveAllEntriesByField(SCCOLROW nField)
194 while( RemoveEntryByField( nField ) ) {}
197 void ScQueryParamBase::Resize(size_t nNew)
199 if (nNew < MAXQUERY)
200 nNew = MAXQUERY; // never less than MAXQUERY
202 m_Entries.resize(nNew);
205 void ScQueryParamBase::FillInExcelSyntax(
206 svl::SharedStringPool& rPool, const OUString& rCellStr, SCSIZE nIndex, ScInterpreterContext* pContext )
208 if (nIndex >= m_Entries.size())
209 Resize(nIndex+1);
211 ScQueryEntry& rEntry = GetEntry(nIndex);
212 ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
213 bool bByEmpty = false;
214 bool bByNonEmpty = false;
216 if (rCellStr.isEmpty())
217 rItem.maString = svl::SharedString::getEmptyString();
218 else
220 rEntry.bDoQuery = true;
221 // Operatoren herausfiltern
222 if (rCellStr[0] == '<')
224 if (rCellStr.getLength() > 1 && rCellStr[1] == '>')
226 rItem.maString = rPool.intern(rCellStr.copy(2));
227 rEntry.eOp = SC_NOT_EQUAL;
228 if (rCellStr.getLength() == 2)
229 bByNonEmpty = true;
231 else if (rCellStr.getLength() > 1 && rCellStr[1] == '=')
233 rItem.maString = rPool.intern(rCellStr.copy(2));
234 rEntry.eOp = SC_LESS_EQUAL;
236 else
238 rItem.maString = rPool.intern(rCellStr.copy(1));
239 rEntry.eOp = SC_LESS;
242 else if (rCellStr[0]== '>')
244 if (rCellStr.getLength() > 1 && rCellStr[1] == '=')
246 rItem.maString = rPool.intern(rCellStr.copy(2));
247 rEntry.eOp = SC_GREATER_EQUAL;
249 else
251 rItem.maString = rPool.intern(rCellStr.copy(1));
252 rEntry.eOp = SC_GREATER;
255 else
257 if (rCellStr[0] == '=')
259 rItem.maString = rPool.intern(rCellStr.copy(1));
260 if (rCellStr.getLength() == 1)
261 bByEmpty = true;
263 else
264 rItem.maString = rPool.intern(rCellStr);
265 rEntry.eOp = SC_EQUAL;
269 if (!pContext)
270 return;
272 /* TODO: pContext currently is also used as a flag whether matching
273 * empty cells with an empty string is triggered from the interpreter.
274 * This could be handled independently if all queries should support
275 * it, needs to be evaluated if that actually is desired. */
277 // Interpreter queries have only one query, also QueryByEmpty and
278 // QueryByNonEmpty rely on that.
279 if (nIndex != 0)
280 return;
282 // (empty = empty) is a match, and (empty <> not-empty) also is a
283 // match. (empty = 0) is not a match.
284 rItem.mbMatchEmpty = ((rEntry.eOp == SC_EQUAL && rItem.maString.isEmpty())
285 || (rEntry.eOp == SC_NOT_EQUAL && !rItem.maString.isEmpty()));
287 // SetQueryBy override item members with special values, so do this last.
288 if (bByEmpty)
289 rEntry.SetQueryByEmpty();
290 else if (bByNonEmpty)
291 rEntry.SetQueryByNonEmpty();
292 else
294 sal_uInt32 nFormat = 0;
295 bool bNumber = pContext->NFIsNumberFormat( rItem.maString.getString(), nFormat, rItem.mfVal);
296 rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
300 ScQueryParamTable::ScQueryParamTable() :
301 nCol1(0),nRow1(0),nCol2(0),nRow2(0),nTab(0)
305 ScQueryParamTable::~ScQueryParamTable()
309 ScQueryParam::ScQueryParam() :
310 bDestPers(true),
311 nDestTab(0),
312 nDestCol(0),
313 nDestRow(0)
315 Clear();
318 ScQueryParam::ScQueryParam( const ScQueryParam& ) = default;
320 ScQueryParam::ScQueryParam( const ScDBQueryParamInternal& r ) :
321 ScQueryParamBase(r),
322 ScQueryParamTable(r),
323 bDestPers(true),
324 nDestTab(0),
325 nDestCol(0),
326 nDestRow(0)
330 ScQueryParam::~ScQueryParam()
334 void ScQueryParam::Clear()
336 nCol1=nCol2 = 0;
337 nRow1=nRow2 = 0;
338 nTab = SCTAB_MAX;
339 eSearchType = utl::SearchParam::SearchType::Normal;
340 bHasHeader = bCaseSens = false;
341 bInplace = bByRow = bDuplicate = true;
343 for (auto & itr : m_Entries)
345 itr.Clear();
348 ClearDestParams();
351 void ScQueryParam::ClearDestParams()
353 bDestPers = true;
354 nDestTab = 0;
355 nDestCol = 0;
356 nDestRow = 0;
359 ScQueryParam& ScQueryParam::operator=( const ScQueryParam& ) = default;
361 bool ScQueryParam::operator==( const ScQueryParam& rOther ) const
363 bool bEqual = false;
365 // Are the number of queries equal?
366 SCSIZE nUsed = 0;
367 SCSIZE nOtherUsed = 0;
368 SCSIZE nEntryCount = GetEntryCount();
369 SCSIZE nOtherEntryCount = rOther.GetEntryCount();
371 while (nUsed<nEntryCount && m_Entries[nUsed].bDoQuery) ++nUsed;
372 while (nOtherUsed<nOtherEntryCount && rOther.m_Entries[nOtherUsed].bDoQuery)
373 ++nOtherUsed;
375 if ( (nUsed == nOtherUsed)
376 && (nCol1 == rOther.nCol1)
377 && (nRow1 == rOther.nRow1)
378 && (nCol2 == rOther.nCol2)
379 && (nRow2 == rOther.nRow2)
380 && (nTab == rOther.nTab)
381 && (bHasHeader == rOther.bHasHeader)
382 && (bByRow == rOther.bByRow)
383 && (bInplace == rOther.bInplace)
384 && (bCaseSens == rOther.bCaseSens)
385 && (eSearchType == rOther.eSearchType)
386 && (bDuplicate == rOther.bDuplicate)
387 && (bDestPers == rOther.bDestPers)
388 && (nDestTab == rOther.nDestTab)
389 && (nDestCol == rOther.nDestCol)
390 && (nDestRow == rOther.nDestRow) )
392 bEqual = true;
393 for ( SCSIZE i=0; i<nUsed && bEqual; i++ )
394 bEqual = m_Entries[i] == rOther.m_Entries[i];
396 return bEqual;
399 void ScQueryParam::MoveToDest()
401 if (!bInplace)
403 SCCOL nDifX = nDestCol - nCol1;
404 SCROW nDifY = nDestRow - nRow1;
405 SCTAB nDifZ = nDestTab - nTab;
407 nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nDifX );
408 nRow1 = sal::static_int_cast<SCROW>( nRow1 + nDifY );
409 nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nDifX );
410 nRow2 = sal::static_int_cast<SCROW>( nRow2 + nDifY );
411 nTab = sal::static_int_cast<SCTAB>( nTab + nDifZ );
412 size_t n = m_Entries.size();
413 for (size_t i=0; i<n; i++)
414 m_Entries[i].nField += nDifX;
416 bInplace = true;
418 else
420 OSL_FAIL("MoveToDest, bInplace == TRUE");
424 ScDBQueryParamBase::ScDBQueryParamBase(DataType eType) :
425 mnField(-1),
426 mbSkipString(true),
427 meType(eType)
431 ScDBQueryParamBase::~ScDBQueryParamBase()
435 ScDBQueryParamInternal::ScDBQueryParamInternal() :
436 ScDBQueryParamBase(ScDBQueryParamBase::INTERNAL)
440 ScDBQueryParamInternal::~ScDBQueryParamInternal()
444 bool ScDBQueryParamInternal::IsValidFieldIndex() const
446 return nCol1 <= mnField && mnField <= nCol2;
449 ScDBQueryParamMatrix::ScDBQueryParamMatrix() :
450 ScDBQueryParamBase(ScDBQueryParamBase::MATRIX)
454 bool ScDBQueryParamMatrix::IsValidFieldIndex() const
456 SCSIZE nC, nR;
457 mpMatrix->GetDimensions(nC, nR);
458 return 0 <= mnField && o3tl::make_unsigned(mnField) <= nC;
461 ScDBQueryParamMatrix::~ScDBQueryParamMatrix()
465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */