1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svl/zforlist.hxx>
22 #include "scitems.hxx"
24 #include "dociter.hxx"
25 #include "document.hxx"
28 #include "formulacell.hxx"
29 #include "attarray.hxx"
30 #include "patattr.hxx"
31 #include "docoptio.hxx"
32 #include "cellform.hxx"
33 #include "segmenttree.hxx"
34 #include "progress.hxx"
35 #include "queryparam.hxx"
36 #include "queryentry.hxx"
37 #include "globstr.hrc"
38 #include "editutil.hxx"
39 #include "cellvalue.hxx"
40 #include "scmatrix.hxx"
41 #include <rowheightcontext.hxx>
43 #include <tools/fract.hxx>
44 #include <editeng/editobj.hxx>
45 #include <svl/sharedstring.hxx>
49 using ::rtl::math::approxEqual
;
53 // iterators have very high frequency use -> custom debug.
54 // #define debugiter(...) fprintf(stderr, __VA_ARGS__)
55 #define debugiter(...)
57 // STATIC DATA -----------------------------------------------------------
61 template<typename _Iter
>
62 void incBlock(std::pair
<_Iter
, size_t>& rPos
)
64 // Move to the next block.
69 template<typename _Iter
>
70 void decBlock(std::pair
<_Iter
, size_t>& rPos
)
72 // Move to the last element of the previous block.
74 rPos
.second
= rPos
.first
->size
- 1;
79 void ScAttrArray_IterGetNumberFormat( sal_uLong
& nFormat
, const ScAttrArray
*& rpArr
,
80 SCROW
& nAttrEndRow
, const ScAttrArray
* pNewArr
, SCROW nRow
,
83 if ( rpArr
!= pNewArr
|| nAttrEndRow
< nRow
)
86 SCROW nRowEnd
= MAXROW
;
87 const ScPatternAttr
* pPattern
;
88 if( !(pPattern
= pNewArr
->GetPatternRange( nRowStart
, nRowEnd
, nRow
) ) )
90 pPattern
= pDoc
->GetDefPattern();
94 nFormat
= pPattern
->GetNumberFormat( pDoc
->GetFormatTable() );
96 nAttrEndRow
= nRowEnd
;
100 ScValueIterator::ScValueIterator( ScDocument
* pDocument
, const ScRange
& rRange
,
101 sal_uInt16 nSubTotalFlags
, bool bTextZero
)
104 , nNumFormat(0) // Initialized in GetNumberFormat
106 , maStartPos(rRange
.aStart
)
107 , maEndPos(rRange
.aEnd
)
111 , mnSubTotalFlags(nSubTotalFlags
)
112 , nNumFmtType(css::util::NumberFormat::UNDEFINED
)
114 , bCalcAsShown(pDocument
->GetDocOptions().IsCalcAsShown())
115 , bTextAsZero(bTextZero
)
118 SCTAB nDocMaxTab
= pDocument
->GetTableCount() - 1;
120 if (!ValidCol(maStartPos
.Col())) maStartPos
.SetCol(MAXCOL
);
121 if (!ValidCol(maEndPos
.Col())) maEndPos
.SetCol(MAXCOL
);
122 if (!ValidRow(maStartPos
.Row())) maStartPos
.SetRow(MAXROW
);
123 if (!ValidRow(maEndPos
.Row())) maEndPos
.SetRow(MAXROW
);
124 if (!ValidTab(maStartPos
.Tab()) || maStartPos
.Tab() > nDocMaxTab
) maStartPos
.SetTab(nDocMaxTab
);
125 if (!ValidTab(maEndPos
.Tab()) || maEndPos
.Tab() > nDocMaxTab
) maEndPos
.SetTab(nDocMaxTab
);
128 SCROW
ScValueIterator::GetRow() const
130 // Position of the head of the current block + offset within the block
131 // equals the logical element position.
132 return maCurPos
.first
->position
+ maCurPos
.second
;
135 void ScValueIterator::IncBlock()
141 void ScValueIterator::IncPos()
143 if (maCurPos
.second
+ 1 < maCurPos
.first
->size
)
144 // Move within the same block.
147 // Move to the next block.
151 void ScValueIterator::SetPos(size_t nPos
)
153 maCurPos
= mpCells
->position(maCurPos
.first
, nPos
);
156 bool ScValueIterator::GetThis(double& rValue
, sal_uInt16
& rErr
)
160 bool bNextColumn
= maCurPos
.first
== mpCells
->end();
163 if (GetRow() > maEndPos
.Row())
167 ScColumn
* pCol
= &(pDoc
->maTabs
[mnTab
])->aCol
[mnCol
];
170 // Find the next available column.
174 if (mnCol
> maEndPos
.Col())
176 mnCol
= maStartPos
.Col();
178 if (mnTab
> maEndPos
.Tab())
181 return false; // Over and out
184 pCol
= &(pDoc
->maTabs
[mnTab
])->aCol
[mnCol
];
186 while (pCol
->IsEmptyData());
188 mpCells
= &pCol
->maCells
;
189 maCurPos
= mpCells
->position(maStartPos
.Row());
192 SCROW nCurRow
= GetRow();
194 // Skip all filtered or hidden rows, depending on mnSubTotalFlags
195 if ( ( ( mnSubTotalFlags
& SUBTOTAL_IGN_FILTERED
) &&
196 pDoc
->RowFiltered( nCurRow
, mnTab
, NULL
, &nLastRow
) ) ||
197 ( ( mnSubTotalFlags
& SUBTOTAL_IGN_HIDDEN
) &&
198 pDoc
->RowHidden( nCurRow
, mnTab
, NULL
, &nLastRow
) ) )
204 switch (maCurPos
.first
->type
)
206 case sc::element_type_numeric
:
209 rValue
= sc::numeric_block::at(*maCurPos
.first
->data
, maCurPos
.second
);
213 ScAttrArray_IterGetNumberFormat(nNumFormat
, pAttrArray
,
214 nAttrEndRow
, pCol
->pAttrArray
, nCurRow
, pDoc
);
215 rValue
= pDoc
->RoundValueAsShown(rValue
, nNumFormat
);
217 return true; // Found it!
220 case sc::element_type_formula
:
222 ScFormulaCell
& rCell
= *sc::formula_block::at(*maCurPos
.first
->data
, maCurPos
.second
);
223 if ( ( mnSubTotalFlags
& SUBTOTAL_IGN_NESTED_ST_AG
) && rCell
.IsSubTotal() )
225 // Skip subtotal formula cells.
230 if (rCell
.GetErrorOrValue(rErr
, rValue
))
232 if ( rErr
&& ( mnSubTotalFlags
& SUBTOTAL_IGN_ERR_VAL
) )
238 return true; // Found it!
240 else if (bTextAsZero
)
249 case sc::element_type_string
:
250 case sc::element_type_edittext
:
256 nNumFmtType
= css::util::NumberFormat::NUMBER
;
264 case sc::element_type_empty
:
266 // Skip the whole block.
272 void ScValueIterator::GetCurNumFmtInfo( short& nType
, sal_uLong
& nIndex
)
274 if (!bNumValid
&& mnTab
< pDoc
->GetTableCount())
276 SCROW nCurRow
= GetRow();
277 const ScColumn
* pCol
= &(pDoc
->maTabs
[mnTab
])->aCol
[mnCol
];
278 nNumFmtIndex
= pCol
->GetNumberFormat(nCurRow
);
279 nNumFmtType
= pDoc
->GetFormatTable()->GetType( nNumFmtIndex
);
284 nIndex
= nNumFmtIndex
;
287 bool ScValueIterator::GetFirst(double& rValue
, sal_uInt16
& rErr
)
289 mnCol
= maStartPos
.Col();
290 mnTab
= maStartPos
.Tab();
292 ScTable
* pTab
= pDoc
->FetchTable(mnTab
);
296 nNumFormat
= 0; // Initialized in GetNumberFormat
300 mpCells
= &pTab
->aCol
[maStartPos
.Col()].maCells
;
301 maCurPos
= mpCells
->position(maStartPos
.Row());
302 return GetThis(rValue
, rErr
);
305 bool ScValueIterator::GetNext(double& rValue
, sal_uInt16
& rErr
)
308 return GetThis(rValue
, rErr
);
311 ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator
* pParent
) :
316 ScDBQueryDataIterator::DataAccess::~DataAccess()
320 const sc::CellStoreType
* ScDBQueryDataIterator::GetColumnCellStore(ScDocument
& rDoc
, SCTAB nTab
, SCCOL nCol
)
322 ScTable
* pTab
= rDoc
.FetchTable(nTab
);
326 return &pTab
->aCol
[nCol
].maCells
;
329 const ScAttrArray
* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument
& rDoc
, SCTAB nTab
, SCCOL nCol
)
331 if (nTab
>= rDoc
.GetTableCount())
332 OSL_FAIL("try to access index out of bounds, FIX IT");
333 ScColumn
* pCol
= &rDoc
.maTabs
[nTab
]->aCol
[nCol
];
334 return pCol
->pAttrArray
;
337 bool ScDBQueryDataIterator::IsQueryValid(
338 ScDocument
& rDoc
, const ScQueryParam
& rParam
, SCTAB nTab
, SCROW nRow
, ScRefCellValue
* pCell
)
340 if (nTab
>= rDoc
.GetTableCount())
341 OSL_FAIL("try to access index out of bounds, FIX IT");
342 return rDoc
.maTabs
[nTab
]->ValidQuery(nRow
, rParam
, pCell
);
345 ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator
* pParent
, ScDBQueryParamInternal
* pParam
, ScDocument
* pDoc
)
346 : DataAccess(pParent
)
351 , nNumFormat(0) // Initialized in GetNumberFormat
353 , nCol(mpParam
->mnField
)
354 , nRow(mpParam
->nRow1
)
356 , nTab(mpParam
->nTab
)
358 , bCalcAsShown(pDoc
->GetDocOptions().IsCalcAsShown())
361 SCSIZE nCount
= mpParam
->GetEntryCount();
362 for (i
=0; (i
<nCount
) && (mpParam
->GetEntry(i
).bDoQuery
); i
++)
364 ScQueryEntry
& rEntry
= mpParam
->GetEntry(i
);
365 ScQueryEntry::QueryItemsType
& rItems
= rEntry
.GetQueryItems();
367 ScQueryEntry::Item
& rItem
= rItems
.front();
368 sal_uInt32 nIndex
= 0;
369 bool bNumber
= mpDoc
->GetFormatTable()->IsNumberFormat(
370 rItem
.maString
.getString(), nIndex
, rItem
.mfVal
);
371 rItem
.meType
= bNumber
? ScQueryEntry::ByValue
: ScQueryEntry::ByString
;
375 ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
379 bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value
& rValue
)
381 // Start with the current row position, and find the first row position
382 // that satisfies the query.
384 // If the query starts in the same column as the result vector we can
385 // prefetch the cell which saves us one fetch in the success case.
386 SCCOLROW nFirstQueryField
= mpParam
->GetEntry(0).nField
;
387 ScRefCellValue aCell
;
391 if (maCurPos
.first
== mpCells
->end() || nRow
> mpParam
->nRow2
)
393 // Bottom of the range reached. Bail out.
398 if (maCurPos
.first
->type
== sc::element_type_empty
)
400 // Skip the whole empty block.
405 ScRefCellValue
* pCell
= NULL
;
406 if (nCol
== static_cast<SCCOL
>(nFirstQueryField
))
408 aCell
= sc::toRefCell(maCurPos
.first
, maCurPos
.second
);
412 if (ScDBQueryDataIterator::IsQueryValid(*mpDoc
, *mpParam
, nTab
, nRow
, pCell
))
415 aCell
= sc::toRefCell(maCurPos
.first
, maCurPos
.second
);
416 switch (aCell
.meType
)
420 rValue
.mfValue
= aCell
.mfValue
;
421 rValue
.mbIsNumber
= true;
424 const ScAttrArray
* pNewAttrArray
=
425 ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc
, nTab
, nCol
);
426 ScAttrArray_IterGetNumberFormat( nNumFormat
, pAttrArray
,
427 nAttrEndRow
, pNewAttrArray
, nRow
, mpDoc
);
428 rValue
.mfValue
= mpDoc
->RoundValueAsShown( rValue
.mfValue
, nNumFormat
);
430 nNumFmtType
= css::util::NumberFormat::NUMBER
;
433 return true; // Found it!
436 case CELLTYPE_FORMULA
:
438 if (aCell
.mpFormula
->IsValue())
440 rValue
.mfValue
= aCell
.mpFormula
->GetValue();
441 rValue
.mbIsNumber
= true;
442 mpDoc
->GetNumberFormatInfo(
443 nNumFmtType
, nNumFmtIndex
, ScAddress(nCol
, nRow
, nTab
));
444 rValue
.mnError
= aCell
.mpFormula
->GetErrCode();
445 return true; // Found it!
447 else if(mpParam
->mbSkipString
)
451 rValue
.maString
= aCell
.mpFormula
->GetString().getString();
452 rValue
.mfValue
= 0.0;
453 rValue
.mnError
= aCell
.mpFormula
->GetErrCode();
454 rValue
.mbIsNumber
= false;
459 case CELLTYPE_STRING
:
461 if (mpParam
->mbSkipString
)
465 rValue
.maString
= aCell
.getString(mpDoc
);
466 rValue
.mfValue
= 0.0;
468 rValue
.mbIsNumber
= false;
479 // statement unreachable
482 bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value
& rValue
)
484 if (mpParam
->bHasHeader
)
487 mpCells
= ScDBQueryDataIterator::GetColumnCellStore(*mpDoc
, nTab
, nCol
);
491 maCurPos
= mpCells
->position(nRow
);
492 return getCurrent(rValue
);
495 bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value
& rValue
)
497 if (!mpCells
|| maCurPos
.first
== mpCells
->end())
501 return getCurrent(rValue
);
504 void ScDBQueryDataIterator::DataAccessInternal::incBlock()
509 nRow
= maCurPos
.first
->position
;
512 void ScDBQueryDataIterator::DataAccessInternal::incPos()
514 if (maCurPos
.second
+ 1 < maCurPos
.first
->size
)
516 // Move within the same block.
521 // Move to the next block.
525 ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator
* pParent
, ScDBQueryParamMatrix
* pParam
)
526 : DataAccess(pParent
)
531 mpParam
->mpMatrix
->GetDimensions(nC
, nR
);
532 mnRows
= static_cast<SCROW
>(nR
);
533 mnCols
= static_cast<SCCOL
>(nC
);
536 ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix()
540 bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value
& rValue
)
542 // Starting from row == mnCurRow, get the first row that satisfies all the
544 for ( ;mnCurRow
< mnRows
; ++mnCurRow
)
546 const ScMatrix
& rMat
= *mpParam
->mpMatrix
;
547 if (rMat
.IsEmpty(mpParam
->mnField
, mnCurRow
))
548 // Don't take empty values into account.
551 bool bIsStrVal
= rMat
.IsString(mpParam
->mnField
, mnCurRow
);
552 if (bIsStrVal
&& mpParam
->mbSkipString
)
555 if (isValidQuery(mnCurRow
, rMat
))
557 rValue
.maString
= rMat
.GetString(mpParam
->mnField
, mnCurRow
).getString();
558 rValue
.mfValue
= rMat
.GetDouble(mpParam
->mnField
, mnCurRow
);
559 rValue
.mbIsNumber
= !bIsStrVal
;
567 bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value
& rValue
)
569 mnCurRow
= mpParam
->bHasHeader
? 1 : 0;
570 return getCurrent(rValue
);
573 bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value
& rValue
)
576 return getCurrent(rValue
);
581 bool isQueryByValue(const ScQueryEntry::Item
& rItem
, const ScMatrix
& rMat
, SCSIZE nCol
, SCSIZE nRow
)
583 if (rItem
.meType
== ScQueryEntry::ByString
)
586 if (!rMat
.IsValueOrEmpty(nCol
, nRow
))
592 bool isQueryByString(const ScQueryEntry
& rEntry
, const ScQueryEntry::Item
& rItem
, const ScMatrix
& rMat
, SCSIZE nCol
, SCSIZE nRow
)
599 case SC_DOES_NOT_CONTAIN
:
602 case SC_DOES_NOT_BEGIN_WITH
:
603 case SC_DOES_NOT_END_WITH
:
609 if (rItem
.meType
== ScQueryEntry::ByString
&& rMat
.IsString(nCol
, nRow
))
617 bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow
, const ScMatrix
& rMat
) const
619 SCSIZE nEntryCount
= mpParam
->GetEntryCount();
620 vector
<bool> aResults
;
621 aResults
.reserve(nEntryCount
);
623 const CollatorWrapper
& rCollator
=
624 mpParam
->bCaseSens
? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
626 for (SCSIZE i
= 0; i
< nEntryCount
; ++i
)
628 const ScQueryEntry
& rEntry
= mpParam
->GetEntry(i
);
629 const ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
630 if (!rEntry
.bDoQuery
)
639 case SC_GREATER_EQUAL
:
643 // Only the above operators are supported.
649 SCSIZE nField
= static_cast<SCSIZE
>(rEntry
.nField
);
650 if (isQueryByValue(rItem
, rMat
, nField
, nRow
))
653 double fMatVal
= rMat
.GetDouble(nField
, nRow
);
654 bool bEqual
= approxEqual(fMatVal
, rItem
.mfVal
);
661 bValid
= (fMatVal
< rItem
.mfVal
) && !bEqual
;
664 bValid
= (fMatVal
> rItem
.mfVal
) && !bEqual
;
667 bValid
= (fMatVal
< rItem
.mfVal
) || bEqual
;
669 case SC_GREATER_EQUAL
:
670 bValid
= (fMatVal
> rItem
.mfVal
) || bEqual
;
679 else if (isQueryByString(rEntry
, rItem
, rMat
, nField
, nRow
))
684 // Equality check first.
685 svl::SharedString aMatStr
= rMat
.GetString(nField
, nRow
);
686 svl::SharedString aQueryStr
= rEntry
.GetQueryItem().maString
;
688 rtl_uString
* p1
= mpParam
->bCaseSens
? aMatStr
.getData() : aMatStr
.getDataIgnoreCase();
689 rtl_uString
* p2
= mpParam
->bCaseSens
? aQueryStr
.getData() : aQueryStr
.getDataIgnoreCase();
707 // Unequality check using collator.
708 sal_Int32 nCompare
= rCollator
.compareString(aMatStr
.getString(), aQueryStr
.getString());
712 bValid
= (nCompare
< 0);
715 bValid
= (nCompare
> 0);
718 bValid
= (nCompare
<= 0);
720 case SC_GREATER_EQUAL
:
721 bValid
= (nCompare
>= 0);
730 if (aResults
.empty())
731 // First query entry.
732 aResults
.push_back(bValid
);
733 else if (rEntry
.eConnect
== SC_AND
)
735 // For AND op, tuck the result into the last result value.
736 size_t n
= aResults
.size();
737 aResults
[n
-1] = aResults
[n
-1] && bValid
;
740 // For OR op, store its own result.
741 aResults
.push_back(bValid
);
744 // Row is valid as long as there is at least one result being true.
745 vector
<bool>::const_iterator itr
= aResults
.begin(), itrEnd
= aResults
.end();
746 for (; itr
!= itrEnd
; ++itr
)
753 ScDBQueryDataIterator::Value::Value() :
754 mnError(0), mbIsNumber(true)
756 ::rtl::math::setNan(&mfValue
);
759 ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument
* pDocument
, ScDBQueryParamBase
* pParam
) :
762 switch (mpParam
->GetType())
764 case ScDBQueryParamBase::INTERNAL
:
766 ScDBQueryParamInternal
* p
= static_cast<ScDBQueryParamInternal
*>(pParam
);
767 mpData
.reset(new DataAccessInternal(this, p
, pDocument
));
770 case ScDBQueryParamBase::MATRIX
:
772 ScDBQueryParamMatrix
* p
= static_cast<ScDBQueryParamMatrix
*>(pParam
);
773 mpData
.reset(new DataAccessMatrix(this, p
));
778 bool ScDBQueryDataIterator::GetFirst(Value
& rValue
)
780 return mpData
->getFirst(rValue
);
783 bool ScDBQueryDataIterator::GetNext(Value
& rValue
)
785 return mpData
->getNext(rValue
);
788 ScCellIterator::ScCellIterator( ScDocument
* pDoc
, const ScRange
& rRange
, sal_uInt16 nSubTotalFlags
) :
790 maStartPos(rRange
.aStart
),
791 maEndPos(rRange
.aEnd
),
792 mnSubTotalFlags(nSubTotalFlags
)
797 void ScCellIterator::incBlock()
800 maCurColPos
.second
= 0;
802 maCurPos
.SetRow(maCurColPos
.first
->position
);
805 void ScCellIterator::incPos()
807 if (maCurColPos
.second
+ 1 < maCurColPos
.first
->size
)
809 // Move within the same block.
810 ++maCurColPos
.second
;
814 // Move to the next block.
818 void ScCellIterator::setPos(size_t nPos
)
820 maCurColPos
= getColumn()->maCells
.position(maCurColPos
.first
, nPos
);
821 maCurPos
.SetRow(nPos
);
824 const ScColumn
* ScCellIterator::getColumn() const
826 return &mpDoc
->maTabs
[maCurPos
.Tab()]->aCol
[maCurPos
.Col()];
829 void ScCellIterator::init()
831 SCTAB nDocMaxTab
= mpDoc
->GetTableCount() - 1;
833 PutInOrder(maStartPos
, maEndPos
);
835 if (!ValidCol(maStartPos
.Col())) maStartPos
.SetCol(MAXCOL
);
836 if (!ValidCol(maEndPos
.Col())) maEndPos
.SetCol(MAXCOL
);
837 if (!ValidRow(maStartPos
.Row())) maStartPos
.SetRow(MAXROW
);
838 if (!ValidRow(maEndPos
.Row())) maEndPos
.SetRow(MAXROW
);
839 if (!ValidTab(maStartPos
.Tab(), nDocMaxTab
)) maStartPos
.SetTab(nDocMaxTab
);
840 if (!ValidTab(maEndPos
.Tab(), nDocMaxTab
)) maEndPos
.SetTab(nDocMaxTab
);
842 while (maEndPos
.Tab() > 0 && !mpDoc
->maTabs
[maEndPos
.Tab()])
843 maEndPos
.IncTab(-1); // Only the tables in use
845 if (maStartPos
.Tab() > maEndPos
.Tab())
846 maStartPos
.SetTab(maEndPos
.Tab());
848 maCurPos
= maStartPos
;
850 if (!mpDoc
->maTabs
[maCurPos
.Tab()])
852 OSL_FAIL("Table not found");
853 maStartPos
= ScAddress(MAXCOL
+1, MAXROW
+1, MAXTAB
+1); // -> Abort on GetFirst.
854 maCurPos
= maStartPos
;
858 bool ScCellIterator::getCurrent()
860 const ScColumn
* pCol
= getColumn();
864 bool bNextColumn
= maCurColPos
.first
== pCol
->maCells
.end();
867 if (maCurPos
.Row() > maEndPos
.Row())
873 // Move to the next column.
874 maCurPos
.SetRow(maStartPos
.Row());
878 if (maCurPos
.Col() > maEndPos
.Col())
880 maCurPos
.SetCol(maStartPos
.Col());
882 if (maCurPos
.Tab() > maEndPos
.Tab())
885 return false; // Over and out
890 while (pCol
->IsEmptyData());
892 maCurColPos
= pCol
->maCells
.position(maCurPos
.Row());
895 if (maCurColPos
.first
->type
== sc::element_type_empty
)
902 // Skip all filtered or hidden rows, depending on mSubTotalFlags
903 if ( ( ( mnSubTotalFlags
& SUBTOTAL_IGN_FILTERED
) &&
904 pCol
->GetDoc().RowFiltered(maCurPos
.Row(), maCurPos
.Tab(), NULL
, &nLastRow
) ) ||
905 ( ( mnSubTotalFlags
& SUBTOTAL_IGN_HIDDEN
) &&
906 pCol
->GetDoc().RowHidden(maCurPos
.Row(), maCurPos
.Tab(), NULL
, &nLastRow
) ) )
912 if (maCurColPos
.first
->type
== sc::element_type_formula
)
914 if ( mnSubTotalFlags
)
916 ScFormulaCell
* pCell
= sc::formula_block::at(*maCurColPos
.first
->data
, maCurColPos
.second
);
917 // Skip formula cells with Subtotal formulae or errors, depending on mnSubTotalFlags
918 if ( ( ( mnSubTotalFlags
& SUBTOTAL_IGN_NESTED_ST_AG
) && pCell
->IsSubTotal() ) ||
919 ( ( mnSubTotalFlags
& SUBTOTAL_IGN_ERR_VAL
) && pCell
->GetErrCode() ) )
927 maCurCell
= sc::toRefCell(maCurColPos
.first
, maCurColPos
.second
);
933 OUString
ScCellIterator::getString()
935 return maCurCell
.getString(mpDoc
);
938 ScCellValue
ScCellIterator::getCellValue() const
941 aRet
.meType
= maCurCell
.meType
;
943 switch (maCurCell
.meType
)
945 case CELLTYPE_STRING
:
946 aRet
.mpString
= new svl::SharedString(*maCurCell
.mpString
);
949 aRet
.mpEditText
= maCurCell
.mpEditText
->Clone();
952 aRet
.mfValue
= maCurCell
.mfValue
;
954 case CELLTYPE_FORMULA
:
955 aRet
.mpFormula
= maCurCell
.mpFormula
->Clone();
964 bool ScCellIterator::hasString() const
966 return maCurCell
.hasString();
969 bool ScCellIterator::hasEmptyData() const
971 if (maCurCell
.isEmpty())
974 if (maCurCell
.meType
== CELLTYPE_FORMULA
)
975 return maCurCell
.mpFormula
->IsEmpty();
980 bool ScCellIterator::isEmpty() const
982 return maCurCell
.isEmpty();
985 bool ScCellIterator::equalsWithoutFormat( const ScAddress
& rPos
) const
987 ScRefCellValue aOther
;
988 aOther
.assign(*mpDoc
, rPos
);
989 return maCurCell
.equalsWithoutFormat(aOther
);
992 bool ScCellIterator::first()
994 if (!ValidTab(maCurPos
.Tab()))
997 maCurPos
= maStartPos
;
998 const ScColumn
* pCol
= getColumn();
1000 maCurColPos
= pCol
->maCells
.position(maCurPos
.Row());
1001 return getCurrent();
1004 bool ScCellIterator::next()
1007 return getCurrent();
1010 ScQueryCellIterator::ScQueryCellIterator(ScDocument
* pDocument
, SCTAB nTable
,
1011 const ScQueryParam
& rParam
, bool bMod
) :
1012 mpParam(new ScQueryParam(rParam
)),
1015 nStopOnMismatch( nStopOnMismatchDisabled
),
1016 nTestEqualCondition( nTestEqualConditionDisabled
),
1017 bAdvanceQuery( false ),
1018 bIgnoreMismatchOnLeadingStrings( false )
1020 nCol
= mpParam
->nCol1
;
1021 nRow
= mpParam
->nRow1
;
1023 if (bMod
) // Or else it's already inserted
1025 SCSIZE nCount
= mpParam
->GetEntryCount();
1026 for (i
= 0; (i
< nCount
) && (mpParam
->GetEntry(i
).bDoQuery
); ++i
)
1028 ScQueryEntry
& rEntry
= mpParam
->GetEntry(i
);
1029 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
1030 sal_uInt32 nIndex
= 0;
1031 bool bNumber
= pDoc
->GetFormatTable()->IsNumberFormat(
1032 rItem
.maString
.getString(), nIndex
, rItem
.mfVal
);
1033 rItem
.meType
= bNumber
? ScQueryEntry::ByValue
: ScQueryEntry::ByString
;
1036 nNumFormat
= 0; // Initialized in GetNumberFormat
1041 void ScQueryCellIterator::InitPos()
1043 nRow
= mpParam
->nRow1
;
1044 if (mpParam
->bHasHeader
&& mpParam
->bByRow
)
1046 ScColumn
* pCol
= &(pDoc
->maTabs
[nTab
])->aCol
[nCol
];
1047 maCurPos
= pCol
->maCells
.position(nRow
);
1050 void ScQueryCellIterator::IncPos()
1052 if (maCurPos
.second
+ 1 < maCurPos
.first
->size
)
1054 // Move within the same block.
1059 // Move to the next block.
1063 void ScQueryCellIterator::IncBlock()
1066 maCurPos
.second
= 0;
1068 nRow
= maCurPos
.first
->position
;
1071 bool ScQueryCellIterator::GetThis()
1073 if (nTab
>= pDoc
->GetTableCount())
1074 OSL_FAIL("try to access index out of bounds, FIX IT");
1075 const ScQueryEntry
& rEntry
= mpParam
->GetEntry(0);
1076 const ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
1078 SCCOLROW nFirstQueryField
= rEntry
.nField
;
1079 bool bAllStringIgnore
= bIgnoreMismatchOnLeadingStrings
&&
1080 rItem
.meType
!= ScQueryEntry::ByString
;
1081 bool bFirstStringIgnore
= bIgnoreMismatchOnLeadingStrings
&&
1082 !mpParam
->bHasHeader
&& rItem
.meType
== ScQueryEntry::ByString
&&
1083 ((mpParam
->bByRow
&& nRow
== mpParam
->nRow1
) ||
1084 (!mpParam
->bByRow
&& nCol
== mpParam
->nCol1
));
1086 ScColumn
* pCol
= &(pDoc
->maTabs
[nTab
])->aCol
[nCol
];
1089 bool bNextColumn
= maCurPos
.first
== pCol
->maCells
.end();
1092 if (nRow
> mpParam
->nRow2
)
1100 if ( ++nCol
> mpParam
->nCol2
)
1101 return false; // Over and out
1102 if ( bAdvanceQuery
)
1104 AdvanceQueryParamEntryField();
1105 nFirstQueryField
= rEntry
.nField
;
1107 pCol
= &(pDoc
->maTabs
[nTab
])->aCol
[nCol
];
1109 while (pCol
->IsEmptyData());
1113 bFirstStringIgnore
= bIgnoreMismatchOnLeadingStrings
&&
1114 !mpParam
->bHasHeader
&& rItem
.meType
== ScQueryEntry::ByString
&&
1118 if (maCurPos
.first
->type
== sc::element_type_empty
)
1120 if (rItem
.mbMatchEmpty
&& rEntry
.GetQueryItems().size() == 1)
1122 // This shortcut, instead of determining if any SC_OR query
1123 // exists or this query is SC_AND'ed (which wouldn't make
1124 // sense, but..) and evaluating them in ValidQuery(), is
1125 // possible only because the interpreter is the only caller
1126 // that sets mbMatchEmpty and there is only one item in those
1128 // XXX this would have to be reworked if other filters used it
1129 // in different manners and evaluation would have to be done in
1140 ScRefCellValue aCell
= sc::toRefCell(maCurPos
.first
, maCurPos
.second
);
1142 if (bAllStringIgnore
&& aCell
.hasString())
1146 bool bTestEqualCondition
= false;
1147 if ( pDoc
->maTabs
[nTab
]->ValidQuery( nRow
, *mpParam
,
1148 (nCol
== static_cast<SCCOL
>(nFirstQueryField
) ? &aCell
: NULL
),
1149 (nTestEqualCondition
? &bTestEqualCondition
: NULL
) ) )
1151 if ( nTestEqualCondition
&& bTestEqualCondition
)
1152 nTestEqualCondition
|= nTestEqualConditionMatched
;
1153 return !aCell
.isEmpty(); // Found it!
1155 else if ( nStopOnMismatch
)
1157 // Yes, even a mismatch may have a fulfilled equal
1158 // condition if regular expressions were involved and
1159 // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
1160 if ( nTestEqualCondition
&& bTestEqualCondition
)
1162 nTestEqualCondition
|= nTestEqualConditionMatched
;
1163 nStopOnMismatch
|= nStopOnMismatchOccurred
;
1167 if (bFirstStringIgnore
)
1169 if (aCell
.hasString())
1181 nStopOnMismatch
|= nStopOnMismatchOccurred
;
1188 bFirstStringIgnore
= false;
1192 bool ScQueryCellIterator::GetFirst()
1194 if (nTab
>= pDoc
->GetTableCount())
1195 OSL_FAIL("try to access index out of bounds, FIX IT");
1196 nCol
= mpParam
->nCol1
;
1201 bool ScQueryCellIterator::GetNext()
1204 if ( nStopOnMismatch
)
1205 nStopOnMismatch
= nStopOnMismatchEnabled
;
1206 if ( nTestEqualCondition
)
1207 nTestEqualCondition
= nTestEqualConditionEnabled
;
1211 void ScQueryCellIterator::AdvanceQueryParamEntryField()
1213 SCSIZE nEntries
= mpParam
->GetEntryCount();
1214 for ( SCSIZE j
= 0; j
< nEntries
; j
++ )
1216 ScQueryEntry
& rEntry
= mpParam
->GetEntry( j
);
1217 if ( rEntry
.bDoQuery
)
1219 if ( rEntry
.nField
< MAXCOL
)
1223 OSL_FAIL( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
1231 bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL
& nFoundCol
,
1232 SCROW
& nFoundRow
, bool bSearchForEqualAfterMismatch
,
1233 bool bIgnoreMismatchOnLeadingStringsP
)
1235 // Set and automatically reset mpParam->mbRangeLookup when returning. We
1236 // could use comphelper::FlagRestorationGuard, but really, that one is
1237 // overengineered for this simple purpose here.
1242 BoolResetter( bool& r
, bool b
) : mr(r
), mb(r
) { r
= b
; }
1243 ~BoolResetter() { mr
= mb
; }
1244 } aRangeLookupResetter( mpParam
->mbRangeLookup
, true);
1246 nFoundCol
= MAXCOL
+1;
1247 nFoundRow
= MAXROW
+1;
1248 SetStopOnMismatch( true ); // assume sorted keys
1249 SetTestEqualCondition( true );
1250 bIgnoreMismatchOnLeadingStrings
= bIgnoreMismatchOnLeadingStringsP
;
1251 bool bRegExp
= mpParam
->bRegExp
&& mpParam
->GetEntry(0).GetQueryItem().meType
== ScQueryEntry::ByString
;
1252 bool bBinary
= !bRegExp
&& mpParam
->bByRow
&& (mpParam
->GetEntry(0).eOp
==
1253 SC_LESS_EQUAL
|| mpParam
->GetEntry(0).eOp
== SC_GREATER_EQUAL
);
1254 bool bFound
= false;
1259 // BinarySearch() already positions correctly and only needs real
1260 // query comparisons afterwards, skip the verification check below.
1261 mpParam
->mbRangeLookup
= false;
1267 bFound
= GetFirst();
1271 // First equal entry or last smaller than (greater than) entry.
1272 PositionType aPosSave
;
1276 nFoundCol
= GetCol();
1277 nFoundRow
= GetRow();
1278 aPosSave
= maCurPos
;
1280 while ( !IsEqualConditionFulfilled() && (bNext
= GetNext()));
1282 // There may be no pNext but equal condition fulfilled if regular
1283 // expressions are involved. Keep the found entry and proceed.
1284 if (!bNext
&& !IsEqualConditionFulfilled())
1286 // Step back to last in range and adjust position markers for
1287 // GetNumberFormat() or similar.
1288 SCCOL nColDiff
= nCol
- nFoundCol
;
1291 maCurPos
= aPosSave
;
1292 if (mpParam
->mbRangeLookup
)
1294 // Verify that the found entry does not only fulfill the range
1295 // lookup but also the real query, i.e. not numeric was found
1296 // if query is ByString and vice versa.
1297 mpParam
->mbRangeLookup
= false;
1298 // Step back the last field advance if GetNext() did one.
1299 if (bAdvanceQuery
&& nColDiff
)
1301 SCSIZE nEntries
= mpParam
->GetEntryCount();
1302 for (SCSIZE j
=0; j
< nEntries
; ++j
)
1304 ScQueryEntry
& rEntry
= mpParam
->GetEntry( j
);
1305 if (rEntry
.bDoQuery
)
1307 if (rEntry
.nField
- nColDiff
>= 0)
1308 rEntry
.nField
-= nColDiff
;
1311 assert(!"FindEqualOrSortedLastInRange: rEntry.nField -= nColDiff < 0");
1321 nFoundCol
= MAXCOL
+1;
1322 nFoundRow
= MAXROW
+1;
1327 if ( IsEqualConditionFulfilled() )
1329 // Position on last equal entry.
1330 SCSIZE nEntries
= mpParam
->GetEntryCount();
1331 for ( SCSIZE j
= 0; j
< nEntries
; j
++ )
1333 ScQueryEntry
& rEntry
= mpParam
->GetEntry( j
);
1334 if ( rEntry
.bDoQuery
)
1336 switch ( rEntry
.eOp
)
1338 case SC_LESS_EQUAL
:
1339 case SC_GREATER_EQUAL
:
1340 rEntry
.eOp
= SC_EQUAL
;
1344 // added to avoid warnings
1351 PositionType aPosSave
;
1352 bIgnoreMismatchOnLeadingStrings
= false;
1353 SetTestEqualCondition( false );
1356 nFoundCol
= GetCol();
1357 nFoundRow
= GetRow();
1358 aPosSave
= maCurPos
;
1359 } while (GetNext());
1361 // Step back conditions are the same as above
1364 maCurPos
= aPosSave
;
1367 if ( (bSearchForEqualAfterMismatch
|| mpParam
->bRegExp
) &&
1368 StoppedOnMismatch() )
1370 // Assume found entry to be the last value less than respectively
1371 // greater than the query. But keep on searching for an equal match.
1372 SCSIZE nEntries
= mpParam
->GetEntryCount();
1373 for ( SCSIZE j
= 0; j
< nEntries
; j
++ )
1375 ScQueryEntry
& rEntry
= mpParam
->GetEntry( j
);
1376 if ( rEntry
.bDoQuery
)
1378 switch ( rEntry
.eOp
)
1380 case SC_LESS_EQUAL
:
1381 case SC_GREATER_EQUAL
:
1382 rEntry
.eOp
= SC_EQUAL
;
1386 // added to avoid warnings
1393 SetStopOnMismatch( false );
1394 SetTestEqualCondition( false );
1397 // Last of a consecutive area, avoid searching the entire parameter
1398 // range as it is a real performance bottleneck in case of regular
1400 PositionType aPosSave
;
1403 nFoundCol
= GetCol();
1404 nFoundRow
= GetRow();
1405 aPosSave
= maCurPos
;
1406 SetStopOnMismatch( true );
1407 } while (GetNext());
1410 maCurPos
= aPosSave
;
1413 return (nFoundCol
<= MAXCOL
) && (nFoundRow
<= MAXROW
);
1419 * This class sequentially indexes non-empty cells in order, from the top of
1420 * the block where the start row position is, to the bottom of the block
1421 * where the end row position is. It skips all empty blocks that may be
1422 * present in between.
1424 * The index value is an offset from the first element of the first block
1425 * disregarding all empty cell blocks.
1427 class NonEmptyCellIndexer
1429 typedef std::map
<size_t, sc::CellStoreType::const_iterator
> BlockMapType
;
1431 BlockMapType maBlockMap
;
1433 const sc::CellStoreType
& mrCells
;
1442 typedef std::pair
<ScRefCellValue
, SCROW
> CellType
;
1445 * @param rCells cell storage container
1446 * @param nStartRow logical start row position
1447 * @param nEndRow logical end row position, inclusive.
1448 * @param bSkipTopStrBlock when true, skip all leading string cells.
1450 NonEmptyCellIndexer(
1451 const sc::CellStoreType
& rCells
, SCROW nStartRow
, SCROW nEndRow
, bool bSkipTopStrBlock
) :
1452 mrCells(rCells
), mnLowIndex(0), mnHighIndex(0), mbValid(true)
1454 if (nEndRow
< nStartRow
)
1460 // Find the low position.
1462 sc::CellStoreType::const_position_type aLoPos
= mrCells
.position(nStartRow
);
1463 if (aLoPos
.first
->type
== sc::element_type_empty
)
1466 if (aLoPos
.first
== rCells
.end())
1472 if (bSkipTopStrBlock
)
1474 // Skip all leading string or empty blocks.
1475 while (aLoPos
.first
->type
== sc::element_type_string
||
1476 aLoPos
.first
->type
== sc::element_type_edittext
||
1477 aLoPos
.first
->type
== sc::element_type_empty
)
1480 if (aLoPos
.first
== rCells
.end())
1488 SCROW nFirstRow
= aLoPos
.first
->position
;
1489 SCROW nLastRow
= aLoPos
.first
->position
+ aLoPos
.first
->size
- 1;
1491 if (nFirstRow
> nEndRow
)
1493 // Both start and end row positions are within the leading skipped
1499 // Calculate the index of the low position.
1500 if (nFirstRow
< nStartRow
)
1501 mnLowIndex
= nStartRow
- nFirstRow
;
1504 // Start row is within the skipped block(s). Set it to the first
1505 // element of the low block.
1509 if (nEndRow
< nLastRow
)
1511 assert(nEndRow
>= nFirstRow
);
1512 mnHighIndex
= nEndRow
- nFirstRow
;
1514 maBlockMap
.insert(BlockMapType::value_type(aLoPos
.first
->size
, aLoPos
.first
));
1518 // Find the high position.
1520 sc::CellStoreType::const_position_type aHiPos
= mrCells
.position(aLoPos
.first
, nEndRow
);
1521 if (aHiPos
.first
->type
== sc::element_type_empty
)
1523 // Move to the last position of the previous block.
1526 // Check the row position of the end of the previous block, and make sure it's valid.
1527 SCROW nBlockEndRow
= aHiPos
.first
->position
+ aHiPos
.first
->size
- 1;
1528 if (nBlockEndRow
< nStartRow
)
1535 // Tag the start and end blocks, and all blocks in between in order
1536 // but skip all empty blocks.
1539 sc::CellStoreType::const_iterator itBlk
= aLoPos
.first
;
1540 while (itBlk
!= aHiPos
.first
)
1542 if (itBlk
->type
== sc::element_type_empty
)
1548 nPos
+= itBlk
->size
;
1549 maBlockMap
.insert(BlockMapType::value_type(nPos
, itBlk
));
1552 if (itBlk
->type
== sc::element_type_empty
)
1555 assert(itBlk
!= mrCells
.end());
1558 assert(itBlk
== aHiPos
.first
);
1559 nPos
+= itBlk
->size
;
1560 maBlockMap
.insert(BlockMapType::value_type(nPos
, itBlk
));
1562 // Calculate the high index.
1563 BlockMapType::const_reverse_iterator ri
= maBlockMap
.rbegin();
1564 mnHighIndex
= ri
->first
;
1565 mnHighIndex
-= ri
->second
->size
;
1566 mnHighIndex
+= aHiPos
.second
;
1569 sc::CellStoreType::const_position_type
getPosition( size_t nIndex
) const
1572 assert(mnLowIndex
<= nIndex
);
1573 assert(nIndex
<= mnHighIndex
);
1575 sc::CellStoreType::const_position_type
aRet(mrCells
.end(), 0);
1577 BlockMapType::const_iterator it
= maBlockMap
.upper_bound(nIndex
);
1578 if (it
== maBlockMap
.end())
1581 sc::CellStoreType::const_iterator itBlk
= it
->second
;
1582 size_t nBlkIndex
= it
->first
- itBlk
->size
; // index of the first element of the block.
1583 assert(nBlkIndex
<= nIndex
);
1584 assert(nIndex
< it
->first
);
1586 size_t nOffset
= nIndex
- nBlkIndex
;
1588 aRet
.second
= nOffset
;
1592 CellType
getCell( size_t nIndex
) const
1594 std::pair
<ScRefCellValue
, SCROW
> aRet
;
1597 sc::CellStoreType::const_position_type aPos
= getPosition(nIndex
);
1598 if (aPos
.first
== mrCells
.end())
1601 aRet
.first
= sc::toRefCell(aPos
.first
, aPos
.second
);
1602 aRet
.second
= aPos
.first
->position
+ aPos
.second
;
1606 size_t getLowIndex() const { return mnLowIndex
; }
1608 size_t getHighIndex() const { return mnHighIndex
; }
1610 bool isValid() const { return mbValid
; }
1615 bool ScQueryCellIterator::BinarySearch()
1617 // TODO: This will be extremely slow with mdds::multi_type_vector.
1619 if (nTab
>= pDoc
->GetTableCount())
1620 OSL_FAIL("try to access index out of bounds, FIX IT");
1621 nCol
= mpParam
->nCol1
;
1622 ScColumn
* pCol
= &(pDoc
->maTabs
[nTab
])->aCol
[nCol
];
1623 if (pCol
->IsEmptyData())
1626 CollatorWrapper
* pCollator
= (mpParam
->bCaseSens
? ScGlobal::GetCaseCollator() :
1627 ScGlobal::GetCollator());
1628 SvNumberFormatter
& rFormatter
= *(pDoc
->GetFormatTable());
1629 const ScQueryEntry
& rEntry
= mpParam
->GetEntry(0);
1630 const ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
1631 bool bLessEqual
= rEntry
.eOp
== SC_LESS_EQUAL
;
1632 bool bByString
= rItem
.meType
== ScQueryEntry::ByString
;
1633 bool bAllStringIgnore
= bIgnoreMismatchOnLeadingStrings
&& !bByString
;
1634 bool bFirstStringIgnore
= bIgnoreMismatchOnLeadingStrings
&&
1635 !mpParam
->bHasHeader
&& bByString
;
1637 nRow
= mpParam
->nRow1
;
1638 if (mpParam
->bHasHeader
)
1641 ScRefCellValue aCell
;
1642 if (bFirstStringIgnore
)
1644 sc::CellStoreType::const_position_type aPos
= pCol
->maCells
.position(nRow
);
1645 if (aPos
.first
->type
== sc::element_type_string
|| aPos
.first
->type
== sc::element_type_edittext
)
1647 aCell
= sc::toRefCell(aPos
.first
, aPos
.second
);
1648 sal_uLong nFormat
= pCol
->GetNumberFormat(nRow
);
1650 ScCellFormat::GetInputString(aCell
, nFormat
, aCellStr
, rFormatter
, pDoc
);
1651 sal_Int32 nTmp
= pCollator
->compareString(aCellStr
, rEntry
.GetQueryItem().maString
.getString());
1652 if ((rEntry
.eOp
== SC_LESS_EQUAL
&& nTmp
> 0) ||
1653 (rEntry
.eOp
== SC_GREATER_EQUAL
&& nTmp
< 0) ||
1654 (rEntry
.eOp
== SC_EQUAL
&& nTmp
!= 0))
1659 NonEmptyCellIndexer
aIndexer(pCol
->maCells
, nRow
, mpParam
->nRow2
, bAllStringIgnore
);
1660 if (!aIndexer
.isValid())
1663 size_t nLo
= aIndexer
.getLowIndex();
1664 size_t nHi
= aIndexer
.getHighIndex();
1665 NonEmptyCellIndexer::CellType aCellData
;
1667 // Bookkeeping values for breaking up the binary search in case the data
1668 // range isn't strictly sorted.
1669 size_t nLastInRange
= nLo
;
1670 size_t nFirstLastInRange
= nLastInRange
;
1671 double fLastInRangeValue
= bLessEqual
?
1672 -(::std::numeric_limits
<double>::max()) :
1673 ::std::numeric_limits
<double>::max();
1674 OUString aLastInRangeString
;
1676 aLastInRangeString
= OUString(sal_Unicode(0xFFFF));
1678 aCellData
= aIndexer
.getCell(nLastInRange
);
1679 aCell
= aCellData
.first
;
1680 if (aCell
.hasString())
1682 sal_uLong nFormat
= pCol
->GetNumberFormat(aCellData
.second
);
1684 ScCellFormat::GetInputString(aCell
, nFormat
, aStr
, rFormatter
, pDoc
);
1685 aLastInRangeString
= aStr
;
1689 switch (aCell
.meType
)
1691 case CELLTYPE_VALUE
:
1692 fLastInRangeValue
= aCell
.mfValue
;
1694 case CELLTYPE_FORMULA
:
1695 fLastInRangeValue
= aCell
.mpFormula
->GetValue();
1699 // added to avoid warnings
1705 bool bFound
= false;
1707 while (nLo
<= nHi
&& !bDone
)
1709 size_t nMid
= (nLo
+nHi
)/2;
1720 aCellData
= aIndexer
.getCell(i
);
1721 aCell
= aCellData
.first
;
1722 bool bStr
= aCell
.hasString();
1725 // compares are content<query:-1, content>query:1
1726 // Cell value comparison similar to ScTable::ValidQuery()
1727 if (!bStr
&& !bByString
)
1730 switch (aCell
.meType
)
1732 case CELLTYPE_VALUE
:
1733 case CELLTYPE_FORMULA
:
1734 nCellVal
= aCell
.getValue();
1739 if ((nCellVal
< rItem
.mfVal
) && !::rtl::math::approxEqual(
1740 nCellVal
, rItem
.mfVal
))
1745 if (fLastInRangeValue
< nCellVal
)
1747 fLastInRangeValue
= nCellVal
;
1750 else if (fLastInRangeValue
> nCellVal
)
1752 // not strictly sorted, continue with GetThis()
1753 nLastInRange
= nFirstLastInRange
;
1758 else if ((nCellVal
> rItem
.mfVal
) && !::rtl::math::approxEqual(
1759 nCellVal
, rItem
.mfVal
))
1764 if (fLastInRangeValue
> nCellVal
)
1766 fLastInRangeValue
= nCellVal
;
1769 else if (fLastInRangeValue
< nCellVal
)
1771 // not strictly sorted, continue with GetThis()
1772 nLastInRange
= nFirstLastInRange
;
1778 else if (bStr
&& bByString
)
1781 sal_uLong nFormat
= pCol
->GetNumberFormat(aCellData
.second
);
1782 ScCellFormat::GetInputString(aCell
, nFormat
, aCellStr
, rFormatter
, pDoc
);
1784 nRes
= pCollator
->compareString(aCellStr
, rEntry
.GetQueryItem().maString
.getString());
1785 if (nRes
< 0 && bLessEqual
)
1787 sal_Int32 nTmp
= pCollator
->compareString( aLastInRangeString
,
1791 aLastInRangeString
= aCellStr
;
1796 // not strictly sorted, continue with GetThis()
1797 nLastInRange
= nFirstLastInRange
;
1801 else if (nRes
> 0 && !bLessEqual
)
1803 sal_Int32 nTmp
= pCollator
->compareString( aLastInRangeString
,
1807 aLastInRangeString
= aCellStr
;
1812 // not strictly sorted, continue with GetThis()
1813 nLastInRange
= nFirstLastInRange
;
1818 else if (!bStr
&& bByString
)
1820 nRes
= -1; // numeric < string
1824 else // if (bStr && !bByString)
1826 nRes
= 1; // string > numeric
1834 else // assumed to be SC_GREATER_EQUAL
1851 else // assumed to be SC_GREATER_EQUAL
1857 bDone
= bFound
= true;
1863 // If all hits didn't result in a moving limit there's something
1864 // strange, e.g. data range not properly sorted, or only identical
1865 // values encountered, which doesn't mean there aren't any others in
1866 // between.. leave it to GetThis(). The condition for this would be
1867 // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
1868 // Else, in case no exact match was found, we step back for a
1869 // subsequent GetThis() to find the last in range. Effectively this is
1870 // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
1874 aCellData
= aIndexer
.getCell(nLo
);
1875 if (nLo
<= nHi
&& aCellData
.second
<= mpParam
->nRow2
)
1877 nRow
= aCellData
.second
;
1878 maCurPos
= aIndexer
.getPosition(nLo
);
1883 nRow
= mpParam
->nRow2
+ 1;
1884 // Set current position to the last possible row.
1885 maCurPos
.first
= pCol
->maCells
.end();
1887 maCurPos
.second
= maCurPos
.first
->size
- 1;
1892 ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument
* pDocument
, SCTAB nTable
,
1893 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) :
1904 if (mnTab
>= pDoc
->GetTableCount())
1905 OSL_FAIL("try to access index out of bounds, FIX IT");
1907 pNextRows
= new SCROW
[ nCol2
-nCol1
+1 ];
1908 pNextIndices
= new SCSIZE
[ nCol2
-nCol1
+1 ];
1909 maColPositions
.reserve( nCol2
-nCol1
+1 );
1914 ScHorizontalCellIterator::~ScHorizontalCellIterator()
1916 delete [] pNextRows
;
1917 delete [] pNextIndices
;
1920 void ScHorizontalCellIterator::SetTab( SCTAB nTabP
)
1926 maColPositions
.resize(0);
1928 // Set the start position in each column.
1929 for (SCCOL i
= nStartCol
; i
<= nEndCol
; ++i
)
1931 ScColumn
* pCol
= &pDoc
->maTabs
[mnTab
]->aCol
[i
];
1933 aParam
.maPos
= pCol
->maCells
.position(nStartRow
).first
;
1934 aParam
.maEnd
= pCol
->maCells
.end();
1937 // find first non-empty element.
1938 while (aParam
.maPos
!= aParam
.maEnd
) {
1939 if (aParam
.maPos
->type
== sc::element_type_empty
)
1943 maColPositions
.push_back( aParam
);
1949 if (maColPositions
.size() == 0)
1952 maColPos
= maColPositions
.begin();
1957 ScRefCellValue
* ScHorizontalCellIterator::GetNext( SCCOL
& rCol
, SCROW
& rRow
)
1961 debugiter("no more !\n");
1965 // Return the current non-empty cell, and move the cursor to the next one.
1966 ColParam
& r
= *maColPos
;
1968 rCol
= mnCol
= r
.mnCol
;
1970 debugiter("return col %d row %d\n", (int)rCol
, (int)rRow
);
1972 size_t nOffset
= static_cast<size_t>(mnRow
) - r
.maPos
->position
;
1973 maCurCell
= sc::toRefCell(r
.maPos
, nOffset
);
1975 debugiter("advance to: col %d row %d\n", (int)maColPos
->mnCol
, (int)mnRow
);
1980 bool ScHorizontalCellIterator::GetPos( SCCOL
& rCol
, SCROW
& rRow
)
1987 // Skip any invalid / empty cells across the current row,
1988 // we only advance the cursor if the current entry is invalid.
1989 // if we return true we have a valid cursor (or hit the end)
1990 bool ScHorizontalCellIterator::SkipInvalidInRow()
1993 assert (maColPos
!= maColPositions
.end());
1995 // Find the next non-empty cell in the current row.
1996 while( maColPos
!= maColPositions
.end() )
1998 ColParam
& r
= *maColPos
;
1999 assert (r
.maPos
!= r
.maEnd
);
2001 size_t nRow
= static_cast<size_t>(mnRow
);
2003 if (nRow
>= r
.maPos
->position
)
2005 if (nRow
< r
.maPos
->position
+ r
.maPos
->size
)
2007 mnCol
= maColPos
->mnCol
;
2008 debugiter("found valid cell at column %d, row %d\n",
2009 (int)mnCol
, (int)mnRow
);
2010 assert(r
.maPos
->type
!= sc::element_type_empty
);
2015 bool bMoreBlocksInColumn
= false;
2016 // This block is behind the current row position. Advance the block.
2017 for (++r
.maPos
; r
.maPos
!= r
.maEnd
; ++r
.maPos
)
2019 if (nRow
< r
.maPos
->position
+ r
.maPos
->size
&&
2020 r
.maPos
->type
!= sc::element_type_empty
)
2022 bMoreBlocksInColumn
= true;
2026 if (!bMoreBlocksInColumn
)
2028 debugiter("remove column %d at row %d\n",
2029 (int)maColPos
->mnCol
, (int)nRow
);
2030 maColPos
= maColPositions
.erase(maColPos
);
2031 if (maColPositions
.size() == 0)
2033 debugiter("no more columns\n");
2039 debugiter("advanced column %d to block starting row %d, retying\n",
2040 (int)maColPos
->mnCol
, r
.maPos
->position
);
2046 debugiter("skip empty cells at column %d, row %d\n",
2047 (int)maColPos
->mnCol
, (int)nRow
);
2052 // No more columns with anything interesting in them ?
2053 if (maColPositions
.size() == 0)
2055 debugiter("no more live columns left - done\n");
2063 /// Find the next row that has some real content in one of it's columns.
2064 SCROW
ScHorizontalCellIterator::FindNextNonEmptyRow()
2066 size_t nNextRow
= MAXROW
+1;
2068 for (std::vector
<ColParam
>::iterator it
= maColPositions
.begin();
2069 it
!= maColPositions
.end(); ++it
)
2073 assert(static_cast<size_t>(mnRow
) <= r
.maPos
->position
);
2074 nNextRow
= std::min (nNextRow
, static_cast<size_t>(r
.maPos
->position
));
2077 SCROW nRow
= std::max(static_cast<SCROW
>(nNextRow
), mnRow
);
2078 debugiter("Next non empty row is %d\n", (int) nRow
);
2082 void ScHorizontalCellIterator::Advance()
2085 assert (maColPos
!= maColPositions
.end());
2092 void ScHorizontalCellIterator::SkipInvalid()
2094 if (maColPos
== maColPositions
.end() ||
2095 !SkipInvalidInRow())
2099 if (mnRow
> nEndRow
)
2105 maColPos
= maColPositions
.begin();
2106 debugiter("moving to next row\n");
2107 if (SkipInvalidInRow())
2109 debugiter("moved to valid cell in next row (or end)\n");
2113 mnRow
= FindNextNonEmptyRow();
2114 maColPos
= maColPositions
.begin();
2115 bool bCorrect
= SkipInvalidInRow();
2116 assert (bCorrect
); (void) bCorrect
;
2119 if (mnRow
> nEndRow
)
2123 ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument
* pDocument
,
2124 const ScRange
& rRange
, bool bTextZero
) :
2127 nEndTab( rRange
.aEnd
.Tab() ),
2128 nNumFmtType( css::util::NumberFormat::UNDEFINED
),
2130 bCalcAsShown( pDocument
->GetDocOptions().IsCalcAsShown() ),
2131 bTextAsZero( bTextZero
)
2133 SCCOL nStartCol
= rRange
.aStart
.Col();
2134 SCROW nStartRow
= rRange
.aStart
.Row();
2135 SCTAB nStartTab
= rRange
.aStart
.Tab();
2136 SCCOL nEndCol
= rRange
.aEnd
.Col();
2137 SCROW nEndRow
= rRange
.aEnd
.Row();
2138 PutInOrder( nStartCol
, nEndCol
);
2139 PutInOrder( nStartRow
, nEndRow
);
2140 PutInOrder( nStartTab
, nEndTab
);
2142 if (!ValidCol(nStartCol
)) nStartCol
= MAXCOL
;
2143 if (!ValidCol(nEndCol
)) nEndCol
= MAXCOL
;
2144 if (!ValidRow(nStartRow
)) nStartRow
= MAXROW
;
2145 if (!ValidRow(nEndRow
)) nEndRow
= MAXROW
;
2146 if (!ValidTab(nStartTab
)) nStartTab
= MAXTAB
;
2147 if (!ValidTab(nEndTab
)) nEndTab
= MAXTAB
;
2149 nCurCol
= nStartCol
;
2150 nCurRow
= nStartRow
;
2151 nCurTab
= nStartTab
;
2153 nNumFormat
= 0; // Will be initialized in GetNumberFormat()
2157 pCellIter
= new ScHorizontalCellIterator( pDoc
, nStartTab
, nStartCol
,
2158 nStartRow
, nEndCol
, nEndRow
);
2161 ScHorizontalValueIterator::~ScHorizontalValueIterator()
2166 bool ScHorizontalValueIterator::GetNext( double& rValue
, sal_uInt16
& rErr
)
2168 bool bFound
= false;
2171 ScRefCellValue
* pCell
= pCellIter
->GetNext( nCurCol
, nCurRow
);
2174 if ( nCurTab
< nEndTab
)
2176 pCellIter
->SetTab( ++nCurTab
);
2177 pCell
= pCellIter
->GetNext( nCurCol
, nCurRow
);
2182 switch (pCell
->meType
)
2184 case CELLTYPE_VALUE
:
2187 rValue
= pCell
->mfValue
;
2191 ScColumn
* pCol
= &pDoc
->maTabs
[nCurTab
]->aCol
[nCurCol
];
2192 ScAttrArray_IterGetNumberFormat( nNumFormat
, pAttrArray
,
2193 nAttrEndRow
, pCol
->pAttrArray
, nCurRow
, pDoc
);
2194 rValue
= pDoc
->RoundValueAsShown( rValue
, nNumFormat
);
2199 case CELLTYPE_FORMULA
:
2201 rErr
= pCell
->mpFormula
->GetErrCode();
2202 if (rErr
|| pCell
->mpFormula
->IsValue())
2204 rValue
= pCell
->mpFormula
->GetValue();
2208 else if ( bTextAsZero
)
2216 case CELLTYPE_STRING
:
2217 case CELLTYPE_EDIT
:
2223 nNumFmtType
= css::util::NumberFormat::NUMBER
;
2230 default: ; // nothing
2236 ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument
* pDocument
, SCTAB nTable
,
2237 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
) :
2245 if (nTab
>= pDoc
->GetTableCount())
2246 OSL_FAIL("try to access index out of bounds, FIX IT");
2247 OSL_ENSURE( pDoc
->maTabs
[nTab
], "Table does not exist" );
2252 bRepeatedRow
= false;
2254 pIndices
= new SCSIZE
[nEndCol
-nStartCol
+1];
2255 pNextEnd
= new SCROW
[nEndCol
-nStartCol
+1];
2256 pHorizEnd
= new SCCOL
[nEndCol
-nStartCol
+1];
2257 ppPatterns
= new const ScPatternAttr
*[nEndCol
-nStartCol
+1];
2259 InitForNextRow(true);
2262 ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
2264 delete[] ppPatterns
;
2270 void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization
)
2273 nMinNextEnd
= MAXROW
;
2274 SCCOL nThisHead
= 0;
2276 for (SCCOL i
=nStartCol
; i
<=nEndCol
; i
++)
2278 SCCOL nPos
= i
- nStartCol
;
2279 if ( bInitialization
|| pNextEnd
[nPos
] < nRow
)
2281 const ScAttrArray
* pArray
= pDoc
->maTabs
[nTab
]->aCol
[i
].pAttrArray
;
2282 OSL_ENSURE( pArray
, "pArray == 0" );
2285 if (bInitialization
)
2287 pArray
->Search( nStartRow
, nIndex
);
2288 pIndices
[nPos
] = nIndex
;
2289 pHorizEnd
[nPos
] = MAXCOL
+1; // only for OSL_ENSURE
2292 nIndex
= ++pIndices
[nPos
];
2294 if ( nIndex
< pArray
->nCount
)
2296 const ScPatternAttr
* pPattern
= pArray
->pData
[nIndex
].pPattern
;
2297 SCROW nThisEnd
= pArray
->pData
[nIndex
].nRow
;
2299 if ( IsDefaultItem( pPattern
) )
2302 bEmpty
= false; // Found attributes
2304 pNextEnd
[nPos
] = nThisEnd
;
2305 OSL_ENSURE( pNextEnd
[nPos
] >= nRow
, "Sequence out of order" );
2306 ppPatterns
[nPos
] = pPattern
;
2310 OSL_FAIL("AttrArray does not range to MAXROW");
2311 pNextEnd
[nPos
] = MAXROW
;
2312 ppPatterns
[nPos
] = NULL
;
2315 else if ( ppPatterns
[nPos
] )
2316 bEmpty
= false; // Area not at the end yet
2318 if ( nMinNextEnd
> pNextEnd
[nPos
] )
2319 nMinNextEnd
= pNextEnd
[nPos
];
2321 // store positions of ScHorizontalAttrIterator elements (minimizing expensive ScPatternAttr comparisons)
2322 if (i
> nStartCol
&& ppPatterns
[nThisHead
] != ppPatterns
[nPos
])
2324 pHorizEnd
[nThisHead
] = i
- 1;
2325 nThisHead
= nPos
; // start position of the next horizontal group
2330 nRow
= nMinNextEnd
; // Skip until end of next section
2332 pHorizEnd
[nThisHead
] = nEndCol
; // set the end position of the last horizontal group, too
2336 bool ScHorizontalAttrIterator::InitForNextAttr()
2338 if ( !ppPatterns
[nCol
-nStartCol
] ) // Skip default items
2340 OSL_ENSURE( pHorizEnd
[nCol
-nStartCol
] < MAXCOL
+1, "missing stored data" );
2341 nCol
= pHorizEnd
[nCol
-nStartCol
] + 1;
2342 if ( nCol
> nEndCol
)
2349 const ScPatternAttr
* ScHorizontalAttrIterator::GetNext( SCCOL
& rCol1
, SCCOL
& rCol2
, SCROW
& rRow
)
2351 if (nTab
>= pDoc
->GetTableCount())
2352 OSL_FAIL("try to access index out of bounds, FIX IT");
2355 if ( !bRowEmpty
&& nCol
<= nEndCol
&& InitForNextAttr() )
2357 const ScPatternAttr
* pPat
= ppPatterns
[nCol
-nStartCol
];
2360 OSL_ENSURE( pHorizEnd
[nCol
-nStartCol
] < MAXCOL
+1, "missing stored data" );
2361 nCol
= pHorizEnd
[nCol
-nStartCol
];
2363 ++nCol
; // Count up for next call
2364 return pPat
; // Found it!
2369 if ( nRow
> nEndRow
) // Already at the end?
2370 return NULL
; // Found nothing
2371 nCol
= nStartCol
; // Start at the left again
2373 if ( bRowEmpty
|| nRow
> nMinNextEnd
)
2374 InitForNextRow(false);
2378 inline bool IsGreater( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
2380 return ( nRow1
> nRow2
) || ( nRow1
== nRow2
&& nCol1
> nCol2
);
2383 ScUsedAreaIterator::ScUsedAreaIterator( ScDocument
* pDocument
, SCTAB nTable
,
2384 SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
2385 : aCellIter( pDocument
, nTable
, nCol1
, nRow1
, nCol2
, nRow2
)
2386 , aAttrIter( pDocument
, nTable
, nCol1
, nRow1
, nCol2
, nRow2
)
2394 , nFoundStartCol( 0 )
2397 , pFoundPattern( NULL
)
2399 pCell
= aCellIter
.GetNext( nCellCol
, nCellRow
);
2400 pPattern
= aAttrIter
.GetNext( nAttrCol1
, nAttrCol2
, nAttrRow
);
2403 ScUsedAreaIterator::~ScUsedAreaIterator()
2407 bool ScUsedAreaIterator::GetNext()
2409 // Forward iterators
2410 if ( pCell
&& IsGreater( nNextCol
, nNextRow
, nCellCol
, nCellRow
) )
2411 pCell
= aCellIter
.GetNext( nCellCol
, nCellRow
);
2413 while (pCell
&& pCell
->isEmpty())
2414 pCell
= aCellIter
.GetNext( nCellCol
, nCellRow
);
2416 if ( pPattern
&& IsGreater( nNextCol
, nNextRow
, nAttrCol2
, nAttrRow
) )
2417 pPattern
= aAttrIter
.GetNext( nAttrCol1
, nAttrCol2
, nAttrRow
);
2419 if ( pPattern
&& nAttrRow
== nNextRow
&& nAttrCol1
< nNextCol
)
2420 nAttrCol1
= nNextCol
;
2424 bool bUseCell
= false;
2426 if ( pCell
&& pPattern
)
2428 if ( IsGreater( nCellCol
, nCellRow
, nAttrCol1
, nAttrRow
) ) // Only attributes at the beginning?
2430 maFoundCell
.clear();
2431 pFoundPattern
= pPattern
;
2432 nFoundRow
= nAttrRow
;
2433 nFoundStartCol
= nAttrCol1
;
2434 if ( nCellRow
== nAttrRow
&& nCellCol
<= nAttrCol2
) // Area also contains cell?
2435 nFoundEndCol
= nCellCol
- 1; // Only until right before the cell
2437 nFoundEndCol
= nAttrCol2
; // Everything
2442 if ( nAttrRow
== nCellRow
&& nAttrCol1
== nCellCol
) // Attributes on the cell?
2443 pFoundPattern
= pPattern
;
2445 pFoundPattern
= NULL
;
2448 else if ( pCell
) // Just a cell -> take over right away
2450 pFoundPattern
= NULL
;
2451 bUseCell
= true; // Cell position
2453 else if ( pPattern
) // Just attributes -> take over right away
2455 maFoundCell
.clear();
2456 pFoundPattern
= pPattern
;
2457 nFoundRow
= nAttrRow
;
2458 nFoundStartCol
= nAttrCol1
;
2459 nFoundEndCol
= nAttrCol2
;
2464 if ( bUseCell
) // Cell position
2467 maFoundCell
= *pCell
;
2469 maFoundCell
.clear();
2471 nFoundRow
= nCellRow
;
2472 nFoundStartCol
= nFoundEndCol
= nCellCol
;
2477 nNextRow
= nFoundRow
;
2478 nNextCol
= nFoundEndCol
+ 1;
2484 ScDocAttrIterator::ScDocAttrIterator(ScDocument
* pDocument
, SCTAB nTable
,
2485 SCCOL nCol1
, SCROW nRow1
,
2486 SCCOL nCol2
, SCROW nRow2
) :
2494 if ( ValidTab(nTab
) && nTab
< pDoc
->GetTableCount() && pDoc
->maTabs
[nTab
] )
2495 pColIter
= pDoc
->maTabs
[nTab
]->aCol
[nCol
].CreateAttrIterator( nStartRow
, nEndRow
);
2500 ScDocAttrIterator::~ScDocAttrIterator()
2505 const ScPatternAttr
* ScDocAttrIterator::GetNext( SCCOL
& rCol
, SCROW
& rRow1
, SCROW
& rRow2
)
2509 const ScPatternAttr
* pPattern
= pColIter
->Next( rRow1
, rRow2
);
2518 if ( nCol
<= nEndCol
)
2519 pColIter
= pDoc
->maTabs
[nTab
]->aCol
[nCol
].CreateAttrIterator( nStartRow
, nEndRow
);
2523 return NULL
; // Nothing anymore
2526 ScDocRowHeightUpdater::TabRanges::TabRanges(SCTAB nTab
) :
2527 mnTab(nTab
), mpRanges(new ScFlatBoolRowSegments
)
2531 ScDocRowHeightUpdater::ScDocRowHeightUpdater(ScDocument
& rDoc
, OutputDevice
* pOutDev
, double fPPTX
, double fPPTY
, const vector
<TabRanges
>* pTabRangesArray
) :
2532 mrDoc(rDoc
), mpOutDev(pOutDev
), mfPPTX(fPPTX
), mfPPTY(fPPTY
), mpTabRangesArray(pTabRangesArray
)
2536 void ScDocRowHeightUpdater::update()
2538 if (!mpTabRangesArray
|| mpTabRangesArray
->empty())
2540 // No ranges defined. Update all rows in all tables.
2545 sal_uInt32 nCellCount
= 0;
2546 vector
<TabRanges
>::const_iterator itr
= mpTabRangesArray
->begin(), itrEnd
= mpTabRangesArray
->end();
2547 for (; itr
!= itrEnd
; ++itr
)
2549 ScFlatBoolRowSegments::RangeData aData
;
2550 ScFlatBoolRowSegments::RangeIterator
aRangeItr(*itr
->mpRanges
);
2551 for (bool bFound
= aRangeItr
.getFirst(aData
); bFound
; bFound
= aRangeItr
.getNext(aData
))
2556 nCellCount
+= aData
.mnRow2
- aData
.mnRow1
+ 1;
2560 ScProgress
aProgress(mrDoc
.GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING
), nCellCount
);
2562 Fraction
aZoom(1, 1);
2563 itr
= mpTabRangesArray
->begin();
2564 sal_uInt32 nProgressStart
= 0;
2565 sc::RowHeightContext
aCxt(mfPPTX
, mfPPTY
, aZoom
, aZoom
, mpOutDev
);
2566 for (; itr
!= itrEnd
; ++itr
)
2568 SCTAB nTab
= itr
->mnTab
;
2569 if (!ValidTab(nTab
) || nTab
>= mrDoc
.GetTableCount() || !mrDoc
.maTabs
[nTab
])
2572 ScFlatBoolRowSegments::RangeData aData
;
2573 ScFlatBoolRowSegments::RangeIterator
aRangeItr(*itr
->mpRanges
);
2574 for (bool bFound
= aRangeItr
.getFirst(aData
); bFound
; bFound
= aRangeItr
.getNext(aData
))
2579 mrDoc
.maTabs
[nTab
]->SetOptimalHeight(
2580 aCxt
, aData
.mnRow1
, aData
.mnRow2
, &aProgress
, nProgressStart
);
2582 nProgressStart
+= aData
.mnRow2
- aData
.mnRow1
+ 1;
2587 void ScDocRowHeightUpdater::updateAll()
2589 sal_uInt32 nCellCount
= 0;
2590 for (SCTAB nTab
= 0; nTab
< mrDoc
.GetTableCount(); ++nTab
)
2592 if (!ValidTab(nTab
) || !mrDoc
.maTabs
[nTab
])
2595 nCellCount
+= mrDoc
.maTabs
[nTab
]->GetWeightedCount();
2598 ScProgress
aProgress(mrDoc
.GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING
), nCellCount
);
2600 Fraction
aZoom(1, 1);
2601 sc::RowHeightContext
aCxt(mfPPTX
, mfPPTY
, aZoom
, aZoom
, mpOutDev
);
2602 sal_uLong nProgressStart
= 0;
2603 for (SCTAB nTab
= 0; nTab
< mrDoc
.GetTableCount(); ++nTab
)
2605 if (!ValidTab(nTab
) || !mrDoc
.maTabs
[nTab
])
2608 mrDoc
.maTabs
[nTab
]->SetOptimalHeight(aCxt
, 0, MAXROW
, &aProgress
, nProgressStart
);
2609 nProgressStart
+= mrDoc
.maTabs
[nTab
]->GetWeightedCount();
2613 ScAttrRectIterator::ScAttrRectIterator(ScDocument
* pDocument
, SCTAB nTable
,
2614 SCCOL nCol1
, SCROW nRow1
,
2615 SCCOL nCol2
, SCROW nRow2
) :
2621 nIterStartCol( nCol1
),
2622 nIterEndCol( nCol1
)
2624 if ( ValidTab(nTab
) && nTab
< pDoc
->GetTableCount() && pDoc
->maTabs
[nTab
] )
2626 pColIter
= pDoc
->maTabs
[nTab
]->aCol
[nIterStartCol
].CreateAttrIterator( nStartRow
, nEndRow
);
2627 while ( nIterEndCol
< nEndCol
&&
2628 pDoc
->maTabs
[nTab
]->aCol
[nIterEndCol
].IsAllAttrEqual(
2629 pDoc
->maTabs
[nTab
]->aCol
[nIterEndCol
+1], nStartRow
, nEndRow
) )
2636 ScAttrRectIterator::~ScAttrRectIterator()
2641 void ScAttrRectIterator::DataChanged()
2645 SCROW nNextRow
= pColIter
->GetNextRow();
2647 pColIter
= pDoc
->maTabs
[nTab
]->aCol
[nIterStartCol
].CreateAttrIterator( nNextRow
, nEndRow
);
2651 const ScPatternAttr
* ScAttrRectIterator::GetNext( SCCOL
& rCol1
, SCCOL
& rCol2
,
2652 SCROW
& rRow1
, SCROW
& rRow2
)
2656 const ScPatternAttr
* pPattern
= pColIter
->Next( rRow1
, rRow2
);
2659 rCol1
= nIterStartCol
;
2660 rCol2
= nIterEndCol
;
2665 nIterStartCol
= nIterEndCol
+1;
2666 if ( nIterStartCol
<= nEndCol
)
2668 nIterEndCol
= nIterStartCol
;
2669 pColIter
= pDoc
->maTabs
[nTab
]->aCol
[nIterStartCol
].CreateAttrIterator( nStartRow
, nEndRow
);
2670 while ( nIterEndCol
< nEndCol
&&
2671 pDoc
->maTabs
[nTab
]->aCol
[nIterEndCol
].IsAllAttrEqual(
2672 pDoc
->maTabs
[nTab
]->aCol
[nIterEndCol
+1], nStartRow
, nEndRow
) )
2678 return NULL
; // Nothing anymore
2681 SCROW
ScRowBreakIterator::NOT_FOUND
= -1;
2683 ScRowBreakIterator::ScRowBreakIterator(set
<SCROW
>& rBreaks
) :
2685 maItr(rBreaks
.begin()), maEnd(rBreaks
.end())
2689 SCROW
ScRowBreakIterator::first()
2691 maItr
= mrBreaks
.begin();
2692 return maItr
== maEnd
? NOT_FOUND
: *maItr
;
2695 SCROW
ScRowBreakIterator::next()
2698 return maItr
== maEnd
? NOT_FOUND
: *maItr
;
2701 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */