| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_sc.hxx" |
| |
| // INCLUDE --------------------------------------------------------------- |
| |
| #include <svl/zforlist.hxx> |
| |
| #include "scitems.hxx" |
| #include "global.hxx" |
| #include "dociter.hxx" |
| #include "document.hxx" |
| #include "table.hxx" |
| #include "column.hxx" |
| #include "cell.hxx" |
| #include "attarray.hxx" |
| #include "patattr.hxx" |
| #include "docoptio.hxx" |
| #include "cellform.hxx" |
| |
| #include <vector> |
| |
| using ::rtl::math::approxEqual; |
| using ::std::vector; |
| using ::rtl::OUString; |
| using ::std::set; |
| |
| // STATIC DATA ----------------------------------------------------------- |
| |
| namespace { |
| |
| void lcl_toUpper(OUString& rStr) |
| { |
| rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, static_cast<sal_uInt16>(rStr.getLength())); |
| } |
| |
| } |
| |
| ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument, |
| SCTAB nStartTable, SCTAB nEndTable ) : |
| pDoc( pDocument ), |
| nStartTab( nStartTable ), |
| nEndTab( nEndTable ) |
| { |
| PutInOrder( nStartTab, nEndTab ); |
| if (!ValidTab(nStartTab)) nStartTab = MAXTAB; |
| if (!ValidTab(nEndTab)) nEndTab = MAXTAB; |
| |
| pDefPattern = pDoc->GetDefPattern(); |
| |
| nCol = 0; |
| nRow = 0; |
| nTab = nStartTab; |
| |
| nColPos = 0; |
| nAttrPos = 0; |
| } |
| |
| ScDocumentIterator::~ScDocumentIterator() |
| { |
| } |
| |
| sal_Bool ScDocumentIterator::GetThisCol() |
| { |
| ScTable* pTab; |
| while ( (pTab = pDoc->pTab[nTab]) == NULL ) |
| { |
| if ( nTab == nEndTab ) |
| { |
| nCol = MAXCOL; |
| nRow = MAXROW; |
| return sal_False; |
| } |
| ++nTab; |
| } |
| ScColumn* pCol = &pTab->aCol[nCol]; |
| ScAttrArray* pAtt = pCol->pAttrArray; |
| |
| sal_Bool bFound = sal_False; |
| do |
| { |
| SCROW nColRow; |
| SCROW nAttrEnd; |
| |
| do |
| { |
| nAttrEnd = pAtt->pData[nAttrPos].nRow; |
| if (nAttrEnd < nRow) |
| ++nAttrPos; |
| } |
| while (nAttrEnd < nRow); |
| |
| do |
| { |
| nColRow = (nColPos < pCol->nCount) ? pCol->pItems[nColPos].nRow : MAXROW+1; |
| if (nColRow < nRow) |
| ++nColPos; |
| } |
| while (nColRow < nRow); |
| |
| if (nColRow == nRow) |
| { |
| bFound = sal_True; |
| pCell = pCol->pItems[nColPos].pCell; |
| pPattern = pAtt->pData[nAttrPos].pPattern; |
| } |
| else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern ) |
| { |
| bFound = sal_True; |
| pCell = NULL; |
| pPattern = pAtt->pData[nAttrPos].pPattern; |
| } |
| else |
| { |
| nRow = Min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) ); |
| } |
| } |
| while (!bFound && nRow <= MAXROW); |
| |
| return bFound; |
| } |
| |
| sal_Bool ScDocumentIterator::GetThis() |
| { |
| sal_Bool bEnd = sal_False; |
| sal_Bool bSuccess = sal_False; |
| |
| while ( !bSuccess && !bEnd ) |
| { |
| if ( nRow > MAXROW ) |
| bSuccess = sal_False; |
| else |
| bSuccess = GetThisCol(); |
| |
| if ( !bSuccess ) |
| { |
| ++nCol; |
| if (nCol > MAXCOL) |
| { |
| nCol = 0; |
| ++nTab; |
| if (nTab > nEndTab) |
| bEnd = sal_True; |
| } |
| nRow = 0; |
| nColPos = 0; |
| nAttrPos = 0; |
| } |
| } |
| |
| return !bEnd; |
| } |
| |
| sal_Bool ScDocumentIterator::GetFirst() |
| { |
| nCol = 0; |
| nTab = nStartTab; |
| |
| nRow = 0; |
| nColPos = 0; |
| nAttrPos = 0; |
| |
| return GetThis(); |
| } |
| |
| sal_Bool ScDocumentIterator::GetNext() |
| { |
| ++nRow; |
| |
| return GetThis(); |
| } |
| |
| //------------------------------------------------------------------------ |
| |
| ScBaseCell* ScDocumentIterator::GetCell() |
| { |
| return pCell; |
| } |
| |
| const ScPatternAttr* ScDocumentIterator::GetPattern() |
| { |
| return pPattern; |
| } |
| |
| void ScDocumentIterator::GetPos( SCCOL& rCol, SCROW& rRow, SCTAB& rTab ) |
| { |
| rCol = nCol; |
| rRow = nRow; |
| rTab = nTab; |
| } |
| |
| |
| //------------------------------------------------------------------------ |
| //------------------------------------------------------------------------ |
| void lcl_IterGetNumberFormat( sal_uLong& nFormat, const ScAttrArray*& rpArr, |
| SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow, |
| ScDocument* pDoc ) |
| { |
| if ( rpArr != pNewArr || nAttrEndRow < nRow ) |
| { |
| SCSIZE nPos; |
| pNewArr->Search( nRow, nPos ); // nPos 0 gueltig wenn nicht gefunden |
| const ScPatternAttr* pPattern = pNewArr->pData[nPos].pPattern; |
| nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() ); |
| rpArr = pNewArr; |
| nAttrEndRow = pNewArr->pData[nPos].nRow; |
| } |
| } |
| |
| //UNUSED2008-05 ScValueIterator::ScValueIterator( ScDocument* pDocument, |
| //UNUSED2008-05 SCCOL nSCol, SCROW nSRow, SCTAB nSTab, |
| //UNUSED2008-05 SCCOL nECol, SCROW nERow, SCTAB nETab, |
| //UNUSED2008-05 sal_Bool bSTotal, sal_Bool bTextZero ) : |
| //UNUSED2008-05 pDoc( pDocument ), |
| //UNUSED2008-05 nNumFmtIndex(0), |
| //UNUSED2008-05 nStartCol( nSCol), |
| //UNUSED2008-05 nStartRow( nSRow), |
| //UNUSED2008-05 nStartTab( nSTab ), |
| //UNUSED2008-05 nEndCol( nECol ), |
| //UNUSED2008-05 nEndRow( nERow), |
| //UNUSED2008-05 nEndTab( nETab ), |
| //UNUSED2008-05 nNumFmtType( NUMBERFORMAT_UNDEFINED ), |
| //UNUSED2008-05 bNumValid( sal_False ), |
| //UNUSED2008-05 bSubTotal(bSTotal), |
| //UNUSED2008-05 bNextValid( sal_False ), |
| //UNUSED2008-05 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ), |
| //UNUSED2008-05 bTextAsZero( bTextZero ) |
| //UNUSED2008-05 { |
| //UNUSED2008-05 PutInOrder( nStartCol, nEndCol); |
| //UNUSED2008-05 PutInOrder( nStartRow, nEndRow); |
| //UNUSED2008-05 PutInOrder( nStartTab, nEndTab ); |
| //UNUSED2008-05 |
| //UNUSED2008-05 if (!ValidCol(nStartCol)) nStartCol = MAXCOL; |
| //UNUSED2008-05 if (!ValidCol(nEndCol)) nEndCol = MAXCOL; |
| //UNUSED2008-05 if (!ValidRow(nStartRow)) nStartRow = MAXROW; |
| //UNUSED2008-05 if (!ValidRow(nEndRow)) nEndRow = MAXROW; |
| //UNUSED2008-05 if (!ValidTab(nStartTab)) nStartTab = MAXTAB; |
| //UNUSED2008-05 if (!ValidTab(nEndTab)) nEndTab = MAXTAB; |
| //UNUSED2008-05 |
| //UNUSED2008-05 nCol = nStartCol; |
| //UNUSED2008-05 nRow = nStartRow; |
| //UNUSED2008-05 nTab = nStartTab; |
| //UNUSED2008-05 |
| //UNUSED2008-05 nColRow = 0; // wird bei GetFirst initialisiert |
| //UNUSED2008-05 |
| //UNUSED2008-05 nNumFormat = 0; // werden bei GetNumberFormat initialisiert |
| //UNUSED2008-05 pAttrArray = 0; |
| //UNUSED2008-05 nAttrEndRow = 0; |
| //UNUSED2008-05 } |
| |
| ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange, |
| sal_Bool bSTotal, sal_Bool bTextZero ) : |
| pDoc( pDocument ), |
| nNumFmtIndex(0), |
| nStartCol( rRange.aStart.Col() ), |
| nStartRow( rRange.aStart.Row() ), |
| nStartTab( rRange.aStart.Tab() ), |
| nEndCol( rRange.aEnd.Col() ), |
| nEndRow( rRange.aEnd.Row() ), |
| nEndTab( rRange.aEnd.Tab() ), |
| nNumFmtType( NUMBERFORMAT_UNDEFINED ), |
| bNumValid( sal_False ), |
| bSubTotal(bSTotal), |
| bNextValid( sal_False ), |
| bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ), |
| bTextAsZero( bTextZero ) |
| { |
| PutInOrder( nStartCol, nEndCol); |
| PutInOrder( nStartRow, nEndRow); |
| PutInOrder( nStartTab, nEndTab ); |
| |
| if (!ValidCol(nStartCol)) nStartCol = MAXCOL; |
| if (!ValidCol(nEndCol)) nEndCol = MAXCOL; |
| if (!ValidRow(nStartRow)) nStartRow = MAXROW; |
| if (!ValidRow(nEndRow)) nEndRow = MAXROW; |
| if (!ValidTab(nStartTab)) nStartTab = MAXTAB; |
| if (!ValidTab(nEndTab)) nEndTab = MAXTAB; |
| |
| nCol = nStartCol; |
| nRow = nStartRow; |
| nTab = nStartTab; |
| |
| nColRow = 0; // wird bei GetFirst initialisiert |
| |
| nNumFormat = 0; // werden bei GetNumberFormat initialisiert |
| pAttrArray = 0; |
| nAttrEndRow = 0; |
| } |
| |
| sal_Bool ScValueIterator::GetThis(double& rValue, sal_uInt16& rErr) |
| { |
| ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| for (;;) |
| { |
| if ( nRow > nEndRow ) |
| { |
| nRow = nStartRow; |
| do |
| { |
| nCol++; |
| if ( nCol > nEndCol ) |
| { |
| nCol = nStartCol; |
| nTab++; |
| if ( nTab > nEndTab ) |
| { |
| // rValue = 0.0; //! do not change caller's value! |
| rErr = 0; |
| return sal_False; // Ende und Aus |
| } |
| } |
| pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| } while ( pCol->nCount == 0 ); |
| pCol->Search( nRow, nColRow ); |
| } |
| |
| while (( nColRow < pCol->nCount ) && ( pCol->pItems[nColRow].nRow < nRow )) |
| nColRow++; |
| |
| if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow ) |
| { |
| nRow = pCol->pItems[nColRow].nRow + 1; |
| if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow-1 ) ) |
| { |
| ScBaseCell* pCell = pCol->pItems[nColRow].pCell; |
| ++nColRow; |
| switch (pCell->GetCellType()) |
| { |
| case CELLTYPE_VALUE: |
| { |
| bNumValid = sal_False; |
| rValue = ((ScValueCell*)pCell)->GetValue(); |
| rErr = 0; |
| --nRow; |
| if ( bCalcAsShown ) |
| { |
| lcl_IterGetNumberFormat( nNumFormat, pAttrArray, |
| nAttrEndRow, pCol->pAttrArray, nRow, pDoc ); |
| rValue = pDoc->RoundValueAsShown( rValue, nNumFormat ); |
| } |
| // |
| // wenn in der selben Spalte gleich noch eine Value-Cell folgt, die |
| // auch noch im Block liegt, den Wert jetzt schon holen |
| // |
| if ( nColRow < pCol->nCount && |
| pCol->pItems[nColRow].nRow <= nEndRow && |
| pCol->pItems[nColRow].pCell->GetCellType() == CELLTYPE_VALUE && |
| !bSubTotal ) |
| { |
| fNextValue = ((ScValueCell*)pCol->pItems[nColRow].pCell)->GetValue(); |
| nNextRow = pCol->pItems[nColRow].nRow; |
| bNextValid = sal_True; |
| if ( bCalcAsShown ) |
| { |
| lcl_IterGetNumberFormat( nNumFormat, pAttrArray, |
| nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc ); |
| fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat ); |
| } |
| } |
| |
| return sal_True; // gefunden |
| } |
| // break; |
| case CELLTYPE_FORMULA: |
| { |
| if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal()) |
| { |
| rErr = ((ScFormulaCell*)pCell)->GetErrCode(); |
| if ( rErr || ((ScFormulaCell*)pCell)->IsValue() ) |
| { |
| rValue = ((ScFormulaCell*)pCell)->GetValue(); |
| nRow--; |
| bNumValid = sal_False; |
| return sal_True; // gefunden |
| } |
| else if ( bTextAsZero ) |
| { |
| rValue = 0.0; |
| nRow--; |
| bNumValid = sal_False; |
| return sal_True; |
| } |
| } |
| } |
| break; |
| case CELLTYPE_STRING : |
| case CELLTYPE_EDIT : |
| { |
| if ( bTextAsZero ) |
| { |
| rErr = 0; |
| rValue = 0.0; |
| nNumFmtType = NUMBERFORMAT_NUMBER; |
| nNumFmtIndex = 0; |
| bNumValid = sal_True; |
| --nRow; |
| return sal_True; |
| } |
| } |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| } |
| else |
| nRow = nEndRow + 1; // naechste Spalte |
| } |
| } |
| |
| void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex ) |
| { |
| if (!bNumValid) |
| { |
| const ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| nNumFmtIndex = pCol->GetNumberFormat( nRow ); |
| if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) |
| { |
| const ScBaseCell* pCell; |
| SCSIZE nIdx = nColRow - 1; |
| // there might be rearranged something, so be on the safe side |
| if ( nIdx < pCol->nCount && pCol->pItems[nIdx].nRow == nRow ) |
| pCell = pCol->pItems[nIdx].pCell; |
| else |
| { |
| if ( pCol->Search( nRow, nIdx ) ) |
| pCell = pCol->pItems[nIdx].pCell; |
| else |
| pCell = NULL; |
| } |
| if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) |
| ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex ); |
| else |
| nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); |
| } |
| else |
| nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); |
| bNumValid = sal_True; |
| } |
| nType = nNumFmtType; |
| nIndex = nNumFmtIndex; |
| } |
| |
| sal_Bool ScValueIterator::GetFirst(double& rValue, sal_uInt16& rErr) |
| { |
| nCol = nStartCol; |
| nRow = nStartRow; |
| nTab = nStartTab; |
| |
| // nColRow = 0; |
| ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| pCol->Search( nRow, nColRow ); |
| |
| nNumFormat = 0; // werden bei GetNumberFormat initialisiert |
| pAttrArray = 0; |
| nAttrEndRow = 0; |
| |
| return GetThis(rValue, rErr); |
| } |
| |
| /* ist inline: |
| sal_Bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr) |
| { |
| ++nRow; |
| return GetThis(rValue, rErr); |
| } |
| */ |
| |
| // ============================================================================ |
| |
| ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) : |
| mpParent(pParent) |
| { |
| } |
| |
| ScDBQueryDataIterator::DataAccess::~DataAccess() |
| { |
| } |
| |
| SCROW ScDBQueryDataIterator::GetRowByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow) |
| { |
| ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; |
| return pCol->pItems[nColRow].nRow; |
| } |
| |
| ScBaseCell* ScDBQueryDataIterator::GetCellByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow) |
| { |
| ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; |
| return pCol->pItems[nColRow].pCell; |
| } |
| |
| ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol) |
| { |
| ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; |
| return pCol->pAttrArray; |
| } |
| |
| bool ScDBQueryDataIterator::IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScBaseCell* pCell) |
| { |
| return rDoc.pTab[nTab]->ValidQuery(nRow, rParam, NULL, pCell); |
| } |
| |
| SCSIZE ScDBQueryDataIterator::SearchColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCROW nRow, SCCOL nCol) |
| { |
| ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol]; |
| SCSIZE nColRow; |
| pCol->Search(nRow, nColRow); |
| return nColRow; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) : |
| DataAccess(pParent), |
| mpParam(pParam), |
| mpDoc(pDoc), |
| bCalcAsShown( pDoc->GetDocOptions().IsCalcAsShown() ) |
| { |
| nCol = mpParam->mnField; |
| nRow = mpParam->nRow1; |
| nTab = mpParam->nTab; |
| |
| nColRow = 0; // wird bei GetFirst initialisiert |
| SCSIZE i; |
| SCSIZE nCount = mpParam->GetEntryCount(); |
| for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++) |
| { |
| ScQueryEntry& rEntry = mpParam->GetEntry(i); |
| sal_uInt32 nIndex = 0; |
| rEntry.bQueryByString = |
| !(mpDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal)); |
| } |
| nNumFormat = 0; // werden bei GetNumberFormat initialisiert |
| pAttrArray = 0; |
| nAttrEndRow = 0; |
| } |
| |
| ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal() |
| { |
| } |
| |
| bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue) |
| { |
| SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField; |
| for ( ;; ) |
| { |
| if (nRow > mpParam->nRow2) |
| { |
| // Bottom of the range reached. Bail out. |
| rValue.mnError = 0; |
| return false; |
| } |
| |
| SCSIZE nCellCount = mpDoc->GetCellCount(nTab, nCol); |
| SCROW nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, nColRow); |
| while ( (nColRow < nCellCount) && (nThisRow < nRow) ) |
| nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, ++nColRow); |
| |
| if ( nColRow < nCellCount && nThisRow <= mpParam->nRow2 ) |
| { |
| nRow = nThisRow; |
| ScBaseCell* pCell = NULL; |
| if (nCol == static_cast<SCCOL>(nFirstQueryField)) |
| pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow); |
| |
| if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, pCell)) |
| { |
| // #i109812# get cell here if it wasn't done above |
| if (nCol != static_cast<SCCOL>(nFirstQueryField)) |
| pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow); |
| |
| switch (pCell ? pCell->GetCellType() : CELLTYPE_NONE) |
| { |
| case CELLTYPE_VALUE: |
| { |
| rValue.mfValue = ((ScValueCell*)pCell)->GetValue(); |
| rValue.mbIsNumber = true; |
| if ( bCalcAsShown ) |
| { |
| const ScAttrArray* pNewAttrArray = |
| ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol); |
| lcl_IterGetNumberFormat( nNumFormat, pAttrArray, |
| nAttrEndRow, pNewAttrArray, nRow, mpDoc ); |
| rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat ); |
| } |
| nNumFmtType = NUMBERFORMAT_NUMBER; |
| nNumFmtIndex = 0; |
| rValue.mnError = 0; |
| return sal_True; // gefunden |
| } |
| // break; |
| case CELLTYPE_FORMULA: |
| { |
| if (((ScFormulaCell*)pCell)->IsValue()) |
| { |
| rValue.mfValue = ((ScFormulaCell*)pCell)->GetValue(); |
| rValue.mbIsNumber = true; |
| mpDoc->GetNumberFormatInfo( nNumFmtType, |
| nNumFmtIndex, ScAddress( nCol, nRow, nTab ), |
| pCell ); |
| rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode(); |
| return sal_True; // gefunden |
| } |
| else |
| nRow++; |
| } |
| break; |
| case CELLTYPE_STRING: |
| case CELLTYPE_EDIT: |
| if (mpParam->mbSkipString) |
| ++nRow; |
| else |
| { |
| rValue.maString = pCell->GetStringData(); |
| rValue.mfValue = 0.0; |
| rValue.mnError = 0; |
| rValue.mbIsNumber = false; |
| return true; |
| } |
| break; |
| default: |
| nRow++; |
| break; |
| } |
| } |
| else |
| nRow++; |
| } |
| else |
| nRow = mpParam->nRow2 + 1; // Naechste Spalte |
| } |
| // statement unreachable |
| // return false; |
| } |
| |
| bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue) |
| { |
| if (mpParam->bHasHeader) |
| nRow++; |
| |
| nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol); |
| return getCurrent(rValue); |
| } |
| |
| bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue) |
| { |
| ++nRow; |
| return getCurrent(rValue); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) : |
| DataAccess(pParent), |
| mpParam(pParam) |
| { |
| SCSIZE nC, nR; |
| mpParam->mpMatrix->GetDimensions(nC, nR); |
| mnRows = static_cast<SCROW>(nR); |
| mnCols = static_cast<SCCOL>(nC); |
| } |
| |
| ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix() |
| { |
| } |
| |
| bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue) |
| { |
| // Starting from row == mnCurRow, get the first row that satisfies all the |
| // query parameters. |
| for ( ;mnCurRow < mnRows; ++mnCurRow) |
| { |
| const ScMatrix& rMat = *mpParam->mpMatrix; |
| if (rMat.IsEmpty(mpParam->mnField, mnCurRow)) |
| // Don't take empty values into account. |
| continue; |
| |
| bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow); |
| if (bIsStrVal && mpParam->mbSkipString) |
| continue; |
| |
| if (isValidQuery(mnCurRow, rMat)) |
| { |
| rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow); |
| rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow); |
| rValue.mbIsNumber = !bIsStrVal; |
| rValue.mnError = 0; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue) |
| { |
| mnCurRow = mpParam->bHasHeader ? 1 : 0; |
| return getCurrent(rValue); |
| } |
| |
| bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue) |
| { |
| ++mnCurRow; |
| return getCurrent(rValue); |
| } |
| |
| namespace { |
| |
| bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow) |
| { |
| if (rEntry.bQueryByString) |
| return false; |
| |
| if (!rMat.IsValueOrEmpty(nCol, nRow)) |
| return false; |
| |
| return true; |
| } |
| |
| bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow) |
| { |
| switch (rEntry.eOp) |
| { |
| case SC_EQUAL: |
| case SC_NOT_EQUAL: |
| case SC_CONTAINS: |
| case SC_DOES_NOT_CONTAIN: |
| case SC_BEGINS_WITH: |
| case SC_ENDS_WITH: |
| case SC_DOES_NOT_BEGIN_WITH: |
| case SC_DOES_NOT_END_WITH: |
| return true; |
| default: |
| ; |
| } |
| |
| if (rEntry.bQueryByString && rMat.IsString(nCol, nRow)) |
| return true; |
| |
| return false; |
| } |
| |
| } |
| |
| bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const |
| { |
| SCSIZE nEntryCount = mpParam->GetEntryCount(); |
| vector<bool> aResults; |
| aResults.reserve(nEntryCount); |
| |
| const CollatorWrapper& rCollator = |
| mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator(); |
| |
| for (SCSIZE i = 0; i < nEntryCount; ++i) |
| { |
| const ScQueryEntry& rEntry = mpParam->GetEntry(i); |
| if (!rEntry.bDoQuery) |
| continue; |
| |
| switch (rEntry.eOp) |
| { |
| case SC_EQUAL: |
| case SC_LESS: |
| case SC_GREATER: |
| case SC_LESS_EQUAL: |
| case SC_GREATER_EQUAL: |
| case SC_NOT_EQUAL: |
| break; |
| default: |
| // Only the above operators are supported. |
| continue; |
| } |
| |
| bool bValid = false; |
| |
| SCSIZE nField = static_cast<SCSIZE>(rEntry.nField); |
| if (lcl_isQueryByValue(rEntry, rMat, nField, nRow)) |
| { |
| // By value |
| double fMatVal = rMat.GetDouble(nField, nRow); |
| bool bEqual = approxEqual(fMatVal, rEntry.nVal); |
| switch (rEntry.eOp) |
| { |
| case SC_EQUAL: |
| bValid = bEqual; |
| break; |
| case SC_LESS: |
| bValid = (fMatVal < rEntry.nVal) && !bEqual; |
| break; |
| case SC_GREATER: |
| bValid = (fMatVal > rEntry.nVal) && !bEqual; |
| break; |
| case SC_LESS_EQUAL: |
| bValid = (fMatVal < rEntry.nVal) || bEqual; |
| break; |
| case SC_GREATER_EQUAL: |
| bValid = (fMatVal > rEntry.nVal) || bEqual; |
| break; |
| case SC_NOT_EQUAL: |
| bValid = !bEqual; |
| break; |
| default: |
| ; |
| } |
| } |
| else if (lcl_isQueryByString(rEntry, rMat, nField, nRow)) |
| { |
| // By string |
| do |
| { |
| if (!rEntry.pStr) |
| break; |
| |
| // Equality check first. |
| |
| OUString aMatStr = rMat.GetString(nField, nRow); |
| lcl_toUpper(aMatStr); |
| OUString aQueryStr = *rEntry.pStr; |
| lcl_toUpper(aQueryStr); |
| bool bDone = false; |
| switch (rEntry.eOp) |
| { |
| case SC_EQUAL: |
| bValid = aMatStr.equals(aQueryStr); |
| bDone = true; |
| break; |
| case SC_NOT_EQUAL: |
| bValid = !aMatStr.equals(aQueryStr); |
| bDone = true; |
| break; |
| default: |
| ; |
| } |
| |
| if (bDone) |
| break; |
| |
| // Unequality check using collator. |
| |
| sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr); |
| switch (rEntry.eOp) |
| { |
| case SC_LESS : |
| bValid = (nCompare < 0); |
| break; |
| case SC_GREATER : |
| bValid = (nCompare > 0); |
| break; |
| case SC_LESS_EQUAL : |
| bValid = (nCompare <= 0); |
| break; |
| case SC_GREATER_EQUAL : |
| bValid = (nCompare >= 0); |
| break; |
| default: |
| ; |
| } |
| } |
| while (false); |
| } |
| else if (mpParam->bMixedComparison) |
| { |
| // Not used at the moment. |
| } |
| |
| if (aResults.empty()) |
| // First query entry. |
| aResults.push_back(bValid); |
| else if (rEntry.eConnect == SC_AND) |
| { |
| // For AND op, tuck the result into the last result value. |
| size_t n = aResults.size(); |
| aResults[n-1] = aResults[n-1] && bValid; |
| } |
| else |
| // For OR op, store its own result. |
| aResults.push_back(bValid); |
| } |
| |
| // Row is valid as long as there is at least one result being true. |
| vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end(); |
| for (; itr != itrEnd; ++itr) |
| if (*itr) |
| return true; |
| |
| return false; |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| ScDBQueryDataIterator::Value::Value() : |
| mnError(0), mbIsNumber(true) |
| { |
| ::rtl::math::setNan(&mfValue); |
| } |
| |
| // ---------------------------------------------------------------------------- |
| |
| ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) : |
| mpParam (pParam) |
| { |
| switch (mpParam->GetType()) |
| { |
| case ScDBQueryParamBase::INTERNAL: |
| { |
| ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam); |
| mpData.reset(new DataAccessInternal(this, p, pDocument)); |
| } |
| break; |
| case ScDBQueryParamBase::MATRIX: |
| { |
| ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam); |
| mpData.reset(new DataAccessMatrix(this, p)); |
| } |
| } |
| } |
| |
| bool ScDBQueryDataIterator::GetFirst(Value& rValue) |
| { |
| return mpData->getFirst(rValue); |
| } |
| |
| bool ScDBQueryDataIterator::GetNext(Value& rValue) |
| { |
| return mpData->getNext(rValue); |
| } |
| |
| // ============================================================================ |
| |
| ScCellIterator::ScCellIterator( ScDocument* pDocument, |
| SCCOL nSCol, SCROW nSRow, SCTAB nSTab, |
| SCCOL nECol, SCROW nERow, SCTAB nETab, sal_Bool bSTotal ) : |
| pDoc( pDocument ), |
| nStartCol( nSCol), |
| nStartRow( nSRow), |
| nStartTab( nSTab ), |
| nEndCol( nECol ), |
| nEndRow( nERow), |
| nEndTab( nETab ), |
| bSubTotal(bSTotal) |
| |
| { |
| PutInOrder( nStartCol, nEndCol); |
| PutInOrder( nStartRow, nEndRow); |
| PutInOrder( nStartTab, nEndTab ); |
| |
| if (!ValidCol(nStartCol)) nStartCol = MAXCOL; |
| if (!ValidCol(nEndCol)) nEndCol = MAXCOL; |
| if (!ValidRow(nStartRow)) nStartRow = MAXROW; |
| if (!ValidRow(nEndRow)) nEndRow = MAXROW; |
| if (!ValidTab(nStartTab)) nStartTab = MAXTAB; |
| if (!ValidTab(nEndTab)) nEndTab = MAXTAB; |
| |
| while (nEndTab>0 && !pDoc->pTab[nEndTab]) |
| --nEndTab; // nur benutzte Tabellen |
| if (nStartTab>nEndTab) |
| nStartTab = nEndTab; |
| |
| nCol = nStartCol; |
| nRow = nStartRow; |
| nTab = nStartTab; |
| nColRow = 0; // wird bei GetFirst initialisiert |
| |
| if (!pDoc->pTab[nTab]) |
| { |
| DBG_ERROR("Tabelle nicht gefunden"); |
| nStartCol = nCol = MAXCOL+1; |
| nStartRow = nRow = MAXROW+1; |
| nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst |
| } |
| } |
| |
| ScCellIterator::ScCellIterator |
| ( ScDocument* pDocument, const ScRange& rRange, sal_Bool bSTotal ) : |
| pDoc( pDocument ), |
| nStartCol( rRange.aStart.Col() ), |
| nStartRow( rRange.aStart.Row() ), |
| nStartTab( rRange.aStart.Tab() ), |
| nEndCol( rRange.aEnd.Col() ), |
| nEndRow( rRange.aEnd.Row() ), |
| nEndTab( rRange.aEnd.Tab() ), |
| bSubTotal(bSTotal) |
| |
| { |
| PutInOrder( nStartCol, nEndCol); |
| PutInOrder( nStartRow, nEndRow); |
| PutInOrder( nStartTab, nEndTab ); |
| |
| if (!ValidCol(nStartCol)) nStartCol = MAXCOL; |
| if (!ValidCol(nEndCol)) nEndCol = MAXCOL; |
| if (!ValidRow(nStartRow)) nStartRow = MAXROW; |
| if (!ValidRow(nEndRow)) nEndRow = MAXROW; |
| if (!ValidTab(nStartTab)) nStartTab = MAXTAB; |
| if (!ValidTab(nEndTab)) nEndTab = MAXTAB; |
| |
| while (nEndTab>0 && !pDoc->pTab[nEndTab]) |
| --nEndTab; // nur benutzte Tabellen |
| if (nStartTab>nEndTab) |
| nStartTab = nEndTab; |
| |
| nCol = nStartCol; |
| nRow = nStartRow; |
| nTab = nStartTab; |
| nColRow = 0; // wird bei GetFirst initialisiert |
| |
| if (!pDoc->pTab[nTab]) |
| { |
| DBG_ERROR("Tabelle nicht gefunden"); |
| nStartCol = nCol = MAXCOL+1; |
| nStartRow = nRow = MAXROW+1; |
| nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst |
| } |
| } |
| |
| ScBaseCell* ScCellIterator::GetThis() |
| { |
| ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| for ( ;; ) |
| { |
| if ( nRow > nEndRow ) |
| { |
| nRow = nStartRow; |
| do |
| { |
| nCol++; |
| if ( nCol > nEndCol ) |
| { |
| nCol = nStartCol; |
| nTab++; |
| if ( nTab > nEndTab ) |
| return NULL; // Ende und Aus |
| } |
| pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| } while ( pCol->nCount == 0 ); |
| pCol->Search( nRow, nColRow ); |
| } |
| |
| while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) ) |
| nColRow++; |
| |
| if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow ) |
| { |
| nRow = pCol->pItems[nColRow].nRow; |
| if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow ) ) |
| { |
| ScBaseCell* pCell = pCol->pItems[nColRow].pCell; |
| |
| if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA |
| && ((ScFormulaCell*)pCell)->IsSubTotal() ) |
| nRow++; // Sub-Total-Zeilen nicht |
| else |
| return pCell; // gefunden |
| } |
| else |
| nRow++; |
| } |
| else |
| nRow = nEndRow + 1; // Naechste Spalte |
| } |
| } |
| |
| ScBaseCell* ScCellIterator::GetFirst() |
| { |
| if ( !ValidTab(nTab) ) |
| return NULL; |
| nCol = nStartCol; |
| nRow = nStartRow; |
| nTab = nStartTab; |
| // nColRow = 0; |
| ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| pCol->Search( nRow, nColRow ); |
| return GetThis(); |
| } |
| |
| ScBaseCell* ScCellIterator::GetNext() |
| { |
| ++nRow; |
| return GetThis(); |
| } |
| |
| //------------------------------------------------------------------------------- |
| |
| ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable, |
| const ScQueryParam& rParam, sal_Bool bMod ) : |
| aParam (rParam), |
| pDoc( pDocument ), |
| nTab( nTable), |
| nStopOnMismatch( nStopOnMismatchDisabled ), |
| nTestEqualCondition( nTestEqualConditionDisabled ), |
| bAdvanceQuery( sal_False ), |
| bIgnoreMismatchOnLeadingStrings( sal_False ) |
| { |
| nCol = aParam.nCol1; |
| nRow = aParam.nRow1; |
| nColRow = 0; // wird bei GetFirst initialisiert |
| SCSIZE i; |
| if (bMod) // sonst schon eingetragen |
| { |
| for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++) |
| { |
| ScQueryEntry& rEntry = aParam.GetEntry(i); |
| sal_uInt32 nIndex = 0; |
| rEntry.bQueryByString = |
| !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, |
| nIndex, rEntry.nVal)); |
| } |
| } |
| nNumFormat = 0; // werden bei GetNumberFormat initialisiert |
| pAttrArray = 0; |
| nAttrEndRow = 0; |
| } |
| |
| ScBaseCell* ScQueryCellIterator::GetThis() |
| { |
| ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| const ScQueryEntry& rEntry = aParam.GetEntry(0); |
| SCCOLROW nFirstQueryField = rEntry.nField; |
| bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && |
| !rEntry.bQueryByString; |
| bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && |
| !aParam.bHasHeader && rEntry.bQueryByString && |
| ((aParam.bByRow && nRow == aParam.nRow1) || |
| (!aParam.bByRow && nCol == aParam.nCol1)); |
| for ( ;; ) |
| { |
| if ( nRow > aParam.nRow2 ) |
| { |
| nRow = aParam.nRow1; |
| if (aParam.bHasHeader && aParam.bByRow) |
| nRow++; |
| do |
| { |
| if ( ++nCol > aParam.nCol2 ) |
| return NULL; // Ende und Aus |
| if ( bAdvanceQuery ) |
| { |
| AdvanceQueryParamEntryField(); |
| nFirstQueryField = rEntry.nField; |
| } |
| pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| } while ( pCol->nCount == 0 ); |
| pCol->Search( nRow, nColRow ); |
| bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && |
| !aParam.bHasHeader && rEntry.bQueryByString && |
| aParam.bByRow; |
| } |
| |
| while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow ) |
| nColRow++; |
| |
| if ( nColRow < pCol->nCount && |
| (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 ) |
| { |
| ScBaseCell* pCell = pCol->pItems[nColRow].pCell; |
| if ( pCell->GetCellType() == CELLTYPE_NOTE ) |
| ++nRow; |
| else if (bAllStringIgnore && pCell->HasStringData()) |
| ++nRow; |
| else |
| { |
| sal_Bool bTestEqualCondition; |
| if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL, |
| (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL), |
| (nTestEqualCondition ? &bTestEqualCondition : NULL) ) ) |
| { |
| if ( nTestEqualCondition && bTestEqualCondition ) |
| nTestEqualCondition |= nTestEqualConditionMatched; |
| return pCell; // found |
| } |
| else if ( nStopOnMismatch ) |
| { |
| // Yes, even a mismatch may have a fulfilled equal |
| // condition if regular expressions were involved and |
| // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried. |
| if ( nTestEqualCondition && bTestEqualCondition ) |
| { |
| nTestEqualCondition |= nTestEqualConditionMatched; |
| nStopOnMismatch |= nStopOnMismatchOccured; |
| return NULL; |
| } |
| bool bStop; |
| if (bFirstStringIgnore) |
| { |
| if (pCell->HasStringData()) |
| { |
| ++nRow; |
| bStop = false; |
| } |
| else |
| bStop = true; |
| } |
| else |
| bStop = true; |
| if (bStop) |
| { |
| nStopOnMismatch |= nStopOnMismatchOccured; |
| return NULL; |
| } |
| } |
| else |
| nRow++; |
| } |
| } |
| else |
| nRow = aParam.nRow2 + 1; // Naechste Spalte |
| bFirstStringIgnore = false; |
| } |
| } |
| |
| ScBaseCell* ScQueryCellIterator::GetFirst() |
| { |
| nCol = aParam.nCol1; |
| nRow = aParam.nRow1; |
| if (aParam.bHasHeader) |
| nRow++; |
| // nColRow = 0; |
| ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| pCol->Search( nRow, nColRow ); |
| return GetThis(); |
| } |
| |
| ScBaseCell* ScQueryCellIterator::GetNext() |
| { |
| ++nRow; |
| if ( nStopOnMismatch ) |
| nStopOnMismatch = nStopOnMismatchEnabled; |
| if ( nTestEqualCondition ) |
| nTestEqualCondition = nTestEqualConditionEnabled; |
| return GetThis(); |
| } |
| |
| void ScQueryCellIterator::AdvanceQueryParamEntryField() |
| { |
| SCSIZE nEntries = aParam.GetEntryCount(); |
| for ( SCSIZE j = 0; j < nEntries; j++ ) |
| { |
| ScQueryEntry& rEntry = aParam.GetEntry( j ); |
| if ( rEntry.bDoQuery ) |
| { |
| if ( rEntry.nField < MAXCOL ) |
| rEntry.nField++; |
| else |
| { |
| DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" ); |
| } |
| } |
| else |
| break; // for |
| } |
| } |
| |
| |
| sal_Bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol, |
| SCROW& nFoundRow, sal_Bool bSearchForEqualAfterMismatch, |
| sal_Bool bIgnoreMismatchOnLeadingStringsP ) |
| { |
| nFoundCol = MAXCOL+1; |
| nFoundRow = MAXROW+1; |
| SetStopOnMismatch( sal_True ); // assume sorted keys |
| SetTestEqualCondition( sal_True ); |
| bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP; |
| bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString; |
| bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp == |
| SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL); |
| if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst()) |
| { |
| // First equal entry or last smaller than (greater than) entry. |
| SCSIZE nColRowSave; |
| ScBaseCell* pNext = 0; |
| do |
| { |
| nFoundCol = GetCol(); |
| nFoundRow = GetRow(); |
| nColRowSave = nColRow; |
| } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL ); |
| // There may be no pNext but equal condition fulfilled if regular |
| // expressions are involved. Keep the found entry and proceed. |
| if (!pNext && !IsEqualConditionFulfilled()) |
| { |
| // Step back to last in range and adjust position markers for |
| // GetNumberFormat() or similar. |
| nCol = nFoundCol; |
| nRow = nFoundRow; |
| nColRow = nColRowSave; |
| } |
| } |
| if ( IsEqualConditionFulfilled() ) |
| { |
| // Position on last equal entry. |
| SCSIZE nEntries = aParam.GetEntryCount(); |
| for ( SCSIZE j = 0; j < nEntries; j++ ) |
| { |
| ScQueryEntry& rEntry = aParam.GetEntry( j ); |
| if ( rEntry.bDoQuery ) |
| { |
| switch ( rEntry.eOp ) |
| { |
| case SC_LESS_EQUAL : |
| case SC_GREATER_EQUAL : |
| rEntry.eOp = SC_EQUAL; |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| else |
| break; // for |
| } |
| SCSIZE nColRowSave; |
| bIgnoreMismatchOnLeadingStrings = sal_False; |
| SetTestEqualCondition( sal_False ); |
| do |
| { |
| nFoundCol = GetCol(); |
| nFoundRow = GetRow(); |
| nColRowSave = nColRow; |
| } while (GetNext()); |
| // Step back conditions same as above |
| nCol = nFoundCol; |
| nRow = nFoundRow; |
| nColRow = nColRowSave; |
| return sal_True; |
| } |
| if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) && |
| StoppedOnMismatch() ) |
| { |
| // Assume found entry to be the last value less than respectively |
| // greater than the query. But keep on searching for an equal match. |
| SCSIZE nEntries = aParam.GetEntryCount(); |
| for ( SCSIZE j = 0; j < nEntries; j++ ) |
| { |
| ScQueryEntry& rEntry = aParam.GetEntry( j ); |
| if ( rEntry.bDoQuery ) |
| { |
| switch ( rEntry.eOp ) |
| { |
| case SC_LESS_EQUAL : |
| case SC_GREATER_EQUAL : |
| rEntry.eOp = SC_EQUAL; |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| else |
| break; // for |
| } |
| SetStopOnMismatch( sal_False ); |
| SetTestEqualCondition( sal_False ); |
| if (GetNext()) |
| { |
| // Last of a consecutive area, avoid searching the entire parameter |
| // range as it is a real performance bottleneck in case of regular |
| // expressions. |
| SCSIZE nColRowSave; |
| do |
| { |
| nFoundCol = GetCol(); |
| nFoundRow = GetRow(); |
| nColRowSave = nColRow; |
| SetStopOnMismatch( sal_True ); |
| } while (GetNext()); |
| nCol = nFoundCol; |
| nRow = nFoundRow; |
| nColRow = nColRowSave; |
| } |
| } |
| return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW); |
| } |
| |
| |
| ScBaseCell* ScQueryCellIterator::BinarySearch() |
| { |
| nCol = aParam.nCol1; |
| ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol]; |
| if (!pCol->nCount) |
| return 0; |
| |
| ScBaseCell* pCell; |
| SCSIZE nHi, nLo; |
| CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::GetCaseCollator() : |
| ScGlobal::GetCollator()); |
| SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable()); |
| const ScQueryEntry& rEntry = aParam.GetEntry(0); |
| bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL; |
| bool bByString = rEntry.bQueryByString; |
| bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString; |
| bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings && |
| !aParam.bHasHeader && bByString; |
| |
| nRow = aParam.nRow1; |
| if (aParam.bHasHeader) |
| nRow++; |
| const ColEntry* pItems = pCol->pItems; |
| if (pCol->Search( nRow, nLo ) && bFirstStringIgnore && |
| pItems[nLo].pCell->HasStringData()) |
| { |
| String aCellStr; |
| sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLo].nRow); |
| ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr, |
| rFormatter); |
| sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr); |
| if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) || |
| (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) || |
| (rEntry.eOp == SC_EQUAL && nTmp != 0)) |
| ++nLo; |
| } |
| if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0) |
| --nHi; |
| while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount && |
| pItems[nLo].pCell->HasStringData()) |
| ++nLo; |
| |
| // Bookkeeping values for breaking up the binary search in case the data |
| // range isn't strictly sorted. |
| SCSIZE nLastInRange = nLo; |
| SCSIZE nFirstLastInRange = nLastInRange; |
| double fLastInRangeValue = bLessEqual ? |
| -(::std::numeric_limits<double>::max()) : |
| ::std::numeric_limits<double>::max(); |
| String aLastInRangeString; |
| if (!bLessEqual) |
| aLastInRangeString.Assign( sal_Unicode(0xFFFF)); |
| if (nLastInRange < pCol->nCount) |
| { |
| pCell = pItems[nLastInRange].pCell; |
| if (pCell->HasStringData()) |
| { |
| sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow); |
| ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString, |
| rFormatter); |
| } |
| else |
| { |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : |
| fLastInRangeValue = |
| static_cast<ScValueCell*>(pCell)->GetValue(); |
| break; |
| case CELLTYPE_FORMULA : |
| fLastInRangeValue = |
| static_cast<ScFormulaCell*>(pCell)->GetValue(); |
| break; |
| default: |
| { |
| // added to avoid warnings |
| } |
| } |
| } |
| } |
| |
| sal_Int32 nRes = 0; |
| bool bFound = false; |
| bool bDone = false; |
| while (nLo <= nHi && !bDone) |
| { |
| SCSIZE nMid = (nLo+nHi)/2; |
| SCSIZE i = nMid; |
| while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE) |
| ++i; |
| if (i > nHi) |
| { |
| if (nMid > 0) |
| nHi = nMid - 1; |
| else |
| bDone = true; |
| continue; // while |
| } |
| sal_Bool bStr = pItems[i].pCell->HasStringData(); |
| nRes = 0; |
| // compares are content<query:-1, content>query:1 |
| // Cell value comparison similar to ScTable::ValidQuery() |
| if (!bStr && !bByString) |
| { |
| double nCellVal; |
| pCell = pItems[i].pCell; |
| switch ( pCell->GetCellType() ) |
| { |
| case CELLTYPE_VALUE : |
| nCellVal = static_cast<ScValueCell*>(pCell)->GetValue(); |
| break; |
| case CELLTYPE_FORMULA : |
| nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue(); |
| break; |
| default: |
| nCellVal = 0.0; |
| } |
| if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( |
| nCellVal, rEntry.nVal)) |
| { |
| nRes = -1; |
| if (bLessEqual) |
| { |
| if (fLastInRangeValue < nCellVal) |
| { |
| fLastInRangeValue = nCellVal; |
| nLastInRange = i; |
| } |
| else if (fLastInRangeValue > nCellVal) |
| { |
| // not strictly sorted, continue with GetThis() |
| nLastInRange = nFirstLastInRange; |
| bDone = true; |
| } |
| } |
| } |
| else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( |
| nCellVal, rEntry.nVal)) |
| { |
| nRes = 1; |
| if (!bLessEqual) |
| { |
| if (fLastInRangeValue > nCellVal) |
| { |
| fLastInRangeValue = nCellVal; |
| nLastInRange = i; |
| } |
| else if (fLastInRangeValue < nCellVal) |
| { |
| // not strictly sorted, continue with GetThis() |
| nLastInRange = nFirstLastInRange; |
| bDone = true; |
| } |
| } |
| } |
| } |
| else if (bStr && bByString) |
| { |
| String aCellStr; |
| sal_uLong nFormat = pCol->GetNumberFormat( pItems[i].nRow); |
| ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr, |
| rFormatter); |
| nRes = pCollator->compareString( aCellStr, *rEntry.pStr); |
| if (nRes < 0 && bLessEqual) |
| { |
| sal_Int32 nTmp = pCollator->compareString( aLastInRangeString, |
| aCellStr); |
| if (nTmp < 0) |
| { |
| aLastInRangeString = aCellStr; |
| nLastInRange = i; |
| } |
| else if (nTmp > 0) |
| { |
| // not strictly sorted, continue with GetThis() |
| nLastInRange = nFirstLastInRange; |
| bDone = true; |
| } |
| } |
| else if (nRes > 0 && !bLessEqual) |
| { |
| sal_Int32 nTmp = pCollator->compareString( aLastInRangeString, |
| aCellStr); |
| if (nTmp > 0) |
| { |
| aLastInRangeString = aCellStr; |
| nLastInRange = i; |
| } |
| else if (nTmp < 0) |
| { |
| // not strictly sorted, continue with GetThis() |
| nLastInRange = nFirstLastInRange; |
| bDone = true; |
| } |
| } |
| } |
| else if (!bStr && bByString) |
| { |
| nRes = -1; // numeric < string |
| if (bLessEqual) |
| nLastInRange = i; |
| } |
| else // if (bStr && !bByString) |
| { |
| nRes = 1; // string > numeric |
| if (!bLessEqual) |
| nLastInRange = i; |
| } |
| if (nRes < 0) |
| { |
| if (bLessEqual) |
| nLo = nMid + 1; |
| else // assumed to be SC_GREATER_EQUAL |
| { |
| if (nMid > 0) |
| nHi = nMid - 1; |
| else |
| bDone = true; |
| } |
| } |
| else if (nRes > 0) |
| { |
| if (bLessEqual) |
| { |
| if (nMid > 0) |
| nHi = nMid - 1; |
| else |
| bDone = true; |
| } |
| else // assumed to be SC_GREATER_EQUAL |
| nLo = nMid + 1; |
| } |
| else |
| { |
| nLo = i; |
| bDone = bFound = true; |
| } |
| } |
| if (!bFound) |
| { |
| // If all hits didn't result in a moving limit there's something |
| // strange, e.g. data range not properly sorted, or only identical |
| // values encountered, which doesn't mean there aren't any others in |
| // between.. leave it to GetThis(). The condition for this would be |
| // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange; |
| // Else, in case no exact match was found, we step back for a |
| // subsequent GetThis() to find the last in range. Effectively this is |
| // --nLo with nLastInRange == nLo-1. Both conditions combined yield: |
| nLo = nLastInRange; |
| } |
| if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2) |
| { |
| nRow = pItems[nLo].nRow; |
| pCell = pItems[nLo].pCell; |
| nColRow = nLo; |
| } |
| else |
| { |
| nRow = aParam.nRow2 + 1; |
| pCell = 0; |
| nColRow = pCol->nCount - 1; |
| } |
| return pCell; |
| } |
| |
| |
| //------------------------------------------------------------------------------- |
| |
| ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable, |
| SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : |
| pDoc( pDocument ), |
| nTab( nTable ), |
| nStartCol( nCol1 ), |
| nEndCol( nCol2 ), |
| nStartRow( nRow1 ), |
| nEndRow( nRow2 ), |
| nCol( nCol1 ), |
| nRow( nRow1 ), |
| bMore( sal_True ) |
| { |
| |
| pNextRows = new SCROW[ nCol2-nCol1+1 ]; |
| pNextIndices = new SCSIZE[ nCol2-nCol1+1 ]; |
| |
| SetTab( nTab ); |
| } |
| |
| ScHorizontalCellIterator::~ScHorizontalCellIterator() |
| { |
| delete [] pNextRows; |
| delete [] pNextIndices; |
| } |
| |
| void ScHorizontalCellIterator::SetTab( SCTAB nTabP ) |
| { |
| nTab = nTabP; |
| nRow = nStartRow; |
| nCol = nStartCol; |
| bMore = sal_True; |
| |
| for (SCCOL i=nStartCol; i<=nEndCol; i++) |
| { |
| ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i]; |
| |
| SCSIZE nIndex; |
| pCol->Search( nStartRow, nIndex ); |
| if ( nIndex < pCol->nCount ) |
| { |
| pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow; |
| pNextIndices[i-nStartCol] = nIndex; |
| } |
| else |
| { |
| pNextRows[i-nStartCol] = MAXROWCOUNT; // nichts gefunden |
| pNextIndices[i-nStartCol] = MAXROWCOUNT; |
| } |
| } |
| |
| if (pNextRows[0] != nStartRow) |
| Advance(); |
| } |
| |
| ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow ) |
| { |
| if ( bMore ) |
| { |
| rCol = nCol; |
| rRow = nRow; |
| |
| ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol]; |
| SCSIZE nIndex = pNextIndices[nCol-nStartCol]; |
| DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" ); |
| ScBaseCell* pCell = pCol->pItems[nIndex].pCell; |
| if ( ++nIndex < pCol->nCount ) |
| { |
| pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow; |
| pNextIndices[nCol-nStartCol] = nIndex; |
| } |
| else |
| { |
| pNextRows[nCol-nStartCol] = MAXROWCOUNT; // nichts gefunden |
| pNextIndices[nCol-nStartCol] = MAXROWCOUNT; |
| } |
| |
| Advance(); |
| return pCell; |
| } |
| else |
| return NULL; |
| } |
| |
| sal_Bool ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow ) |
| { |
| rCol = nCol; |
| rRow = nRow; |
| return bMore; |
| } |
| |
| void ScHorizontalCellIterator::Advance() |
| { |
| sal_Bool bFound = sal_False; |
| SCCOL i; |
| |
| for (i=nCol+1; i<=nEndCol && !bFound; i++) |
| if (pNextRows[i-nStartCol] == nRow) |
| { |
| nCol = i; |
| bFound = sal_True; |
| } |
| |
| if (!bFound) |
| { |
| SCROW nMinRow = MAXROW+1; |
| for (i=nStartCol; i<=nEndCol; i++) |
| if (pNextRows[i-nStartCol] < nMinRow) |
| { |
| nCol = i; |
| nMinRow = pNextRows[i-nStartCol]; |
| } |
| |
| if (nMinRow <= nEndRow) |
| { |
| nRow = nMinRow; |
| bFound = sal_True; |
| } |
| } |
| |
| if ( !bFound ) |
| bMore = sal_False; |
| } |
| |
| //------------------------------------------------------------------------ |
| |
| ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument* pDocument, |
| const ScRange& rRange, bool bSTotal, bool bTextZero ) : |
| pDoc( pDocument ), |
| nNumFmtIndex(0), |
| nEndTab( rRange.aEnd.Tab() ), |
| nNumFmtType( NUMBERFORMAT_UNDEFINED ), |
| bNumValid( false ), |
| bSubTotal( bSTotal ), |
| bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ), |
| bTextAsZero( bTextZero ) |
| { |
| SCCOL nStartCol = rRange.aStart.Col(); |
| SCROW nStartRow = rRange.aStart.Row(); |
| SCTAB nStartTab = rRange.aStart.Tab(); |
| SCCOL nEndCol = rRange.aEnd.Col(); |
| SCROW nEndRow = rRange.aEnd.Row(); |
| PutInOrder( nStartCol, nEndCol); |
| PutInOrder( nStartRow, nEndRow); |
| PutInOrder( nStartTab, nEndTab ); |
| |
| if (!ValidCol(nStartCol)) nStartCol = MAXCOL; |
| if (!ValidCol(nEndCol)) nEndCol = MAXCOL; |
| if (!ValidRow(nStartRow)) nStartRow = MAXROW; |
| if (!ValidRow(nEndRow)) nEndRow = MAXROW; |
| if (!ValidTab(nStartTab)) nStartTab = MAXTAB; |
| if (!ValidTab(nEndTab)) nEndTab = MAXTAB; |
| |
| nCurCol = nStartCol; |
| nCurRow = nStartRow; |
| nCurTab = nStartTab; |
| |
| nNumFormat = 0; // will be initialized in GetNumberFormat() |
| pAttrArray = 0; |
| nAttrEndRow = 0; |
| |
| pCellIter = new ScHorizontalCellIterator( pDoc, nStartTab, nStartCol, |
| nStartRow, nEndCol, nEndRow ); |
| } |
| |
| ScHorizontalValueIterator::~ScHorizontalValueIterator() |
| { |
| delete pCellIter; |
| } |
| |
| bool ScHorizontalValueIterator::GetNext( double& rValue, sal_uInt16& rErr ) |
| { |
| bool bFound = false; |
| while ( !bFound ) |
| { |
| ScBaseCell* pCell = pCellIter->GetNext( nCurCol, nCurRow ); |
| while ( !pCell ) |
| { |
| if ( nCurTab < nEndTab ) |
| { |
| pCellIter->SetTab( ++nCurTab); |
| pCell = pCellIter->GetNext( nCurCol, nCurRow ); |
| } |
| else |
| return false; |
| } |
| if ( !bSubTotal || !pDoc->pTab[nCurTab]->RowFiltered( nCurRow ) ) |
| { |
| switch (pCell->GetCellType()) |
| { |
| case CELLTYPE_VALUE: |
| { |
| bNumValid = false; |
| rValue = ((ScValueCell*)pCell)->GetValue(); |
| rErr = 0; |
| if ( bCalcAsShown ) |
| { |
| ScColumn* pCol = &pDoc->pTab[nCurTab]->aCol[nCurCol]; |
| lcl_IterGetNumberFormat( nNumFormat, pAttrArray, |
| nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc ); |
| rValue = pDoc->RoundValueAsShown( rValue, nNumFormat ); |
| } |
| bFound = true; |
| } |
| break; |
| case CELLTYPE_FORMULA: |
| { |
| if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal()) |
| { |
| rErr = ((ScFormulaCell*)pCell)->GetErrCode(); |
| if ( rErr || ((ScFormulaCell*)pCell)->IsValue() ) |
| { |
| rValue = ((ScFormulaCell*)pCell)->GetValue(); |
| bNumValid = false; |
| bFound = true; |
| } |
| else if ( bTextAsZero ) |
| { |
| rValue = 0.0; |
| bNumValid = false; |
| bFound = true; |
| } |
| } |
| } |
| break; |
| case CELLTYPE_STRING : |
| case CELLTYPE_EDIT : |
| { |
| if ( bTextAsZero ) |
| { |
| rErr = 0; |
| rValue = 0.0; |
| nNumFmtType = NUMBERFORMAT_NUMBER; |
| nNumFmtIndex = 0; |
| bNumValid = true; |
| bFound = true; |
| } |
| } |
| break; |
| default: |
| ; // nothing |
| } |
| } |
| } |
| return bFound; |
| } |
| |
| void ScHorizontalValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex ) |
| { |
| if (!bNumValid) |
| { |
| const ScColumn* pCol = &(pDoc->pTab[nCurTab])->aCol[nCurCol]; |
| nNumFmtIndex = pCol->GetNumberFormat( nCurRow ); |
| if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 ) |
| { |
| const ScBaseCell* pCell; |
| SCSIZE nCurIndex; |
| if ( pCol->Search( nCurRow, nCurIndex ) ) |
| pCell = pCol->pItems[nCurIndex].pCell; |
| else |
| pCell = NULL; |
| if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA ) |
| ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex ); |
| else |
| nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); |
| } |
| else |
| nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex ); |
| bNumValid = true; |
| } |
| nType = nNumFmtType; |
| nIndex = nNumFmtIndex; |
| } |
| |
| //------------------------------------------------------------------------------- |
| |
| ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable, |
| SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : |
| pDoc( pDocument ), |
| nTab( nTable ), |
| nStartCol( nCol1 ), |
| nStartRow( nRow1 ), |
| nEndCol( nCol2 ), |
| nEndRow( nRow2 ) |
| { |
| DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" ); |
| |
| SCCOL i; |
| |
| nRow = nStartRow; |
| nCol = nStartCol; |
| bRowEmpty = sal_False; |
| |
| pIndices = new SCSIZE[nEndCol-nStartCol+1]; |
| pNextEnd = new SCROW[nEndCol-nStartCol+1]; |
| ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1]; |
| |
| SCROW nSkipTo = MAXROW; |
| sal_Bool bEmpty = sal_True; |
| for (i=nStartCol; i<=nEndCol; i++) |
| { |
| SCCOL nPos = i - nStartCol; |
| ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray; |
| DBG_ASSERT( pArray, "pArray == 0" ); |
| |
| SCSIZE nIndex; |
| pArray->Search( nStartRow, nIndex ); |
| |
| const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern; |
| SCROW nThisEnd = pArray->pData[nIndex].nRow; |
| if ( IsDefaultItem( pPattern ) ) |
| { |
| pPattern = NULL; |
| if ( nThisEnd < nSkipTo ) |
| nSkipTo = nThisEnd; // nSkipTo kann gleich hier gesetzt werden |
| } |
| else |
| bEmpty = sal_False; // Attribute gefunden |
| |
| pIndices[nPos] = nIndex; |
| pNextEnd[nPos] = nThisEnd; |
| ppPatterns[nPos] = pPattern; |
| } |
| |
| if (bEmpty) |
| nRow = nSkipTo; // bis zum naechsten Bereichsende ueberspringen |
| bRowEmpty = bEmpty; |
| } |
| |
| ScHorizontalAttrIterator::~ScHorizontalAttrIterator() |
| { |
| delete[] (ScPatternAttr**)ppPatterns; |
| delete[] pNextEnd; |
| delete[] pIndices; |
| } |
| |
| const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow ) |
| { |
| for (;;) |
| { |
| if (!bRowEmpty) |
| { |
| // in dieser Zeile suchen |
| |
| while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] ) |
| ++nCol; |
| |
| if ( nCol <= nEndCol ) |
| { |
| const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol]; |
| rRow = nRow; |
| rCol1 = nCol; |
| while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat ) |
| ++nCol; |
| rCol2 = nCol; |
| ++nCol; // hochzaehlen fuer naechsten Aufruf |
| return pPat; // gefunden |
| } |
| } |
| |
| // naechste Zeile |
| |
| ++nRow; |
| if ( nRow > nEndRow ) // schon am Ende? |
| return NULL; // nichts gefunden |
| |
| sal_Bool bEmpty = sal_True; |
| SCCOL i; |
| |
| for ( i = nStartCol; i <= nEndCol; i++) |
| { |
| SCCOL nPos = i-nStartCol; |
| if ( pNextEnd[nPos] < nRow ) |
| { |
| ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray; |
| |
| SCSIZE nIndex = ++pIndices[nPos]; |
| if ( nIndex < pArray->nCount ) |
| { |
| const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern; |
| SCROW nThisEnd = pArray->pData[nIndex].nRow; |
| if ( IsDefaultItem( pPattern ) ) |
| pPattern = NULL; |
| else |
| bEmpty = sal_False; // Attribute gefunden |
| |
| pNextEnd[nPos] = nThisEnd; |
| ppPatterns[nPos] = pPattern; |
| |
| DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" ); |
| } |
| else |
| { |
| DBG_ERROR("AttrArray reicht nicht bis MAXROW"); |
| pNextEnd[nPos] = MAXROW; |
| ppPatterns[nPos] = NULL; |
| } |
| } |
| else if ( ppPatterns[nPos] ) |
| bEmpty = sal_False; // Bereich noch nicht zuende |
| } |
| |
| if (bEmpty) |
| { |
| SCCOL nCount = nEndCol-nStartCol+1; |
| SCROW nSkipTo = pNextEnd[0]; // naechstes Bereichsende suchen |
| for (i=1; i<nCount; i++) |
| if ( pNextEnd[i] < nSkipTo ) |
| nSkipTo = pNextEnd[i]; |
| nRow = nSkipTo; // leere Zeilen ueberspringen |
| } |
| bRowEmpty = bEmpty; |
| nCol = nStartCol; // wieder links anfangen |
| } |
| |
| // return NULL; |
| } |
| |
| //------------------------------------------------------------------------------- |
| |
| inline sal_Bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) |
| { |
| return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 ); |
| } |
| |
| ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable, |
| SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) : |
| aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ), |
| aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ), |
| nNextCol( nCol1 ), |
| nNextRow( nRow1 ) |
| { |
| pCell = aCellIter.GetNext( nCellCol, nCellRow ); |
| pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow ); |
| } |
| |
| ScUsedAreaIterator::~ScUsedAreaIterator() |
| { |
| } |
| |
| sal_Bool ScUsedAreaIterator::GetNext() |
| { |
| // Iteratoren weiterzaehlen |
| |
| if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) ) |
| pCell = aCellIter.GetNext( nCellCol, nCellRow ); |
| |
| while ( pCell && pCell->IsBlank() ) |
| pCell = aCellIter.GetNext( nCellCol, nCellRow ); |
| |
| if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) ) |
| pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow ); |
| |
| if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol ) |
| nAttrCol1 = nNextCol; |
| |
| // naechsten Abschnitt heraussuchen |
| |
| sal_Bool bFound = sal_True; |
| sal_Bool bUseCell = sal_False; |
| |
| if ( pCell && pPattern ) |
| { |
| if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // vorne nur Attribute ? |
| { |
| pFoundCell = NULL; |
| pFoundPattern = pPattern; |
| nFoundRow = nAttrRow; |
| nFoundStartCol = nAttrCol1; |
| if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // auch Zelle im Bereich ? |
| nFoundEndCol = nCellCol - 1; // nur bis vor der Zelle |
| else |
| nFoundEndCol = nAttrCol2; // alles |
| } |
| else |
| { |
| bUseCell = sal_True; |
| if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attribute auf der Zelle ? |
| pFoundPattern = pPattern; |
| else |
| pFoundPattern = NULL; |
| } |
| } |
| else if ( pCell ) // nur Zelle -> direkt uebernehmen |
| { |
| pFoundPattern = NULL; |
| bUseCell = sal_True; // Position von Zelle |
| } |
| else if ( pPattern ) // nur Attribute -> direkt uebernehmen |
| { |
| pFoundCell = NULL; |
| pFoundPattern = pPattern; |
| nFoundRow = nAttrRow; |
| nFoundStartCol = nAttrCol1; |
| nFoundEndCol = nAttrCol2; |
| } |
| else // gar nichts |
| bFound = sal_False; |
| |
| if ( bUseCell ) // Position von Zelle |
| { |
| pFoundCell = pCell; |
| nFoundRow = nCellRow; |
| nFoundStartCol = nFoundEndCol = nCellCol; |
| } |
| |
| if (bFound) |
| { |
| nNextRow = nFoundRow; |
| nNextCol = nFoundEndCol + 1; |
| } |
| |
| return bFound; |
| } |
| |
| //------------------------------------------------------------------------------- |
| |
| ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable, |
| SCCOL nCol1, SCROW nRow1, |
| SCCOL nCol2, SCROW nRow2) : |
| pDoc( pDocument ), |
| nTab( nTable ), |
| nEndCol( nCol2 ), |
| nStartRow( nRow1 ), |
| nEndRow( nRow2 ), |
| nCol( nCol1 ) |
| { |
| if ( ValidTab(nTab) && pDoc->pTab[nTab] ) |
| pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow ); |
| else |
| pColIter = NULL; |
| } |
| |
| ScDocAttrIterator::~ScDocAttrIterator() |
| { |
| delete pColIter; |
| } |
| |
| const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 ) |
| { |
| while ( pColIter ) |
| { |
| const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 ); |
| if ( pPattern ) |
| { |
| rCol = nCol; |
| return pPattern; |
| } |
| |
| delete pColIter; |
| ++nCol; |
| if ( nCol <= nEndCol ) |
| pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow ); |
| else |
| pColIter = NULL; |
| } |
| return NULL; // is nix mehr |
| } |
| |
| //------------------------------------------------------------------------------- |
| |
| ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable, |
| SCCOL nCol1, SCROW nRow1, |
| SCCOL nCol2, SCROW nRow2) : |
| pDoc( pDocument ), |
| nTab( nTable ), |
| nEndCol( nCol2 ), |
| nStartRow( nRow1 ), |
| nEndRow( nRow2 ), |
| nIterStartCol( nCol1 ), |
| nIterEndCol( nCol1 ) |
| { |
| if ( ValidTab(nTab) && pDoc->pTab[nTab] ) |
| { |
| pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow ); |
| while ( nIterEndCol < nEndCol && |
| pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual( |
| pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) ) |
| ++nIterEndCol; |
| } |
| else |
| pColIter = NULL; |
| } |
| |
| ScAttrRectIterator::~ScAttrRectIterator() |
| { |
| delete pColIter; |
| } |
| |
| void ScAttrRectIterator::DataChanged() |
| { |
| if (pColIter) |
| { |
| SCROW nNextRow = pColIter->GetNextRow(); |
| delete pColIter; |
| pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow ); |
| } |
| } |
| |
| const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, |
| SCROW& rRow1, SCROW& rRow2 ) |
| { |
| while ( pColIter ) |
| { |
| const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 ); |
| if ( pPattern ) |
| { |
| rCol1 = nIterStartCol; |
| rCol2 = nIterEndCol; |
| return pPattern; |
| } |
| |
| delete pColIter; |
| nIterStartCol = nIterEndCol+1; |
| if ( nIterStartCol <= nEndCol ) |
| { |
| nIterEndCol = nIterStartCol; |
| pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow ); |
| while ( nIterEndCol < nEndCol && |
| pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual( |
| pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) ) |
| ++nIterEndCol; |
| } |
| else |
| pColIter = NULL; |
| } |
| return NULL; // is nix mehr |
| } |
| |
| // ============================================================================ |
| |
| SCROW ScRowBreakIterator::NOT_FOUND = -1; |
| |
| ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) : |
| mrBreaks(rBreaks), |
| maItr(rBreaks.begin()), maEnd(rBreaks.end()) |
| { |
| } |
| |
| SCROW ScRowBreakIterator::first() |
| { |
| maItr = mrBreaks.begin(); |
| return maItr == maEnd ? NOT_FOUND : *maItr; |
| } |
| |
| SCROW ScRowBreakIterator::next() |
| { |
| ++maItr; |
| return maItr == maEnd ? NOT_FOUND : *maItr; |
| } |