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
),
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
)
91 eSearchType
= r
.eSearchType
;
92 bHasHeader
= r
.bHasHeader
;
94 bInplace
= r
.bInplace
;
95 bCaseSens
= r
.bCaseSens
;
96 bDuplicate
= r
.bDuplicate
;
97 mbRangeLookup
= r
.mbRangeLookup
;
98 m_Entries
= r
.m_Entries
;
103 ScQueryParamBase::~ScQueryParamBase()
107 bool ScQueryParamBase::IsValidFieldIndex() const
112 SCSIZE
ScQueryParamBase::GetEntryCount() const
114 return m_Entries
.size();
117 const ScQueryEntry
& ScQueryParamBase::GetEntry(SCSIZE n
) const
122 ScQueryEntry
& ScQueryParamBase::GetEntry(SCSIZE 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())
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!
154 // no existing entry found, and we are not creating a new one.
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
)
168 aEntries
.push_back(&rxEntry
);
173 bool ScQueryParamBase::RemoveEntryByField(SCCOLROW nField
)
175 EntriesType::iterator itr
= std::find_if(
176 m_Entries
.begin(), m_Entries
.end(), FindByField(nField
));
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
185 m_Entries
.resize(MAXQUERY
);
192 void ScQueryParamBase::RemoveAllEntriesByField(SCCOLROW nField
)
194 while( RemoveEntryByField( nField
) ) {}
197 void ScQueryParamBase::Resize(size_t nNew
)
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())
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();
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)
231 else if (rCellStr
.getLength() > 1 && rCellStr
[1] == '=')
233 rItem
.maString
= rPool
.intern(rCellStr
.copy(2));
234 rEntry
.eOp
= SC_LESS_EQUAL
;
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
;
251 rItem
.maString
= rPool
.intern(rCellStr
.copy(1));
252 rEntry
.eOp
= SC_GREATER
;
257 if (rCellStr
[0] == '=')
259 rItem
.maString
= rPool
.intern(rCellStr
.copy(1));
260 if (rCellStr
.getLength() == 1)
264 rItem
.maString
= rPool
.intern(rCellStr
);
265 rEntry
.eOp
= SC_EQUAL
;
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.
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.
289 rEntry
.SetQueryByEmpty();
290 else if (bByNonEmpty
)
291 rEntry
.SetQueryByNonEmpty();
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() :
318 ScQueryParam::ScQueryParam( const ScQueryParam
& ) = default;
320 ScQueryParam::ScQueryParam( const ScDBQueryParamInternal
& r
) :
322 ScQueryParamTable(r
),
330 ScQueryParam::~ScQueryParam()
334 void ScQueryParam::Clear()
339 eSearchType
= utl::SearchParam::SearchType::Normal
;
340 bHasHeader
= bCaseSens
= false;
341 bInplace
= bByRow
= bDuplicate
= true;
343 for (auto & itr
: m_Entries
)
351 void ScQueryParam::ClearDestParams()
359 ScQueryParam
& ScQueryParam::operator=( const ScQueryParam
& ) = default;
361 bool ScQueryParam::operator==( const ScQueryParam
& rOther
) const
365 // Are the number of queries equal?
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
)
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
) )
393 for ( SCSIZE i
=0; i
<nUsed
&& bEqual
; i
++ )
394 bEqual
= m_Entries
[i
] == rOther
.m_Entries
[i
];
399 void ScQueryParam::MoveToDest()
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
;
420 OSL_FAIL("MoveToDest, bInplace == TRUE");
424 ScDBQueryParamBase::ScDBQueryParamBase(DataType 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
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: */