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