tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / tool / queryparam.cxx
blobaafe0d891951d5340b055b25e1f4576e2a98ccb7
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 bHasTotals(false),
72 bByRow(true),
73 bInplace(true),
74 bCaseSens(false),
75 bDuplicate(false),
76 mbRangeLookup(false)
78 m_Entries.resize(MAXQUERY);
81 ScQueryParamBase::ScQueryParamBase(const ScQueryParamBase& r) :
82 eSearchType(r.eSearchType), bHasHeader(r.bHasHeader), bHasTotals(r.bHasTotals), bByRow(r.bByRow),
83 bInplace(r.bInplace), bCaseSens(r.bCaseSens), bDuplicate(r.bDuplicate),
84 mbRangeLookup(r.mbRangeLookup), m_Entries(r.m_Entries)
88 ScQueryParamBase& ScQueryParamBase::operator=(const ScQueryParamBase& r)
90 if (this != &r)
92 eSearchType = r.eSearchType;
93 bHasHeader = r.bHasHeader;
94 bHasTotals = r.bHasTotals;
95 bByRow = r.bByRow;
96 bInplace = r.bInplace;
97 bCaseSens = r.bCaseSens;
98 bDuplicate = r.bDuplicate;
99 mbRangeLookup = r.mbRangeLookup;
100 m_Entries = r.m_Entries;
102 return *this;
105 ScQueryParamBase::~ScQueryParamBase()
109 bool ScQueryParamBase::IsValidFieldIndex() const
111 return true;
114 SCSIZE ScQueryParamBase::GetEntryCount() const
116 return m_Entries.size();
119 const ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n) const
121 return m_Entries[n];
124 ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n)
126 return m_Entries[n];
129 ScQueryEntry& ScQueryParamBase::AppendEntry()
131 // Find the first unused entry.
132 EntriesType::iterator itr = std::find_if(
133 m_Entries.begin(), m_Entries.end(), FindUnused());
135 if (itr != m_Entries.end())
136 // Found!
137 return *itr;
139 // Add a new entry to the end.
140 m_Entries.push_back(ScQueryEntry());
141 return m_Entries.back();
144 ScQueryEntry* ScQueryParamBase::FindEntryByField(SCCOLROW nField, bool bNew)
146 EntriesType::iterator itr = std::find_if(
147 m_Entries.begin(), m_Entries.end(), FindByField(nField));
149 if (itr != m_Entries.end())
151 // existing entry found!
152 return &*itr;
155 if (!bNew)
156 // no existing entry found, and we are not creating a new one.
157 return nullptr;
159 return &AppendEntry();
162 std::vector<ScQueryEntry*> ScQueryParamBase::FindAllEntriesByField(SCCOLROW nField)
164 std::vector<ScQueryEntry*> aEntries;
166 auto fFind = FindByField(nField);
168 for (auto& rxEntry : m_Entries)
169 if (fFind(rxEntry))
170 aEntries.push_back(&rxEntry);
172 return aEntries;
175 bool ScQueryParamBase::RemoveEntryByField(SCCOLROW nField)
177 EntriesType::iterator itr = std::find_if(
178 m_Entries.begin(), m_Entries.end(), FindByField(nField));
179 bool bRet = false;
181 if (itr != m_Entries.end())
183 m_Entries.erase(itr);
184 if (m_Entries.size() < MAXQUERY)
185 // Make sure that we have at least MAXQUERY number of entries at
186 // all times.
187 m_Entries.resize(MAXQUERY);
188 bRet = true;
191 return bRet;
194 void ScQueryParamBase::RemoveAllEntriesByField(SCCOLROW nField)
196 while( RemoveEntryByField( nField ) ) {}
199 void ScQueryParamBase::Resize(size_t nNew)
201 if (nNew < MAXQUERY)
202 nNew = MAXQUERY; // never less than MAXQUERY
204 m_Entries.resize(nNew);
207 void ScQueryParamBase::FillInExcelSyntax(
208 svl::SharedStringPool& rPool, const OUString& rCellStr, SCSIZE nIndex, ScInterpreterContext* pContext )
210 if (nIndex >= m_Entries.size())
211 Resize(nIndex+1);
213 ScQueryEntry& rEntry = GetEntry(nIndex);
214 ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
215 bool bByEmpty = false;
216 bool bByNonEmpty = false;
218 if (rCellStr.isEmpty())
219 rItem.maString = svl::SharedString::getEmptyString();
220 else
222 rEntry.bDoQuery = true;
223 // Operatoren herausfiltern
224 if (rCellStr[0] == '<')
226 if (rCellStr.getLength() > 1 && rCellStr[1] == '>')
228 rItem.maString = rPool.intern(rCellStr.copy(2));
229 rEntry.eOp = SC_NOT_EQUAL;
230 if (rCellStr.getLength() == 2)
231 bByNonEmpty = true;
233 else if (rCellStr.getLength() > 1 && rCellStr[1] == '=')
235 rItem.maString = rPool.intern(rCellStr.copy(2));
236 rEntry.eOp = SC_LESS_EQUAL;
238 else
240 rItem.maString = rPool.intern(rCellStr.copy(1));
241 rEntry.eOp = SC_LESS;
244 else if (rCellStr[0]== '>')
246 if (rCellStr.getLength() > 1 && rCellStr[1] == '=')
248 rItem.maString = rPool.intern(rCellStr.copy(2));
249 rEntry.eOp = SC_GREATER_EQUAL;
251 else
253 rItem.maString = rPool.intern(rCellStr.copy(1));
254 rEntry.eOp = SC_GREATER;
257 else
259 if (rCellStr[0] == '=')
261 rItem.maString = rPool.intern(rCellStr.copy(1));
262 if (rCellStr.getLength() == 1)
263 bByEmpty = true;
265 else
266 rItem.maString = rPool.intern(rCellStr);
267 rEntry.eOp = SC_EQUAL;
271 if (!pContext)
272 return;
274 /* TODO: pContext currently is also used as a flag whether matching
275 * empty cells with an empty string is triggered from the interpreter.
276 * This could be handled independently if all queries should support
277 * it, needs to be evaluated if that actually is desired. */
279 // Interpreter queries have only one query, also QueryByEmpty and
280 // QueryByNonEmpty rely on that.
281 if (nIndex != 0)
282 return;
284 // (empty = empty) is a match, and (empty <> not-empty) also is a
285 // match. (empty = 0) is not a match.
286 rItem.mbMatchEmpty = ((rEntry.eOp == SC_EQUAL && rItem.maString.isEmpty())
287 || (rEntry.eOp == SC_NOT_EQUAL && !rItem.maString.isEmpty()));
289 // SetQueryBy override item members with special values, so do this last.
290 if (bByEmpty)
291 rEntry.SetQueryByEmpty();
292 else if (bByNonEmpty)
293 rEntry.SetQueryByNonEmpty();
294 else
296 sal_uInt32 nFormat = 0;
297 bool bNumber = pContext->NFIsNumberFormat( rItem.maString.getString(), nFormat, rItem.mfVal);
298 rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
302 ScQueryParamTable::ScQueryParamTable() :
303 nCol1(0),nRow1(0),nCol2(0),nRow2(0),nTab(0)
307 ScQueryParamTable::~ScQueryParamTable()
311 ScQueryParam::ScQueryParam() :
312 bDestPers(true),
313 nDestTab(0),
314 nDestCol(0),
315 nDestRow(0)
317 Clear();
320 ScQueryParam::ScQueryParam( const ScQueryParam& ) = default;
322 ScQueryParam::ScQueryParam( const ScDBQueryParamInternal& r ) :
323 ScQueryParamBase(r),
324 ScQueryParamTable(r),
325 bDestPers(true),
326 nDestTab(0),
327 nDestCol(0),
328 nDestRow(0)
332 ScQueryParam::~ScQueryParam()
336 void ScQueryParam::Clear()
338 nCol1=nCol2 = 0;
339 nRow1=nRow2 = 0;
340 nTab = SCTAB_MAX;
341 eSearchType = utl::SearchParam::SearchType::Normal;
342 bHasHeader = bHasTotals = bCaseSens = false;
343 bInplace = bByRow = bDuplicate = true;
345 for (auto & itr : m_Entries)
347 itr.Clear();
350 ClearDestParams();
353 void ScQueryParam::ClearDestParams()
355 bDestPers = true;
356 nDestTab = 0;
357 nDestCol = 0;
358 nDestRow = 0;
361 ScQueryParam& ScQueryParam::operator=( const ScQueryParam& ) = default;
363 bool ScQueryParam::operator==( const ScQueryParam& rOther ) const
365 bool bEqual = false;
367 // Are the number of queries equal?
368 SCSIZE nUsed = 0;
369 SCSIZE nOtherUsed = 0;
370 SCSIZE nEntryCount = GetEntryCount();
371 SCSIZE nOtherEntryCount = rOther.GetEntryCount();
373 while (nUsed<nEntryCount && m_Entries[nUsed].bDoQuery) ++nUsed;
374 while (nOtherUsed<nOtherEntryCount && rOther.m_Entries[nOtherUsed].bDoQuery)
375 ++nOtherUsed;
377 if ( (nUsed == nOtherUsed)
378 && (nCol1 == rOther.nCol1)
379 && (nRow1 == rOther.nRow1)
380 && (nCol2 == rOther.nCol2)
381 && (nRow2 == rOther.nRow2)
382 && (nTab == rOther.nTab)
383 && (bHasHeader == rOther.bHasHeader)
384 && (bHasTotals == rOther.bHasTotals)
385 && (bByRow == rOther.bByRow)
386 && (bInplace == rOther.bInplace)
387 && (bCaseSens == rOther.bCaseSens)
388 && (eSearchType == rOther.eSearchType)
389 && (bDuplicate == rOther.bDuplicate)
390 && (bDestPers == rOther.bDestPers)
391 && (nDestTab == rOther.nDestTab)
392 && (nDestCol == rOther.nDestCol)
393 && (nDestRow == rOther.nDestRow) )
395 bEqual = true;
396 for ( SCSIZE i=0; i<nUsed && bEqual; i++ )
397 bEqual = m_Entries[i] == rOther.m_Entries[i];
399 return bEqual;
402 void ScQueryParam::MoveToDest()
404 if (!bInplace)
406 SCCOL nDifX = nDestCol - nCol1;
407 SCROW nDifY = nDestRow - nRow1;
408 SCTAB nDifZ = nDestTab - nTab;
410 nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nDifX );
411 nRow1 = sal::static_int_cast<SCROW>( nRow1 + nDifY );
412 nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nDifX );
413 nRow2 = sal::static_int_cast<SCROW>( nRow2 + nDifY );
414 nTab = sal::static_int_cast<SCTAB>( nTab + nDifZ );
415 size_t n = m_Entries.size();
416 for (size_t i=0; i<n; i++)
417 m_Entries[i].nField += nDifX;
419 bInplace = true;
421 else
423 OSL_FAIL("MoveToDest, bInplace == TRUE");
427 ScDBQueryParamBase::ScDBQueryParamBase(DataType eType) :
428 mnField(-1),
429 mbSkipString(true),
430 meType(eType)
434 ScDBQueryParamBase::~ScDBQueryParamBase()
438 ScDBQueryParamInternal::ScDBQueryParamInternal() :
439 ScDBQueryParamBase(ScDBQueryParamBase::INTERNAL)
443 ScDBQueryParamInternal::~ScDBQueryParamInternal()
447 bool ScDBQueryParamInternal::IsValidFieldIndex() const
449 return nCol1 <= mnField && mnField <= nCol2;
452 ScDBQueryParamMatrix::ScDBQueryParamMatrix() :
453 ScDBQueryParamBase(ScDBQueryParamBase::MATRIX)
457 bool ScDBQueryParamMatrix::IsValidFieldIndex() const
459 SCSIZE nC, nR;
460 mpMatrix->GetDimensions(nC, nR);
461 return 0 <= mnField && o3tl::make_unsigned(mnField) <= nC;
464 ScDBQueryParamMatrix::~ScDBQueryParamMatrix()
468 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */