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