Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <svl/zforlist.hxx>
21 :
22 : #include "scitems.hxx"
23 : #include "global.hxx"
24 : #include "dociter.hxx"
25 : #include "document.hxx"
26 : #include "table.hxx"
27 : #include "column.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 :
42 : #include "tools/fract.hxx"
43 : #include "editeng/editobj.hxx"
44 :
45 : #include <vector>
46 :
47 : using ::rtl::math::approxEqual;
48 : using ::std::vector;
49 : using ::std::set;
50 :
51 : // STATIC DATA -----------------------------------------------------------
52 :
53 : namespace {
54 :
55 0 : void upperCase(OUString& rStr)
56 : {
57 0 : rStr = ScGlobal::pCharClass->uppercase(rStr.trim());
58 0 : }
59 :
60 : template<typename _Iter>
61 12 : void incBlock(std::pair<_Iter, size_t>& rPos)
62 : {
63 : // Move to the next block.
64 12 : ++rPos.first;
65 12 : rPos.second = 0;
66 12 : }
67 :
68 : template<typename _Iter>
69 1 : void incPos(std::pair<_Iter, size_t>& rPos)
70 : {
71 1 : if (rPos.second + 1 < rPos.first->size)
72 : // Increment within the block.
73 1 : ++rPos.second;
74 : else
75 0 : incBlock(rPos);
76 1 : }
77 :
78 : template<typename _Iter>
79 274 : size_t toLogicalPos(const std::pair<_Iter, size_t>& rPos)
80 : {
81 274 : return rPos.first->position + rPos.second;
82 : }
83 :
84 : }
85 :
86 0 : void ScAttrArray_IterGetNumberFormat( sal_uLong& nFormat, const ScAttrArray*& rpArr,
87 : SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
88 : ScDocument* pDoc )
89 : {
90 0 : if ( rpArr != pNewArr || nAttrEndRow < nRow )
91 : {
92 0 : SCROW nRowStart = 0;
93 0 : SCROW nRowEnd = MAXROW;
94 : const ScPatternAttr* pPattern;
95 0 : if( !(pPattern = pNewArr->GetPatternRange( nRowStart, nRowEnd, nRow ) ) )
96 : {
97 0 : pPattern = pDoc->GetDefPattern();
98 0 : nRowEnd = MAXROW;
99 : }
100 :
101 0 : nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() );
102 0 : rpArr = pNewArr;
103 0 : nAttrEndRow = nRowEnd;
104 : }
105 0 : }
106 :
107 8 : ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange,
108 : bool bSTotal, bool bTextZero ) :
109 : pDoc( pDocument ),
110 : nNumFmtIndex(0),
111 : maStartPos(rRange.aStart),
112 : maEndPos(rRange.aEnd),
113 : nNumFmtType( NUMBERFORMAT_UNDEFINED ),
114 : bNumValid( false ),
115 : bSubTotal(bSTotal),
116 8 : bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
117 16 : bTextAsZero( bTextZero )
118 : {
119 8 : SCTAB nDocMaxTab = pDocument->GetTableCount() - 1;
120 :
121 8 : if (!ValidCol(maStartPos.Col())) maStartPos.SetCol(MAXCOL);
122 8 : if (!ValidCol(maEndPos.Col())) maEndPos.SetCol(MAXCOL);
123 8 : if (!ValidRow(maStartPos.Row())) maStartPos.SetRow(MAXROW);
124 8 : if (!ValidRow(maEndPos.Row())) maEndPos.SetRow(MAXROW);
125 8 : if (!ValidTab(maStartPos.Tab()) || maStartPos.Tab() > nDocMaxTab) maStartPos.SetTab(nDocMaxTab);
126 8 : if (!ValidTab(maEndPos.Tab()) || maEndPos.Tab() > nDocMaxTab) maEndPos.SetTab(nDocMaxTab);
127 :
128 8 : nNumFormat = 0; // Initialized in GetNumberFormat
129 8 : pAttrArray = 0;
130 8 : nAttrEndRow = 0;
131 8 : }
132 :
133 3082 : SCROW ScValueIterator::GetRow() const
134 : {
135 : // Position of the head of the current block + offset within the block
136 : // equals the logical element position.
137 3082 : return maCurPos.first->position + maCurPos.second;
138 : }
139 :
140 8 : void ScValueIterator::IncBlock()
141 : {
142 8 : ++maCurPos.first;
143 8 : maCurPos.second = 0;
144 8 : }
145 :
146 1536 : void ScValueIterator::IncPos()
147 : {
148 1536 : if (maCurPos.second + 1 < maCurPos.first->size)
149 : // Move within the same block.
150 1528 : ++maCurPos.second;
151 : else
152 : // Move to the next block.
153 8 : IncBlock();
154 1536 : }
155 :
156 0 : void ScValueIterator::SetPos(size_t nPos)
157 : {
158 0 : maCurPos = mpCells->position(maCurPos.first, nPos);
159 0 : }
160 :
161 1544 : bool ScValueIterator::GetThis(double& rValue, sal_uInt16& rErr)
162 : {
163 : while (true)
164 : {
165 1544 : bool bNextColumn = maCurPos.first == mpCells->end();
166 1544 : if (!bNextColumn)
167 : {
168 1544 : if (GetRow() > maEndPos.Row())
169 8 : bNextColumn = true;
170 : }
171 :
172 1544 : ScColumn* pCol = NULL;
173 1544 : if (bNextColumn)
174 : {
175 : // Find the next available column.
176 0 : do
177 : {
178 8 : ++mnCol;
179 8 : if (mnCol > maEndPos.Col())
180 : {
181 8 : mnCol = maStartPos.Col();
182 8 : ++mnTab;
183 8 : if (mnTab > maEndPos.Tab())
184 : {
185 8 : rErr = 0;
186 1552 : return false; // Over and out
187 : }
188 : }
189 0 : pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol];
190 : }
191 : while (pCol->IsEmptyData());
192 :
193 0 : mpCells = &pCol->maCells;
194 0 : maCurPos = mpCells->position(maStartPos.Row());
195 : }
196 :
197 1536 : SCROW nCurRow = GetRow();
198 : SCROW nLastRow;
199 1536 : if (bSubTotal && pDoc->maTabs[mnTab]->RowFiltered(nCurRow, NULL, &nLastRow))
200 : {
201 : // Skip all filtered rows for subtotal mode.
202 0 : SetPos(nLastRow+1);
203 0 : continue;
204 : }
205 :
206 1536 : switch (maCurPos.first->type)
207 : {
208 : case sc::element_type_numeric:
209 : {
210 1536 : bNumValid = false;
211 1536 : rValue = sc::numeric_block::at(*maCurPos.first->data, maCurPos.second);
212 1536 : rErr = 0;
213 1536 : if (bCalcAsShown)
214 : {
215 : ScAttrArray_IterGetNumberFormat(nNumFormat, pAttrArray,
216 0 : nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc);
217 0 : rValue = pDoc->RoundValueAsShown(rValue, nNumFormat);
218 : }
219 1536 : return true; // Found it!
220 : }
221 : break;
222 : case sc::element_type_formula:
223 : {
224 0 : ScFormulaCell& rCell = *sc::formula_block::at(*maCurPos.first->data, maCurPos.second);
225 0 : if (bSubTotal && rCell.IsSubTotal())
226 : {
227 : // Skip subtotal formula cells.
228 0 : IncPos();
229 0 : break;
230 : }
231 :
232 0 : if (rCell.GetErrorOrValue(rErr, rValue))
233 : {
234 0 : bNumValid = false;
235 0 : return true; // Found it!
236 : }
237 0 : else if (bTextAsZero)
238 : {
239 0 : rValue = 0.0;
240 0 : bNumValid = false;
241 0 : return true;
242 : }
243 0 : IncPos();
244 : }
245 0 : break;
246 : case sc::element_type_string :
247 : case sc::element_type_edittext :
248 : {
249 0 : if (bTextAsZero)
250 : {
251 0 : rErr = 0;
252 0 : rValue = 0.0;
253 0 : nNumFmtType = NUMBERFORMAT_NUMBER;
254 0 : nNumFmtIndex = 0;
255 0 : bNumValid = true;
256 0 : return true;
257 : }
258 0 : IncBlock();
259 : }
260 0 : break;
261 : case sc::element_type_empty:
262 : default:
263 : // Skip the whole block.
264 0 : IncBlock();
265 : }
266 0 : }
267 : }
268 :
269 2 : void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
270 : {
271 2 : if (!bNumValid && mnTab < pDoc->GetTableCount())
272 : {
273 2 : SCROW nCurRow = GetRow();
274 2 : const ScColumn* pCol = &(pDoc->maTabs[mnTab])->aCol[mnCol];
275 2 : nNumFmtIndex = pCol->GetNumberFormat(nCurRow);
276 2 : nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
277 2 : bNumValid = true;
278 : }
279 :
280 2 : nType = nNumFmtType;
281 2 : nIndex = nNumFmtIndex;
282 2 : }
283 :
284 8 : bool ScValueIterator::GetFirst(double& rValue, sal_uInt16& rErr)
285 : {
286 8 : mnCol = maStartPos.Col();
287 8 : mnTab = maStartPos.Tab();
288 :
289 8 : ScTable* pTab = pDoc->FetchTable(mnTab);
290 8 : if (!pTab)
291 0 : return false;
292 :
293 8 : nNumFormat = 0; // Initialized in GetNumberFormat
294 8 : pAttrArray = 0;
295 8 : nAttrEndRow = 0;
296 :
297 8 : mpCells = &pTab->aCol[maStartPos.Col()].maCells;
298 8 : maCurPos = mpCells->position(maStartPos.Row());
299 8 : return GetThis(rValue, rErr);
300 : }
301 :
302 1536 : bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr)
303 : {
304 1536 : IncPos();
305 1536 : return GetThis(rValue, rErr);
306 : }
307 :
308 : // ============================================================================
309 :
310 4 : ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) :
311 4 : mpParent(pParent)
312 : {
313 4 : }
314 :
315 4 : ScDBQueryDataIterator::DataAccess::~DataAccess()
316 : {
317 4 : }
318 :
319 4 : const sc::CellStoreType* ScDBQueryDataIterator::GetColumnCellStore(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
320 : {
321 4 : ScTable* pTab = rDoc.FetchTable(nTab);
322 4 : if (!pTab)
323 0 : return NULL;
324 :
325 4 : return &pTab->aCol[nCol].maCells;
326 : }
327 :
328 0 : const ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
329 : {
330 0 : if (nTab >= rDoc.GetTableCount())
331 : OSL_FAIL("try to access index out of bounds, FIX IT");
332 0 : ScColumn* pCol = &rDoc.maTabs[nTab]->aCol[nCol];
333 0 : return pCol->pAttrArray;
334 : }
335 :
336 24 : bool ScDBQueryDataIterator::IsQueryValid(
337 : ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScRefCellValue& rCell)
338 : {
339 24 : if (nTab >= rDoc.GetTableCount())
340 : OSL_FAIL("try to access index out of bounds, FIX IT");
341 24 : return rDoc.maTabs[nTab]->ValidQuery(nRow, rParam, &rCell);
342 : }
343 :
344 : // ----------------------------------------------------------------------------
345 :
346 4 : ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) :
347 : DataAccess(pParent),
348 : mpCells(NULL),
349 : mpParam(pParam),
350 : mpDoc(pDoc),
351 4 : bCalcAsShown( pDoc->GetDocOptions().IsCalcAsShown() )
352 : {
353 4 : nCol = mpParam->mnField;
354 4 : nRow = mpParam->nRow1;
355 4 : nTab = mpParam->nTab;
356 : SCSIZE i;
357 4 : SCSIZE nCount = mpParam->GetEntryCount();
358 8 : for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++)
359 : {
360 4 : ScQueryEntry& rEntry = mpParam->GetEntry(i);
361 4 : ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
362 4 : rItems.resize(1);
363 4 : ScQueryEntry::Item& rItem = rItems.front();
364 4 : sal_uInt32 nIndex = 0;
365 : bool bNumber = mpDoc->GetFormatTable()->IsNumberFormat(
366 4 : rItem.maString, nIndex, rItem.mfVal);
367 4 : rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
368 : }
369 4 : nNumFormat = 0; // Initialized in GetNumberFormat
370 4 : pAttrArray = 0;
371 4 : nAttrEndRow = 0;
372 4 : }
373 :
374 8 : ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
375 : {
376 8 : }
377 :
378 28 : bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
379 : {
380 : // Start with the current row position, and find the first row position
381 : // that satisfies the query.
382 :
383 : // TODO: The following line nFirstQueryField is supposed to be used some
384 : // way. Find out how it's supposed to be used and fix this bug.
385 :
386 : // SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
387 : while (true)
388 : {
389 28 : if (maCurPos.first == mpCells->end() || nRow > mpParam->nRow2)
390 : {
391 : // Bottom of the range reached. Bail out.
392 4 : rValue.mnError = 0;
393 24 : return false;
394 : }
395 :
396 24 : if (maCurPos.first->type == sc::element_type_empty)
397 : {
398 : // Skip the whole empty block.
399 0 : incBlock();
400 0 : continue;
401 : }
402 :
403 24 : ScRefCellValue aCell;
404 24 : aCell.assign(maCurPos.first, maCurPos.second);
405 :
406 24 : if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, aCell))
407 : {
408 16 : switch (aCell.meType)
409 : {
410 : case CELLTYPE_VALUE:
411 : {
412 16 : rValue.mfValue = aCell.mfValue;
413 16 : rValue.mbIsNumber = true;
414 16 : if ( bCalcAsShown )
415 : {
416 : const ScAttrArray* pNewAttrArray =
417 0 : ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol);
418 : ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
419 0 : nAttrEndRow, pNewAttrArray, nRow, mpDoc );
420 0 : rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat );
421 : }
422 16 : nNumFmtType = NUMBERFORMAT_NUMBER;
423 16 : nNumFmtIndex = 0;
424 16 : rValue.mnError = 0;
425 16 : return true; // Found it!
426 : }
427 :
428 : case CELLTYPE_FORMULA:
429 : {
430 0 : if (aCell.mpFormula->IsValue())
431 : {
432 0 : rValue.mfValue = aCell.mpFormula->GetValue();
433 0 : rValue.mbIsNumber = true;
434 : mpDoc->GetNumberFormatInfo(
435 0 : nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab));
436 0 : rValue.mnError = aCell.mpFormula->GetErrCode();
437 0 : return true; // Found it!
438 : }
439 0 : else if(mpParam->mbSkipString)
440 0 : incPos();
441 : else
442 : {
443 0 : rValue.maString = aCell.mpFormula->GetString();
444 0 : rValue.mfValue = 0.0;
445 0 : rValue.mnError = aCell.mpFormula->GetErrCode();
446 0 : rValue.mbIsNumber = false;
447 0 : return true;
448 : }
449 : }
450 0 : break;
451 : case CELLTYPE_STRING:
452 : case CELLTYPE_EDIT:
453 0 : if (mpParam->mbSkipString)
454 0 : incPos();
455 : else
456 : {
457 0 : rValue.maString = aCell.getString();
458 0 : rValue.mfValue = 0.0;
459 0 : rValue.mnError = 0;
460 0 : rValue.mbIsNumber = false;
461 0 : return true;
462 : }
463 0 : break;
464 : default:
465 0 : incPos();
466 : }
467 : }
468 : else
469 8 : incPos();
470 16 : }
471 : // statement unreachable
472 : }
473 :
474 4 : bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue)
475 : {
476 4 : if (mpParam->bHasHeader)
477 4 : ++nRow;
478 :
479 4 : mpCells = ScDBQueryDataIterator::GetColumnCellStore(*mpDoc, nTab, nCol);
480 4 : if (!mpCells)
481 0 : return false;
482 :
483 4 : maCurPos = mpCells->position(nRow);
484 4 : return getCurrent(rValue);
485 : }
486 :
487 16 : bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue)
488 : {
489 16 : if (!mpCells || maCurPos.first == mpCells->end())
490 0 : return false;
491 :
492 16 : incPos();
493 16 : return getCurrent(rValue);
494 : }
495 :
496 4 : void ScDBQueryDataIterator::DataAccessInternal::incBlock()
497 : {
498 4 : ++maCurPos.first;
499 4 : maCurPos.second = 0;
500 :
501 4 : nRow = maCurPos.first->position;
502 4 : }
503 :
504 24 : void ScDBQueryDataIterator::DataAccessInternal::incPos()
505 : {
506 24 : if (maCurPos.second + 1 < maCurPos.first->size)
507 : {
508 : // Move within the same block.
509 20 : ++maCurPos.second;
510 20 : ++nRow;
511 : }
512 : else
513 : // Move to the next block.
514 4 : incBlock();
515 24 : }
516 :
517 0 : void ScDBQueryDataIterator::DataAccessInternal::setPos(size_t nPos)
518 : {
519 0 : maCurPos = mpCells->position(maCurPos.first, nPos);
520 0 : nRow = nPos;
521 0 : }
522 :
523 : // ----------------------------------------------------------------------------
524 :
525 0 : ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) :
526 : DataAccess(pParent),
527 0 : mpParam(pParam)
528 : {
529 : SCSIZE nC, nR;
530 0 : mpParam->mpMatrix->GetDimensions(nC, nR);
531 0 : mnRows = static_cast<SCROW>(nR);
532 0 : mnCols = static_cast<SCCOL>(nC);
533 0 : }
534 :
535 0 : ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix()
536 : {
537 0 : }
538 :
539 0 : bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue)
540 : {
541 : // Starting from row == mnCurRow, get the first row that satisfies all the
542 : // query parameters.
543 0 : for ( ;mnCurRow < mnRows; ++mnCurRow)
544 : {
545 0 : const ScMatrix& rMat = *mpParam->mpMatrix;
546 0 : if (rMat.IsEmpty(mpParam->mnField, mnCurRow))
547 : // Don't take empty values into account.
548 0 : continue;
549 :
550 0 : bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow);
551 0 : if (bIsStrVal && mpParam->mbSkipString)
552 0 : continue;
553 :
554 0 : if (isValidQuery(mnCurRow, rMat))
555 : {
556 0 : rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow);
557 0 : rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow);
558 0 : rValue.mbIsNumber = !bIsStrVal;
559 0 : rValue.mnError = 0;
560 0 : return true;
561 : }
562 : }
563 0 : return false;
564 : }
565 :
566 0 : bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue)
567 : {
568 0 : mnCurRow = mpParam->bHasHeader ? 1 : 0;
569 0 : return getCurrent(rValue);
570 : }
571 :
572 0 : bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue)
573 : {
574 0 : ++mnCurRow;
575 0 : return getCurrent(rValue);
576 : }
577 :
578 : namespace {
579 :
580 0 : bool isQueryByValue(const ScQueryEntry::Item& rItem, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
581 : {
582 0 : if (rItem.meType == ScQueryEntry::ByString)
583 0 : return false;
584 :
585 0 : if (!rMat.IsValueOrEmpty(nCol, nRow))
586 0 : return false;
587 :
588 0 : return true;
589 : }
590 :
591 0 : bool isQueryByString(const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
592 : {
593 0 : switch (rEntry.eOp)
594 : {
595 : case SC_EQUAL:
596 : case SC_NOT_EQUAL:
597 : case SC_CONTAINS:
598 : case SC_DOES_NOT_CONTAIN:
599 : case SC_BEGINS_WITH:
600 : case SC_ENDS_WITH:
601 : case SC_DOES_NOT_BEGIN_WITH:
602 : case SC_DOES_NOT_END_WITH:
603 0 : return true;
604 : default:
605 : ;
606 : }
607 :
608 0 : if (rItem.meType == ScQueryEntry::ByString && rMat.IsString(nCol, nRow))
609 0 : return true;
610 :
611 0 : return false;
612 : }
613 :
614 : }
615 :
616 0 : bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const
617 : {
618 0 : SCSIZE nEntryCount = mpParam->GetEntryCount();
619 0 : vector<bool> aResults;
620 0 : aResults.reserve(nEntryCount);
621 :
622 : const CollatorWrapper& rCollator =
623 0 : mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
624 :
625 0 : for (SCSIZE i = 0; i < nEntryCount; ++i)
626 : {
627 0 : const ScQueryEntry& rEntry = mpParam->GetEntry(i);
628 0 : const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
629 0 : if (!rEntry.bDoQuery)
630 0 : continue;
631 :
632 0 : switch (rEntry.eOp)
633 : {
634 : case SC_EQUAL:
635 : case SC_LESS:
636 : case SC_GREATER:
637 : case SC_LESS_EQUAL:
638 : case SC_GREATER_EQUAL:
639 : case SC_NOT_EQUAL:
640 0 : break;
641 : default:
642 : // Only the above operators are supported.
643 0 : continue;
644 : }
645 :
646 0 : bool bValid = false;
647 :
648 0 : SCSIZE nField = static_cast<SCSIZE>(rEntry.nField);
649 0 : if (isQueryByValue(rItem, rMat, nField, nRow))
650 : {
651 : // By value
652 0 : double fMatVal = rMat.GetDouble(nField, nRow);
653 0 : bool bEqual = approxEqual(fMatVal, rItem.mfVal);
654 0 : switch (rEntry.eOp)
655 : {
656 : case SC_EQUAL:
657 0 : bValid = bEqual;
658 0 : break;
659 : case SC_LESS:
660 0 : bValid = (fMatVal < rItem.mfVal) && !bEqual;
661 0 : break;
662 : case SC_GREATER:
663 0 : bValid = (fMatVal > rItem.mfVal) && !bEqual;
664 0 : break;
665 : case SC_LESS_EQUAL:
666 0 : bValid = (fMatVal < rItem.mfVal) || bEqual;
667 0 : break;
668 : case SC_GREATER_EQUAL:
669 0 : bValid = (fMatVal > rItem.mfVal) || bEqual;
670 0 : break;
671 : case SC_NOT_EQUAL:
672 0 : bValid = !bEqual;
673 0 : break;
674 : default:
675 : ;
676 : }
677 : }
678 0 : else if (isQueryByString(rEntry, rItem, rMat, nField, nRow))
679 : {
680 : // By string
681 : do
682 : {
683 : // Equality check first.
684 0 : OUString aMatStr = rMat.GetString(nField, nRow);
685 0 : upperCase(aMatStr);
686 0 : OUString aQueryStr = rEntry.GetQueryItem().maString;
687 0 : upperCase(aQueryStr);
688 0 : bool bDone = false;
689 0 : switch (rEntry.eOp)
690 : {
691 : case SC_EQUAL:
692 0 : bValid = aMatStr.equals(aQueryStr);
693 0 : bDone = true;
694 0 : break;
695 : case SC_NOT_EQUAL:
696 0 : bValid = !aMatStr.equals(aQueryStr);
697 0 : bDone = true;
698 0 : break;
699 : default:
700 : ;
701 : }
702 :
703 0 : if (bDone)
704 0 : break;
705 :
706 : // Unequality check using collator.
707 0 : sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr);
708 0 : switch (rEntry.eOp)
709 : {
710 : case SC_LESS :
711 0 : bValid = (nCompare < 0);
712 0 : break;
713 : case SC_GREATER :
714 0 : bValid = (nCompare > 0);
715 0 : break;
716 : case SC_LESS_EQUAL :
717 0 : bValid = (nCompare <= 0);
718 0 : break;
719 : case SC_GREATER_EQUAL :
720 0 : bValid = (nCompare >= 0);
721 0 : break;
722 : default:
723 : ;
724 0 : }
725 : }
726 : while (false);
727 : }
728 :
729 0 : if (aResults.empty())
730 : // First query entry.
731 0 : aResults.push_back(bValid);
732 0 : else if (rEntry.eConnect == SC_AND)
733 : {
734 : // For AND op, tuck the result into the last result value.
735 0 : size_t n = aResults.size();
736 0 : aResults[n-1] = aResults[n-1] && bValid;
737 : }
738 : else
739 : // For OR op, store its own result.
740 0 : aResults.push_back(bValid);
741 : }
742 :
743 : // Row is valid as long as there is at least one result being true.
744 0 : vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end();
745 0 : for (; itr != itrEnd; ++itr)
746 0 : if (*itr)
747 0 : return true;
748 :
749 0 : return false;
750 : }
751 :
752 : // ----------------------------------------------------------------------------
753 :
754 4 : ScDBQueryDataIterator::Value::Value() :
755 4 : mnError(0), mbIsNumber(true)
756 : {
757 4 : ::rtl::math::setNan(&mfValue);
758 4 : }
759 :
760 : // ----------------------------------------------------------------------------
761 :
762 4 : ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) :
763 4 : mpParam (pParam)
764 : {
765 4 : switch (mpParam->GetType())
766 : {
767 : case ScDBQueryParamBase::INTERNAL:
768 : {
769 4 : ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam);
770 4 : mpData.reset(new DataAccessInternal(this, p, pDocument));
771 : }
772 4 : break;
773 : case ScDBQueryParamBase::MATRIX:
774 : {
775 0 : ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam);
776 0 : mpData.reset(new DataAccessMatrix(this, p));
777 : }
778 : }
779 4 : }
780 :
781 4 : bool ScDBQueryDataIterator::GetFirst(Value& rValue)
782 : {
783 4 : return mpData->getFirst(rValue);
784 : }
785 :
786 16 : bool ScDBQueryDataIterator::GetNext(Value& rValue)
787 : {
788 16 : return mpData->getNext(rValue);
789 : }
790 :
791 119 : ScCellIterator::ScCellIterator( ScDocument* pDoc, const ScRange& rRange, bool bSTotal ) :
792 : mpDoc(pDoc),
793 : maStartPos(rRange.aStart),
794 : maEndPos(rRange.aEnd),
795 119 : mbSubTotal(bSTotal)
796 : {
797 119 : init();
798 119 : }
799 :
800 694 : void ScCellIterator::incBlock()
801 : {
802 694 : ++maCurColPos.first;
803 694 : maCurColPos.second = 0;
804 :
805 694 : maCurPos.SetRow(maCurColPos.first->position);
806 694 : }
807 :
808 1548 : void ScCellIterator::incPos()
809 : {
810 1548 : if (maCurColPos.second + 1 < maCurColPos.first->size)
811 : {
812 : // Move within the same block.
813 1161 : ++maCurColPos.second;
814 1161 : maCurPos.IncRow();
815 : }
816 : else
817 : // Move to the next block.
818 387 : incBlock();
819 1548 : }
820 :
821 0 : void ScCellIterator::setPos(size_t nPos)
822 : {
823 0 : maCurColPos = getColumn()->maCells.position(maCurColPos.first, nPos);
824 0 : maCurPos.SetRow(nPos);
825 0 : }
826 :
827 33633 : const ScColumn* ScCellIterator::getColumn() const
828 : {
829 33633 : return &mpDoc->maTabs[maCurPos.Tab()]->aCol[maCurPos.Col()];
830 : }
831 :
832 119 : void ScCellIterator::init()
833 : {
834 119 : SCTAB nDocMaxTab = mpDoc->GetTableCount() - 1;
835 :
836 119 : PutInOrder(maStartPos, maEndPos);
837 :
838 119 : if (!ValidCol(maStartPos.Col())) maStartPos.SetCol(MAXCOL);
839 119 : if (!ValidCol(maEndPos.Col())) maEndPos.SetCol(MAXCOL);
840 119 : if (!ValidRow(maStartPos.Row())) maStartPos.SetRow(MAXROW);
841 119 : if (!ValidRow(maEndPos.Row())) maEndPos.SetRow(MAXROW);
842 119 : if (!ValidTab(maStartPos.Tab(), nDocMaxTab)) maStartPos.SetTab(nDocMaxTab);
843 119 : if (!ValidTab(maEndPos.Tab(), nDocMaxTab)) maEndPos.SetTab(nDocMaxTab);
844 :
845 238 : while (maEndPos.Tab() > 0 && !mpDoc->maTabs[maEndPos.Tab()])
846 0 : maEndPos.IncTab(-1); // Only the tables in use
847 :
848 119 : if (maStartPos.Tab() > maEndPos.Tab())
849 0 : maStartPos.SetTab(maEndPos.Tab());
850 :
851 119 : maCurPos = maStartPos;
852 :
853 119 : if (!mpDoc->maTabs[maCurPos.Tab()])
854 : {
855 : OSL_FAIL("Table not found");
856 0 : maStartPos = ScAddress(MAXCOL+1, MAXROW+1, MAXTAB+1); // -> Abort on GetFirst.
857 0 : maCurPos = maStartPos;
858 : }
859 119 : }
860 :
861 1667 : bool ScCellIterator::getCurrent()
862 : {
863 1667 : const ScColumn* pCol = getColumn();
864 :
865 : while (true)
866 : {
867 1974 : bool bNextColumn = maCurColPos.first == pCol->maCells.end();
868 1974 : if (!bNextColumn)
869 : {
870 1816 : if (maCurPos.Row() > maEndPos.Row())
871 184 : bNextColumn = true;
872 : }
873 :
874 1974 : if (bNextColumn)
875 : {
876 : // Move to the next column.
877 342 : maCurPos.SetRow(maStartPos.Row());
878 31847 : do
879 : {
880 31966 : maCurPos.IncCol();
881 31966 : if (maCurPos.Col() > maEndPos.Col())
882 : {
883 119 : maCurPos.SetCol(maStartPos.Col());
884 119 : maCurPos.IncTab();
885 119 : if (maCurPos.Tab() > maEndPos.Tab())
886 : {
887 119 : maCurCell.clear();
888 1786 : return false; // Over and out
889 : }
890 : }
891 31847 : pCol = getColumn();
892 : }
893 : while (pCol->IsEmptyData());
894 :
895 223 : maCurColPos = pCol->maCells.position(maCurPos.Row());
896 : }
897 :
898 1855 : if (maCurColPos.first->type == sc::element_type_empty)
899 : {
900 307 : incBlock();
901 614 : continue;
902 : }
903 :
904 : SCROW nLastRow;
905 1548 : if (mbSubTotal && pCol->GetDoc().maTabs[maCurPos.Tab()]->RowFiltered(maCurPos.Row(), NULL, &nLastRow))
906 : {
907 : // Skip all filtered rows for subtotal mode.
908 0 : setPos(nLastRow+1);
909 0 : continue;
910 : }
911 :
912 1548 : if (maCurColPos.first->type == sc::element_type_formula)
913 : {
914 688 : const ScFormulaCell* pCell = sc::formula_block::at(*maCurColPos.first->data, maCurColPos.second);
915 688 : if (pCell->IsSubTotal())
916 : {
917 : // Skip subtotal formula cells.
918 0 : incPos();
919 0 : continue;
920 : }
921 : }
922 :
923 1548 : maCurCell.assign(maCurColPos.first, maCurColPos.second);
924 1548 : return true;
925 : }
926 307 : return false;
927 : }
928 :
929 974 : CellType ScCellIterator::getType() const
930 : {
931 974 : return maCurCell.meType;
932 : }
933 :
934 0 : OUString ScCellIterator::getString()
935 : {
936 0 : return maCurCell.getString();
937 : }
938 :
939 0 : const EditTextObject* ScCellIterator::getEditText() const
940 : {
941 0 : return maCurCell.mpEditText;
942 : }
943 :
944 346 : ScFormulaCell* ScCellIterator::getFormulaCell()
945 : {
946 346 : return maCurCell.mpFormula;
947 : }
948 :
949 0 : const ScFormulaCell* ScCellIterator::getFormulaCell() const
950 : {
951 0 : return maCurCell.mpFormula;
952 : }
953 :
954 0 : double ScCellIterator::getValue()
955 : {
956 0 : return maCurCell.getValue();
957 : }
958 :
959 0 : ScCellValue ScCellIterator::getCellValue() const
960 : {
961 0 : ScCellValue aRet;
962 0 : aRet.meType = maCurCell.meType;
963 :
964 0 : switch (maCurCell.meType)
965 : {
966 : case CELLTYPE_STRING:
967 0 : aRet.mpString = new OUString(*maCurCell.mpString);
968 0 : break;
969 : case CELLTYPE_EDIT:
970 0 : aRet.mpEditText = maCurCell.mpEditText->Clone();
971 0 : break;
972 : case CELLTYPE_VALUE:
973 0 : aRet.mfValue = maCurCell.mfValue;
974 0 : break;
975 : case CELLTYPE_FORMULA:
976 0 : aRet.mpFormula = maCurCell.mpFormula->Clone();
977 0 : break;
978 : default:
979 : ;
980 : }
981 :
982 0 : return aRet;
983 : }
984 :
985 0 : const ScRefCellValue& ScCellIterator::getRefCellValue() const
986 : {
987 0 : return maCurCell;
988 : }
989 :
990 398 : bool ScCellIterator::hasString() const
991 : {
992 398 : return maCurCell.hasString();
993 : }
994 :
995 0 : bool ScCellIterator::hasNumeric() const
996 : {
997 0 : return maCurCell.hasNumeric();
998 : }
999 :
1000 86 : bool ScCellIterator::hasEmptyData() const
1001 : {
1002 86 : if (maCurCell.isEmpty())
1003 0 : return true;
1004 :
1005 86 : if (maCurCell.meType == CELLTYPE_FORMULA)
1006 86 : return maCurCell.mpFormula->IsEmpty();
1007 :
1008 0 : return false;
1009 : }
1010 :
1011 153 : bool ScCellIterator::isEmpty() const
1012 : {
1013 153 : return maCurCell.isEmpty();
1014 : }
1015 :
1016 58 : bool ScCellIterator::equalsWithoutFormat( const ScAddress& rPos ) const
1017 : {
1018 58 : ScRefCellValue aOther;
1019 58 : aOther.assign(*mpDoc, rPos);
1020 58 : return maCurCell.equalsWithoutFormat(aOther);
1021 : }
1022 :
1023 119 : bool ScCellIterator::first()
1024 : {
1025 119 : if (!ValidTab(maCurPos.Tab()))
1026 0 : return false;
1027 :
1028 119 : maCurPos = maStartPos;
1029 119 : const ScColumn* pCol = getColumn();
1030 :
1031 119 : maCurColPos = pCol->maCells.position(maCurPos.Row());
1032 119 : return getCurrent();
1033 : }
1034 :
1035 1548 : bool ScCellIterator::next()
1036 : {
1037 1548 : incPos();
1038 1548 : return getCurrent();
1039 : }
1040 :
1041 : //-------------------------------------------------------------------------------
1042 :
1043 88 : ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
1044 : const ScQueryParam& rParam, bool bMod ) :
1045 88 : mpParam(new ScQueryParam(rParam)),
1046 : pDoc( pDocument ),
1047 : nTab( nTable),
1048 : nStopOnMismatch( nStopOnMismatchDisabled ),
1049 : nTestEqualCondition( nTestEqualConditionDisabled ),
1050 : bAdvanceQuery( false ),
1051 176 : bIgnoreMismatchOnLeadingStrings( false )
1052 : {
1053 88 : nCol = mpParam->nCol1;
1054 88 : nRow = mpParam->nRow1;
1055 : SCSIZE i;
1056 88 : if (bMod) // Or else it's already inserted
1057 : {
1058 4 : SCSIZE nCount = mpParam->GetEntryCount();
1059 12 : for (i = 0; (i < nCount) && (mpParam->GetEntry(i).bDoQuery); ++i)
1060 : {
1061 8 : ScQueryEntry& rEntry = mpParam->GetEntry(i);
1062 8 : ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
1063 8 : sal_uInt32 nIndex = 0;
1064 : bool bNumber = pDoc->GetFormatTable()->IsNumberFormat(
1065 8 : rItem.maString, nIndex, rItem.mfVal);
1066 8 : rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
1067 : }
1068 : }
1069 88 : nNumFormat = 0; // Initialized in GetNumberFormat
1070 88 : pAttrArray = 0;
1071 88 : nAttrEndRow = 0;
1072 88 : }
1073 :
1074 38 : void ScQueryCellIterator::InitPos()
1075 : {
1076 38 : nRow = mpParam->nRow1;
1077 38 : if (mpParam->bHasHeader && mpParam->bByRow)
1078 4 : ++nRow;
1079 38 : ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
1080 38 : maCurPos = pCol->maCells.position(nRow);
1081 38 : }
1082 :
1083 407 : void ScQueryCellIterator::IncPos()
1084 : {
1085 407 : if (maCurPos.second + 1 < maCurPos.first->size)
1086 : {
1087 : // Move within the same block.
1088 291 : ++maCurPos.second;
1089 291 : ++nRow;
1090 : }
1091 : else
1092 : // Move to the next block.
1093 116 : IncBlock();
1094 407 : }
1095 :
1096 140 : void ScQueryCellIterator::IncBlock()
1097 : {
1098 140 : ++maCurPos.first;
1099 140 : maCurPos.second = 0;
1100 :
1101 140 : nRow = maCurPos.first->position;
1102 140 : }
1103 :
1104 233 : bool ScQueryCellIterator::GetThis()
1105 : {
1106 233 : if (nTab >= pDoc->GetTableCount())
1107 : OSL_FAIL("try to access index out of bounds, FIX IT");
1108 233 : const ScQueryEntry& rEntry = mpParam->GetEntry(0);
1109 233 : const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
1110 :
1111 233 : SCCOLROW nFirstQueryField = rEntry.nField;
1112 327 : bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1113 327 : rItem.meType != ScQueryEntry::ByString;
1114 94 : bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1115 358 : !mpParam->bHasHeader && rItem.meType == ScQueryEntry::ByString &&
1116 89 : ((mpParam->bByRow && nRow == mpParam->nRow1) ||
1117 262 : (!mpParam->bByRow && nCol == mpParam->nCol1));
1118 :
1119 233 : ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
1120 : while (true)
1121 : {
1122 519 : bool bNextColumn = maCurPos.first == pCol->maCells.end();
1123 519 : if (!bNextColumn)
1124 : {
1125 517 : if (nRow > mpParam->nRow2)
1126 44 : bNextColumn = true;
1127 : }
1128 :
1129 519 : if (bNextColumn)
1130 : {
1131 0 : do
1132 : {
1133 46 : if ( ++nCol > mpParam->nCol2 )
1134 279 : return false; // Over and out
1135 0 : if ( bAdvanceQuery )
1136 : {
1137 0 : AdvanceQueryParamEntryField();
1138 0 : nFirstQueryField = rEntry.nField;
1139 : }
1140 0 : pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
1141 : }
1142 : while (pCol->IsEmptyData());
1143 :
1144 0 : InitPos();
1145 :
1146 0 : bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1147 0 : !mpParam->bHasHeader && rItem.meType == ScQueryEntry::ByString &&
1148 0 : mpParam->bByRow;
1149 : }
1150 :
1151 473 : if (maCurPos.first->type == sc::element_type_empty)
1152 : {
1153 24 : IncBlock();
1154 24 : continue;
1155 : }
1156 :
1157 449 : ScRefCellValue aCell;
1158 449 : aCell.assign(maCurPos.first, maCurPos.second);
1159 :
1160 449 : if (bAllStringIgnore && aCell.hasString())
1161 27 : IncPos();
1162 : else
1163 : {
1164 422 : bool bTestEqualCondition = false;
1165 1266 : if ( pDoc->maTabs[nTab]->ValidQuery( nRow, *mpParam,
1166 422 : (nCol == static_cast<SCCOL>(nFirstQueryField) ? &aCell : NULL),
1167 1688 : (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
1168 : {
1169 150 : if ( nTestEqualCondition && bTestEqualCondition )
1170 2 : nTestEqualCondition |= nTestEqualConditionMatched;
1171 337 : return !aCell.isEmpty(); // Found it!
1172 : }
1173 272 : else if ( nStopOnMismatch )
1174 : {
1175 : // Yes, even a mismatch may have a fulfilled equal
1176 : // condition if regular expressions were involved and
1177 : // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
1178 37 : if ( nTestEqualCondition && bTestEqualCondition )
1179 : {
1180 0 : nTestEqualCondition |= nTestEqualConditionMatched;
1181 0 : nStopOnMismatch |= nStopOnMismatchOccurred;
1182 0 : return false;
1183 : }
1184 : bool bStop;
1185 37 : if (bFirstStringIgnore)
1186 : {
1187 0 : if (aCell.hasString())
1188 : {
1189 0 : IncPos();
1190 0 : bStop = false;
1191 : }
1192 : else
1193 0 : bStop = true;
1194 : }
1195 : else
1196 37 : bStop = true;
1197 37 : if (bStop)
1198 : {
1199 37 : nStopOnMismatch |= nStopOnMismatchOccurred;
1200 37 : return false;
1201 : }
1202 : }
1203 : else
1204 235 : IncPos();
1205 : }
1206 262 : bFirstStringIgnore = false;
1207 548 : }
1208 : }
1209 :
1210 38 : bool ScQueryCellIterator::GetFirst()
1211 : {
1212 38 : if (nTab >= pDoc->GetTableCount())
1213 : OSL_FAIL("try to access index out of bounds, FIX IT");
1214 38 : nCol = mpParam->nCol1;
1215 38 : InitPos();
1216 38 : return GetThis();
1217 : }
1218 :
1219 145 : bool ScQueryCellIterator::GetNext()
1220 : {
1221 145 : IncPos();
1222 145 : if ( nStopOnMismatch )
1223 46 : nStopOnMismatch = nStopOnMismatchEnabled;
1224 145 : if ( nTestEqualCondition )
1225 44 : nTestEqualCondition = nTestEqualConditionEnabled;
1226 145 : return GetThis();
1227 : }
1228 :
1229 0 : void ScQueryCellIterator::AdvanceQueryParamEntryField()
1230 : {
1231 0 : SCSIZE nEntries = mpParam->GetEntryCount();
1232 0 : for ( SCSIZE j = 0; j < nEntries; j++ )
1233 : {
1234 0 : ScQueryEntry& rEntry = mpParam->GetEntry( j );
1235 0 : if ( rEntry.bDoQuery )
1236 : {
1237 0 : if ( rEntry.nField < MAXCOL )
1238 0 : rEntry.nField++;
1239 : else
1240 : {
1241 : OSL_FAIL( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
1242 : }
1243 : }
1244 : else
1245 0 : break; // for
1246 : }
1247 0 : }
1248 :
1249 :
1250 50 : bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
1251 : SCROW& nFoundRow, bool bSearchForEqualAfterMismatch,
1252 : bool bIgnoreMismatchOnLeadingStringsP )
1253 : {
1254 50 : nFoundCol = MAXCOL+1;
1255 50 : nFoundRow = MAXROW+1;
1256 50 : SetStopOnMismatch( true ); // assume sorted keys
1257 50 : SetTestEqualCondition( true );
1258 50 : bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP;
1259 50 : bool bRegExp = mpParam->bRegExp && mpParam->GetEntry(0).GetQueryItem().meType == ScQueryEntry::ByString;
1260 100 : bool bBinary = !bRegExp && mpParam->bByRow && (mpParam->GetEntry(0).eOp ==
1261 68 : SC_LESS_EQUAL || mpParam->GetEntry(0).eOp == SC_GREATER_EQUAL);
1262 50 : if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst())
1263 : {
1264 : // First equal entry or last smaller than (greater than) entry.
1265 45 : PositionType aPosSave;
1266 45 : bool bNext = false;
1267 46 : do
1268 : {
1269 46 : nFoundCol = GetCol();
1270 46 : nFoundRow = GetRow();
1271 46 : aPosSave = maCurPos;
1272 : }
1273 46 : while ( !IsEqualConditionFulfilled() && (bNext = GetNext()));
1274 :
1275 : // There may be no pNext but equal condition fulfilled if regular
1276 : // expressions are involved. Keep the found entry and proceed.
1277 45 : if (!bNext && !IsEqualConditionFulfilled())
1278 : {
1279 : // Step back to last in range and adjust position markers for
1280 : // GetNumberFormat() or similar.
1281 43 : nCol = nFoundCol;
1282 43 : nRow = nFoundRow;
1283 43 : maCurPos = aPosSave;
1284 : }
1285 : }
1286 50 : if ( IsEqualConditionFulfilled() )
1287 : {
1288 : // Position on last equal entry.
1289 2 : SCSIZE nEntries = mpParam->GetEntryCount();
1290 8 : for ( SCSIZE j = 0; j < nEntries; j++ )
1291 : {
1292 4 : ScQueryEntry& rEntry = mpParam->GetEntry( j );
1293 4 : if ( rEntry.bDoQuery )
1294 : {
1295 2 : switch ( rEntry.eOp )
1296 : {
1297 : case SC_LESS_EQUAL :
1298 : case SC_GREATER_EQUAL :
1299 2 : rEntry.eOp = SC_EQUAL;
1300 2 : break;
1301 : default:
1302 : {
1303 : // added to avoid warnings
1304 : }
1305 : }
1306 : }
1307 : else
1308 2 : break; // for
1309 : }
1310 2 : PositionType aPosSave;
1311 2 : bIgnoreMismatchOnLeadingStrings = false;
1312 2 : SetTestEqualCondition( false );
1313 2 : do
1314 : {
1315 2 : nFoundCol = GetCol();
1316 2 : nFoundRow = GetRow();
1317 2 : aPosSave = maCurPos;
1318 : } while (GetNext());
1319 :
1320 : // Step back conditions are the same as above
1321 2 : nCol = nFoundCol;
1322 2 : nRow = nFoundRow;
1323 2 : maCurPos = aPosSave;
1324 2 : return true;
1325 : }
1326 48 : if ( (bSearchForEqualAfterMismatch || mpParam->bRegExp) &&
1327 0 : StoppedOnMismatch() )
1328 : {
1329 : // Assume found entry to be the last value less than respectively
1330 : // greater than the query. But keep on searching for an equal match.
1331 0 : SCSIZE nEntries = mpParam->GetEntryCount();
1332 0 : for ( SCSIZE j = 0; j < nEntries; j++ )
1333 : {
1334 0 : ScQueryEntry& rEntry = mpParam->GetEntry( j );
1335 0 : if ( rEntry.bDoQuery )
1336 : {
1337 0 : switch ( rEntry.eOp )
1338 : {
1339 : case SC_LESS_EQUAL :
1340 : case SC_GREATER_EQUAL :
1341 0 : rEntry.eOp = SC_EQUAL;
1342 0 : break;
1343 : default:
1344 : {
1345 : // added to avoid warnings
1346 : }
1347 : }
1348 : }
1349 : else
1350 0 : break; // for
1351 : }
1352 0 : SetStopOnMismatch( false );
1353 0 : SetTestEqualCondition( false );
1354 0 : if (GetNext())
1355 : {
1356 : // Last of a consecutive area, avoid searching the entire parameter
1357 : // range as it is a real performance bottleneck in case of regular
1358 : // expressions.
1359 0 : PositionType aPosSave;
1360 0 : do
1361 : {
1362 0 : nFoundCol = GetCol();
1363 0 : nFoundRow = GetRow();
1364 0 : aPosSave = maCurPos;
1365 0 : SetStopOnMismatch( true );
1366 : } while (GetNext());
1367 0 : nCol = nFoundCol;
1368 0 : nRow = nFoundRow;
1369 0 : maCurPos = aPosSave;
1370 : }
1371 : }
1372 48 : return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
1373 : }
1374 :
1375 :
1376 50 : bool ScQueryCellIterator::BinarySearch()
1377 : {
1378 : // TODO: This will be extremely slow with mdds::multi_type_vector.
1379 :
1380 50 : if (nTab >= pDoc->GetTableCount())
1381 : OSL_FAIL("try to access index out of bounds, FIX IT");
1382 50 : nCol = mpParam->nCol1;
1383 50 : ScColumn* pCol = &(pDoc->maTabs[nTab])->aCol[nCol];
1384 50 : if (pCol->IsEmptyData())
1385 0 : return false;
1386 :
1387 50 : PositionType aHiPos, aLoPos;
1388 50 : ScRefCellValue aCell;
1389 :
1390 50 : CollatorWrapper* pCollator = (mpParam->bCaseSens ? ScGlobal::GetCaseCollator() :
1391 50 : ScGlobal::GetCollator());
1392 50 : SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
1393 50 : const ScQueryEntry& rEntry = mpParam->GetEntry(0);
1394 50 : const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
1395 50 : bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
1396 50 : bool bByString = rItem.meType == ScQueryEntry::ByString;
1397 50 : bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
1398 50 : bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1399 100 : !mpParam->bHasHeader && bByString;
1400 :
1401 50 : nRow = mpParam->nRow1;
1402 50 : if (mpParam->bHasHeader)
1403 0 : nRow++;
1404 :
1405 50 : aLoPos = pCol->maCells.position(nRow);
1406 50 : if (bFirstStringIgnore && aLoPos.first->type == sc::element_type_string)
1407 : {
1408 4 : OUString aCellStr;
1409 4 : sal_uLong nFormat = pCol->GetNumberFormat(toLogicalPos(aLoPos));
1410 4 : aCell.assign(aLoPos.first, aLoPos.second);
1411 4 : ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter);
1412 4 : sal_Int32 nTmp = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString);
1413 8 : if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
1414 11 : (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
1415 3 : (rEntry.eOp == SC_EQUAL && nTmp != 0))
1416 : {
1417 : // Skip the first string value at low point.
1418 1 : incPos(aLoPos);
1419 4 : }
1420 : }
1421 :
1422 50 : aHiPos = pCol->maCells.position(mpParam->nRow2);
1423 50 : if (bAllStringIgnore)
1424 : {
1425 : // Skip all string cells, but never go past the high point.
1426 33 : if (aLoPos.first->type == sc::element_type_string)
1427 : {
1428 12 : if (aLoPos.first == pCol->maCells.end())
1429 : // This is the last block. Move to the last element in this block.
1430 0 : aLoPos.second = aLoPos.first->size - 1;
1431 : else
1432 : // Move to the next block.
1433 12 : incBlock(aLoPos);
1434 : }
1435 :
1436 33 : if (toLogicalPos(aLoPos) > toLogicalPos(aHiPos))
1437 : // Never go past the high point.
1438 0 : aLoPos = aHiPos;
1439 : }
1440 :
1441 : // Bookkeeping values for breaking up the binary search in case the data
1442 : // range isn't strictly sorted.
1443 50 : PositionType aLastInRange = aLoPos;
1444 50 : PositionType aFirstLastInRange = aLastInRange;
1445 : double fLastInRangeValue = bLessEqual ?
1446 32 : -(::std::numeric_limits<double>::max()) :
1447 82 : ::std::numeric_limits<double>::max();
1448 100 : OUString aLastInRangeString;
1449 50 : if (!bLessEqual)
1450 18 : aLastInRangeString = OUString(sal_Unicode(0xFFFF));
1451 50 : if (aLastInRange.first != pCol->maCells.end())
1452 : {
1453 50 : aCell.assign(aLastInRange.first, aLastInRange.second);
1454 50 : if (aCell.hasString())
1455 : {
1456 4 : sal_uLong nFormat = pCol->GetNumberFormat(toLogicalPos(aLastInRange));
1457 4 : OUString aStr;
1458 4 : ScCellFormat::GetInputString(aCell, nFormat, aStr, rFormatter);
1459 4 : aLastInRangeString = aStr;
1460 : }
1461 : else
1462 : {
1463 46 : switch (aCell.meType)
1464 : {
1465 : case CELLTYPE_VALUE :
1466 46 : fLastInRangeValue = aCell.mfValue;
1467 46 : break;
1468 : case CELLTYPE_FORMULA :
1469 0 : fLastInRangeValue = aCell.mpFormula->GetValue();
1470 0 : break;
1471 : default:
1472 : {
1473 : // added to avoid warnings
1474 : }
1475 : }
1476 : }
1477 : }
1478 :
1479 50 : sal_Int32 nRes = 0;
1480 50 : bool bFound = false;
1481 50 : bool bDone = false;
1482 50 : size_t nLogicalLow = toLogicalPos(aLoPos), nLogicalHigh = toLogicalPos(aHiPos);
1483 279 : while (nLogicalLow <= nLogicalHigh && !bDone)
1484 : {
1485 179 : size_t nMid = (nLogicalLow+nLogicalHigh)/2;
1486 179 : size_t i = nMid;
1487 179 : if (i > nLogicalHigh)
1488 : {
1489 0 : if (nMid > 0)
1490 0 : nLogicalHigh = nMid - 1;
1491 : else
1492 0 : bDone = true;
1493 0 : continue; // while
1494 : }
1495 :
1496 179 : PositionType aPos = pCol->maCells.position(i);
1497 179 : bool bStr = aPos.first->type == sc::element_type_string;
1498 179 : nRes = 0;
1499 :
1500 : // compares are content<query:-1, content>query:1
1501 : // Cell value comparison similar to ScTable::ValidQuery()
1502 179 : if (!bStr && !bByString)
1503 : {
1504 : double nCellVal;
1505 108 : aCell.assign(aPos.first, aPos.second);
1506 108 : switch (aCell.meType)
1507 : {
1508 : case CELLTYPE_VALUE :
1509 108 : nCellVal = aCell.mfValue;
1510 108 : break;
1511 : case CELLTYPE_FORMULA :
1512 0 : nCellVal = aCell.mpFormula->GetValue();
1513 0 : break;
1514 : default:
1515 0 : nCellVal = 0.0;
1516 : }
1517 158 : if ((nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(
1518 50 : nCellVal, rItem.mfVal))
1519 : {
1520 50 : nRes = -1;
1521 50 : if (bLessEqual)
1522 : {
1523 35 : if (fLastInRangeValue < nCellVal)
1524 : {
1525 31 : fLastInRangeValue = nCellVal;
1526 31 : aLastInRange = aPos;
1527 : }
1528 4 : else if (fLastInRangeValue > nCellVal)
1529 : {
1530 : // not strictly sorted, continue with GetThis()
1531 0 : aLastInRange = aFirstLastInRange;
1532 0 : bDone = true;
1533 : }
1534 : }
1535 : }
1536 116 : else if ((nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(
1537 58 : nCellVal, rItem.mfVal))
1538 : {
1539 58 : nRes = 1;
1540 58 : if (!bLessEqual)
1541 : {
1542 27 : if (fLastInRangeValue > nCellVal)
1543 : {
1544 26 : fLastInRangeValue = nCellVal;
1545 26 : aLastInRange = aPos;
1546 : }
1547 1 : else if (fLastInRangeValue < nCellVal)
1548 : {
1549 : // not strictly sorted, continue with GetThis()
1550 0 : aLastInRange = aFirstLastInRange;
1551 0 : bDone = true;
1552 : }
1553 : }
1554 108 : }
1555 : }
1556 71 : else if (bStr && bByString)
1557 : {
1558 39 : OUString aCellStr;
1559 39 : sal_uLong nFormat = pCol->GetNumberFormat(i);
1560 39 : aCell.assign(aPos.first, aPos.second);
1561 39 : ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter);
1562 :
1563 39 : nRes = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString);
1564 39 : if (nRes < 0 && bLessEqual)
1565 : {
1566 : sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1567 19 : aCellStr);
1568 19 : if (nTmp < 0)
1569 : {
1570 18 : aLastInRangeString = aCellStr;
1571 18 : aLastInRange = aPos;
1572 : }
1573 1 : else if (nTmp > 0)
1574 : {
1575 : // not strictly sorted, continue with GetThis()
1576 0 : aLastInRange = aFirstLastInRange;
1577 0 : bDone = true;
1578 19 : }
1579 : }
1580 20 : else if (nRes > 0 && !bLessEqual)
1581 : {
1582 : sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1583 4 : aCellStr);
1584 4 : if (nTmp > 0)
1585 : {
1586 2 : aLastInRangeString = aCellStr;
1587 2 : aLastInRange = aPos;
1588 : }
1589 2 : else if (nTmp < 0)
1590 : {
1591 : // not strictly sorted, continue with GetThis()
1592 0 : aLastInRange = aFirstLastInRange;
1593 0 : bDone = true;
1594 : }
1595 39 : }
1596 : }
1597 32 : else if (!bStr && bByString)
1598 : {
1599 20 : nRes = -1; // numeric < string
1600 40 : if (bLessEqual)
1601 14 : aLastInRange = aPos;
1602 : }
1603 : else // if (bStr && !bByString)
1604 : {
1605 12 : nRes = 1; // string > numeric
1606 12 : if (!bLessEqual)
1607 0 : aLastInRange = aPos;
1608 : }
1609 179 : if (nRes < 0)
1610 : {
1611 93 : if (bLessEqual)
1612 68 : nLogicalLow = nMid + 1;
1613 : else // assumed to be SC_GREATER_EQUAL
1614 : {
1615 25 : if (nMid > 0)
1616 25 : nLogicalHigh = nMid - 1;
1617 : else
1618 0 : bDone = true;
1619 : }
1620 : }
1621 86 : else if (nRes > 0)
1622 : {
1623 84 : if (bLessEqual)
1624 : {
1625 53 : if (nMid > 0)
1626 52 : nLogicalHigh = nMid - 1;
1627 : else
1628 1 : bDone = true;
1629 : }
1630 : else // assumed to be SC_GREATER_EQUAL
1631 31 : nLogicalLow = nMid + 1;
1632 : }
1633 : else
1634 : {
1635 2 : aLoPos = aPos;
1636 2 : bDone = bFound = true;
1637 : }
1638 : }
1639 50 : if (!bFound)
1640 : {
1641 : // If all hits didn't result in a moving limit there's something
1642 : // strange, e.g. data range not properly sorted, or only identical
1643 : // values encountered, which doesn't mean there aren't any others in
1644 : // between.. leave it to GetThis(). The condition for this would be
1645 : // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
1646 : // Else, in case no exact match was found, we step back for a
1647 : // subsequent GetThis() to find the last in range. Effectively this is
1648 : // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
1649 48 : aLoPos = aLastInRange;
1650 : }
1651 :
1652 50 : if (aLoPos.first != pCol->maCells.end() && toLogicalPos(aLoPos) <= static_cast<size_t>(mpParam->nRow2))
1653 : {
1654 50 : nRow = toLogicalPos(aLoPos);
1655 50 : maCurPos = aLoPos;
1656 50 : return true;
1657 : }
1658 : else
1659 : {
1660 0 : nRow = mpParam->nRow2 + 1;
1661 : // Set current position to the last possible row.
1662 0 : maCurPos.first = pCol->maCells.end();
1663 0 : --maCurPos.first;
1664 0 : maCurPos.second = maCurPos.first->size - 1;
1665 0 : return false;
1666 50 : }
1667 : }
1668 :
1669 :
1670 : //-------------------------------------------------------------------------------
1671 :
1672 3693 : ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
1673 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1674 3693 : maColPositions(nCol2-nCol1+1),
1675 : pDoc( pDocument ),
1676 : mnTab( nTable ),
1677 : nStartCol( nCol1 ),
1678 : nEndCol( nCol2 ),
1679 : nStartRow( nRow1 ),
1680 : nEndRow( nRow2 ),
1681 : mnCol( nCol1 ),
1682 : mnRow( nRow1 ),
1683 7386 : bMore(false)
1684 : {
1685 3693 : if (mnTab >= pDoc->GetTableCount())
1686 : OSL_FAIL("try to access index out of bounds, FIX IT");
1687 :
1688 3693 : pNextRows = new SCROW[ nCol2-nCol1+1 ];
1689 3693 : pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
1690 :
1691 3693 : SetTab( mnTab );
1692 3693 : }
1693 :
1694 7386 : ScHorizontalCellIterator::~ScHorizontalCellIterator()
1695 : {
1696 3693 : delete [] pNextRows;
1697 3693 : delete [] pNextIndices;
1698 3693 : }
1699 :
1700 3693 : void ScHorizontalCellIterator::SetTab( SCTAB nTabP )
1701 : {
1702 3693 : bMore = false;
1703 3693 : mnTab = nTabP;
1704 3693 : mnRow = nStartRow;
1705 3693 : mnCol = nStartCol;
1706 :
1707 : // Set the start position in each column.
1708 1562412 : for (SCCOL i = nStartCol; i <= nEndCol; ++i)
1709 : {
1710 1558719 : ScColumn* pCol = &pDoc->maTabs[mnTab]->aCol[i];
1711 1558719 : ColParam& rParam = maColPositions[i-nStartCol];
1712 1558719 : rParam.maPos = pCol->maCells.position(nStartRow).first;
1713 1558719 : rParam.maEnd = pCol->maCells.end();
1714 1558719 : if (rParam.maPos != rParam.maEnd)
1715 1558719 : bMore = true;
1716 : }
1717 :
1718 3693 : if (!bMore)
1719 3693 : return;
1720 :
1721 3693 : ColParam& rParam = maColPositions[0];
1722 3693 : if (rParam.maPos == rParam.maEnd || rParam.maPos->type == sc::element_type_empty)
1723 : // Skip to the first non-empty cell.
1724 2502 : Advance();
1725 : }
1726 :
1727 159 : void ScHorizontalCellIterator::RehashCol( SCCOL nCol )
1728 : {
1729 159 : if (nCol < nStartCol || nEndCol < nCol)
1730 159 : return;
1731 :
1732 159 : ColParam& rParam = maColPositions[nCol-nStartCol];
1733 159 : ScColumn& rCol = pDoc->maTabs[mnTab]->aCol[nCol];
1734 159 : rParam.maPos = rCol.maCells.position(mnRow).first;
1735 159 : rParam.maEnd = rCol.maCells.end();
1736 : }
1737 :
1738 16523 : ScRefCellValue* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
1739 : {
1740 16523 : if (!bMore)
1741 2323 : return NULL;
1742 :
1743 : // Return the current non-empty cell, and move the cursor to the next one.
1744 14200 : rCol = mnCol;
1745 14200 : rRow = mnRow;
1746 :
1747 14200 : ColParam& r = maColPositions[mnCol-nStartCol];
1748 14200 : size_t nOffset = static_cast<size_t>(mnRow) - r.maPos->position;
1749 14200 : maCurCell.assign(r.maPos, nOffset);
1750 14200 : Advance();
1751 :
1752 14200 : return &maCurCell;
1753 : }
1754 :
1755 221 : bool ScHorizontalCellIterator::GetPos( SCCOL& rCol, SCROW& rRow )
1756 : {
1757 221 : rCol = mnCol;
1758 221 : rRow = mnRow;
1759 221 : return bMore;
1760 : }
1761 :
1762 : namespace {
1763 :
1764 3485680 : bool advanceBlock(size_t nRow, sc::CellStoreType::const_iterator& rPos, const sc::CellStoreType::const_iterator& rEnd)
1765 : {
1766 3485680 : if (nRow < rPos->position + rPos->size)
1767 : // Block already contains the specified row. Nothing to do.
1768 3481223 : return true;
1769 :
1770 : // This block is behind the current row position. Advance the block.
1771 4457 : for (++rPos; rPos != rEnd; ++rPos)
1772 : {
1773 4457 : if (nRow < rPos->position + rPos->size)
1774 : // Found the block that contains the specified row.
1775 4457 : return true;
1776 : }
1777 :
1778 : // No more blocks.
1779 0 : return false;
1780 : }
1781 :
1782 : }
1783 :
1784 16702 : void ScHorizontalCellIterator::Advance()
1785 : {
1786 : // Find the next non-empty cell in the current row.
1787 2412166 : for (SCCOL i = mnCol+1; i <= nEndCol; ++i)
1788 : {
1789 2406514 : ColParam& r = maColPositions[i-nStartCol];
1790 2406514 : if (r.maPos == r.maEnd)
1791 232251 : continue;
1792 :
1793 2174263 : size_t nRow = static_cast<size_t>(mnRow);
1794 2174263 : if (nRow < r.maPos->position)
1795 1157 : continue;
1796 :
1797 2173106 : if (!advanceBlock(nRow, r.maPos, r.maEnd))
1798 0 : continue;
1799 :
1800 2173106 : if (r.maPos->type == sc::element_type_empty)
1801 2162056 : continue;
1802 :
1803 : // Found in the current row.
1804 11050 : mnCol = i;
1805 11050 : bMore = true;
1806 11050 : return;
1807 : }
1808 :
1809 : // Move to the next row that has at least one non-empty cell.
1810 5652 : ++mnRow;
1811 11743 : while (mnRow <= nEndRow)
1812 : {
1813 5911 : size_t nRow = static_cast<size_t>(mnRow);
1814 5911 : size_t nNextRow = MAXROW+1;
1815 5911 : size_t nNextRowPos = 0;
1816 1422854 : for (size_t i = nNextRowPos, n = maColPositions.size(); i < n; ++i)
1817 : {
1818 1419931 : ColParam& r = maColPositions[i];
1819 1419931 : if (r.maPos == r.maEnd)
1820 : // This column has ended.
1821 105022 : continue;
1822 :
1823 1314909 : if (nRow < r.maPos->position)
1824 : {
1825 : // This block is ahread of the current row position. Skip it.
1826 2335 : if (r.maPos->position < nNextRow)
1827 : {
1828 511 : nNextRow = r.maPos->position;
1829 511 : nNextRowPos = i;
1830 : }
1831 2335 : continue;
1832 : }
1833 :
1834 1312574 : if (!advanceBlock(nRow, r.maPos, r.maEnd))
1835 0 : continue;
1836 :
1837 1312574 : if (r.maPos->type == sc::element_type_empty)
1838 : {
1839 : // Empty block. Move to the next block and try next column.
1840 1309586 : ++r.maPos;
1841 1309586 : if (r.maPos->position < nNextRow)
1842 : {
1843 601 : nNextRow = r.maPos->position;
1844 601 : nNextRowPos = i;
1845 : }
1846 1309586 : continue;
1847 : }
1848 :
1849 : // Found a non-empty cell block!
1850 2988 : mnCol = i + nStartCol;
1851 2988 : mnRow = nRow;
1852 2988 : bMore = true;
1853 2988 : return;
1854 : }
1855 :
1856 2923 : if (nNextRow > static_cast<size_t>(MAXROW))
1857 : {
1858 : // No more blocks to search.
1859 2484 : bMore = false;
1860 2484 : return;
1861 : }
1862 :
1863 439 : mnRow = nNextRow; // move to the next non-empty row.
1864 : }
1865 :
1866 180 : bMore = false;
1867 : }
1868 :
1869 : //------------------------------------------------------------------------
1870 :
1871 0 : ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument* pDocument,
1872 : const ScRange& rRange, bool bSTotal, bool bTextZero ) :
1873 : pDoc( pDocument ),
1874 : nNumFmtIndex(0),
1875 0 : nEndTab( rRange.aEnd.Tab() ),
1876 : nNumFmtType( NUMBERFORMAT_UNDEFINED ),
1877 : bNumValid( false ),
1878 : bSubTotal( bSTotal ),
1879 0 : bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
1880 0 : bTextAsZero( bTextZero )
1881 : {
1882 0 : SCCOL nStartCol = rRange.aStart.Col();
1883 0 : SCROW nStartRow = rRange.aStart.Row();
1884 0 : SCTAB nStartTab = rRange.aStart.Tab();
1885 0 : SCCOL nEndCol = rRange.aEnd.Col();
1886 0 : SCROW nEndRow = rRange.aEnd.Row();
1887 0 : PutInOrder( nStartCol, nEndCol);
1888 0 : PutInOrder( nStartRow, nEndRow);
1889 0 : PutInOrder( nStartTab, nEndTab );
1890 :
1891 0 : if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
1892 0 : if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
1893 0 : if (!ValidRow(nStartRow)) nStartRow = MAXROW;
1894 0 : if (!ValidRow(nEndRow)) nEndRow = MAXROW;
1895 0 : if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
1896 0 : if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
1897 :
1898 0 : nCurCol = nStartCol;
1899 0 : nCurRow = nStartRow;
1900 0 : nCurTab = nStartTab;
1901 :
1902 0 : nNumFormat = 0; // Will be initialized in GetNumberFormat()
1903 0 : pAttrArray = 0;
1904 0 : nAttrEndRow = 0;
1905 :
1906 : pCellIter = new ScHorizontalCellIterator( pDoc, nStartTab, nStartCol,
1907 0 : nStartRow, nEndCol, nEndRow );
1908 0 : }
1909 :
1910 0 : ScHorizontalValueIterator::~ScHorizontalValueIterator()
1911 : {
1912 0 : delete pCellIter;
1913 0 : }
1914 :
1915 0 : bool ScHorizontalValueIterator::GetNext( double& rValue, sal_uInt16& rErr )
1916 : {
1917 0 : bool bFound = false;
1918 0 : while ( !bFound )
1919 : {
1920 0 : ScRefCellValue* pCell = pCellIter->GetNext( nCurCol, nCurRow );
1921 0 : while ( !pCell )
1922 : {
1923 0 : if ( nCurTab < nEndTab )
1924 : {
1925 0 : pCellIter->SetTab( ++nCurTab);
1926 0 : pCell = pCellIter->GetNext( nCurCol, nCurRow );
1927 : }
1928 : else
1929 0 : return false;
1930 : }
1931 0 : if ( !bSubTotal || !pDoc->maTabs[nCurTab]->RowFiltered( nCurRow ) )
1932 : {
1933 0 : switch (pCell->meType)
1934 : {
1935 : case CELLTYPE_VALUE:
1936 : {
1937 0 : bNumValid = false;
1938 0 : rValue = pCell->mfValue;
1939 0 : rErr = 0;
1940 0 : if ( bCalcAsShown )
1941 : {
1942 0 : ScColumn* pCol = &pDoc->maTabs[nCurTab]->aCol[nCurCol];
1943 : ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
1944 0 : nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc );
1945 0 : rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
1946 : }
1947 0 : bFound = true;
1948 : }
1949 0 : break;
1950 : case CELLTYPE_FORMULA:
1951 : {
1952 0 : if (!bSubTotal || !pCell->mpFormula->IsSubTotal())
1953 : {
1954 0 : rErr = pCell->mpFormula->GetErrCode();
1955 0 : if (rErr || pCell->mpFormula->IsValue())
1956 : {
1957 0 : rValue = pCell->mpFormula->GetValue();
1958 0 : bNumValid = false;
1959 0 : bFound = true;
1960 : }
1961 0 : else if ( bTextAsZero )
1962 : {
1963 0 : rValue = 0.0;
1964 0 : bNumValid = false;
1965 0 : bFound = true;
1966 : }
1967 : }
1968 : }
1969 0 : break;
1970 : case CELLTYPE_STRING :
1971 : case CELLTYPE_EDIT :
1972 : {
1973 0 : if ( bTextAsZero )
1974 : {
1975 0 : rErr = 0;
1976 0 : rValue = 0.0;
1977 0 : nNumFmtType = NUMBERFORMAT_NUMBER;
1978 0 : nNumFmtIndex = 0;
1979 0 : bNumValid = true;
1980 0 : bFound = true;
1981 : }
1982 : }
1983 0 : break;
1984 : default: ; // nothing
1985 : }
1986 : }
1987 : }
1988 0 : return bFound;
1989 : }
1990 :
1991 : //-------------------------------------------------------------------------------
1992 :
1993 14 : ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable,
1994 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1995 : pDoc( pDocument ),
1996 : nTab( nTable ),
1997 : nStartCol( nCol1 ),
1998 : nStartRow( nRow1 ),
1999 : nEndCol( nCol2 ),
2000 14 : nEndRow( nRow2 )
2001 : {
2002 14 : if (nTab >= pDoc->GetTableCount())
2003 : OSL_FAIL("try to access index out of bounds, FIX IT");
2004 : OSL_ENSURE( pDoc->maTabs[nTab], "Table does not exist" );
2005 :
2006 : SCCOL i;
2007 :
2008 14 : nRow = nStartRow;
2009 14 : nCol = nStartCol;
2010 14 : bRowEmpty = false;
2011 :
2012 14 : pIndices = new SCSIZE[nEndCol-nStartCol+1];
2013 14 : pNextEnd = new SCROW[nEndCol-nStartCol+1];
2014 14 : ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1];
2015 :
2016 14 : SCROW nSkipTo = MAXROW;
2017 14 : bool bEmpty = true;
2018 10510 : for (i=nStartCol; i<=nEndCol; i++)
2019 : {
2020 10496 : SCCOL nPos = i - nStartCol;
2021 10496 : const ScAttrArray* pArray = pDoc->maTabs[nTab]->aCol[i].pAttrArray;
2022 : OSL_ENSURE( pArray, "pArray == 0" );
2023 :
2024 : SCSIZE nIndex;
2025 10496 : pArray->Search( nStartRow, nIndex );
2026 :
2027 10496 : const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
2028 10496 : SCROW nThisEnd = pArray->pData[nIndex].nRow;
2029 10496 : if ( IsDefaultItem( pPattern ) )
2030 : {
2031 8454 : pPattern = NULL;
2032 8454 : if ( nThisEnd < nSkipTo )
2033 3 : nSkipTo = nThisEnd; // nSkipTo can be set here already
2034 : }
2035 : else
2036 2042 : bEmpty = false; // Found attributes
2037 :
2038 10496 : pIndices[nPos] = nIndex;
2039 10496 : pNextEnd[nPos] = nThisEnd;
2040 10496 : ppPatterns[nPos] = pPattern;
2041 : }
2042 :
2043 14 : if (bEmpty)
2044 12 : nRow = nSkipTo; // Skip until end of next section
2045 :
2046 14 : bRowEmpty = bEmpty;
2047 14 : }
2048 :
2049 14 : ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
2050 : {
2051 14 : delete[] ppPatterns;
2052 14 : delete[] pNextEnd;
2053 14 : delete[] pIndices;
2054 14 : }
2055 :
2056 253 : const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
2057 : {
2058 253 : if (nTab >= pDoc->GetTableCount())
2059 : OSL_FAIL("try to access index out of bounds, FIX IT");
2060 : for (;;)
2061 : {
2062 285 : if (!bRowEmpty)
2063 : {
2064 : // Search in this row
2065 21902 : while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] )
2066 21356 : ++nCol;
2067 :
2068 273 : if ( nCol <= nEndCol )
2069 : {
2070 239 : const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
2071 239 : rRow = nRow;
2072 239 : rCol1 = nCol;
2073 13699 : while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat )
2074 13221 : ++nCol;
2075 239 : rCol2 = nCol;
2076 239 : ++nCol; // Count up for next call
2077 239 : return pPat; // Found it!
2078 : }
2079 : }
2080 :
2081 : // Next row
2082 46 : ++nRow;
2083 46 : if ( nRow > nEndRow ) // Already at the end?
2084 14 : return NULL; // Found nothing
2085 :
2086 32 : bool bEmpty = true;
2087 : SCCOL i;
2088 :
2089 32800 : for ( i = nStartCol; i <= nEndCol; i++)
2090 : {
2091 32768 : SCCOL nPos = i-nStartCol;
2092 32768 : if ( pNextEnd[nPos] < nRow )
2093 : {
2094 16 : const ScAttrArray* pArray = pDoc->maTabs[nTab]->aCol[i].pAttrArray;
2095 :
2096 16 : SCSIZE nIndex = ++pIndices[nPos];
2097 16 : if ( nIndex < pArray->nCount )
2098 : {
2099 16 : const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
2100 16 : SCROW nThisEnd = pArray->pData[nIndex].nRow;
2101 16 : if ( IsDefaultItem( pPattern ) )
2102 2 : pPattern = NULL;
2103 : else
2104 14 : bEmpty = false; // Found attributes
2105 :
2106 16 : pNextEnd[nPos] = nThisEnd;
2107 16 : ppPatterns[nPos] = pPattern;
2108 :
2109 : OSL_ENSURE( pNextEnd[nPos] >= nRow, "Sequence out of order" );
2110 : }
2111 : else
2112 : {
2113 : OSL_FAIL("AttrArray does not range to MAXROW");
2114 0 : pNextEnd[nPos] = MAXROW;
2115 0 : ppPatterns[nPos] = NULL;
2116 : }
2117 : }
2118 32752 : else if ( ppPatterns[nPos] )
2119 11404 : bEmpty = false; // Area not at the end yet
2120 : }
2121 :
2122 32 : if (bEmpty)
2123 : {
2124 0 : SCCOL nCount = nEndCol-nStartCol+1;
2125 0 : SCROW nSkipTo = pNextEnd[0]; // Search next end of area
2126 0 : for (i=1; i<nCount; i++)
2127 0 : if ( pNextEnd[i] < nSkipTo )
2128 0 : nSkipTo = pNextEnd[i];
2129 0 : nRow = nSkipTo; // Skip empty rows
2130 : }
2131 32 : bRowEmpty = bEmpty;
2132 32 : nCol = nStartCol; // Start at the left again
2133 32 : }
2134 : }
2135 :
2136 : //-------------------------------------------------------------------------------
2137 :
2138 785 : inline bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2139 : {
2140 785 : return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
2141 : }
2142 :
2143 14 : ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable,
2144 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
2145 : aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
2146 : aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
2147 : nNextCol( nCol1 ),
2148 14 : nNextRow( nRow1 )
2149 : {
2150 14 : pCell = aCellIter.GetNext( nCellCol, nCellRow );
2151 14 : pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
2152 14 : }
2153 :
2154 14 : ScUsedAreaIterator::~ScUsedAreaIterator()
2155 : {
2156 14 : }
2157 :
2158 299 : bool ScUsedAreaIterator::GetNext()
2159 : {
2160 : // Forward iterators
2161 299 : if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) )
2162 246 : pCell = aCellIter.GetNext( nCellCol, nCellRow );
2163 :
2164 598 : while (pCell && pCell->isEmpty())
2165 0 : pCell = aCellIter.GetNext( nCellCol, nCellRow );
2166 :
2167 299 : if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) )
2168 239 : pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
2169 :
2170 299 : if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
2171 0 : nAttrCol1 = nNextCol;
2172 :
2173 : // Find next area
2174 299 : bool bFound = true;
2175 299 : bool bUseCell = false;
2176 :
2177 299 : if ( pCell && pPattern )
2178 : {
2179 490 : if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // Only attributes at the beginning?
2180 : {
2181 37 : maFoundCell.clear();
2182 37 : pFoundPattern = pPattern;
2183 37 : nFoundRow = nAttrRow;
2184 37 : nFoundStartCol = nAttrCol1;
2185 37 : if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // Area also contains cell?
2186 0 : nFoundEndCol = nCellCol - 1; // Only until right before the cell
2187 : else
2188 37 : nFoundEndCol = nAttrCol2; // Everything
2189 : }
2190 : else
2191 : {
2192 208 : bUseCell = true;
2193 208 : if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attributes on the cell?
2194 200 : pFoundPattern = pPattern;
2195 : else
2196 8 : pFoundPattern = NULL;
2197 : }
2198 : }
2199 54 : else if ( pCell ) // Just a cell -> take over right away
2200 : {
2201 38 : pFoundPattern = NULL;
2202 38 : bUseCell = true; // Cell position
2203 : }
2204 16 : else if ( pPattern ) // Just attributes -> take over right away
2205 : {
2206 2 : maFoundCell.clear();
2207 2 : pFoundPattern = pPattern;
2208 2 : nFoundRow = nAttrRow;
2209 2 : nFoundStartCol = nAttrCol1;
2210 2 : nFoundEndCol = nAttrCol2;
2211 : }
2212 : else // Nothing
2213 14 : bFound = false;
2214 :
2215 299 : if ( bUseCell ) // Cell position
2216 : {
2217 246 : if (pCell)
2218 246 : maFoundCell = *pCell;
2219 : else
2220 0 : maFoundCell.clear();
2221 :
2222 246 : nFoundRow = nCellRow;
2223 246 : nFoundStartCol = nFoundEndCol = nCellCol;
2224 : }
2225 :
2226 299 : if (bFound)
2227 : {
2228 285 : nNextRow = nFoundRow;
2229 285 : nNextCol = nFoundEndCol + 1;
2230 : }
2231 :
2232 299 : return bFound;
2233 : }
2234 :
2235 285 : const ScRefCellValue& ScUsedAreaIterator::GetCell() const
2236 : {
2237 285 : return maFoundCell;
2238 : }
2239 :
2240 : //-------------------------------------------------------------------------------
2241 :
2242 355361 : ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable,
2243 : SCCOL nCol1, SCROW nRow1,
2244 : SCCOL nCol2, SCROW nRow2) :
2245 : pDoc( pDocument ),
2246 : nTab( nTable ),
2247 : nEndCol( nCol2 ),
2248 : nStartRow( nRow1 ),
2249 : nEndRow( nRow2 ),
2250 355361 : nCol( nCol1 )
2251 : {
2252 355361 : if ( ValidTab(nTab) && nTab < pDoc->GetTableCount() && pDoc->maTabs[nTab] )
2253 355361 : pColIter = pDoc->maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2254 : else
2255 0 : pColIter = NULL;
2256 355361 : }
2257 :
2258 355361 : ScDocAttrIterator::~ScDocAttrIterator()
2259 : {
2260 355361 : delete pColIter;
2261 355361 : }
2262 :
2263 710842 : const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
2264 : {
2265 1776002 : while ( pColIter )
2266 : {
2267 711865 : const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2268 711865 : if ( pPattern )
2269 : {
2270 357547 : rCol = nCol;
2271 357547 : return pPattern;
2272 : }
2273 :
2274 354318 : delete pColIter;
2275 354318 : ++nCol;
2276 354318 : if ( nCol <= nEndCol )
2277 1023 : pColIter = pDoc->maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2278 : else
2279 353295 : pColIter = NULL;
2280 : }
2281 353295 : return NULL; // Nothing anymore
2282 : }
2283 :
2284 : // ============================================================================
2285 :
2286 0 : ScDocRowHeightUpdater::TabRanges::TabRanges(SCTAB nTab) :
2287 0 : mnTab(nTab), mpRanges(new ScFlatBoolRowSegments)
2288 : {
2289 0 : }
2290 :
2291 8 : ScDocRowHeightUpdater::ScDocRowHeightUpdater(ScDocument& rDoc, OutputDevice* pOutDev, double fPPTX, double fPPTY, const vector<TabRanges>* pTabRangesArray) :
2292 8 : mrDoc(rDoc), mpOutDev(pOutDev), mfPPTX(fPPTX), mfPPTY(fPPTY), mpTabRangesArray(pTabRangesArray)
2293 : {
2294 8 : }
2295 :
2296 8 : void ScDocRowHeightUpdater::update()
2297 : {
2298 8 : if (!mpTabRangesArray || mpTabRangesArray->empty())
2299 : {
2300 : // No ranges defined. Update all rows in all tables.
2301 8 : updateAll();
2302 16 : return;
2303 : }
2304 :
2305 0 : sal_uInt32 nCellCount = 0;
2306 0 : vector<TabRanges>::const_iterator itr = mpTabRangesArray->begin(), itrEnd = mpTabRangesArray->end();
2307 0 : for (; itr != itrEnd; ++itr)
2308 : {
2309 : ScFlatBoolRowSegments::RangeData aData;
2310 0 : ScFlatBoolRowSegments::RangeIterator aRangeItr(*itr->mpRanges);
2311 0 : for (bool bFound = aRangeItr.getFirst(aData); bFound; bFound = aRangeItr.getNext(aData))
2312 : {
2313 0 : if (!aData.mbValue)
2314 0 : continue;
2315 :
2316 0 : nCellCount += aData.mnRow2 - aData.mnRow1 + 1;
2317 : }
2318 : }
2319 :
2320 0 : ScProgress aProgress(mrDoc.GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount);
2321 :
2322 0 : Fraction aZoom(1, 1);
2323 0 : itr = mpTabRangesArray->begin();
2324 0 : sal_uInt32 nProgressStart = 0;
2325 0 : for (; itr != itrEnd; ++itr)
2326 : {
2327 0 : SCTAB nTab = itr->mnTab;
2328 0 : if (!ValidTab(nTab) || nTab >= mrDoc.GetTableCount() || !mrDoc.maTabs[nTab])
2329 0 : continue;
2330 :
2331 : ScFlatBoolRowSegments::RangeData aData;
2332 0 : ScFlatBoolRowSegments::RangeIterator aRangeItr(*itr->mpRanges);
2333 0 : for (bool bFound = aRangeItr.getFirst(aData); bFound; bFound = aRangeItr.getNext(aData))
2334 : {
2335 0 : if (!aData.mbValue)
2336 0 : continue;
2337 :
2338 0 : mrDoc.maTabs[nTab]->SetOptimalHeight(
2339 0 : aData.mnRow1, aData.mnRow2, 0, mpOutDev, mfPPTX, mfPPTY, aZoom, aZoom, false, &aProgress, nProgressStart);
2340 :
2341 0 : nProgressStart += aData.mnRow2 - aData.mnRow1 + 1;
2342 : }
2343 0 : }
2344 : }
2345 :
2346 8 : void ScDocRowHeightUpdater::updateAll()
2347 : {
2348 8 : sal_uInt32 nCellCount = 0;
2349 16 : for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab)
2350 : {
2351 8 : if (!ValidTab(nTab) || !mrDoc.maTabs[nTab])
2352 0 : continue;
2353 :
2354 8 : nCellCount += mrDoc.maTabs[nTab]->GetWeightedCount();
2355 : }
2356 :
2357 8 : ScProgress aProgress(mrDoc.GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), nCellCount);
2358 :
2359 8 : Fraction aZoom(1, 1);
2360 8 : sal_uLong nProgressStart = 0;
2361 16 : for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab)
2362 : {
2363 8 : if (!ValidTab(nTab) || !mrDoc.maTabs[nTab])
2364 0 : continue;
2365 :
2366 8 : mrDoc.maTabs[nTab]->SetOptimalHeight(
2367 16 : 0, MAXROW, 0, mpOutDev, mfPPTX, mfPPTY, aZoom, aZoom, false, &aProgress, nProgressStart);
2368 :
2369 8 : nProgressStart += mrDoc.maTabs[nTab]->GetWeightedCount();
2370 8 : }
2371 8 : }
2372 :
2373 : //-------------------------------------------------------------------------------
2374 :
2375 22 : ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable,
2376 : SCCOL nCol1, SCROW nRow1,
2377 : SCCOL nCol2, SCROW nRow2) :
2378 : pDoc( pDocument ),
2379 : nTab( nTable ),
2380 : nEndCol( nCol2 ),
2381 : nStartRow( nRow1 ),
2382 : nEndRow( nRow2 ),
2383 : nIterStartCol( nCol1 ),
2384 22 : nIterEndCol( nCol1 )
2385 : {
2386 22 : if ( ValidTab(nTab) && nTab < pDoc->GetTableCount() && pDoc->maTabs[nTab] )
2387 : {
2388 22 : pColIter = pDoc->maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2389 28711 : while ( nIterEndCol < nEndCol &&
2390 14336 : pDoc->maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2391 28672 : pDoc->maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2392 14331 : ++nIterEndCol;
2393 : }
2394 : else
2395 0 : pColIter = NULL;
2396 22 : }
2397 :
2398 22 : ScAttrRectIterator::~ScAttrRectIterator()
2399 : {
2400 22 : delete pColIter;
2401 22 : }
2402 :
2403 0 : void ScAttrRectIterator::DataChanged()
2404 : {
2405 0 : if (pColIter)
2406 : {
2407 0 : SCROW nNextRow = pColIter->GetNextRow();
2408 0 : delete pColIter;
2409 0 : pColIter = pDoc->maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
2410 : }
2411 0 : }
2412 :
2413 121 : const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
2414 : SCROW& rRow1, SCROW& rRow2 )
2415 : {
2416 299 : while ( pColIter )
2417 : {
2418 157 : const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2419 157 : if ( pPattern )
2420 : {
2421 100 : rCol1 = nIterStartCol;
2422 100 : rCol2 = nIterEndCol;
2423 100 : return pPattern;
2424 : }
2425 :
2426 57 : delete pColIter;
2427 57 : nIterStartCol = nIterEndCol+1;
2428 57 : if ( nIterStartCol <= nEndCol )
2429 : {
2430 36 : nIterEndCol = nIterStartCol;
2431 36 : pColIter = pDoc->maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2432 10261 : while ( nIterEndCol < nEndCol &&
2433 5110 : pDoc->maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2434 10220 : pDoc->maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2435 5079 : ++nIterEndCol;
2436 : }
2437 : else
2438 21 : pColIter = NULL;
2439 : }
2440 21 : return NULL; // Nothing anymore
2441 : }
2442 :
2443 : // ============================================================================
2444 :
2445 : SCROW ScRowBreakIterator::NOT_FOUND = -1;
2446 :
2447 80 : ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) :
2448 : mrBreaks(rBreaks),
2449 80 : maItr(rBreaks.begin()), maEnd(rBreaks.end())
2450 : {
2451 80 : }
2452 :
2453 80 : SCROW ScRowBreakIterator::first()
2454 : {
2455 80 : maItr = mrBreaks.begin();
2456 80 : return maItr == maEnd ? NOT_FOUND : *maItr;
2457 : }
2458 :
2459 3 : SCROW ScRowBreakIterator::next()
2460 : {
2461 3 : ++maItr;
2462 3 : return maItr == maEnd ? NOT_FOUND : *maItr;
2463 93 : }
2464 :
2465 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|