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