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