diff options
Diffstat (limited to 'sc/source/core/tool/queryparam.cxx')
-rw-r--r-- | sc/source/core/tool/queryparam.cxx | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/sc/source/core/tool/queryparam.cxx b/sc/source/core/tool/queryparam.cxx new file mode 100644 index 000000000..286a1ef4f --- /dev/null +++ b/sc/source/core/tool/queryparam.cxx @@ -0,0 +1,464 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <queryparam.hxx> +#include <queryentry.hxx> +#include <scmatrix.hxx> + +#include <svl/sharedstringpool.hxx> +#include <svl/numformat.hxx> +#include <o3tl/safeint.hxx> +#include <osl/diagnose.h> + +#include <algorithm> + +namespace { + +const size_t MAXQUERY = 8; + +class FindByField +{ + SCCOLROW mnField; +public: + explicit FindByField(SCCOLROW nField) : mnField(nField) {} + bool operator() (const ScQueryEntry& rpEntry) const + { + return rpEntry.bDoQuery && rpEntry.nField == mnField; + } +}; + +struct FindUnused +{ + bool operator() (const ScQueryEntry& rpEntry) const + { + return !rpEntry.bDoQuery; + } +}; + +} + +ScQueryParamBase::const_iterator ScQueryParamBase::begin() const +{ + return m_Entries.begin(); +} + +ScQueryParamBase::const_iterator ScQueryParamBase::end() const +{ + return m_Entries.end(); +} + +ScQueryParamBase::ScQueryParamBase() : + eSearchType(utl::SearchParam::SearchType::Normal), + bHasHeader(true), + bByRow(true), + bInplace(true), + bCaseSens(false), + bDuplicate(false), + mbRangeLookup(false) +{ + m_Entries.resize(MAXQUERY); +} + +ScQueryParamBase::ScQueryParamBase(const ScQueryParamBase& r) : + eSearchType(r.eSearchType), bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace), + bCaseSens(r.bCaseSens), bDuplicate(r.bDuplicate), mbRangeLookup(r.mbRangeLookup), + m_Entries(r.m_Entries) +{ +} + +ScQueryParamBase& ScQueryParamBase::operator=(const ScQueryParamBase& r) +{ + if (this != &r) + { + eSearchType = r.eSearchType; + bHasHeader = r.bHasHeader; + bByRow = r.bByRow; + bInplace = r.bInplace; + bCaseSens = r.bCaseSens; + bDuplicate = r.bDuplicate; + mbRangeLookup = r.mbRangeLookup; + m_Entries = r.m_Entries; + } + return *this; +} + +ScQueryParamBase::~ScQueryParamBase() +{ +} + +bool ScQueryParamBase::IsValidFieldIndex() const +{ + return true; +} + +SCSIZE ScQueryParamBase::GetEntryCount() const +{ + return m_Entries.size(); +} + +const ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n) const +{ + return m_Entries[n]; +} + +ScQueryEntry& ScQueryParamBase::GetEntry(SCSIZE n) +{ + return m_Entries[n]; +} + +ScQueryEntry& ScQueryParamBase::AppendEntry() +{ + // Find the first unused entry. + EntriesType::iterator itr = std::find_if( + m_Entries.begin(), m_Entries.end(), FindUnused()); + + if (itr != m_Entries.end()) + // Found! + return *itr; + + // Add a new entry to the end. + m_Entries.push_back(ScQueryEntry()); + return m_Entries.back(); +} + +ScQueryEntry* ScQueryParamBase::FindEntryByField(SCCOLROW nField, bool bNew) +{ + EntriesType::iterator itr = std::find_if( + m_Entries.begin(), m_Entries.end(), FindByField(nField)); + + if (itr != m_Entries.end()) + { + // existing entry found! + return &*itr; + } + + if (!bNew) + // no existing entry found, and we are not creating a new one. + return nullptr; + + return &AppendEntry(); +} + +std::vector<ScQueryEntry*> ScQueryParamBase::FindAllEntriesByField(SCCOLROW nField) +{ + std::vector<ScQueryEntry*> aEntries; + + auto fFind = FindByField(nField); + + for (auto& rxEntry : m_Entries) + if (fFind(rxEntry)) + aEntries.push_back(&rxEntry); + + return aEntries; +} + +bool ScQueryParamBase::RemoveEntryByField(SCCOLROW nField) +{ + EntriesType::iterator itr = std::find_if( + m_Entries.begin(), m_Entries.end(), FindByField(nField)); + bool bRet = false; + + if (itr != m_Entries.end()) + { + m_Entries.erase(itr); + if (m_Entries.size() < MAXQUERY) + // Make sure that we have at least MAXQUERY number of entries at + // all times. + m_Entries.resize(MAXQUERY); + bRet = true; + } + + return bRet; +} + +void ScQueryParamBase::RemoveAllEntriesByField(SCCOLROW nField) +{ + while( RemoveEntryByField( nField ) ) {} +} + +void ScQueryParamBase::Resize(size_t nNew) +{ + if (nNew < MAXQUERY) + nNew = MAXQUERY; // never less than MAXQUERY + + m_Entries.resize(nNew); +} + +void ScQueryParamBase::FillInExcelSyntax( + svl::SharedStringPool& rPool, const OUString& rCellStr, SCSIZE nIndex, SvNumberFormatter* pFormatter ) +{ + if (nIndex >= m_Entries.size()) + Resize(nIndex+1); + + ScQueryEntry& rEntry = GetEntry(nIndex); + ScQueryEntry::Item& rItem = rEntry.GetQueryItem(); + bool bByEmpty = false; + bool bByNonEmpty = false; + + if (rCellStr.isEmpty()) + rItem.maString = svl::SharedString::getEmptyString(); + else + { + rEntry.bDoQuery = true; + // Operatoren herausfiltern + if (rCellStr[0] == '<') + { + if (rCellStr.getLength() > 1 && rCellStr[1] == '>') + { + rItem.maString = rPool.intern(rCellStr.copy(2)); + rEntry.eOp = SC_NOT_EQUAL; + if (rCellStr.getLength() == 2) + bByNonEmpty = true; + } + else if (rCellStr.getLength() > 1 && rCellStr[1] == '=') + { + rItem.maString = rPool.intern(rCellStr.copy(2)); + rEntry.eOp = SC_LESS_EQUAL; + } + else + { + rItem.maString = rPool.intern(rCellStr.copy(1)); + rEntry.eOp = SC_LESS; + } + } + else if (rCellStr[0]== '>') + { + if (rCellStr.getLength() > 1 && rCellStr[1] == '=') + { + rItem.maString = rPool.intern(rCellStr.copy(2)); + rEntry.eOp = SC_GREATER_EQUAL; + } + else + { + rItem.maString = rPool.intern(rCellStr.copy(1)); + rEntry.eOp = SC_GREATER; + } + } + else + { + if (rCellStr[0] == '=') + { + rItem.maString = rPool.intern(rCellStr.copy(1)); + if (rCellStr.getLength() == 1) + bByEmpty = true; + } + else + rItem.maString = rPool.intern(rCellStr); + rEntry.eOp = SC_EQUAL; + } + } + + if (!pFormatter) + return; + + /* TODO: pFormatter currently is also used as a flag whether matching + * empty cells with an empty string is triggered from the interpreter. + * This could be handled independently if all queries should support + * it, needs to be evaluated if that actually is desired. */ + + // Interpreter queries have only one query, also QueryByEmpty and + // QueryByNonEmpty rely on that. + if (nIndex != 0) + return; + + // (empty = empty) is a match, and (empty <> not-empty) also is a + // match. (empty = 0) is not a match. + rItem.mbMatchEmpty = ((rEntry.eOp == SC_EQUAL && rItem.maString.isEmpty()) + || (rEntry.eOp == SC_NOT_EQUAL && !rItem.maString.isEmpty())); + + // SetQueryBy override item members with special values, so do this last. + if (bByEmpty) + rEntry.SetQueryByEmpty(); + else if (bByNonEmpty) + rEntry.SetQueryByNonEmpty(); + else + { + sal_uInt32 nFormat = 0; + bool bNumber = pFormatter->IsNumberFormat( rItem.maString.getString(), nFormat, rItem.mfVal); + rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString; + } +} + +ScQueryParamTable::ScQueryParamTable() : + nCol1(0),nRow1(0),nCol2(0),nRow2(0),nTab(0) +{ +} + +ScQueryParamTable::~ScQueryParamTable() +{ +} + +ScQueryParam::ScQueryParam() : + bDestPers(true), + nDestTab(0), + nDestCol(0), + nDestRow(0) +{ + Clear(); +} + +ScQueryParam::ScQueryParam( const ScQueryParam& ) = default; + +ScQueryParam::ScQueryParam( const ScDBQueryParamInternal& r ) : + ScQueryParamBase(r), + ScQueryParamTable(r), + bDestPers(true), + nDestTab(0), + nDestCol(0), + nDestRow(0) +{ +} + +ScQueryParam::~ScQueryParam() +{ +} + +void ScQueryParam::Clear() +{ + nCol1=nCol2 = 0; + nRow1=nRow2 = 0; + nTab = SCTAB_MAX; + eSearchType = utl::SearchParam::SearchType::Normal; + bHasHeader = bCaseSens = false; + bInplace = bByRow = bDuplicate = true; + + for (auto & itr : m_Entries) + { + itr.Clear(); + } + + ClearDestParams(); +} + +void ScQueryParam::ClearDestParams() +{ + bDestPers = true; + nDestTab = 0; + nDestCol = 0; + nDestRow = 0; +} + +ScQueryParam& ScQueryParam::operator=( const ScQueryParam& ) = default; + +bool ScQueryParam::operator==( const ScQueryParam& rOther ) const +{ + bool bEqual = false; + + // Are the number of queries equal? + SCSIZE nUsed = 0; + SCSIZE nOtherUsed = 0; + SCSIZE nEntryCount = GetEntryCount(); + SCSIZE nOtherEntryCount = rOther.GetEntryCount(); + + while (nUsed<nEntryCount && m_Entries[nUsed].bDoQuery) ++nUsed; + while (nOtherUsed<nOtherEntryCount && rOther.m_Entries[nOtherUsed].bDoQuery) + ++nOtherUsed; + + if ( (nUsed == nOtherUsed) + && (nCol1 == rOther.nCol1) + && (nRow1 == rOther.nRow1) + && (nCol2 == rOther.nCol2) + && (nRow2 == rOther.nRow2) + && (nTab == rOther.nTab) + && (bHasHeader == rOther.bHasHeader) + && (bByRow == rOther.bByRow) + && (bInplace == rOther.bInplace) + && (bCaseSens == rOther.bCaseSens) + && (eSearchType == rOther.eSearchType) + && (bDuplicate == rOther.bDuplicate) + && (bDestPers == rOther.bDestPers) + && (nDestTab == rOther.nDestTab) + && (nDestCol == rOther.nDestCol) + && (nDestRow == rOther.nDestRow) ) + { + bEqual = true; + for ( SCSIZE i=0; i<nUsed && bEqual; i++ ) + bEqual = m_Entries[i] == rOther.m_Entries[i]; + } + return bEqual; +} + +void ScQueryParam::MoveToDest() +{ + if (!bInplace) + { + SCCOL nDifX = nDestCol - nCol1; + SCROW nDifY = nDestRow - nRow1; + SCTAB nDifZ = nDestTab - nTab; + + nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nDifX ); + nRow1 = sal::static_int_cast<SCROW>( nRow1 + nDifY ); + nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nDifX ); + nRow2 = sal::static_int_cast<SCROW>( nRow2 + nDifY ); + nTab = sal::static_int_cast<SCTAB>( nTab + nDifZ ); + size_t n = m_Entries.size(); + for (size_t i=0; i<n; i++) + m_Entries[i].nField += nDifX; + + bInplace = true; + } + else + { + OSL_FAIL("MoveToDest, bInplace == TRUE"); + } +} + +ScDBQueryParamBase::ScDBQueryParamBase(DataType eType) : + mnField(-1), + mbSkipString(true), + meType(eType) +{ +} + +ScDBQueryParamBase::~ScDBQueryParamBase() +{ +} + +ScDBQueryParamInternal::ScDBQueryParamInternal() : + ScDBQueryParamBase(ScDBQueryParamBase::INTERNAL) +{ +} + +ScDBQueryParamInternal::~ScDBQueryParamInternal() +{ +} + +bool ScDBQueryParamInternal::IsValidFieldIndex() const +{ + return nCol1 <= mnField && mnField <= nCol2; +} + +ScDBQueryParamMatrix::ScDBQueryParamMatrix() : + ScDBQueryParamBase(ScDBQueryParamBase::MATRIX) +{ +} + +bool ScDBQueryParamMatrix::IsValidFieldIndex() const +{ + SCSIZE nC, nR; + mpMatrix->GetDimensions(nC, nR); + return 0 <= mnField && o3tl::make_unsigned(mnField) <= nC; +} + +ScDBQueryParamMatrix::~ScDBQueryParamMatrix() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |