update dev300-m57
[ooovba.git] / sc / source / core / data / dociter.cxx
blob911d473c23607bc553da20174c0291eebde2551b
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"
51 // STATIC DATA -----------------------------------------------------------
53 ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument,
54 SCTAB nStartTable, SCTAB nEndTable ) :
55 pDoc( pDocument ),
56 nStartTab( nStartTable ),
57 nEndTab( nEndTable )
59 PutInOrder( nStartTab, nEndTab );
60 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
61 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
63 pDefPattern = pDoc->GetDefPattern();
65 nCol = 0;
66 nRow = 0;
67 nTab = nStartTab;
69 nColPos = 0;
70 nAttrPos = 0;
73 ScDocumentIterator::~ScDocumentIterator()
77 BOOL ScDocumentIterator::GetThisCol()
79 ScTable* pTab;
80 while ( (pTab = pDoc->pTab[nTab]) == NULL )
82 if ( nTab == nEndTab )
84 nCol = MAXCOL;
85 nRow = MAXROW;
86 return FALSE;
88 ++nTab;
90 ScColumn* pCol = &pTab->aCol[nCol];
91 ScAttrArray* pAtt = pCol->pAttrArray;
93 BOOL bFound = FALSE;
96 SCROW nColRow;
97 SCROW nAttrEnd;
101 nAttrEnd = pAtt->pData[nAttrPos].nRow;
102 if (nAttrEnd < nRow)
103 ++nAttrPos;
105 while (nAttrEnd < nRow);
109 nColRow = (nColPos < pCol->nCount) ? pCol->pItems[nColPos].nRow : MAXROW+1;
110 if (nColRow < nRow)
111 ++nColPos;
113 while (nColRow < nRow);
115 if (nColRow == nRow)
117 bFound = TRUE;
118 pCell = pCol->pItems[nColPos].pCell;
119 pPattern = pAtt->pData[nAttrPos].pPattern;
121 else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern )
123 bFound = TRUE;
124 pCell = NULL;
125 pPattern = pAtt->pData[nAttrPos].pPattern;
127 else
129 nRow = Min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) );
132 while (!bFound && nRow <= MAXROW);
134 return bFound;
137 BOOL ScDocumentIterator::GetThis()
139 BOOL bEnd = FALSE;
140 BOOL bSuccess = FALSE;
142 while ( !bSuccess && !bEnd )
144 if ( nRow > MAXROW )
145 bSuccess = FALSE;
146 else
147 bSuccess = GetThisCol();
149 if ( !bSuccess )
151 ++nCol;
152 if (nCol > MAXCOL)
154 nCol = 0;
155 ++nTab;
156 if (nTab > nEndTab)
157 bEnd = TRUE;
159 nRow = 0;
160 nColPos = 0;
161 nAttrPos = 0;
165 return !bEnd;
168 BOOL ScDocumentIterator::GetFirst()
170 nCol = 0;
171 nTab = nStartTab;
173 nRow = 0;
174 nColPos = 0;
175 nAttrPos = 0;
177 return GetThis();
180 BOOL ScDocumentIterator::GetNext()
182 ++nRow;
184 return GetThis();
187 //------------------------------------------------------------------------
189 ScBaseCell* ScDocumentIterator::GetCell()
191 return pCell;
194 const ScPatternAttr* ScDocumentIterator::GetPattern()
196 return pPattern;
199 void ScDocumentIterator::GetPos( SCCOL& rCol, SCROW& rRow, SCTAB& rTab )
201 rCol = nCol;
202 rRow = nRow;
203 rTab = nTab;
207 //------------------------------------------------------------------------
208 //------------------------------------------------------------------------
209 void lcl_IterGetNumberFormat( ULONG& nFormat, const ScAttrArray*& rpArr,
210 SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
211 ScDocument* pDoc )
213 if ( rpArr != pNewArr || nAttrEndRow < nRow )
215 SCSIZE nPos;
216 pNewArr->Search( nRow, nPos ); // nPos 0 gueltig wenn nicht gefunden
217 const ScPatternAttr* pPattern = pNewArr->pData[nPos].pPattern;
218 nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() );
219 rpArr = pNewArr;
220 nAttrEndRow = pNewArr->pData[nPos].nRow;
224 //UNUSED2008-05 ScValueIterator::ScValueIterator( ScDocument* pDocument,
225 //UNUSED2008-05 SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
226 //UNUSED2008-05 SCCOL nECol, SCROW nERow, SCTAB nETab,
227 //UNUSED2008-05 BOOL bSTotal, BOOL bTextZero ) :
228 //UNUSED2008-05 pDoc( pDocument ),
229 //UNUSED2008-05 nNumFmtIndex(0),
230 //UNUSED2008-05 nStartCol( nSCol),
231 //UNUSED2008-05 nStartRow( nSRow),
232 //UNUSED2008-05 nStartTab( nSTab ),
233 //UNUSED2008-05 nEndCol( nECol ),
234 //UNUSED2008-05 nEndRow( nERow),
235 //UNUSED2008-05 nEndTab( nETab ),
236 //UNUSED2008-05 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
237 //UNUSED2008-05 bNumValid( FALSE ),
238 //UNUSED2008-05 bSubTotal(bSTotal),
239 //UNUSED2008-05 bNextValid( FALSE ),
240 //UNUSED2008-05 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
241 //UNUSED2008-05 bTextAsZero( bTextZero )
242 //UNUSED2008-05 {
243 //UNUSED2008-05 PutInOrder( nStartCol, nEndCol);
244 //UNUSED2008-05 PutInOrder( nStartRow, nEndRow);
245 //UNUSED2008-05 PutInOrder( nStartTab, nEndTab );
246 //UNUSED2008-05
247 //UNUSED2008-05 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
248 //UNUSED2008-05 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
249 //UNUSED2008-05 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
250 //UNUSED2008-05 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
251 //UNUSED2008-05 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
252 //UNUSED2008-05 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
253 //UNUSED2008-05
254 //UNUSED2008-05 nCol = nStartCol;
255 //UNUSED2008-05 nRow = nStartRow;
256 //UNUSED2008-05 nTab = nStartTab;
257 //UNUSED2008-05
258 //UNUSED2008-05 nColRow = 0; // wird bei GetFirst initialisiert
259 //UNUSED2008-05
260 //UNUSED2008-05 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
261 //UNUSED2008-05 pAttrArray = 0;
262 //UNUSED2008-05 nAttrEndRow = 0;
263 //UNUSED2008-05 }
265 ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange,
266 BOOL bSTotal, BOOL bTextZero ) :
267 pDoc( pDocument ),
268 nNumFmtIndex(0),
269 nStartCol( rRange.aStart.Col() ),
270 nStartRow( rRange.aStart.Row() ),
271 nStartTab( rRange.aStart.Tab() ),
272 nEndCol( rRange.aEnd.Col() ),
273 nEndRow( rRange.aEnd.Row() ),
274 nEndTab( rRange.aEnd.Tab() ),
275 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
276 bNumValid( FALSE ),
277 bSubTotal(bSTotal),
278 bNextValid( FALSE ),
279 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
280 bTextAsZero( bTextZero )
282 PutInOrder( nStartCol, nEndCol);
283 PutInOrder( nStartRow, nEndRow);
284 PutInOrder( nStartTab, nEndTab );
286 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
287 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
288 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
289 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
290 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
291 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
293 nCol = nStartCol;
294 nRow = nStartRow;
295 nTab = nStartTab;
297 nColRow = 0; // wird bei GetFirst initialisiert
299 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
300 pAttrArray = 0;
301 nAttrEndRow = 0;
304 BOOL ScValueIterator::GetThis(double& rValue, USHORT& rErr)
306 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
307 for (;;)
309 if ( nRow > nEndRow )
311 nRow = nStartRow;
314 nCol++;
315 if ( nCol > nEndCol )
317 nCol = nStartCol;
318 nTab++;
319 if ( nTab > nEndTab )
321 // rValue = 0.0; //! do not change caller's value!
322 rErr = 0;
323 return FALSE; // Ende und Aus
326 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
327 } while ( pCol->nCount == 0 );
328 pCol->Search( nRow, nColRow );
331 while (( nColRow < pCol->nCount ) && ( pCol->pItems[nColRow].nRow < nRow ))
332 nColRow++;
334 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
336 nRow = pCol->pItems[nColRow].nRow + 1;
337 if ( !bSubTotal || !pDoc->pTab[nTab]->IsFiltered( nRow-1 ) )
339 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
340 ++nColRow;
341 switch (pCell->GetCellType())
343 case CELLTYPE_VALUE:
345 bNumValid = FALSE;
346 rValue = ((ScValueCell*)pCell)->GetValue();
347 rErr = 0;
348 --nRow;
349 if ( bCalcAsShown )
351 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
352 nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
353 rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
356 // wenn in der selben Spalte gleich noch eine Value-Cell folgt, die
357 // auch noch im Block liegt, den Wert jetzt schon holen
359 if ( nColRow < pCol->nCount &&
360 pCol->pItems[nColRow].nRow <= nEndRow &&
361 pCol->pItems[nColRow].pCell->GetCellType() == CELLTYPE_VALUE &&
362 !bSubTotal )
364 fNextValue = ((ScValueCell*)pCol->pItems[nColRow].pCell)->GetValue();
365 nNextRow = pCol->pItems[nColRow].nRow;
366 bNextValid = TRUE;
367 if ( bCalcAsShown )
369 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
370 nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc );
371 fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat );
375 return TRUE; // gefunden
377 // break;
378 case CELLTYPE_FORMULA:
380 if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
382 rErr = ((ScFormulaCell*)pCell)->GetErrCode();
383 if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
385 rValue = ((ScFormulaCell*)pCell)->GetValue();
386 nRow--;
387 bNumValid = FALSE;
388 return TRUE; // gefunden
390 else if ( bTextAsZero )
392 rValue = 0.0;
393 nRow--;
394 bNumValid = FALSE;
395 return TRUE;
399 break;
400 case CELLTYPE_STRING :
401 case CELLTYPE_EDIT :
403 if ( bTextAsZero )
405 rErr = 0;
406 rValue = 0.0;
407 nNumFmtType = NUMBERFORMAT_NUMBER;
408 nNumFmtIndex = 0;
409 bNumValid = TRUE;
410 --nRow;
411 return TRUE;
414 break;
415 default:
417 // added to avoid warnings
422 else
423 nRow = nEndRow + 1; // naechste Spalte
427 void ScValueIterator::GetCurNumFmtInfo( short& nType, ULONG& nIndex )
429 if (!bNumValid)
431 const ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
432 nNumFmtIndex = pCol->GetNumberFormat( nRow );
433 if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
435 const ScBaseCell* pCell;
436 SCSIZE nIdx = nColRow - 1;
437 // there might be rearranged something, so be on the safe side
438 if ( nIdx < pCol->nCount && pCol->pItems[nIdx].nRow == nRow )
439 pCell = pCol->pItems[nIdx].pCell;
440 else
442 if ( pCol->Search( nRow, nIdx ) )
443 pCell = pCol->pItems[nIdx].pCell;
444 else
445 pCell = NULL;
447 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
448 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex );
449 else
450 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
452 else
453 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
454 bNumValid = TRUE;
456 nType = nNumFmtType;
457 nIndex = nNumFmtIndex;
460 BOOL ScValueIterator::GetFirst(double& rValue, USHORT& rErr)
462 nCol = nStartCol;
463 nRow = nStartRow;
464 nTab = nStartTab;
466 // nColRow = 0;
467 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
468 pCol->Search( nRow, nColRow );
470 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
471 pAttrArray = 0;
472 nAttrEndRow = 0;
474 return GetThis(rValue, rErr);
477 /* ist inline:
478 BOOL ScValueIterator::GetNext(double& rValue, USHORT& rErr)
480 ++nRow;
481 return GetThis(rValue, rErr);
485 //------------------------------------------------------------------------
486 //------------------------------------------------------------------------
488 ScQueryValueIterator::ScQueryValueIterator(ScDocument* pDocument, SCTAB nTable, const ScQueryParam& rParam) :
489 aParam (rParam),
490 pDoc( pDocument ),
491 nNumFmtIndex(0),
492 nTab( nTable),
493 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
494 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() )
496 nCol = aParam.nCol1;
497 nRow = aParam.nRow1;
498 nColRow = 0; // wird bei GetFirst initialisiert
499 SCSIZE i;
500 SCSIZE nCount = aParam.GetEntryCount();
501 for (i=0; (i<nCount) && (aParam.GetEntry(i).bDoQuery); i++)
503 ScQueryEntry& rEntry = aParam.GetEntry(i);
504 sal_uInt32 nIndex = 0;
505 rEntry.bQueryByString =
506 !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal));
508 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
509 pAttrArray = 0;
510 nAttrEndRow = 0;
513 BOOL ScQueryValueIterator::GetThis(double& rValue, USHORT& rErr)
515 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
516 SCCOLROW nFirstQueryField = aParam.GetEntry(0).nField;
517 for ( ;; )
519 if ( nRow > aParam.nRow2 )
521 nRow = aParam.nRow1;
522 if (aParam.bHasHeader)
523 nRow++;
526 nCol++;
527 if ( nCol > aParam.nCol2 )
529 // rValue = 0.0; // do not change caller's value!
530 rErr = 0;
531 return FALSE; // Ende und Aus
533 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
534 } while ( pCol->nCount == 0 );
535 pCol->Search( nRow, nColRow );
538 while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
539 nColRow++;
541 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= aParam.nRow2 )
543 nRow = pCol->pItems[nColRow].nRow;
544 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
545 if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL,
546 (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL) ) )
548 switch (pCell->GetCellType())
550 case CELLTYPE_VALUE:
552 rValue = ((ScValueCell*)pCell)->GetValue();
553 if ( bCalcAsShown )
555 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
556 nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
557 rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
559 nNumFmtType = NUMBERFORMAT_NUMBER;
560 nNumFmtIndex = 0;
561 rErr = 0;
562 return TRUE; // gefunden
564 // break;
565 case CELLTYPE_FORMULA:
567 if (((ScFormulaCell*)pCell)->IsValue())
569 rValue = ((ScFormulaCell*)pCell)->GetValue();
570 pDoc->GetNumberFormatInfo( nNumFmtType,
571 nNumFmtIndex, ScAddress( nCol, nRow, nTab ),
572 pCell );
573 rErr = ((ScFormulaCell*)pCell)->GetErrCode();
574 return TRUE; // gefunden
576 else
577 nRow++;
579 break;
580 default:
581 nRow++;
582 break;
585 else
586 nRow++;
588 else
589 nRow = aParam.nRow2 + 1; // Naechste Spalte
591 // return FALSE;
594 BOOL ScQueryValueIterator::GetFirst(double& rValue, USHORT& rErr)
596 nCol = aParam.nCol1;
597 nRow = aParam.nRow1;
598 if (aParam.bHasHeader)
599 nRow++;
600 // nColRow = 0;
601 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
602 pCol->Search( nRow, nColRow );
603 return GetThis(rValue, rErr);
606 BOOL ScQueryValueIterator::GetNext(double& rValue, USHORT& rErr)
608 ++nRow;
609 return GetThis(rValue, rErr);
612 //-------------------------------------------------------------------------------
614 ScCellIterator::ScCellIterator( ScDocument* pDocument,
615 SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
616 SCCOL nECol, SCROW nERow, SCTAB nETab, BOOL bSTotal ) :
617 pDoc( pDocument ),
618 nStartCol( nSCol),
619 nStartRow( nSRow),
620 nStartTab( nSTab ),
621 nEndCol( nECol ),
622 nEndRow( nERow),
623 nEndTab( nETab ),
624 bSubTotal(bSTotal)
627 PutInOrder( nStartCol, nEndCol);
628 PutInOrder( nStartRow, nEndRow);
629 PutInOrder( nStartTab, nEndTab );
631 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
632 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
633 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
634 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
635 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
636 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
638 while (nEndTab>0 && !pDoc->pTab[nEndTab])
639 --nEndTab; // nur benutzte Tabellen
640 if (nStartTab>nEndTab)
641 nStartTab = nEndTab;
643 nCol = nStartCol;
644 nRow = nStartRow;
645 nTab = nStartTab;
646 nColRow = 0; // wird bei GetFirst initialisiert
648 if (!pDoc->pTab[nTab])
650 DBG_ERROR("Tabelle nicht gefunden");
651 nStartCol = nCol = MAXCOL+1;
652 nStartRow = nRow = MAXROW+1;
653 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst
657 ScCellIterator::ScCellIterator
658 ( ScDocument* pDocument, const ScRange& rRange, BOOL bSTotal ) :
659 pDoc( pDocument ),
660 nStartCol( rRange.aStart.Col() ),
661 nStartRow( rRange.aStart.Row() ),
662 nStartTab( rRange.aStart.Tab() ),
663 nEndCol( rRange.aEnd.Col() ),
664 nEndRow( rRange.aEnd.Row() ),
665 nEndTab( rRange.aEnd.Tab() ),
666 bSubTotal(bSTotal)
669 PutInOrder( nStartCol, nEndCol);
670 PutInOrder( nStartRow, nEndRow);
671 PutInOrder( nStartTab, nEndTab );
673 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
674 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
675 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
676 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
677 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
678 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
680 while (nEndTab>0 && !pDoc->pTab[nEndTab])
681 --nEndTab; // nur benutzte Tabellen
682 if (nStartTab>nEndTab)
683 nStartTab = nEndTab;
685 nCol = nStartCol;
686 nRow = nStartRow;
687 nTab = nStartTab;
688 nColRow = 0; // wird bei GetFirst initialisiert
690 if (!pDoc->pTab[nTab])
692 DBG_ERROR("Tabelle nicht gefunden");
693 nStartCol = nCol = MAXCOL+1;
694 nStartRow = nRow = MAXROW+1;
695 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst
699 ScBaseCell* ScCellIterator::GetThis()
701 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
702 for ( ;; )
704 if ( nRow > nEndRow )
706 nRow = nStartRow;
709 nCol++;
710 if ( nCol > nEndCol )
712 nCol = nStartCol;
713 nTab++;
714 if ( nTab > nEndTab )
715 return NULL; // Ende und Aus
717 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
718 } while ( pCol->nCount == 0 );
719 pCol->Search( nRow, nColRow );
722 while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
723 nColRow++;
725 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
727 nRow = pCol->pItems[nColRow].nRow;
728 if ( !bSubTotal || !pDoc->pTab[nTab]->IsFiltered( nRow ) )
730 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
732 if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA
733 && ((ScFormulaCell*)pCell)->IsSubTotal() )
734 nRow++; // Sub-Total-Zeilen nicht
735 else
736 return pCell; // gefunden
738 else
739 nRow++;
741 else
742 nRow = nEndRow + 1; // Naechste Spalte
746 ScBaseCell* ScCellIterator::GetFirst()
748 if ( !ValidTab(nTab) )
749 return NULL;
750 nCol = nStartCol;
751 nRow = nStartRow;
752 nTab = nStartTab;
753 // nColRow = 0;
754 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
755 pCol->Search( nRow, nColRow );
756 return GetThis();
759 ScBaseCell* ScCellIterator::GetNext()
761 ++nRow;
762 return GetThis();
765 //-------------------------------------------------------------------------------
767 ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
768 const ScQueryParam& rParam, BOOL bMod ) :
769 aParam (rParam),
770 pDoc( pDocument ),
771 nTab( nTable),
772 nStopOnMismatch( nStopOnMismatchDisabled ),
773 nTestEqualCondition( nTestEqualConditionDisabled ),
774 bAdvanceQuery( FALSE ),
775 bIgnoreMismatchOnLeadingStrings( FALSE )
777 nCol = aParam.nCol1;
778 nRow = aParam.nRow1;
779 nColRow = 0; // wird bei GetFirst initialisiert
780 SCSIZE i;
781 if (bMod) // sonst schon eingetragen
783 for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++)
785 ScQueryEntry& rEntry = aParam.GetEntry(i);
786 sal_uInt32 nIndex = 0;
787 rEntry.bQueryByString =
788 !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr,
789 nIndex, rEntry.nVal));
792 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
793 pAttrArray = 0;
794 nAttrEndRow = 0;
797 ScBaseCell* ScQueryCellIterator::GetThis()
799 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
800 const ScQueryEntry& rEntry = aParam.GetEntry(0);
801 SCCOLROW nFirstQueryField = rEntry.nField;
802 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
803 !rEntry.bQueryByString;
804 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
805 !aParam.bHasHeader && rEntry.bQueryByString &&
806 ((aParam.bByRow && nRow == aParam.nRow1) ||
807 (!aParam.bByRow && nCol == aParam.nCol1));
808 for ( ;; )
810 if ( nRow > aParam.nRow2 )
812 nRow = aParam.nRow1;
813 if (aParam.bHasHeader && aParam.bByRow)
814 nRow++;
817 if ( ++nCol > aParam.nCol2 )
818 return NULL; // Ende und Aus
819 if ( bAdvanceQuery )
821 AdvanceQueryParamEntryField();
822 nFirstQueryField = rEntry.nField;
824 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
825 } while ( pCol->nCount == 0 );
826 pCol->Search( nRow, nColRow );
827 bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
828 !aParam.bHasHeader && rEntry.bQueryByString &&
829 aParam.bByRow;
832 while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow )
833 nColRow++;
835 if ( nColRow < pCol->nCount &&
836 (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 )
838 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
839 if ( pCell->GetCellType() == CELLTYPE_NOTE )
840 ++nRow;
841 else if (bAllStringIgnore && pCell->HasStringData())
842 ++nRow;
843 else
845 BOOL bTestEqualCondition;
846 if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL,
847 (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL),
848 (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
850 if ( nTestEqualCondition && bTestEqualCondition )
851 nTestEqualCondition |= nTestEqualConditionMatched;
852 return pCell; // found
854 else if ( nStopOnMismatch )
856 // Yes, even a mismatch may have a fulfilled equal
857 // condition if regular expressions were involved and
858 // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
859 if ( nTestEqualCondition && bTestEqualCondition )
861 nTestEqualCondition |= nTestEqualConditionMatched;
862 nStopOnMismatch |= nStopOnMismatchOccured;
863 return NULL;
865 bool bStop;
866 if (bFirstStringIgnore)
868 if (pCell->HasStringData())
870 ++nRow;
871 bStop = false;
873 else
874 bStop = true;
876 else
877 bStop = true;
878 if (bStop)
880 nStopOnMismatch |= nStopOnMismatchOccured;
881 return NULL;
884 else
885 nRow++;
888 else
889 nRow = aParam.nRow2 + 1; // Naechste Spalte
890 bFirstStringIgnore = false;
894 ScBaseCell* ScQueryCellIterator::GetFirst()
896 nCol = aParam.nCol1;
897 nRow = aParam.nRow1;
898 if (aParam.bHasHeader)
899 nRow++;
900 // nColRow = 0;
901 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
902 pCol->Search( nRow, nColRow );
903 return GetThis();
906 ScBaseCell* ScQueryCellIterator::GetNext()
908 ++nRow;
909 if ( nStopOnMismatch )
910 nStopOnMismatch = nStopOnMismatchEnabled;
911 if ( nTestEqualCondition )
912 nTestEqualCondition = nTestEqualConditionEnabled;
913 return GetThis();
916 ULONG ScQueryCellIterator::GetNumberFormat()
918 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
919 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
920 nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
921 return nNumFormat;
924 void ScQueryCellIterator::AdvanceQueryParamEntryField()
926 SCSIZE nEntries = aParam.GetEntryCount();
927 for ( SCSIZE j = 0; j < nEntries; j++ )
929 ScQueryEntry& rEntry = aParam.GetEntry( j );
930 if ( rEntry.bDoQuery )
932 if ( rEntry.nField < MAXCOL )
933 rEntry.nField++;
934 else
936 DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
939 else
940 break; // for
945 BOOL ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
946 SCROW& nFoundRow, BOOL bSearchForEqualAfterMismatch,
947 BOOL bIgnoreMismatchOnLeadingStringsP )
949 nFoundCol = MAXCOL+1;
950 nFoundRow = MAXROW+1;
951 SetStopOnMismatch( TRUE ); // assume sorted keys
952 SetTestEqualCondition( TRUE );
953 bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP;
954 bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString;
955 bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp ==
956 SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
957 if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst())
959 // First equal entry or last smaller than (greater than) entry.
960 SCSIZE nColRowSave;
961 ScBaseCell* pNext = 0;
964 nFoundCol = GetCol();
965 nFoundRow = GetRow();
966 nColRowSave = nColRow;
967 } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL );
968 // There may be no pNext but equal condition fulfilled if regular
969 // expressions are involved. Keep the found entry and proceed.
970 if (!pNext && !IsEqualConditionFulfilled())
972 // Step back to last in range and adjust position markers for
973 // GetNumberFormat() or similar.
974 nCol = nFoundCol;
975 nRow = nFoundRow;
976 nColRow = nColRowSave;
979 if ( IsEqualConditionFulfilled() )
981 // Position on last equal entry.
982 SCSIZE nEntries = aParam.GetEntryCount();
983 for ( SCSIZE j = 0; j < nEntries; j++ )
985 ScQueryEntry& rEntry = aParam.GetEntry( j );
986 if ( rEntry.bDoQuery )
988 switch ( rEntry.eOp )
990 case SC_LESS_EQUAL :
991 case SC_GREATER_EQUAL :
992 rEntry.eOp = SC_EQUAL;
993 break;
994 default:
996 // added to avoid warnings
1000 else
1001 break; // for
1003 SCSIZE nColRowSave;
1004 bIgnoreMismatchOnLeadingStrings = FALSE;
1005 SetTestEqualCondition( FALSE );
1008 nFoundCol = GetCol();
1009 nFoundRow = GetRow();
1010 nColRowSave = nColRow;
1011 } while (GetNext());
1012 // Step back conditions same as above
1013 nCol = nFoundCol;
1014 nRow = nFoundRow;
1015 nColRow = nColRowSave;
1016 return TRUE;
1018 if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) &&
1019 StoppedOnMismatch() )
1021 // Assume found entry to be the last value less than respectively
1022 // greater than the query. But keep on searching for an equal match.
1023 SCSIZE nEntries = aParam.GetEntryCount();
1024 for ( SCSIZE j = 0; j < nEntries; j++ )
1026 ScQueryEntry& rEntry = aParam.GetEntry( j );
1027 if ( rEntry.bDoQuery )
1029 switch ( rEntry.eOp )
1031 case SC_LESS_EQUAL :
1032 case SC_GREATER_EQUAL :
1033 rEntry.eOp = SC_EQUAL;
1034 break;
1035 default:
1037 // added to avoid warnings
1041 else
1042 break; // for
1044 SetStopOnMismatch( FALSE );
1045 SetTestEqualCondition( FALSE );
1046 if (GetNext())
1048 // Last of a consecutive area, avoid searching the entire parameter
1049 // range as it is a real performance bottleneck in case of regular
1050 // expressions.
1051 SCSIZE nColRowSave;
1054 nFoundCol = GetCol();
1055 nFoundRow = GetRow();
1056 nColRowSave = nColRow;
1057 SetStopOnMismatch( TRUE );
1058 } while (GetNext());
1059 nCol = nFoundCol;
1060 nRow = nFoundRow;
1061 nColRow = nColRowSave;
1064 return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
1068 ScBaseCell* ScQueryCellIterator::BinarySearch()
1070 nCol = aParam.nCol1;
1071 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1072 if (!pCol->nCount)
1073 return 0;
1075 ScBaseCell* pCell;
1076 SCSIZE nHi, nLo;
1077 CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::pCaseCollator :
1078 ScGlobal::pCollator);
1079 SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
1080 const ScQueryEntry& rEntry = aParam.GetEntry(0);
1081 bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
1082 bool bByString = rEntry.bQueryByString;
1083 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
1084 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1085 !aParam.bHasHeader && bByString;
1087 nRow = aParam.nRow1;
1088 if (aParam.bHasHeader)
1089 nRow++;
1090 const ColEntry* pItems = pCol->pItems;
1091 if (pCol->Search( nRow, nLo ) && bFirstStringIgnore &&
1092 pItems[nLo].pCell->HasStringData())
1094 String aCellStr;
1095 ULONG nFormat = pCol->GetNumberFormat( pItems[nLo].nRow);
1096 ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr,
1097 rFormatter);
1098 sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr);
1099 if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
1100 (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
1101 (rEntry.eOp == SC_EQUAL && nTmp != 0))
1102 ++nLo;
1104 if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0)
1105 --nHi;
1106 while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount &&
1107 pItems[nLo].pCell->HasStringData())
1108 ++nLo;
1110 // Bookkeeping values for breaking up the binary search in case the data
1111 // range isn't strictly sorted.
1112 SCSIZE nLastInRange = nLo;
1113 SCSIZE nFirstLastInRange = nLastInRange;
1114 double fLastInRangeValue = bLessEqual ?
1115 -(::std::numeric_limits<double>::max()) :
1116 ::std::numeric_limits<double>::max();
1117 String aLastInRangeString;
1118 if (!bLessEqual)
1119 aLastInRangeString.Assign( sal_Unicode(0xFFFF));
1120 if (nLastInRange < pCol->nCount)
1122 pCell = pItems[nLastInRange].pCell;
1123 if (pCell->HasStringData())
1125 ULONG nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow);
1126 ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString,
1127 rFormatter);
1129 else
1131 switch ( pCell->GetCellType() )
1133 case CELLTYPE_VALUE :
1134 fLastInRangeValue =
1135 static_cast<ScValueCell*>(pCell)->GetValue();
1136 break;
1137 case CELLTYPE_FORMULA :
1138 fLastInRangeValue =
1139 static_cast<ScFormulaCell*>(pCell)->GetValue();
1140 break;
1141 default:
1143 // added to avoid warnings
1149 sal_Int32 nRes = 0;
1150 bool bFound = false;
1151 bool bDone = false;
1152 while (nLo <= nHi && !bDone)
1154 SCSIZE nMid = (nLo+nHi)/2;
1155 SCSIZE i = nMid;
1156 while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE)
1157 ++i;
1158 if (i > nHi)
1160 if (nMid > 0)
1161 nHi = nMid - 1;
1162 else
1163 bDone = true;
1164 continue; // while
1166 BOOL bStr = pItems[i].pCell->HasStringData();
1167 nRes = 0;
1168 // compares are content<query:-1, content>query:1
1169 // Cell value comparison similar to ScTable::ValidQuery()
1170 if (!bStr && !bByString)
1172 double nCellVal;
1173 pCell = pItems[i].pCell;
1174 switch ( pCell->GetCellType() )
1176 case CELLTYPE_VALUE :
1177 nCellVal = static_cast<ScValueCell*>(pCell)->GetValue();
1178 break;
1179 case CELLTYPE_FORMULA :
1180 nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue();
1181 break;
1182 default:
1183 nCellVal = 0.0;
1185 if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual(
1186 nCellVal, rEntry.nVal))
1188 nRes = -1;
1189 if (bLessEqual)
1191 if (fLastInRangeValue < nCellVal)
1193 fLastInRangeValue = nCellVal;
1194 nLastInRange = i;
1196 else if (fLastInRangeValue > nCellVal)
1198 // not strictly sorted, continue with GetThis()
1199 nLastInRange = nFirstLastInRange;
1200 bDone = true;
1204 else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual(
1205 nCellVal, rEntry.nVal))
1207 nRes = 1;
1208 if (!bLessEqual)
1210 if (fLastInRangeValue > nCellVal)
1212 fLastInRangeValue = nCellVal;
1213 nLastInRange = i;
1215 else if (fLastInRangeValue < nCellVal)
1217 // not strictly sorted, continue with GetThis()
1218 nLastInRange = nFirstLastInRange;
1219 bDone = true;
1224 else if (bStr && bByString)
1226 String aCellStr;
1227 ULONG nFormat = pCol->GetNumberFormat( pItems[i].nRow);
1228 ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr,
1229 rFormatter);
1230 nRes = pCollator->compareString( aCellStr, *rEntry.pStr);
1231 if (nRes < 0 && bLessEqual)
1233 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1234 aCellStr);
1235 if (nTmp < 0)
1237 aLastInRangeString = aCellStr;
1238 nLastInRange = i;
1240 else if (nTmp > 0)
1242 // not strictly sorted, continue with GetThis()
1243 nLastInRange = nFirstLastInRange;
1244 bDone = true;
1247 else if (nRes > 0 && !bLessEqual)
1249 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1250 aCellStr);
1251 if (nTmp > 0)
1253 aLastInRangeString = aCellStr;
1254 nLastInRange = i;
1256 else if (nTmp < 0)
1258 // not strictly sorted, continue with GetThis()
1259 nLastInRange = nFirstLastInRange;
1260 bDone = true;
1264 else if (!bStr && bByString)
1266 nRes = -1; // numeric < string
1267 if (bLessEqual)
1268 nLastInRange = i;
1270 else // if (bStr && !bByString)
1272 nRes = 1; // string > numeric
1273 if (!bLessEqual)
1274 nLastInRange = i;
1276 if (nRes < 0)
1278 if (bLessEqual)
1279 nLo = nMid + 1;
1280 else // assumed to be SC_GREATER_EQUAL
1282 if (nMid > 0)
1283 nHi = nMid - 1;
1284 else
1285 bDone = true;
1288 else if (nRes > 0)
1290 if (bLessEqual)
1292 if (nMid > 0)
1293 nHi = nMid - 1;
1294 else
1295 bDone = true;
1297 else // assumed to be SC_GREATER_EQUAL
1298 nLo = nMid + 1;
1300 else
1302 nLo = i;
1303 bDone = bFound = true;
1306 if (!bFound)
1308 // If all hits didn't result in a moving limit there's something
1309 // strange, e.g. data range not properly sorted, or only identical
1310 // values encountered, which doesn't mean there aren't any others in
1311 // between.. leave it to GetThis(). The condition for this would be
1312 // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
1313 // Else, in case no exact match was found, we step back for a
1314 // subsequent GetThis() to find the last in range. Effectively this is
1315 // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
1316 nLo = nLastInRange;
1318 if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2)
1320 nRow = pItems[nLo].nRow;
1321 pCell = pItems[nLo].pCell;
1322 nColRow = nLo;
1324 else
1326 nRow = aParam.nRow2 + 1;
1327 pCell = 0;
1328 nColRow = pCol->nCount - 1;
1330 return pCell;
1334 //-------------------------------------------------------------------------------
1336 ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
1337 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1338 pDoc( pDocument ),
1339 nTab( nTable ),
1340 nStartCol( nCol1 ),
1341 nEndCol( nCol2 ),
1342 nEndRow( nRow2 ),
1343 nCol( nCol1 ),
1344 nRow( nRow1 ),
1345 bMore( TRUE )
1347 SCCOL i;
1348 SCSIZE nIndex;
1350 pNextRows = new SCROW[ nCol2-nCol1+1 ];
1351 pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
1353 for (i=nStartCol; i<=nEndCol; i++)
1355 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i];
1357 pCol->Search( nRow1, nIndex );
1358 if ( nIndex < pCol->nCount )
1360 pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow;
1361 pNextIndices[i-nStartCol] = nIndex;
1363 else
1365 pNextRows[i-nStartCol] = MAXROWCOUNT; // nichts gefunden
1366 pNextIndices[i-nStartCol] = MAXROWCOUNT;
1370 if (pNextRows[0] != nRow1)
1371 Advance();
1374 ScHorizontalCellIterator::~ScHorizontalCellIterator()
1376 delete [] pNextRows;
1377 delete [] pNextIndices;
1380 ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
1382 if ( bMore )
1384 rCol = nCol;
1385 rRow = nRow;
1387 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol];
1388 SCSIZE nIndex = pNextIndices[nCol-nStartCol];
1389 DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" );
1390 ScBaseCell* pCell = pCol->pItems[nIndex].pCell;
1391 if ( ++nIndex < pCol->nCount )
1393 pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow;
1394 pNextIndices[nCol-nStartCol] = nIndex;
1396 else
1398 pNextRows[nCol-nStartCol] = MAXROWCOUNT; // nichts gefunden
1399 pNextIndices[nCol-nStartCol] = MAXROWCOUNT;
1402 Advance();
1403 return pCell;
1405 else
1406 return NULL;
1409 BOOL ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow )
1411 rCol = nCol;
1412 rRow = nRow;
1413 return bMore;
1416 void ScHorizontalCellIterator::Advance()
1418 BOOL bFound = FALSE;
1419 SCCOL i;
1421 for (i=nCol+1; i<=nEndCol && !bFound; i++)
1422 if (pNextRows[i-nStartCol] == nRow)
1424 nCol = i;
1425 bFound = TRUE;
1428 if (!bFound)
1430 SCROW nMinRow = MAXROW+1;
1431 for (i=nStartCol; i<=nEndCol; i++)
1432 if (pNextRows[i-nStartCol] < nMinRow)
1434 nCol = i;
1435 nMinRow = pNextRows[i-nStartCol];
1438 if (nMinRow <= nEndRow)
1440 nRow = nMinRow;
1441 bFound = TRUE;
1445 if ( !bFound )
1446 bMore = FALSE;
1449 //-------------------------------------------------------------------------------
1451 ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable,
1452 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1453 pDoc( pDocument ),
1454 nTab( nTable ),
1455 nStartCol( nCol1 ),
1456 nStartRow( nRow1 ),
1457 nEndCol( nCol2 ),
1458 nEndRow( nRow2 )
1460 DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" );
1462 SCCOL i;
1464 nRow = nStartRow;
1465 nCol = nStartCol;
1466 bRowEmpty = FALSE;
1468 pIndices = new SCSIZE[nEndCol-nStartCol+1];
1469 pNextEnd = new SCROW[nEndCol-nStartCol+1];
1470 ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1];
1472 SCROW nSkipTo = MAXROW;
1473 BOOL bEmpty = TRUE;
1474 for (i=nStartCol; i<=nEndCol; i++)
1476 SCCOL nPos = i - nStartCol;
1477 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
1478 DBG_ASSERT( pArray, "pArray == 0" );
1480 SCSIZE nIndex;
1481 pArray->Search( nStartRow, nIndex );
1483 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
1484 SCROW nThisEnd = pArray->pData[nIndex].nRow;
1485 if ( IsDefaultItem( pPattern ) )
1487 pPattern = NULL;
1488 if ( nThisEnd < nSkipTo )
1489 nSkipTo = nThisEnd; // nSkipTo kann gleich hier gesetzt werden
1491 else
1492 bEmpty = FALSE; // Attribute gefunden
1494 pIndices[nPos] = nIndex;
1495 pNextEnd[nPos] = nThisEnd;
1496 ppPatterns[nPos] = pPattern;
1499 if (bEmpty)
1500 nRow = nSkipTo; // bis zum naechsten Bereichsende ueberspringen
1501 bRowEmpty = bEmpty;
1504 ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
1506 delete[] (ScPatternAttr**)ppPatterns;
1507 delete[] pNextEnd;
1508 delete[] pIndices;
1511 const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
1513 for (;;)
1515 if (!bRowEmpty)
1517 // in dieser Zeile suchen
1519 while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] )
1520 ++nCol;
1522 if ( nCol <= nEndCol )
1524 const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
1525 rRow = nRow;
1526 rCol1 = nCol;
1527 while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat )
1528 ++nCol;
1529 rCol2 = nCol;
1530 ++nCol; // hochzaehlen fuer naechsten Aufruf
1531 return pPat; // gefunden
1535 // naechste Zeile
1537 ++nRow;
1538 if ( nRow > nEndRow ) // schon am Ende?
1539 return NULL; // nichts gefunden
1541 BOOL bEmpty = TRUE;
1542 SCCOL i;
1544 for ( i = nStartCol; i <= nEndCol; i++)
1546 SCCOL nPos = i-nStartCol;
1547 if ( pNextEnd[nPos] < nRow )
1549 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
1551 SCSIZE nIndex = ++pIndices[nPos];
1552 if ( nIndex < pArray->nCount )
1554 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
1555 SCROW nThisEnd = pArray->pData[nIndex].nRow;
1556 if ( IsDefaultItem( pPattern ) )
1557 pPattern = NULL;
1558 else
1559 bEmpty = FALSE; // Attribute gefunden
1561 pNextEnd[nPos] = nThisEnd;
1562 ppPatterns[nPos] = pPattern;
1564 DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" );
1566 else
1568 DBG_ERROR("AttrArray reicht nicht bis MAXROW");
1569 pNextEnd[nPos] = MAXROW;
1570 ppPatterns[nPos] = NULL;
1573 else if ( ppPatterns[nPos] )
1574 bEmpty = FALSE; // Bereich noch nicht zuende
1577 if (bEmpty)
1579 SCCOL nCount = nEndCol-nStartCol+1;
1580 SCROW nSkipTo = pNextEnd[0]; // naechstes Bereichsende suchen
1581 for (i=1; i<nCount; i++)
1582 if ( pNextEnd[i] < nSkipTo )
1583 nSkipTo = pNextEnd[i];
1584 nRow = nSkipTo; // leere Zeilen ueberspringen
1586 bRowEmpty = bEmpty;
1587 nCol = nStartCol; // wieder links anfangen
1590 // return NULL;
1593 //-------------------------------------------------------------------------------
1595 inline BOOL IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1597 return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
1600 ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable,
1601 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1602 aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
1603 aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
1604 nNextCol( nCol1 ),
1605 nNextRow( nRow1 )
1607 pCell = aCellIter.GetNext( nCellCol, nCellRow );
1608 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
1611 ScUsedAreaIterator::~ScUsedAreaIterator()
1615 BOOL ScUsedAreaIterator::GetNext()
1617 // Iteratoren weiterzaehlen
1619 if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) )
1620 pCell = aCellIter.GetNext( nCellCol, nCellRow );
1622 while ( pCell && pCell->IsBlank() )
1623 pCell = aCellIter.GetNext( nCellCol, nCellRow );
1625 if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) )
1626 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
1628 if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
1629 nAttrCol1 = nNextCol;
1631 // naechsten Abschnitt heraussuchen
1633 BOOL bFound = TRUE;
1634 BOOL bUseCell = FALSE;
1636 if ( pCell && pPattern )
1638 if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // vorne nur Attribute ?
1640 pFoundCell = NULL;
1641 pFoundPattern = pPattern;
1642 nFoundRow = nAttrRow;
1643 nFoundStartCol = nAttrCol1;
1644 if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // auch Zelle im Bereich ?
1645 nFoundEndCol = nCellCol - 1; // nur bis vor der Zelle
1646 else
1647 nFoundEndCol = nAttrCol2; // alles
1649 else
1651 bUseCell = TRUE;
1652 if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attribute auf der Zelle ?
1653 pFoundPattern = pPattern;
1654 else
1655 pFoundPattern = NULL;
1658 else if ( pCell ) // nur Zelle -> direkt uebernehmen
1660 pFoundPattern = NULL;
1661 bUseCell = TRUE; // Position von Zelle
1663 else if ( pPattern ) // nur Attribute -> direkt uebernehmen
1665 pFoundCell = NULL;
1666 pFoundPattern = pPattern;
1667 nFoundRow = nAttrRow;
1668 nFoundStartCol = nAttrCol1;
1669 nFoundEndCol = nAttrCol2;
1671 else // gar nichts
1672 bFound = FALSE;
1674 if ( bUseCell ) // Position von Zelle
1676 pFoundCell = pCell;
1677 nFoundRow = nCellRow;
1678 nFoundStartCol = nFoundEndCol = nCellCol;
1681 if (bFound)
1683 nNextRow = nFoundRow;
1684 nNextCol = nFoundEndCol + 1;
1687 return bFound;
1690 //-------------------------------------------------------------------------------
1692 ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable,
1693 SCCOL nCol1, SCROW nRow1,
1694 SCCOL nCol2, SCROW nRow2) :
1695 pDoc( pDocument ),
1696 nTab( nTable ),
1697 nEndCol( nCol2 ),
1698 nStartRow( nRow1 ),
1699 nEndRow( nRow2 ),
1700 nCol( nCol1 )
1702 if ( ValidTab(nTab) && pDoc->pTab[nTab] )
1703 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
1704 else
1705 pColIter = NULL;
1708 ScDocAttrIterator::~ScDocAttrIterator()
1710 delete pColIter;
1713 const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
1715 while ( pColIter )
1717 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
1718 if ( pPattern )
1720 rCol = nCol;
1721 return pPattern;
1724 delete pColIter;
1725 ++nCol;
1726 if ( nCol <= nEndCol )
1727 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
1728 else
1729 pColIter = NULL;
1731 return NULL; // is nix mehr
1734 //-------------------------------------------------------------------------------
1736 ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable,
1737 SCCOL nCol1, SCROW nRow1,
1738 SCCOL nCol2, SCROW nRow2) :
1739 pDoc( pDocument ),
1740 nTab( nTable ),
1741 nEndCol( nCol2 ),
1742 nStartRow( nRow1 ),
1743 nEndRow( nRow2 ),
1744 nIterStartCol( nCol1 ),
1745 nIterEndCol( nCol1 )
1747 if ( ValidTab(nTab) && pDoc->pTab[nTab] )
1749 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
1750 while ( nIterEndCol < nEndCol &&
1751 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
1752 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
1753 ++nIterEndCol;
1755 else
1756 pColIter = NULL;
1759 ScAttrRectIterator::~ScAttrRectIterator()
1761 delete pColIter;
1764 void ScAttrRectIterator::DataChanged()
1766 if (pColIter)
1768 SCROW nNextRow = pColIter->GetNextRow();
1769 delete pColIter;
1770 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
1774 const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
1775 SCROW& rRow1, SCROW& rRow2 )
1777 while ( pColIter )
1779 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
1780 if ( pPattern )
1782 rCol1 = nIterStartCol;
1783 rCol2 = nIterEndCol;
1784 return pPattern;
1787 delete pColIter;
1788 nIterStartCol = nIterEndCol+1;
1789 if ( nIterStartCol <= nEndCol )
1791 nIterEndCol = nIterStartCol;
1792 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
1793 while ( nIterEndCol < nEndCol &&
1794 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
1795 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
1796 ++nIterEndCol;
1798 else
1799 pColIter = NULL;
1801 return NULL; // is nix mehr