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