/* -*- 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 . */ #ifndef INCLUDED_SC_INC_DOCITER_HXX #define INCLUDED_SC_INC_DOCITER_HXX #include "address.hxx" #include "formulagroup.hxx" #include "global.hxx" #include "scdllapi.h" #include "cellvalue.hxx" #include "mtvelements.hxx" #include "queryparam.hxx" #include #include #include #include #include class ScDocument; class ScPatternAttr; class ScAttrArray; class ScAttrIterator; class ScFlatBoolRowSegments; class ScMatrix; struct ScDBQueryParamBase; struct ScQueryParam; struct ScDBQueryParamInternal; struct ScDBQueryParamMatrix; class ScFormulaCell; class OutputDevice; struct ScInterpreterContext; enum class SvNumFormatType : sal_Int16; class ScValueIterator // walk through all values in an area { typedef sc::CellStoreType::const_position_type PositionType; ScDocument& mrDoc; ScInterpreterContext* pContext; const ScAttrArray* pAttrArray; sal_uInt32 nNumFormat; // for CalcAsShown sal_uInt32 nNumFmtIndex; ScAddress maStartPos; ScAddress maEndPos; SCCOL mnCol; SCTAB mnTab; SCROW nAttrEndRow; SubtotalFlags mnSubTotalFlags; SvNumFormatType nNumFmtType; bool bNumValid; bool bCalcAsShown; bool bTextAsZero; const sc::CellStoreType* mpCells; PositionType maCurPos; SCROW GetRow() const; void IncBlock(); void IncPos(); /** * See if the cell at the current position is a non-empty cell. If not, * move to the next non-empty cell position. */ bool GetThis( double& rValue, FormulaError& rErr ); public: ScValueIterator( ScDocument& rDocument, const ScRange& rRange, SubtotalFlags nSubTotalFlags = SubtotalFlags::NONE, bool bTextAsZero = false ); void GetCurNumFmtInfo( const ScInterpreterContext& rContext, SvNumFormatType& nType, sal_uInt32& nIndex ); /// Does NOT reset rValue if no value found! bool GetFirst( double& rValue, FormulaError& rErr ); /// Does NOT reset rValue if no value found! bool GetNext( double& rValue, FormulaError& rErr ); void SetInterpreterContext( ScInterpreterContext* context ) { pContext = context; } }; class ScDBQueryDataIterator { public: struct Value { OUString maString; double mfValue; FormulaError mnError; bool mbIsNumber; Value(); }; private: static const sc::CellStoreType* GetColumnCellStore(ScDocument& rDoc, SCTAB nTab, SCCOL nCol); static const ScAttrArray* GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol); static bool IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, const ScRefCellValue* pCell); class DataAccess { public: DataAccess(); virtual ~DataAccess() = 0; virtual bool getCurrent(Value& rValue) = 0; virtual bool getFirst(Value& rValue) = 0; virtual bool getNext(Value& rValue) = 0; }; class DataAccessInternal final : public DataAccess { typedef std::pair PositionType; public: DataAccessInternal(ScDBQueryParamInternal* pParam, ScDocument& rDoc, const ScInterpreterContext& rContext); virtual ~DataAccessInternal() override; virtual bool getCurrent(Value& rValue) override; virtual bool getFirst(Value& rValue) override; virtual bool getNext(Value& rValue) override; private: void incBlock(); void incPos(); const sc::CellStoreType* mpCells; PositionType maCurPos; ScDBQueryParamInternal* mpParam; ScDocument& mrDoc; const ScInterpreterContext& mrContext; const ScAttrArray* pAttrArray; sal_uInt32 nNumFormat; // for CalcAsShown sal_uInt32 nNumFmtIndex; SCCOL nCol; SCROW nRow; SCROW nAttrEndRow; SCTAB nTab; SvNumFormatType nNumFmtType; bool bCalcAsShown; }; class DataAccessMatrix final : public DataAccess { public: DataAccessMatrix(ScDBQueryParamMatrix* pParam); virtual ~DataAccessMatrix() override; virtual bool getCurrent(Value& rValue) override; virtual bool getFirst(Value& rValue) override; virtual bool getNext(Value& rValue) override; private: bool isValidQuery(SCROW mnRow, const ScMatrix& rMat) const; ScDBQueryParamMatrix* mpParam; SCROW mnCurRow; SCROW mnRows; }; ::std::unique_ptr mpParam; ::std::unique_ptr mpData; public: ScDBQueryDataIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, std::unique_ptr pParam); /// Does NOT reset rValue if no value found! bool GetFirst(Value& rValue); /// Does NOT reset rValue if no value found! bool GetNext(Value& rValue); }; class ScFormulaGroupIterator { private: ScDocument& mrDoc; SCTAB mnTab; SCCOL mnCol; bool mbNullCol; size_t mnIndex; std::vector maEntries; public: ScFormulaGroupIterator( ScDocument& rDoc ); sc::FormulaGroupEntry* first(); sc::FormulaGroupEntry* next(); }; /** * Walk through all cells in an area. For SubTotal and Aggregate depending on mnSubTotalFlags. **/ class ScCellIterator { typedef std::pair PositionType; ScDocument& mrDoc; ScAddress maStartPos; ScAddress maEndPos; ScAddress maCurPos; PositionType maCurColPos; SubtotalFlags mnSubTotalFlags; ScRefCellValue maCurCell; void incBlock(); void incPos(); void setPos(size_t nPos); const ScColumn* getColumn() const; void init(); bool getCurrent(); public: ScCellIterator( ScDocument& rDoc, const ScRange& rRange, SubtotalFlags nSubTotalFlags = SubtotalFlags::NONE ); const ScAddress& GetPos() const { return maCurPos; } CellType getType() const { return maCurCell.meType;} OUString getString() const; const EditTextObject* getEditText() const { return maCurCell.mpEditText;} ScFormulaCell* getFormulaCell() { return maCurCell.mpFormula;} const ScFormulaCell* getFormulaCell() const { return maCurCell.mpFormula;} ScCellValue getCellValue() const; const ScRefCellValue& getRefCellValue() const { return maCurCell;} bool hasString() const; bool isEmpty() const; bool equalsWithoutFormat( const ScAddress& rPos ) const; bool first(); bool next(); }; class ScQueryCellIterator // walk through all non-empty cells in an area { enum StopOnMismatchBits { nStopOnMismatchDisabled = 0x00, nStopOnMismatchEnabled = 0x01, nStopOnMismatchOccurred = 0x02, nStopOnMismatchExecuted = nStopOnMismatchEnabled | nStopOnMismatchOccurred }; enum TestEqualConditionBits { nTestEqualConditionDisabled = 0x00, nTestEqualConditionEnabled = 0x01, nTestEqualConditionMatched = 0x02, nTestEqualConditionFulfilled = nTestEqualConditionEnabled | nTestEqualConditionMatched }; typedef sc::CellStoreType::const_position_type PositionType; PositionType maCurPos; ScQueryParam maParam; ScDocument& rDoc; const ScInterpreterContext& mrContext; SCTAB nTab; SCCOL nCol; SCROW nRow; sal_uInt8 nStopOnMismatch; sal_uInt8 nTestEqualCondition; bool bAdvanceQuery; bool bIgnoreMismatchOnLeadingStrings; /** Initialize position for new column. */ void InitPos(); void IncPos(); void IncBlock(); bool GetThis(); /* Only works if no regular expression is involved, only searches for rows in one column, and only the first query entry is considered with simple conditions SC_LESS_EQUAL (sorted ascending) or SC_GREATER_EQUAL (sorted descending). Check these things before invocation! Delivers a starting point, continue with GetThis() and GetNext() afterwards. Introduced for FindEqualOrSortedLastInRange() */ bool BinarySearch(); public: ScQueryCellIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, SCTAB nTable, const ScQueryParam& aParam, bool bMod); // when !bMod, the QueryParam has to be filled // (bIsString) bool GetFirst(); bool GetNext(); SCCOL GetCol() const { return nCol; } SCROW GetRow() const { return nRow; } // increments all Entry.nField, if column // changes, for ScInterpreter ScHLookup() void SetAdvanceQueryParamEntryField( bool bVal ) { bAdvanceQuery = bVal; } void AdvanceQueryParamEntryField(); /** If set, iterator stops on first non-matching cell content. May be used in SC_LESS_EQUAL queries where a cell range is assumed to be sorted; stops on first value being greater than the queried value and GetFirst()/GetNext() return NULL. StoppedOnMismatch() returns true then. However, the iterator's conditions are not set to end all queries, GetCol() and GetRow() return values for the non-matching cell, further GetNext() calls may be executed. */ void SetStopOnMismatch( bool bVal ) { nStopOnMismatch = sal::static_int_cast(bVal ? nStopOnMismatchEnabled : nStopOnMismatchDisabled); } bool StoppedOnMismatch() const { return nStopOnMismatch == nStopOnMismatchExecuted; } /** If set, an additional test for SC_EQUAL condition is executed in ScTable::ValidQuery() if SC_LESS_EQUAL or SC_GREATER_EQUAL conditions are to be tested. May be used where a cell range is assumed to be sorted to stop if an equal match is found. */ void SetTestEqualCondition( bool bVal ) { nTestEqualCondition = sal::static_int_cast(bVal ? nTestEqualConditionEnabled : nTestEqualConditionDisabled); } bool IsEqualConditionFulfilled() const { return nTestEqualCondition == nTestEqualConditionFulfilled; } /** In a range assumed to be sorted find either the last of a sequence of equal entries or the last being less than (or greater than) the queried value. Used by the interpreter for [HV]?LOOKUP() and MATCH(). Column and row position of the found entry are returned, otherwise invalid. The search does not stop when encountering a string and does not assume that no values follow anymore. If querying for a string a mismatch on the first entry, e.g. column header, is ignored. @ATTENTION! StopOnMismatch, TestEqualCondition and the internal IgnoreMismatchOnLeadingStrings and query params are in an undefined state upon return! The iterator is not usable anymore except for obtaining the number format! */ bool FindEqualOrSortedLastInRange( SCCOL& nFoundCol, SCROW& nFoundRow ); }; // Used by ScInterpreter::ScCountIf. // Walk through all non-empty cells in an area. class ScCountIfCellIterator { typedef sc::CellStoreType::const_position_type PositionType; PositionType maCurPos; ScQueryParam maParam; ScDocument& rDoc; const ScInterpreterContext& mrContext; SCTAB nTab; SCCOL nCol; SCROW nRow; /** Initialize position for new column. */ void InitPos(); void IncPos(); void IncBlock(); void AdvanceQueryParamEntryField(); public: ScCountIfCellIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, SCTAB nTable, const ScQueryParam& aParam); int GetCount(); }; class ScDocAttrIterator // all attribute areas { private: ScDocument& rDoc; SCTAB nTab; SCCOL nEndCol; SCROW nStartRow; SCROW nEndRow; SCCOL nCol; std::unique_ptr pColIter; public: ScDocAttrIterator(ScDocument& rDocument, SCTAB nTable, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2); ~ScDocAttrIterator(); const ScPatternAttr* GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 ); }; class ScAttrRectIterator // all attribute areas, including areas stretching // across more than one column { private: ScDocument& rDoc; SCTAB nTab; SCCOL nEndCol; SCROW nStartRow; SCROW nEndRow; SCCOL nIterStartCol; SCCOL nIterEndCol; std::unique_ptr pColIter; public: ScAttrRectIterator(ScDocument& rDocument, SCTAB nTable, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2); ~ScAttrRectIterator(); void DataChanged(); const ScPatternAttr* GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow1, SCROW& rRow2 ); }; class ScHorizontalCellIterator // walk through all non empty cells in an area { // row by row struct ColParam { sc::CellStoreType::const_iterator maPos; sc::CellStoreType::const_iterator maEnd; SCCOL mnCol; }; std::vector::iterator maColPos; std::vector maColPositions; ScDocument& rDoc; SCTAB mnTab; SCCOL nStartCol; SCCOL nEndCol; SCROW nStartRow; SCROW nEndRow; SCCOL mnCol; SCROW mnRow; ScRefCellValue maCurCell; bool mbMore; public: ScHorizontalCellIterator(ScDocument& rDocument, SCTAB nTable, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2); ~ScHorizontalCellIterator(); ScRefCellValue* GetNext( SCCOL& rCol, SCROW& rRow ); bool GetPos( SCCOL& rCol, SCROW& rRow ); /// Set a(nother) sheet and (re)init. void SetTab( SCTAB nTab ); private: void Advance(); void SkipInvalid(); bool SkipInvalidInRow(); SCROW FindNextNonEmptyRow(); }; /** Row-wise value iterator. */ class ScHorizontalValueIterator { private: ScDocument& rDoc; const ScAttrArray* pAttrArray; std::unique_ptr pCellIter; sal_uInt32 nNumFormat; // for CalcAsShown SCTAB nEndTab; SCCOL nCurCol; SCROW nCurRow; SCTAB nCurTab; SCROW nAttrEndRow; bool bCalcAsShown; public: ScHorizontalValueIterator( ScDocument& rDocument, const ScRange& rRange ); ~ScHorizontalValueIterator(); /// Does NOT reset rValue if no value found! bool GetNext( double& rValue, FormulaError& rErr ); }; // returns all areas with non-default formatting (horizontal) class ScHorizontalAttrIterator { private: ScDocument& rDoc; SCTAB nTab; SCCOL nStartCol; SCROW nStartRow; SCCOL nEndCol; SCROW nEndRow; std::unique_ptr pNextEnd; std::unique_ptr pHorizEnd; std::unique_ptr pIndices; std::unique_ptr ppPatterns; SCCOL nCol; SCROW nRow; bool bRowEmpty; SCROW nMinNextEnd; void InitForNextRow(bool bInitialization); bool InitForNextAttr(); public: ScHorizontalAttrIterator( ScDocument& rDocument, SCTAB nTable, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); ~ScHorizontalAttrIterator(); const ScPatternAttr* GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow ); }; // returns non-empty cells and areas with formatting (horizontal) class SC_DLLPUBLIC ScUsedAreaIterator { private: ScHorizontalCellIterator aCellIter; ScHorizontalAttrIterator aAttrIter; SCCOL nNextCol; SCROW nNextRow; SCCOL nCellCol; SCROW nCellRow; ScRefCellValue* pCell; SCCOL nAttrCol1; SCCOL nAttrCol2; SCROW nAttrRow; const ScPatternAttr* pPattern; SCCOL nFoundStartCol; // results after GetNext SCCOL nFoundEndCol; SCROW nFoundRow; const ScPatternAttr* pFoundPattern; ScRefCellValue maFoundCell; public: ScUsedAreaIterator( ScDocument& rDocument, SCTAB nTable, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ); ~ScUsedAreaIterator(); bool GetNext(); SCCOL GetStartCol() const { return nFoundStartCol; } SCCOL GetEndCol() const { return nFoundEndCol; } SCROW GetRow() const { return nFoundRow; } const ScPatternAttr* GetPattern() const { return pFoundPattern; } const ScRefCellValue& GetCell() const { return maFoundCell;} }; class ScRowBreakIterator { public: static constexpr SCROW NOT_FOUND = -1; explicit ScRowBreakIterator(::std::set& rBreaks); SCROW first(); SCROW next(); private: ::std::set& mrBreaks; ::std::set::const_iterator maItr; ::std::set::const_iterator maEnd; }; class ScDocRowHeightUpdater { public: struct TabRanges { SCTAB mnTab; ScFlatBoolRowSegments maRanges; TabRanges(SCTAB nTab, SCROW nMaxRow); }; /** * Passing a NULL pointer to pTabRangesArray forces the heights of all * rows in all tables to be updated. */ explicit ScDocRowHeightUpdater( ScDocument& rDoc, OutputDevice* pOutDev, double fPPTX, double fPPTY, const ::std::vector* pTabRangesArray); void update(); private: void updateAll(); private: ScDocument& mrDoc; VclPtr mpOutDev; double mfPPTX; double mfPPTY; const ::std::vector* mpTabRangesArray; }; #endif /* vim:set shiftwidth=4 softtabstop=4 expandtab: */