1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
35 const size_t MAXQUERY
= 8;
41 explicit FindByField(SCCOLROW nField
) : mnField(nField
) {}
42 bool operator() (const ScQueryEntry
& rpEntry
) const
44 return rpEntry
.bDoQuery
&& rpEntry
.nField
== mnField
;
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
),
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
)
92 eSearchType
= r
.eSearchType
;
93 bHasHeader
= r
.bHasHeader
;
94 bHasTotals
= r
.bHasTotals
;
96 bInplace
= r
.bInplace
;
97 bCaseSens
= r
.bCaseSens
;
98 bDuplicate
= r
.bDuplicate
;
99 mbRangeLookup
= r
.mbRangeLookup
;
100 m_Entries
= r
.m_Entries
;
105 ScQueryParamBase::~ScQueryParamBase()
109 bool ScQueryParamBase::IsValidFieldIndex() const
114 SCSIZE
ScQueryParamBase::GetEntryCount() const
116 return m_Entries
.size();
119 const ScQueryEntry
& ScQueryParamBase::GetEntry(SCSIZE n
) const
124 ScQueryEntry
& ScQueryParamBase::GetEntry(SCSIZE 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())
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!
156 // no existing entry found, and we are not creating a new one.
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
)
170 aEntries
.push_back(&rxEntry
);
175 bool ScQueryParamBase::RemoveEntryByField(SCCOLROW nField
)
177 EntriesType::iterator itr
= std::find_if(
178 m_Entries
.begin(), m_Entries
.end(), FindByField(nField
));
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
187 m_Entries
.resize(MAXQUERY
);
194 void ScQueryParamBase::RemoveAllEntriesByField(SCCOLROW nField
)
196 while( RemoveEntryByField( nField
) ) {}
199 void ScQueryParamBase::Resize(size_t nNew
)
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())
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();
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)
233 else if (rCellStr
.getLength() > 1 && rCellStr
[1] == '=')
235 rItem
.maString
= rPool
.intern(rCellStr
.copy(2));
236 rEntry
.eOp
= SC_LESS_EQUAL
;
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
;
253 rItem
.maString
= rPool
.intern(rCellStr
.copy(1));
254 rEntry
.eOp
= SC_GREATER
;
259 if (rCellStr
[0] == '=')
261 rItem
.maString
= rPool
.intern(rCellStr
.copy(1));
262 if (rCellStr
.getLength() == 1)
266 rItem
.maString
= rPool
.intern(rCellStr
);
267 rEntry
.eOp
= SC_EQUAL
;
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.
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.
291 rEntry
.SetQueryByEmpty();
292 else if (bByNonEmpty
)
293 rEntry
.SetQueryByNonEmpty();
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() :
320 ScQueryParam::ScQueryParam( const ScQueryParam
& ) = default;
322 ScQueryParam::ScQueryParam( const ScDBQueryParamInternal
& r
) :
324 ScQueryParamTable(r
),
332 ScQueryParam::~ScQueryParam()
336 void ScQueryParam::Clear()
341 eSearchType
= utl::SearchParam::SearchType::Normal
;
342 bHasHeader
= bHasTotals
= bCaseSens
= false;
343 bInplace
= bByRow
= bDuplicate
= true;
345 for (auto & itr
: m_Entries
)
353 void ScQueryParam::ClearDestParams()
361 ScQueryParam
& ScQueryParam::operator=( const ScQueryParam
& ) = default;
363 bool ScQueryParam::operator==( const ScQueryParam
& rOther
) const
367 // Are the number of queries equal?
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
)
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
) )
396 for ( SCSIZE i
=0; i
<nUsed
&& bEqual
; i
++ )
397 bEqual
= m_Entries
[i
] == rOther
.m_Entries
[i
];
402 void ScQueryParam::MoveToDest()
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
;
423 OSL_FAIL("MoveToDest, bInplace == TRUE");
427 ScDBQueryParamBase::ScDBQueryParamBase(DataType 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
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: */