Update ooo320-m1
[ooovba.git] / sc / source / core / data / dociter.cxx
blob9f9dedbf93294373eae7efa5171a2926ca264d1a
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: dociter.cxx,v $
10 * $Revision: 1.22.88.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include <svtools/zforlist.hxx>
38 #include "scitems.hxx"
39 #include "global.hxx"
40 #include "dociter.hxx"
41 #include "document.hxx"
42 #include "table.hxx"
43 #include "column.hxx"
44 #include "cell.hxx"
45 #include "attarray.hxx"
46 #include "patattr.hxx"
47 #include "docoptio.hxx"
48 #include "cellform.hxx"
50 #include <vector>
52 using ::rtl::math::approxEqual;
53 using ::std::vector;
54 using ::rtl::OUString;
56 // STATIC DATA -----------------------------------------------------------
58 namespace {
60 void lcl_toUpper(OUString& rStr)
62 rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, rStr.getLength());
67 ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument,
68 SCTAB nStartTable, SCTAB nEndTable ) :
69 pDoc( pDocument ),
70 nStartTab( nStartTable ),
71 nEndTab( nEndTable )
73 PutInOrder( nStartTab, nEndTab );
74 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
75 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
77 pDefPattern = pDoc->GetDefPattern();
79 nCol = 0;
80 nRow = 0;
81 nTab = nStartTab;
83 nColPos = 0;
84 nAttrPos = 0;
87 ScDocumentIterator::~ScDocumentIterator()
91 BOOL ScDocumentIterator::GetThisCol()
93 ScTable* pTab;
94 while ( (pTab = pDoc->pTab[nTab]) == NULL )
96 if ( nTab == nEndTab )
98 nCol = MAXCOL;
99 nRow = MAXROW;
100 return FALSE;
102 ++nTab;
104 ScColumn* pCol = &pTab->aCol[nCol];
105 ScAttrArray* pAtt = pCol->pAttrArray;
107 BOOL bFound = FALSE;
110 SCROW nColRow;
111 SCROW nAttrEnd;
115 nAttrEnd = pAtt->pData[nAttrPos].nRow;
116 if (nAttrEnd < nRow)
117 ++nAttrPos;
119 while (nAttrEnd < nRow);
123 nColRow = (nColPos < pCol->nCount) ? pCol->pItems[nColPos].nRow : MAXROW+1;
124 if (nColRow < nRow)
125 ++nColPos;
127 while (nColRow < nRow);
129 if (nColRow == nRow)
131 bFound = TRUE;
132 pCell = pCol->pItems[nColPos].pCell;
133 pPattern = pAtt->pData[nAttrPos].pPattern;
135 else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern )
137 bFound = TRUE;
138 pCell = NULL;
139 pPattern = pAtt->pData[nAttrPos].pPattern;
141 else
143 nRow = Min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) );
146 while (!bFound && nRow <= MAXROW);
148 return bFound;
151 BOOL ScDocumentIterator::GetThis()
153 BOOL bEnd = FALSE;
154 BOOL bSuccess = FALSE;
156 while ( !bSuccess && !bEnd )
158 if ( nRow > MAXROW )
159 bSuccess = FALSE;
160 else
161 bSuccess = GetThisCol();
163 if ( !bSuccess )
165 ++nCol;
166 if (nCol > MAXCOL)
168 nCol = 0;
169 ++nTab;
170 if (nTab > nEndTab)
171 bEnd = TRUE;
173 nRow = 0;
174 nColPos = 0;
175 nAttrPos = 0;
179 return !bEnd;
182 BOOL ScDocumentIterator::GetFirst()
184 nCol = 0;
185 nTab = nStartTab;
187 nRow = 0;
188 nColPos = 0;
189 nAttrPos = 0;
191 return GetThis();
194 BOOL ScDocumentIterator::GetNext()
196 ++nRow;
198 return GetThis();
201 //------------------------------------------------------------------------
203 ScBaseCell* ScDocumentIterator::GetCell()
205 return pCell;
208 const ScPatternAttr* ScDocumentIterator::GetPattern()
210 return pPattern;
213 void ScDocumentIterator::GetPos( SCCOL& rCol, SCROW& rRow, SCTAB& rTab )
215 rCol = nCol;
216 rRow = nRow;
217 rTab = nTab;
221 //------------------------------------------------------------------------
222 //------------------------------------------------------------------------
223 void lcl_IterGetNumberFormat( ULONG& nFormat, const ScAttrArray*& rpArr,
224 SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
225 ScDocument* pDoc )
227 if ( rpArr != pNewArr || nAttrEndRow < nRow )
229 SCSIZE nPos;
230 pNewArr->Search( nRow, nPos ); // nPos 0 gueltig wenn nicht gefunden
231 const ScPatternAttr* pPattern = pNewArr->pData[nPos].pPattern;
232 nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() );
233 rpArr = pNewArr;
234 nAttrEndRow = pNewArr->pData[nPos].nRow;
238 //UNUSED2008-05 ScValueIterator::ScValueIterator( ScDocument* pDocument,
239 //UNUSED2008-05 SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
240 //UNUSED2008-05 SCCOL nECol, SCROW nERow, SCTAB nETab,
241 //UNUSED2008-05 BOOL bSTotal, BOOL bTextZero ) :
242 //UNUSED2008-05 pDoc( pDocument ),
243 //UNUSED2008-05 nNumFmtIndex(0),
244 //UNUSED2008-05 nStartCol( nSCol),
245 //UNUSED2008-05 nStartRow( nSRow),
246 //UNUSED2008-05 nStartTab( nSTab ),
247 //UNUSED2008-05 nEndCol( nECol ),
248 //UNUSED2008-05 nEndRow( nERow),
249 //UNUSED2008-05 nEndTab( nETab ),
250 //UNUSED2008-05 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
251 //UNUSED2008-05 bNumValid( FALSE ),
252 //UNUSED2008-05 bSubTotal(bSTotal),
253 //UNUSED2008-05 bNextValid( FALSE ),
254 //UNUSED2008-05 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
255 //UNUSED2008-05 bTextAsZero( bTextZero )
256 //UNUSED2008-05 {
257 //UNUSED2008-05 PutInOrder( nStartCol, nEndCol);
258 //UNUSED2008-05 PutInOrder( nStartRow, nEndRow);
259 //UNUSED2008-05 PutInOrder( nStartTab, nEndTab );
260 //UNUSED2008-05
261 //UNUSED2008-05 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
262 //UNUSED2008-05 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
263 //UNUSED2008-05 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
264 //UNUSED2008-05 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
265 //UNUSED2008-05 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
266 //UNUSED2008-05 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
267 //UNUSED2008-05
268 //UNUSED2008-05 nCol = nStartCol;
269 //UNUSED2008-05 nRow = nStartRow;
270 //UNUSED2008-05 nTab = nStartTab;
271 //UNUSED2008-05
272 //UNUSED2008-05 nColRow = 0; // wird bei GetFirst initialisiert
273 //UNUSED2008-05
274 //UNUSED2008-05 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
275 //UNUSED2008-05 pAttrArray = 0;
276 //UNUSED2008-05 nAttrEndRow = 0;
277 //UNUSED2008-05 }
279 ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange,
280 BOOL bSTotal, BOOL bTextZero ) :
281 pDoc( pDocument ),
282 nNumFmtIndex(0),
283 nStartCol( rRange.aStart.Col() ),
284 nStartRow( rRange.aStart.Row() ),
285 nStartTab( rRange.aStart.Tab() ),
286 nEndCol( rRange.aEnd.Col() ),
287 nEndRow( rRange.aEnd.Row() ),
288 nEndTab( rRange.aEnd.Tab() ),
289 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
290 bNumValid( FALSE ),
291 bSubTotal(bSTotal),
292 bNextValid( FALSE ),
293 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
294 bTextAsZero( bTextZero )
296 PutInOrder( nStartCol, nEndCol);
297 PutInOrder( nStartRow, nEndRow);
298 PutInOrder( nStartTab, nEndTab );
300 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
301 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
302 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
303 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
304 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
305 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
307 nCol = nStartCol;
308 nRow = nStartRow;
309 nTab = nStartTab;
311 nColRow = 0; // wird bei GetFirst initialisiert
313 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
314 pAttrArray = 0;
315 nAttrEndRow = 0;
318 BOOL ScValueIterator::GetThis(double& rValue, USHORT& rErr)
320 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
321 for (;;)
323 if ( nRow > nEndRow )
325 nRow = nStartRow;
328 nCol++;
329 if ( nCol > nEndCol )
331 nCol = nStartCol;
332 nTab++;
333 if ( nTab > nEndTab )
335 // rValue = 0.0; //! do not change caller's value!
336 rErr = 0;
337 return FALSE; // Ende und Aus
340 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
341 } while ( pCol->nCount == 0 );
342 pCol->Search( nRow, nColRow );
345 while (( nColRow < pCol->nCount ) && ( pCol->pItems[nColRow].nRow < nRow ))
346 nColRow++;
348 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
350 nRow = pCol->pItems[nColRow].nRow + 1;
351 if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow-1 ) )
353 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
354 ++nColRow;
355 switch (pCell->GetCellType())
357 case CELLTYPE_VALUE:
359 bNumValid = FALSE;
360 rValue = ((ScValueCell*)pCell)->GetValue();
361 rErr = 0;
362 --nRow;
363 if ( bCalcAsShown )
365 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
366 nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
367 rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
370 // wenn in der selben Spalte gleich noch eine Value-Cell folgt, die
371 // auch noch im Block liegt, den Wert jetzt schon holen
373 if ( nColRow < pCol->nCount &&
374 pCol->pItems[nColRow].nRow <= nEndRow &&
375 pCol->pItems[nColRow].pCell->GetCellType() == CELLTYPE_VALUE &&
376 !bSubTotal )
378 fNextValue = ((ScValueCell*)pCol->pItems[nColRow].pCell)->GetValue();
379 nNextRow = pCol->pItems[nColRow].nRow;
380 bNextValid = TRUE;
381 if ( bCalcAsShown )
383 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
384 nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc );
385 fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat );
389 return TRUE; // gefunden
391 // break;
392 case CELLTYPE_FORMULA:
394 if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
396 rErr = ((ScFormulaCell*)pCell)->GetErrCode();
397 if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
399 rValue = ((ScFormulaCell*)pCell)->GetValue();
400 nRow--;
401 bNumValid = FALSE;
402 return TRUE; // gefunden
404 else if ( bTextAsZero )
406 rValue = 0.0;
407 nRow--;
408 bNumValid = FALSE;
409 return TRUE;
413 break;
414 case CELLTYPE_STRING :
415 case CELLTYPE_EDIT :
417 if ( bTextAsZero )
419 rErr = 0;
420 rValue = 0.0;
421 nNumFmtType = NUMBERFORMAT_NUMBER;
422 nNumFmtIndex = 0;
423 bNumValid = TRUE;
424 --nRow;
425 return TRUE;
428 break;
429 default:
431 // added to avoid warnings
436 else
437 nRow = nEndRow + 1; // naechste Spalte
441 void ScValueIterator::GetCurNumFmtInfo( short& nType, ULONG& nIndex )
443 if (!bNumValid)
445 const ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
446 nNumFmtIndex = pCol->GetNumberFormat( nRow );
447 if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
449 const ScBaseCell* pCell;
450 SCSIZE nIdx = nColRow - 1;
451 // there might be rearranged something, so be on the safe side
452 if ( nIdx < pCol->nCount && pCol->pItems[nIdx].nRow == nRow )
453 pCell = pCol->pItems[nIdx].pCell;
454 else
456 if ( pCol->Search( nRow, nIdx ) )
457 pCell = pCol->pItems[nIdx].pCell;
458 else
459 pCell = NULL;
461 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
462 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex );
463 else
464 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
466 else
467 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
468 bNumValid = TRUE;
470 nType = nNumFmtType;
471 nIndex = nNumFmtIndex;
474 BOOL ScValueIterator::GetFirst(double& rValue, USHORT& rErr)
476 nCol = nStartCol;
477 nRow = nStartRow;
478 nTab = nStartTab;
480 // nColRow = 0;
481 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
482 pCol->Search( nRow, nColRow );
484 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
485 pAttrArray = 0;
486 nAttrEndRow = 0;
488 return GetThis(rValue, rErr);
491 /* ist inline:
492 BOOL ScValueIterator::GetNext(double& rValue, USHORT& rErr)
494 ++nRow;
495 return GetThis(rValue, rErr);
499 // ============================================================================
501 ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) :
502 mpParent(pParent)
506 ScDBQueryDataIterator::DataAccess::~DataAccess()
510 // ----------------------------------------------------------------------------
512 ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) :
513 DataAccess(pParent),
514 mpParam(pParam),
515 mpDoc(pDoc)
517 nCol = mpParam->mnField;
518 nRow = mpParam->nRow1;
519 nTab = mpParam->nTab;
521 nColRow = 0; // wird bei GetFirst initialisiert
522 SCSIZE i;
523 SCSIZE nCount = mpParam->GetEntryCount();
524 for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++)
526 ScQueryEntry& rEntry = mpParam->GetEntry(i);
527 sal_uInt32 nIndex = 0;
528 rEntry.bQueryByString =
529 !(mpDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal));
531 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
532 pAttrArray = 0;
533 nAttrEndRow = 0;
536 ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
540 bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
542 ScColumn* pCol = &(mpDoc->pTab[nTab])->aCol[nCol];
543 SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
544 for ( ;; )
546 if (nRow > mpParam->nRow2)
548 // Bottom of the range reached. Bail out.
549 rValue.mnError = 0;
550 return false;
553 while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
554 nColRow++;
556 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= mpParam->nRow2 )
558 nRow = pCol->pItems[nColRow].nRow;
559 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
560 if ( (mpDoc->pTab[nTab])->ValidQuery( nRow, *mpParam, NULL,
561 (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL) ) )
563 switch (pCell->GetCellType())
565 case CELLTYPE_VALUE:
567 rValue.mfValue = ((ScValueCell*)pCell)->GetValue();
568 rValue.mbIsNumber = true;
569 if ( bCalcAsShown )
571 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
572 nAttrEndRow, pCol->pAttrArray, nRow, mpDoc );
573 rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat );
575 nNumFmtType = NUMBERFORMAT_NUMBER;
576 nNumFmtIndex = 0;
577 rValue.mnError = 0;
578 return TRUE; // gefunden
580 // break;
581 case CELLTYPE_FORMULA:
583 if (((ScFormulaCell*)pCell)->IsValue())
585 rValue.mfValue = ((ScFormulaCell*)pCell)->GetValue();
586 rValue.mbIsNumber = true;
587 mpDoc->GetNumberFormatInfo( nNumFmtType,
588 nNumFmtIndex, ScAddress( nCol, nRow, nTab ),
589 pCell );
590 rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode();
591 return TRUE; // gefunden
593 else
594 nRow++;
596 break;
597 case CELLTYPE_STRING:
598 case CELLTYPE_EDIT:
599 if (mpParam->mbSkipString)
600 ++nRow;
601 else
603 rValue.maString = pCell->GetStringData();
604 rValue.mfValue = 0.0;
605 rValue.mnError = 0;
606 rValue.mbIsNumber = false;
607 return true;
609 break;
610 default:
611 nRow++;
612 break;
615 else
616 nRow++;
618 else
619 nRow = mpParam->nRow2 + 1; // Naechste Spalte
621 return false;
624 bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue)
626 if (mpParam->bHasHeader)
627 nRow++;
628 // nColRow = 0;
629 ScColumn* pCol = &(mpDoc->pTab[nTab])->aCol[nCol];
630 pCol->Search( nRow, nColRow );
631 return getCurrent(rValue);
634 bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue)
636 ++nRow;
637 return getCurrent(rValue);
640 // ----------------------------------------------------------------------------
642 ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) :
643 DataAccess(pParent),
644 mpParam(pParam)
646 SCSIZE nC, nR;
647 mpParam->mpMatrix->GetDimensions(nC, nR);
648 mnRows = static_cast<SCROW>(nR);
649 mnCols = static_cast<SCCOL>(nC);
652 ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix()
656 bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue)
658 // Starting from row == mnCurRow, get the first row that satisfies all the
659 // query parameters.
660 for ( ;mnCurRow < mnRows; ++mnCurRow)
662 const ScMatrix& rMat = *mpParam->mpMatrix;
663 if (rMat.IsEmpty(mpParam->mnField, mnCurRow))
664 // Don't take empty values into account.
665 continue;
667 bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow);
668 if (bIsStrVal && mpParam->mbSkipString)
669 continue;
671 if (isValidQuery(mnCurRow, rMat))
673 rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow);
674 rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow);
675 rValue.mbIsNumber = !bIsStrVal;
676 rValue.mnError = 0;
677 return true;
680 return false;
683 bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue)
685 mnCurRow = mpParam->bHasHeader ? 1 : 0;
686 return getCurrent(rValue);
689 bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue)
691 ++mnCurRow;
692 return getCurrent(rValue);
695 namespace {
697 bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
699 if (rEntry.bQueryByString)
700 return false;
702 if (!rMat.IsValueOrEmpty(nCol, nRow))
703 return false;
705 return true;
708 bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
710 switch (rEntry.eOp)
712 case SC_EQUAL:
713 case SC_NOT_EQUAL:
714 case SC_CONTAINS:
715 case SC_DOES_NOT_CONTAIN:
716 case SC_BEGINS_WITH:
717 case SC_ENDS_WITH:
718 case SC_DOES_NOT_BEGIN_WITH:
719 case SC_DOES_NOT_END_WITH:
720 return true;
721 default:
725 if (rEntry.bQueryByString && rMat.IsString(nCol, nRow))
726 return true;
728 return false;
733 bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const
735 SCSIZE nEntryCount = mpParam->GetEntryCount();
736 vector<bool> aResults;
737 aResults.reserve(nEntryCount);
739 const CollatorWrapper& rCollator =
740 mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
742 for (SCSIZE i = 0; i < nEntryCount; ++i)
744 const ScQueryEntry& rEntry = mpParam->GetEntry(i);
745 if (!rEntry.bDoQuery)
746 continue;
748 switch (rEntry.eOp)
750 case SC_EQUAL:
751 case SC_LESS:
752 case SC_GREATER:
753 case SC_LESS_EQUAL:
754 case SC_GREATER_EQUAL:
755 case SC_NOT_EQUAL:
756 break;
757 default:
758 // Only the above operators are supported.
759 continue;
762 bool bValid = false;
764 SCSIZE nField = static_cast<SCSIZE>(rEntry.nField);
765 if (lcl_isQueryByValue(rEntry, rMat, nField, nRow))
767 // By value
768 double fMatVal = rMat.GetDouble(nField, nRow);
769 bool bEqual = approxEqual(fMatVal, rEntry.nVal);
770 switch (rEntry.eOp)
772 case SC_EQUAL:
773 bValid = bEqual;
774 break;
775 case SC_LESS:
776 bValid = (fMatVal < rEntry.nVal) && !bEqual;
777 break;
778 case SC_GREATER:
779 bValid = (fMatVal > rEntry.nVal) && !bEqual;
780 break;
781 case SC_LESS_EQUAL:
782 bValid = (fMatVal < rEntry.nVal) || bEqual;
783 break;
784 case SC_GREATER_EQUAL:
785 bValid = (fMatVal > rEntry.nVal) || bEqual;
786 break;
787 case SC_NOT_EQUAL:
788 bValid = !bEqual;
789 break;
790 default:
794 else if (lcl_isQueryByString(rEntry, rMat, nField, nRow))
796 // By string
799 if (!rEntry.pStr)
800 break;
802 // Equality check first.
804 OUString aMatStr = rMat.GetString(nField, nRow);
805 lcl_toUpper(aMatStr);
806 OUString aQueryStr = *rEntry.pStr;
807 lcl_toUpper(aQueryStr);
808 bool bDone = false;
809 switch (rEntry.eOp)
811 case SC_EQUAL:
812 bValid = aMatStr.equals(aQueryStr);
813 bDone = true;
814 break;
815 case SC_NOT_EQUAL:
816 bValid = !aMatStr.equals(aQueryStr);
817 bDone = true;
818 break;
819 default:
823 if (bDone)
824 break;
826 // Unequality check using collator.
828 sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr);
829 switch (rEntry.eOp)
831 case SC_LESS :
832 bValid = (nCompare < 0);
833 break;
834 case SC_GREATER :
835 bValid = (nCompare > 0);
836 break;
837 case SC_LESS_EQUAL :
838 bValid = (nCompare <= 0);
839 break;
840 case SC_GREATER_EQUAL :
841 bValid = (nCompare >= 0);
842 break;
843 default:
847 while (false);
849 else if (mpParam->bMixedComparison)
851 // Not used at the moment.
854 if (aResults.empty())
855 // First query entry.
856 aResults.push_back(bValid);
857 else if (rEntry.eConnect == SC_AND)
859 // For AND op, tuck the result into the last result value.
860 size_t n = aResults.size();
861 aResults[n-1] = aResults[n-1] && bValid;
863 else
864 // For OR op, store its own result.
865 aResults.push_back(bValid);
868 // Row is valid as long as there is at least one result being true.
869 vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end();
870 for (; itr != itrEnd; ++itr)
871 if (*itr)
872 return true;
874 return false;
877 // ----------------------------------------------------------------------------
879 ScDBQueryDataIterator::Value::Value() :
880 mnError(0), mbIsNumber(true)
882 ::rtl::math::setNan(&mfValue);
885 // ----------------------------------------------------------------------------
887 ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) :
888 mpParam (pParam)
890 switch (mpParam->GetType())
892 case ScDBQueryParamBase::INTERNAL:
894 ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam);
895 mpData.reset(new DataAccessInternal(this, p, pDocument));
897 break;
898 case ScDBQueryParamBase::MATRIX:
900 ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam);
901 mpData.reset(new DataAccessMatrix(this, p));
906 bool ScDBQueryDataIterator::GetThis(Value& rValue)
908 return mpData->getCurrent(rValue);
911 bool ScDBQueryDataIterator::GetFirst(Value& rValue)
913 return mpData->getFirst(rValue);
916 bool ScDBQueryDataIterator::GetNext(Value& rValue)
918 return mpData->getNext(rValue);
921 // ============================================================================
923 ScCellIterator::ScCellIterator( ScDocument* pDocument,
924 SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
925 SCCOL nECol, SCROW nERow, SCTAB nETab, BOOL bSTotal ) :
926 pDoc( pDocument ),
927 nStartCol( nSCol),
928 nStartRow( nSRow),
929 nStartTab( nSTab ),
930 nEndCol( nECol ),
931 nEndRow( nERow),
932 nEndTab( nETab ),
933 bSubTotal(bSTotal)
936 PutInOrder( nStartCol, nEndCol);
937 PutInOrder( nStartRow, nEndRow);
938 PutInOrder( nStartTab, nEndTab );
940 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
941 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
942 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
943 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
944 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
945 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
947 while (nEndTab>0 && !pDoc->pTab[nEndTab])
948 --nEndTab; // nur benutzte Tabellen
949 if (nStartTab>nEndTab)
950 nStartTab = nEndTab;
952 nCol = nStartCol;
953 nRow = nStartRow;
954 nTab = nStartTab;
955 nColRow = 0; // wird bei GetFirst initialisiert
957 if (!pDoc->pTab[nTab])
959 DBG_ERROR("Tabelle nicht gefunden");
960 nStartCol = nCol = MAXCOL+1;
961 nStartRow = nRow = MAXROW+1;
962 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst
966 ScCellIterator::ScCellIterator
967 ( ScDocument* pDocument, const ScRange& rRange, BOOL bSTotal ) :
968 pDoc( pDocument ),
969 nStartCol( rRange.aStart.Col() ),
970 nStartRow( rRange.aStart.Row() ),
971 nStartTab( rRange.aStart.Tab() ),
972 nEndCol( rRange.aEnd.Col() ),
973 nEndRow( rRange.aEnd.Row() ),
974 nEndTab( rRange.aEnd.Tab() ),
975 bSubTotal(bSTotal)
978 PutInOrder( nStartCol, nEndCol);
979 PutInOrder( nStartRow, nEndRow);
980 PutInOrder( nStartTab, nEndTab );
982 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
983 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
984 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
985 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
986 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
987 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
989 while (nEndTab>0 && !pDoc->pTab[nEndTab])
990 --nEndTab; // nur benutzte Tabellen
991 if (nStartTab>nEndTab)
992 nStartTab = nEndTab;
994 nCol = nStartCol;
995 nRow = nStartRow;
996 nTab = nStartTab;
997 nColRow = 0; // wird bei GetFirst initialisiert
999 if (!pDoc->pTab[nTab])
1001 DBG_ERROR("Tabelle nicht gefunden");
1002 nStartCol = nCol = MAXCOL+1;
1003 nStartRow = nRow = MAXROW+1;
1004 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst
1008 ScBaseCell* ScCellIterator::GetThis()
1010 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1011 for ( ;; )
1013 if ( nRow > nEndRow )
1015 nRow = nStartRow;
1018 nCol++;
1019 if ( nCol > nEndCol )
1021 nCol = nStartCol;
1022 nTab++;
1023 if ( nTab > nEndTab )
1024 return NULL; // Ende und Aus
1026 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1027 } while ( pCol->nCount == 0 );
1028 pCol->Search( nRow, nColRow );
1031 while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
1032 nColRow++;
1034 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
1036 nRow = pCol->pItems[nColRow].nRow;
1037 if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow ) )
1039 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
1041 if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA
1042 && ((ScFormulaCell*)pCell)->IsSubTotal() )
1043 nRow++; // Sub-Total-Zeilen nicht
1044 else
1045 return pCell; // gefunden
1047 else
1048 nRow++;
1050 else
1051 nRow = nEndRow + 1; // Naechste Spalte
1055 ScBaseCell* ScCellIterator::GetFirst()
1057 if ( !ValidTab(nTab) )
1058 return NULL;
1059 nCol = nStartCol;
1060 nRow = nStartRow;
1061 nTab = nStartTab;
1062 // nColRow = 0;
1063 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1064 pCol->Search( nRow, nColRow );
1065 return GetThis();
1068 ScBaseCell* ScCellIterator::GetNext()
1070 ++nRow;
1071 return GetThis();
1074 //-------------------------------------------------------------------------------
1076 ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
1077 const ScQueryParam& rParam, BOOL bMod ) :
1078 aParam (rParam),
1079 pDoc( pDocument ),
1080 nTab( nTable),
1081 nStopOnMismatch( nStopOnMismatchDisabled ),
1082 nTestEqualCondition( nTestEqualConditionDisabled ),
1083 bAdvanceQuery( FALSE ),
1084 bIgnoreMismatchOnLeadingStrings( FALSE )
1086 nCol = aParam.nCol1;
1087 nRow = aParam.nRow1;
1088 nColRow = 0; // wird bei GetFirst initialisiert
1089 SCSIZE i;
1090 if (bMod) // sonst schon eingetragen
1092 for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++)
1094 ScQueryEntry& rEntry = aParam.GetEntry(i);
1095 sal_uInt32 nIndex = 0;
1096 rEntry.bQueryByString =
1097 !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr,
1098 nIndex, rEntry.nVal));
1101 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
1102 pAttrArray = 0;
1103 nAttrEndRow = 0;
1106 ScBaseCell* ScQueryCellIterator::GetThis()
1108 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1109 const ScQueryEntry& rEntry = aParam.GetEntry(0);
1110 SCCOLROW nFirstQueryField = rEntry.nField;
1111 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1112 !rEntry.bQueryByString;
1113 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1114 !aParam.bHasHeader && rEntry.bQueryByString &&
1115 ((aParam.bByRow && nRow == aParam.nRow1) ||
1116 (!aParam.bByRow && nCol == aParam.nCol1));
1117 for ( ;; )
1119 if ( nRow > aParam.nRow2 )
1121 nRow = aParam.nRow1;
1122 if (aParam.bHasHeader && aParam.bByRow)
1123 nRow++;
1126 if ( ++nCol > aParam.nCol2 )
1127 return NULL; // Ende und Aus
1128 if ( bAdvanceQuery )
1130 AdvanceQueryParamEntryField();
1131 nFirstQueryField = rEntry.nField;
1133 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1134 } while ( pCol->nCount == 0 );
1135 pCol->Search( nRow, nColRow );
1136 bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1137 !aParam.bHasHeader && rEntry.bQueryByString &&
1138 aParam.bByRow;
1141 while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow )
1142 nColRow++;
1144 if ( nColRow < pCol->nCount &&
1145 (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 )
1147 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
1148 if ( pCell->GetCellType() == CELLTYPE_NOTE )
1149 ++nRow;
1150 else if (bAllStringIgnore && pCell->HasStringData())
1151 ++nRow;
1152 else
1154 BOOL bTestEqualCondition;
1155 if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL,
1156 (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL),
1157 (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
1159 if ( nTestEqualCondition && bTestEqualCondition )
1160 nTestEqualCondition |= nTestEqualConditionMatched;
1161 return pCell; // found
1163 else if ( nStopOnMismatch )
1165 // Yes, even a mismatch may have a fulfilled equal
1166 // condition if regular expressions were involved and
1167 // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
1168 if ( nTestEqualCondition && bTestEqualCondition )
1170 nTestEqualCondition |= nTestEqualConditionMatched;
1171 nStopOnMismatch |= nStopOnMismatchOccured;
1172 return NULL;
1174 bool bStop;
1175 if (bFirstStringIgnore)
1177 if (pCell->HasStringData())
1179 ++nRow;
1180 bStop = false;
1182 else
1183 bStop = true;
1185 else
1186 bStop = true;
1187 if (bStop)
1189 nStopOnMismatch |= nStopOnMismatchOccured;
1190 return NULL;
1193 else
1194 nRow++;
1197 else
1198 nRow = aParam.nRow2 + 1; // Naechste Spalte
1199 bFirstStringIgnore = false;
1203 ScBaseCell* ScQueryCellIterator::GetFirst()
1205 nCol = aParam.nCol1;
1206 nRow = aParam.nRow1;
1207 if (aParam.bHasHeader)
1208 nRow++;
1209 // nColRow = 0;
1210 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1211 pCol->Search( nRow, nColRow );
1212 return GetThis();
1215 ScBaseCell* ScQueryCellIterator::GetNext()
1217 ++nRow;
1218 if ( nStopOnMismatch )
1219 nStopOnMismatch = nStopOnMismatchEnabled;
1220 if ( nTestEqualCondition )
1221 nTestEqualCondition = nTestEqualConditionEnabled;
1222 return GetThis();
1225 ULONG ScQueryCellIterator::GetNumberFormat()
1227 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1228 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
1229 nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
1230 return nNumFormat;
1233 void ScQueryCellIterator::AdvanceQueryParamEntryField()
1235 SCSIZE nEntries = aParam.GetEntryCount();
1236 for ( SCSIZE j = 0; j < nEntries; j++ )
1238 ScQueryEntry& rEntry = aParam.GetEntry( j );
1239 if ( rEntry.bDoQuery )
1241 if ( rEntry.nField < MAXCOL )
1242 rEntry.nField++;
1243 else
1245 DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
1248 else
1249 break; // for
1254 BOOL ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
1255 SCROW& nFoundRow, BOOL bSearchForEqualAfterMismatch,
1256 BOOL bIgnoreMismatchOnLeadingStringsP )
1258 nFoundCol = MAXCOL+1;
1259 nFoundRow = MAXROW+1;
1260 SetStopOnMismatch( TRUE ); // assume sorted keys
1261 SetTestEqualCondition( TRUE );
1262 bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP;
1263 bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString;
1264 bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp ==
1265 SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
1266 if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst())
1268 // First equal entry or last smaller than (greater than) entry.
1269 SCSIZE nColRowSave;
1270 ScBaseCell* pNext = 0;
1273 nFoundCol = GetCol();
1274 nFoundRow = GetRow();
1275 nColRowSave = nColRow;
1276 } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL );
1277 // There may be no pNext but equal condition fulfilled if regular
1278 // expressions are involved. Keep the found entry and proceed.
1279 if (!pNext && !IsEqualConditionFulfilled())
1281 // Step back to last in range and adjust position markers for
1282 // GetNumberFormat() or similar.
1283 nCol = nFoundCol;
1284 nRow = nFoundRow;
1285 nColRow = nColRowSave;
1288 if ( IsEqualConditionFulfilled() )
1290 // Position on last equal entry.
1291 SCSIZE nEntries = aParam.GetEntryCount();
1292 for ( SCSIZE j = 0; j < nEntries; j++ )
1294 ScQueryEntry& rEntry = aParam.GetEntry( j );
1295 if ( rEntry.bDoQuery )
1297 switch ( rEntry.eOp )
1299 case SC_LESS_EQUAL :
1300 case SC_GREATER_EQUAL :
1301 rEntry.eOp = SC_EQUAL;
1302 break;
1303 default:
1305 // added to avoid warnings
1309 else
1310 break; // for
1312 SCSIZE nColRowSave;
1313 bIgnoreMismatchOnLeadingStrings = FALSE;
1314 SetTestEqualCondition( FALSE );
1317 nFoundCol = GetCol();
1318 nFoundRow = GetRow();
1319 nColRowSave = nColRow;
1320 } while (GetNext());
1321 // Step back conditions same as above
1322 nCol = nFoundCol;
1323 nRow = nFoundRow;
1324 nColRow = nColRowSave;
1325 return TRUE;
1327 if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) &&
1328 StoppedOnMismatch() )
1330 // Assume found entry to be the last value less than respectively
1331 // greater than the query. But keep on searching for an equal match.
1332 SCSIZE nEntries = aParam.GetEntryCount();
1333 for ( SCSIZE j = 0; j < nEntries; j++ )
1335 ScQueryEntry& rEntry = aParam.GetEntry( j );
1336 if ( rEntry.bDoQuery )
1338 switch ( rEntry.eOp )
1340 case SC_LESS_EQUAL :
1341 case SC_GREATER_EQUAL :
1342 rEntry.eOp = SC_EQUAL;
1343 break;
1344 default:
1346 // added to avoid warnings
1350 else
1351 break; // for
1353 SetStopOnMismatch( FALSE );
1354 SetTestEqualCondition( FALSE );
1355 if (GetNext())
1357 // Last of a consecutive area, avoid searching the entire parameter
1358 // range as it is a real performance bottleneck in case of regular
1359 // expressions.
1360 SCSIZE nColRowSave;
1363 nFoundCol = GetCol();
1364 nFoundRow = GetRow();
1365 nColRowSave = nColRow;
1366 SetStopOnMismatch( TRUE );
1367 } while (GetNext());
1368 nCol = nFoundCol;
1369 nRow = nFoundRow;
1370 nColRow = nColRowSave;
1373 return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
1377 ScBaseCell* ScQueryCellIterator::BinarySearch()
1379 nCol = aParam.nCol1;
1380 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1381 if (!pCol->nCount)
1382 return 0;
1384 ScBaseCell* pCell;
1385 SCSIZE nHi, nLo;
1386 CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::GetCaseCollator() :
1387 ScGlobal::GetCollator());
1388 SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
1389 const ScQueryEntry& rEntry = aParam.GetEntry(0);
1390 bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
1391 bool bByString = rEntry.bQueryByString;
1392 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
1393 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1394 !aParam.bHasHeader && bByString;
1396 nRow = aParam.nRow1;
1397 if (aParam.bHasHeader)
1398 nRow++;
1399 const ColEntry* pItems = pCol->pItems;
1400 if (pCol->Search( nRow, nLo ) && bFirstStringIgnore &&
1401 pItems[nLo].pCell->HasStringData())
1403 String aCellStr;
1404 ULONG nFormat = pCol->GetNumberFormat( pItems[nLo].nRow);
1405 ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr,
1406 rFormatter);
1407 sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr);
1408 if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
1409 (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
1410 (rEntry.eOp == SC_EQUAL && nTmp != 0))
1411 ++nLo;
1413 if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0)
1414 --nHi;
1415 while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount &&
1416 pItems[nLo].pCell->HasStringData())
1417 ++nLo;
1419 // Bookkeeping values for breaking up the binary search in case the data
1420 // range isn't strictly sorted.
1421 SCSIZE nLastInRange = nLo;
1422 SCSIZE nFirstLastInRange = nLastInRange;
1423 double fLastInRangeValue = bLessEqual ?
1424 -(::std::numeric_limits<double>::max()) :
1425 ::std::numeric_limits<double>::max();
1426 String aLastInRangeString;
1427 if (!bLessEqual)
1428 aLastInRangeString.Assign( sal_Unicode(0xFFFF));
1429 if (nLastInRange < pCol->nCount)
1431 pCell = pItems[nLastInRange].pCell;
1432 if (pCell->HasStringData())
1434 ULONG nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow);
1435 ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString,
1436 rFormatter);
1438 else
1440 switch ( pCell->GetCellType() )
1442 case CELLTYPE_VALUE :
1443 fLastInRangeValue =
1444 static_cast<ScValueCell*>(pCell)->GetValue();
1445 break;
1446 case CELLTYPE_FORMULA :
1447 fLastInRangeValue =
1448 static_cast<ScFormulaCell*>(pCell)->GetValue();
1449 break;
1450 default:
1452 // added to avoid warnings
1458 sal_Int32 nRes = 0;
1459 bool bFound = false;
1460 bool bDone = false;
1461 while (nLo <= nHi && !bDone)
1463 SCSIZE nMid = (nLo+nHi)/2;
1464 SCSIZE i = nMid;
1465 while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE)
1466 ++i;
1467 if (i > nHi)
1469 if (nMid > 0)
1470 nHi = nMid - 1;
1471 else
1472 bDone = true;
1473 continue; // while
1475 BOOL bStr = pItems[i].pCell->HasStringData();
1476 nRes = 0;
1477 // compares are content<query:-1, content>query:1
1478 // Cell value comparison similar to ScTable::ValidQuery()
1479 if (!bStr && !bByString)
1481 double nCellVal;
1482 pCell = pItems[i].pCell;
1483 switch ( pCell->GetCellType() )
1485 case CELLTYPE_VALUE :
1486 nCellVal = static_cast<ScValueCell*>(pCell)->GetValue();
1487 break;
1488 case CELLTYPE_FORMULA :
1489 nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue();
1490 break;
1491 default:
1492 nCellVal = 0.0;
1494 if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual(
1495 nCellVal, rEntry.nVal))
1497 nRes = -1;
1498 if (bLessEqual)
1500 if (fLastInRangeValue < nCellVal)
1502 fLastInRangeValue = nCellVal;
1503 nLastInRange = i;
1505 else if (fLastInRangeValue > nCellVal)
1507 // not strictly sorted, continue with GetThis()
1508 nLastInRange = nFirstLastInRange;
1509 bDone = true;
1513 else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual(
1514 nCellVal, rEntry.nVal))
1516 nRes = 1;
1517 if (!bLessEqual)
1519 if (fLastInRangeValue > nCellVal)
1521 fLastInRangeValue = nCellVal;
1522 nLastInRange = i;
1524 else if (fLastInRangeValue < nCellVal)
1526 // not strictly sorted, continue with GetThis()
1527 nLastInRange = nFirstLastInRange;
1528 bDone = true;
1533 else if (bStr && bByString)
1535 String aCellStr;
1536 ULONG nFormat = pCol->GetNumberFormat( pItems[i].nRow);
1537 ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr,
1538 rFormatter);
1539 nRes = pCollator->compareString( aCellStr, *rEntry.pStr);
1540 if (nRes < 0 && bLessEqual)
1542 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1543 aCellStr);
1544 if (nTmp < 0)
1546 aLastInRangeString = aCellStr;
1547 nLastInRange = i;
1549 else if (nTmp > 0)
1551 // not strictly sorted, continue with GetThis()
1552 nLastInRange = nFirstLastInRange;
1553 bDone = true;
1556 else if (nRes > 0 && !bLessEqual)
1558 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1559 aCellStr);
1560 if (nTmp > 0)
1562 aLastInRangeString = aCellStr;
1563 nLastInRange = i;
1565 else if (nTmp < 0)
1567 // not strictly sorted, continue with GetThis()
1568 nLastInRange = nFirstLastInRange;
1569 bDone = true;
1573 else if (!bStr && bByString)
1575 nRes = -1; // numeric < string
1576 if (bLessEqual)
1577 nLastInRange = i;
1579 else // if (bStr && !bByString)
1581 nRes = 1; // string > numeric
1582 if (!bLessEqual)
1583 nLastInRange = i;
1585 if (nRes < 0)
1587 if (bLessEqual)
1588 nLo = nMid + 1;
1589 else // assumed to be SC_GREATER_EQUAL
1591 if (nMid > 0)
1592 nHi = nMid - 1;
1593 else
1594 bDone = true;
1597 else if (nRes > 0)
1599 if (bLessEqual)
1601 if (nMid > 0)
1602 nHi = nMid - 1;
1603 else
1604 bDone = true;
1606 else // assumed to be SC_GREATER_EQUAL
1607 nLo = nMid + 1;
1609 else
1611 nLo = i;
1612 bDone = bFound = true;
1615 if (!bFound)
1617 // If all hits didn't result in a moving limit there's something
1618 // strange, e.g. data range not properly sorted, or only identical
1619 // values encountered, which doesn't mean there aren't any others in
1620 // between.. leave it to GetThis(). The condition for this would be
1621 // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
1622 // Else, in case no exact match was found, we step back for a
1623 // subsequent GetThis() to find the last in range. Effectively this is
1624 // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
1625 nLo = nLastInRange;
1627 if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2)
1629 nRow = pItems[nLo].nRow;
1630 pCell = pItems[nLo].pCell;
1631 nColRow = nLo;
1633 else
1635 nRow = aParam.nRow2 + 1;
1636 pCell = 0;
1637 nColRow = pCol->nCount - 1;
1639 return pCell;
1643 //-------------------------------------------------------------------------------
1645 ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
1646 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1647 pDoc( pDocument ),
1648 nTab( nTable ),
1649 nStartCol( nCol1 ),
1650 nEndCol( nCol2 ),
1651 nEndRow( nRow2 ),
1652 nCol( nCol1 ),
1653 nRow( nRow1 ),
1654 bMore( TRUE )
1656 SCCOL i;
1657 SCSIZE nIndex;
1659 pNextRows = new SCROW[ nCol2-nCol1+1 ];
1660 pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
1662 for (i=nStartCol; i<=nEndCol; i++)
1664 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i];
1666 pCol->Search( nRow1, nIndex );
1667 if ( nIndex < pCol->nCount )
1669 pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow;
1670 pNextIndices[i-nStartCol] = nIndex;
1672 else
1674 pNextRows[i-nStartCol] = MAXROWCOUNT; // nichts gefunden
1675 pNextIndices[i-nStartCol] = MAXROWCOUNT;
1679 if (pNextRows[0] != nRow1)
1680 Advance();
1683 ScHorizontalCellIterator::~ScHorizontalCellIterator()
1685 delete [] pNextRows;
1686 delete [] pNextIndices;
1689 ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
1691 if ( bMore )
1693 rCol = nCol;
1694 rRow = nRow;
1696 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol];
1697 SCSIZE nIndex = pNextIndices[nCol-nStartCol];
1698 DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" );
1699 ScBaseCell* pCell = pCol->pItems[nIndex].pCell;
1700 if ( ++nIndex < pCol->nCount )
1702 pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow;
1703 pNextIndices[nCol-nStartCol] = nIndex;
1705 else
1707 pNextRows[nCol-nStartCol] = MAXROWCOUNT; // nichts gefunden
1708 pNextIndices[nCol-nStartCol] = MAXROWCOUNT;
1711 Advance();
1712 return pCell;
1714 else
1715 return NULL;
1718 BOOL ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow )
1720 rCol = nCol;
1721 rRow = nRow;
1722 return bMore;
1725 void ScHorizontalCellIterator::Advance()
1727 BOOL bFound = FALSE;
1728 SCCOL i;
1730 for (i=nCol+1; i<=nEndCol && !bFound; i++)
1731 if (pNextRows[i-nStartCol] == nRow)
1733 nCol = i;
1734 bFound = TRUE;
1737 if (!bFound)
1739 SCROW nMinRow = MAXROW+1;
1740 for (i=nStartCol; i<=nEndCol; i++)
1741 if (pNextRows[i-nStartCol] < nMinRow)
1743 nCol = i;
1744 nMinRow = pNextRows[i-nStartCol];
1747 if (nMinRow <= nEndRow)
1749 nRow = nMinRow;
1750 bFound = TRUE;
1754 if ( !bFound )
1755 bMore = FALSE;
1758 //-------------------------------------------------------------------------------
1760 ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable,
1761 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1762 pDoc( pDocument ),
1763 nTab( nTable ),
1764 nStartCol( nCol1 ),
1765 nStartRow( nRow1 ),
1766 nEndCol( nCol2 ),
1767 nEndRow( nRow2 )
1769 DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" );
1771 SCCOL i;
1773 nRow = nStartRow;
1774 nCol = nStartCol;
1775 bRowEmpty = FALSE;
1777 pIndices = new SCSIZE[nEndCol-nStartCol+1];
1778 pNextEnd = new SCROW[nEndCol-nStartCol+1];
1779 ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1];
1781 SCROW nSkipTo = MAXROW;
1782 BOOL bEmpty = TRUE;
1783 for (i=nStartCol; i<=nEndCol; i++)
1785 SCCOL nPos = i - nStartCol;
1786 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
1787 DBG_ASSERT( pArray, "pArray == 0" );
1789 SCSIZE nIndex;
1790 pArray->Search( nStartRow, nIndex );
1792 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
1793 SCROW nThisEnd = pArray->pData[nIndex].nRow;
1794 if ( IsDefaultItem( pPattern ) )
1796 pPattern = NULL;
1797 if ( nThisEnd < nSkipTo )
1798 nSkipTo = nThisEnd; // nSkipTo kann gleich hier gesetzt werden
1800 else
1801 bEmpty = FALSE; // Attribute gefunden
1803 pIndices[nPos] = nIndex;
1804 pNextEnd[nPos] = nThisEnd;
1805 ppPatterns[nPos] = pPattern;
1808 if (bEmpty)
1809 nRow = nSkipTo; // bis zum naechsten Bereichsende ueberspringen
1810 bRowEmpty = bEmpty;
1813 ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
1815 delete[] (ScPatternAttr**)ppPatterns;
1816 delete[] pNextEnd;
1817 delete[] pIndices;
1820 const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
1822 for (;;)
1824 if (!bRowEmpty)
1826 // in dieser Zeile suchen
1828 while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] )
1829 ++nCol;
1831 if ( nCol <= nEndCol )
1833 const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
1834 rRow = nRow;
1835 rCol1 = nCol;
1836 while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat )
1837 ++nCol;
1838 rCol2 = nCol;
1839 ++nCol; // hochzaehlen fuer naechsten Aufruf
1840 return pPat; // gefunden
1844 // naechste Zeile
1846 ++nRow;
1847 if ( nRow > nEndRow ) // schon am Ende?
1848 return NULL; // nichts gefunden
1850 BOOL bEmpty = TRUE;
1851 SCCOL i;
1853 for ( i = nStartCol; i <= nEndCol; i++)
1855 SCCOL nPos = i-nStartCol;
1856 if ( pNextEnd[nPos] < nRow )
1858 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
1860 SCSIZE nIndex = ++pIndices[nPos];
1861 if ( nIndex < pArray->nCount )
1863 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
1864 SCROW nThisEnd = pArray->pData[nIndex].nRow;
1865 if ( IsDefaultItem( pPattern ) )
1866 pPattern = NULL;
1867 else
1868 bEmpty = FALSE; // Attribute gefunden
1870 pNextEnd[nPos] = nThisEnd;
1871 ppPatterns[nPos] = pPattern;
1873 DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" );
1875 else
1877 DBG_ERROR("AttrArray reicht nicht bis MAXROW");
1878 pNextEnd[nPos] = MAXROW;
1879 ppPatterns[nPos] = NULL;
1882 else if ( ppPatterns[nPos] )
1883 bEmpty = FALSE; // Bereich noch nicht zuende
1886 if (bEmpty)
1888 SCCOL nCount = nEndCol-nStartCol+1;
1889 SCROW nSkipTo = pNextEnd[0]; // naechstes Bereichsende suchen
1890 for (i=1; i<nCount; i++)
1891 if ( pNextEnd[i] < nSkipTo )
1892 nSkipTo = pNextEnd[i];
1893 nRow = nSkipTo; // leere Zeilen ueberspringen
1895 bRowEmpty = bEmpty;
1896 nCol = nStartCol; // wieder links anfangen
1899 // return NULL;
1902 //-------------------------------------------------------------------------------
1904 inline BOOL IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1906 return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
1909 ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable,
1910 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1911 aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
1912 aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
1913 nNextCol( nCol1 ),
1914 nNextRow( nRow1 )
1916 pCell = aCellIter.GetNext( nCellCol, nCellRow );
1917 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
1920 ScUsedAreaIterator::~ScUsedAreaIterator()
1924 BOOL ScUsedAreaIterator::GetNext()
1926 // Iteratoren weiterzaehlen
1928 if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) )
1929 pCell = aCellIter.GetNext( nCellCol, nCellRow );
1931 while ( pCell && pCell->IsBlank() )
1932 pCell = aCellIter.GetNext( nCellCol, nCellRow );
1934 if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) )
1935 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
1937 if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
1938 nAttrCol1 = nNextCol;
1940 // naechsten Abschnitt heraussuchen
1942 BOOL bFound = TRUE;
1943 BOOL bUseCell = FALSE;
1945 if ( pCell && pPattern )
1947 if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // vorne nur Attribute ?
1949 pFoundCell = NULL;
1950 pFoundPattern = pPattern;
1951 nFoundRow = nAttrRow;
1952 nFoundStartCol = nAttrCol1;
1953 if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // auch Zelle im Bereich ?
1954 nFoundEndCol = nCellCol - 1; // nur bis vor der Zelle
1955 else
1956 nFoundEndCol = nAttrCol2; // alles
1958 else
1960 bUseCell = TRUE;
1961 if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attribute auf der Zelle ?
1962 pFoundPattern = pPattern;
1963 else
1964 pFoundPattern = NULL;
1967 else if ( pCell ) // nur Zelle -> direkt uebernehmen
1969 pFoundPattern = NULL;
1970 bUseCell = TRUE; // Position von Zelle
1972 else if ( pPattern ) // nur Attribute -> direkt uebernehmen
1974 pFoundCell = NULL;
1975 pFoundPattern = pPattern;
1976 nFoundRow = nAttrRow;
1977 nFoundStartCol = nAttrCol1;
1978 nFoundEndCol = nAttrCol2;
1980 else // gar nichts
1981 bFound = FALSE;
1983 if ( bUseCell ) // Position von Zelle
1985 pFoundCell = pCell;
1986 nFoundRow = nCellRow;
1987 nFoundStartCol = nFoundEndCol = nCellCol;
1990 if (bFound)
1992 nNextRow = nFoundRow;
1993 nNextCol = nFoundEndCol + 1;
1996 return bFound;
1999 //-------------------------------------------------------------------------------
2001 ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable,
2002 SCCOL nCol1, SCROW nRow1,
2003 SCCOL nCol2, SCROW nRow2) :
2004 pDoc( pDocument ),
2005 nTab( nTable ),
2006 nEndCol( nCol2 ),
2007 nStartRow( nRow1 ),
2008 nEndRow( nRow2 ),
2009 nCol( nCol1 )
2011 if ( ValidTab(nTab) && pDoc->pTab[nTab] )
2012 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2013 else
2014 pColIter = NULL;
2017 ScDocAttrIterator::~ScDocAttrIterator()
2019 delete pColIter;
2022 const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
2024 while ( pColIter )
2026 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2027 if ( pPattern )
2029 rCol = nCol;
2030 return pPattern;
2033 delete pColIter;
2034 ++nCol;
2035 if ( nCol <= nEndCol )
2036 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2037 else
2038 pColIter = NULL;
2040 return NULL; // is nix mehr
2043 //-------------------------------------------------------------------------------
2045 ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable,
2046 SCCOL nCol1, SCROW nRow1,
2047 SCCOL nCol2, SCROW nRow2) :
2048 pDoc( pDocument ),
2049 nTab( nTable ),
2050 nEndCol( nCol2 ),
2051 nStartRow( nRow1 ),
2052 nEndRow( nRow2 ),
2053 nIterStartCol( nCol1 ),
2054 nIterEndCol( nCol1 )
2056 if ( ValidTab(nTab) && pDoc->pTab[nTab] )
2058 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2059 while ( nIterEndCol < nEndCol &&
2060 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2061 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2062 ++nIterEndCol;
2064 else
2065 pColIter = NULL;
2068 ScAttrRectIterator::~ScAttrRectIterator()
2070 delete pColIter;
2073 void ScAttrRectIterator::DataChanged()
2075 if (pColIter)
2077 SCROW nNextRow = pColIter->GetNextRow();
2078 delete pColIter;
2079 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
2083 const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
2084 SCROW& rRow1, SCROW& rRow2 )
2086 while ( pColIter )
2088 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2089 if ( pPattern )
2091 rCol1 = nIterStartCol;
2092 rCol2 = nIterEndCol;
2093 return pPattern;
2096 delete pColIter;
2097 nIterStartCol = nIterEndCol+1;
2098 if ( nIterStartCol <= nEndCol )
2100 nIterEndCol = nIterStartCol;
2101 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2102 while ( nIterEndCol < nEndCol &&
2103 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2104 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2105 ++nIterEndCol;
2107 else
2108 pColIter = NULL;
2110 return NULL; // is nix mehr