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 #include <osl/diagnose.h>
48 
49 #include <algorithm>
50 #include <vector>
51 
52 using ::rtl::math::approxEqual;
53 using ::std::vector;
54 using ::std::set;
55 
56 // iterators have very high frequency use -> custom debug.
57 // #define debugiter(...) fprintf(stderr, __VA_ARGS__)
58 #define debugiter(...)
59 
60 namespace {
61 
62 template<typename Iter>
63 void incBlock(std::pair<Iter, size_t>& rPos)
64 {
65  // Move to the next block.
66  ++rPos.first;
67  rPos.second = 0;
68 }
69 
70 template<typename Iter>
71 void decBlock(std::pair<Iter, size_t>& rPos)
72 {
73  // Move to the last element of the previous block.
74  --rPos.first;
75  rPos.second = rPos.first->size - 1;
76 }
77 
78 }
79 
80 static void ScAttrArray_IterGetNumberFormat( sal_uInt32& nFormat, const ScAttrArray*& rpArr,
81  SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
82  const ScDocument& rDoc, const ScInterpreterContext* pContext = nullptr )
83 {
84  if ( rpArr == pNewArr && nAttrEndRow >= nRow )
85  return;
86 
87  SCROW nRowStart = 0;
88  SCROW nRowEnd = rDoc.MaxRow();
89  const ScPatternAttr* pPattern = pNewArr->GetPatternRange( nRowStart, nRowEnd, nRow );
90  if( !pPattern )
91  {
92  pPattern = rDoc.GetDefPattern();
93  nRowEnd = rDoc.MaxRow();
94  }
95 
96  nFormat = pPattern->GetNumberFormat( pContext ? pContext->GetFormatTable() : rDoc.GetFormatTable() );
97  rpArr = pNewArr;
98  nAttrEndRow = nRowEnd;
99 }
100 
102  SubtotalFlags nSubTotalFlags, bool bTextZero )
103  : mrDoc(rDocument)
104  , pContext(nullptr)
105  , pAttrArray(nullptr)
106  , nNumFormat(0) // Initialized in GetNumberFormat
107  , nNumFmtIndex(0)
108  , maStartPos(rRange.aStart)
109  , maEndPos(rRange.aEnd)
110  , mnCol(0)
111  , mnTab(0)
112  , nAttrEndRow(0)
113  , mnSubTotalFlags(nSubTotalFlags)
114  , nNumFmtType(SvNumFormatType::UNDEFINED)
115  , bNumValid(false)
116  , bCalcAsShown(rDocument.GetDocOptions().IsCalcAsShown())
117  , bTextAsZero(bTextZero)
118  , mpCells(nullptr)
119 {
120  SCTAB nDocMaxTab = rDocument.GetTableCount() - 1;
121 
122  if (!rDocument.ValidCol(maStartPos.Col())) maStartPos.SetCol(mrDoc.MaxCol());
123  if (!rDocument.ValidCol(maEndPos.Col())) maEndPos.SetCol(mrDoc.MaxCol());
124  if (!rDocument.ValidRow(maStartPos.Row())) maStartPos.SetRow(mrDoc.MaxRow());
125  if (!rDocument.ValidRow(maEndPos.Row())) maEndPos.SetRow(mrDoc.MaxRow());
126  if (!ValidTab(maStartPos.Tab()) || maStartPos.Tab() > nDocMaxTab) maStartPos.SetTab(nDocMaxTab);
127  if (!ValidTab(maEndPos.Tab()) || maEndPos.Tab() > nDocMaxTab) maEndPos.SetTab(nDocMaxTab);
128 }
129 
131 {
132  // Position of the head of the current block + offset within the block
133  // equals the logical element position.
134  return maCurPos.first->position + maCurPos.second;
135 }
136 
138 {
139  ++maCurPos.first;
140  maCurPos.second = 0;
141 }
142 
144 {
145  if (maCurPos.second + 1 < maCurPos.first->size)
146  // Move within the same block.
147  ++maCurPos.second;
148  else
149  // Move to the next block.
150  IncBlock();
151 }
152 
153 bool ScValueIterator::GetThis(double& rValue, FormulaError& rErr)
154 {
155  while (true)
156  {
157  bool bNextColumn = !mpCells || maCurPos.first == mpCells->end();
158  if (!bNextColumn)
159  {
160  if (GetRow() > maEndPos.Row())
161  bNextColumn = true;
162  }
163 
164  ScColumn* pCol;
165  if (!bNextColumn)
166  pCol = &(mrDoc.maTabs[mnTab])->aCol[mnCol];
167  else
168  {
169  // Find the next available column.
170  do
171  {
172  ++mnCol;
173  if (mnCol > maEndPos.Col() || mnCol >= mrDoc.maTabs[mnTab]->GetAllocatedColumnsCount())
174  {
175  mnCol = maStartPos.Col();
176  ++mnTab;
177  if (mnTab > maEndPos.Tab())
178  {
179  rErr = FormulaError::NONE;
180  return false; // Over and out
181  }
182  }
183  pCol = &(mrDoc.maTabs[mnTab])->aCol[mnCol];
184  }
185  while (pCol->IsEmptyData());
186 
187  mpCells = &pCol->maCells;
188  maCurPos = mpCells->position(maStartPos.Row());
189  }
190 
191  SCROW nCurRow = GetRow();
192  SCROW nLastRow;
193  // Skip all filtered or hidden rows, depending on mnSubTotalFlags
195  mrDoc.RowFiltered( nCurRow, mnTab, nullptr, &nLastRow ) ) ||
197  mrDoc.RowHidden( nCurRow, mnTab, nullptr, &nLastRow ) ) )
198  {
199  maCurPos = mpCells->position(maCurPos.first, nLastRow+1);
200  continue;
201  }
202 
203  switch (maCurPos.first->type)
204  {
206  {
207  bNumValid = false;
208  rValue = sc::numeric_block::at(*maCurPos.first->data, maCurPos.second);
209  rErr = FormulaError::NONE;
210  if (bCalcAsShown)
211  {
213  nAttrEndRow, pCol->pAttrArray.get(), nCurRow, mrDoc, pContext);
214  rValue = mrDoc.RoundValueAsShown(rValue, nNumFormat, pContext);
215  }
216  return true; // Found it!
217  }
218  break;
220  {
221  ScFormulaCell& rCell = *sc::formula_block::at(*maCurPos.first->data, maCurPos.second);
223  {
224  // Skip subtotal formula cells.
225  IncPos();
226  break;
227  }
228 
229  if (rCell.GetErrorOrValue(rErr, rValue))
230  {
231  if ( rErr != FormulaError::NONE && ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) )
232  {
233  IncPos();
234  break;
235  }
236  bNumValid = false;
237  return true; // Found it!
238  }
239  else if (bTextAsZero)
240  {
241  rValue = 0.0;
242  bNumValid = false;
243  return true;
244  }
245  IncPos();
246  }
247  break;
250  {
251  if (bTextAsZero)
252  {
253  rErr = FormulaError::NONE;
254  rValue = 0.0;
255  nNumFmtType = SvNumFormatType::NUMBER;
256  nNumFmtIndex = 0;
257  bNumValid = true;
258  return true;
259  }
260  IncBlock();
261  }
262  break;
264  default:
265  // Skip the whole block.
266  IncBlock();
267  }
268  }
269 }
270 
272 {
273  if (!bNumValid && mnTab < mrDoc.GetTableCount())
274  {
275  SCROW nCurRow = GetRow();
276  const ScColumn* pCol = &(mrDoc.maTabs[mnTab])->aCol[mnCol];
277  nNumFmtIndex = pCol->GetNumberFormat(rContext, nCurRow);
279  bNumValid = true;
280  }
281 
282  nType = nNumFmtType;
283  nIndex = nNumFmtIndex;
284 }
285 
286 bool ScValueIterator::GetFirst(double& rValue, FormulaError& rErr)
287 {
288  mnCol = maStartPos.Col();
289  mnTab = maStartPos.Tab();
290 
291  ScTable* pTab = mrDoc.FetchTable(mnTab);
292  if (!pTab)
293  return false;
294 
295  nNumFormat = 0; // Initialized in GetNumberFormat
296  pAttrArray = nullptr;
297  nAttrEndRow = 0;
298 
299  auto nCol = maStartPos.Col();
300  if (nCol < pTab->GetAllocatedColumnsCount())
301  {
302  mpCells = &pTab->aCol[nCol].maCells;
303  maCurPos = mpCells->position(maStartPos.Row());
304  }
305  else
306  mpCells = nullptr;
307  return GetThis(rValue, rErr);
308 }
309 
310 bool ScValueIterator::GetNext(double& rValue, FormulaError& rErr)
311 {
312  IncPos();
313  return GetThis(rValue, rErr);
314 }
315 
317 {
318 }
319 
321 {
322 }
323 
325 {
326  ScTable* pTab = rDoc.FetchTable(nTab);
327  if (!pTab)
328  return nullptr;
329  if (nCol >= pTab->GetAllocatedColumnsCount())
330  return nullptr;
331  return &pTab->aCol[nCol].maCells;
332 }
333 
335 {
336  assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
337  ScColumn* pCol = &rDoc.maTabs[nTab]->aCol[nCol];
338  return pCol->pAttrArray.get();
339 }
340 
342  ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, const ScRefCellValue* pCell)
343 {
344  assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
345  return rDoc.maTabs[nTab]->ValidQuery(nRow, rParam, pCell);
346 }
347 
349  : DataAccess()
350  , mpCells(nullptr)
351  , mpParam(pParam)
352  , mrDoc(rDoc)
353  , mrContext(rContext)
354  , pAttrArray(nullptr)
355  , nNumFormat(0) // Initialized in GetNumberFormat
356  , nNumFmtIndex(0)
357  , nCol(mpParam->mnField)
358  , nRow(mpParam->nRow1)
359  , nAttrEndRow(0)
360  , nTab(mpParam->nTab)
361  , nNumFmtType(SvNumFormatType::ALL)
362  , bCalcAsShown(rDoc.GetDocOptions().IsCalcAsShown())
363 {
364  SCSIZE i;
366  for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++)
367  {
368  ScQueryEntry& rEntry = mpParam->GetEntry(i);
369  ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
370  rItems.resize(1);
371  ScQueryEntry::Item& rItem = rItems.front();
372  sal_uInt32 nIndex = 0;
373  bool bNumber = mrDoc.GetFormatTable()->IsNumberFormat(
374  rItem.maString.getString(), nIndex, rItem.mfVal);
376  }
377 }
378 
380 {
381 }
382 
384 {
385  // Start with the current row position, and find the first row position
386  // that satisfies the query.
387 
388  // If the query starts in the same column as the result vector we can
389  // prefetch the cell which saves us one fetch in the success case.
390  SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
391  ScRefCellValue aCell;
392 
393  while (true)
394  {
395  if (maCurPos.first == mpCells->end() || nRow > mpParam->nRow2)
396  {
397  // Bottom of the range reached. Bail out.
398  rValue.mnError = FormulaError::NONE;
399  return false;
400  }
401 
402  if (maCurPos.first->type == sc::element_type_empty)
403  {
404  // Skip the whole empty block.
405  incBlock();
406  continue;
407  }
408 
409  ScRefCellValue* pCell = nullptr;
410  if (nCol == static_cast<SCCOL>(nFirstQueryField))
411  {
412  aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
413  pCell = &aCell;
414  }
415 
416  if (ScDBQueryDataIterator::IsQueryValid(mrDoc, *mpParam, nTab, nRow, pCell))
417  {
418  if (!pCell)
419  aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
420  switch (aCell.meType)
421  {
422  case CELLTYPE_VALUE:
423  {
424  rValue.mfValue = aCell.mfValue;
425  rValue.mbIsNumber = true;
426  if ( bCalcAsShown )
427  {
428  const ScAttrArray* pNewAttrArray =
429  ScDBQueryDataIterator::GetAttrArrayByCol(mrDoc, nTab, nCol);
430  ScAttrArray_IterGetNumberFormat( nNumFormat, pAttrArray,
431  nAttrEndRow, pNewAttrArray, nRow, mrDoc );
432  rValue.mfValue = mrDoc.RoundValueAsShown( rValue.mfValue, nNumFormat );
433  }
434  nNumFmtType = SvNumFormatType::NUMBER;
435  nNumFmtIndex = 0;
436  rValue.mnError = FormulaError::NONE;
437  return true; // Found it!
438  }
439 
440  case CELLTYPE_FORMULA:
441  {
442  if (aCell.mpFormula->IsValue())
443  {
444  rValue.mfValue = aCell.mpFormula->GetValue();
445  rValue.mbIsNumber = true;
446  mrDoc.GetNumberFormatInfo(
447  mrContext, nNumFmtType, nNumFmtIndex, ScAddress(nCol, nRow, nTab));
448  rValue.mnError = aCell.mpFormula->GetErrCode();
449  return true; // Found it!
450  }
451  else if(mpParam->mbSkipString)
452  incPos();
453  else
454  {
455  rValue.maString = aCell.mpFormula->GetString().getString();
456  rValue.mfValue = 0.0;
457  rValue.mnError = aCell.mpFormula->GetErrCode();
458  rValue.mbIsNumber = false;
459  return true;
460  }
461  }
462  break;
463  case CELLTYPE_STRING:
464  case CELLTYPE_EDIT:
465  if (mpParam->mbSkipString)
466  incPos();
467  else
468  {
469  rValue.maString = aCell.getString(&mrDoc);
470  rValue.mfValue = 0.0;
471  rValue.mnError = FormulaError::NONE;
472  rValue.mbIsNumber = false;
473  return true;
474  }
475  break;
476  default:
477  incPos();
478  }
479  }
480  else
481  incPos();
482  }
483 // statement unreachable
484 }
485 
487 {
488  if (mpParam->bHasHeader)
489  ++nRow;
490 
491  mpCells = ScDBQueryDataIterator::GetColumnCellStore(mrDoc, nTab, nCol);
492  if (!mpCells)
493  return false;
494 
495  maCurPos = mpCells->position(nRow);
496  return getCurrent(rValue);
497 }
498 
500 {
501  if (!mpCells || maCurPos.first == mpCells->end())
502  return false;
503 
504  incPos();
505  return getCurrent(rValue);
506 }
507 
509 {
510  ++maCurPos.first;
511  maCurPos.second = 0;
512 
513  nRow = maCurPos.first->position;
514 }
515 
517 {
518  if (maCurPos.second + 1 < maCurPos.first->size)
519  {
520  // Move within the same block.
521  ++maCurPos.second;
522  ++nRow;
523  }
524  else
525  // Move to the next block.
526  incBlock();
527 }
528 
530  : DataAccess()
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 =
625 
626  for (SCSIZE i = 0; i < nEntryCount; ++i)
627  {
628  const ScQueryEntry& rEntry = mpParam->GetEntry(i);
629  const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
630  if (!rEntry.bDoQuery)
631  continue;
632 
633  switch (rEntry.eOp)
634  {
635  case SC_EQUAL:
636  case SC_LESS:
637  case SC_GREATER:
638  case SC_LESS_EQUAL:
639  case SC_GREATER_EQUAL:
640  case SC_NOT_EQUAL:
641  break;
642  default:
643  // Only the above operators are supported.
644  continue;
645  }
646 
647  bool bValid = false;
648 
649  SCSIZE nField = static_cast<SCSIZE>(rEntry.nField);
650  if (isQueryByValue(rItem, rMat, nField, nRow))
651  {
652  // By value
653  double fMatVal = rMat.GetDouble(nField, nRow);
654  bool bEqual = approxEqual(fMatVal, rItem.mfVal);
655  switch (rEntry.eOp)
656  {
657  case SC_EQUAL:
658  bValid = bEqual;
659  break;
660  case SC_LESS:
661  bValid = (fMatVal < rItem.mfVal) && !bEqual;
662  break;
663  case SC_GREATER:
664  bValid = (fMatVal > rItem.mfVal) && !bEqual;
665  break;
666  case SC_LESS_EQUAL:
667  bValid = (fMatVal < rItem.mfVal) || bEqual;
668  break;
669  case SC_GREATER_EQUAL:
670  bValid = (fMatVal > rItem.mfVal) || bEqual;
671  break;
672  case SC_NOT_EQUAL:
673  bValid = !bEqual;
674  break;
675  default:
676  ;
677  }
678  }
679  else if (isQueryByString(rEntry, rItem, rMat, nField, nRow))
680  {
681  // By string
682  do
683  {
684  // Equality check first.
685  svl::SharedString aMatStr = rMat.GetString(nField, nRow);
686  svl::SharedString aQueryStr = rEntry.GetQueryItem().maString;
687  bool bDone = false;
688  rtl_uString* p1 = mpParam->bCaseSens ? aMatStr.getData() : aMatStr.getDataIgnoreCase();
689  rtl_uString* p2 = mpParam->bCaseSens ? aQueryStr.getData() : aQueryStr.getDataIgnoreCase();
690  switch (rEntry.eOp)
691  {
692  case SC_EQUAL:
693  bValid = (p1 == p2);
694  bDone = true;
695  break;
696  case SC_NOT_EQUAL:
697  bValid = (p1 != p2);
698  bDone = true;
699  break;
700  default:
701  ;
702  }
703 
704  if (bDone)
705  break;
706 
707  // Unequality check using collator.
708  sal_Int32 nCompare = rCollator.compareString(aMatStr.getString(), aQueryStr.getString());
709  switch (rEntry.eOp)
710  {
711  case SC_LESS :
712  bValid = (nCompare < 0);
713  break;
714  case SC_GREATER :
715  bValid = (nCompare > 0);
716  break;
717  case SC_LESS_EQUAL :
718  bValid = (nCompare <= 0);
719  break;
720  case SC_GREATER_EQUAL :
721  bValid = (nCompare >= 0);
722  break;
723  default:
724  ;
725  }
726  }
727  while (false);
728  }
729 
730  if (aResults.empty())
731  // First query entry.
732  aResults.push_back(bValid);
733  else if (rEntry.eConnect == SC_AND)
734  {
735  // For AND op, tuck the result into the last result value.
736  size_t n = aResults.size();
737  aResults[n-1] = aResults[n-1] && bValid;
738  }
739  else
740  // For OR op, store its own result.
741  aResults.push_back(bValid);
742  }
743 
744  // Row is valid as long as there is at least one result being true.
745  return std::find(aResults.begin(), aResults.end(), true) != aResults.end();
746 }
747 
749  mnError(FormulaError::NONE), mbIsNumber(true)
750 {
751  ::rtl::math::setNan(&mfValue);
752 }
753 
754 ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument& rDocument, const ScInterpreterContext& rContext, std::unique_ptr<ScDBQueryParamBase> pParam) :
755  mpParam (std::move(pParam))
756 {
757  switch (mpParam->GetType())
758  {
760  {
761  ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(mpParam.get());
762  mpData.reset(new DataAccessInternal(p, rDocument, rContext));
763  }
764  break;
766  {
767  ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(mpParam.get());
768  mpData.reset(new DataAccessMatrix(p));
769  }
770  }
771 }
772 
774 {
775  return mpData->getFirst(rValue);
776 }
777 
779 {
780  return mpData->getNext(rValue);
781 }
782 
784  mrDoc(rDoc),
785  mnTab(0),
786  mnCol(0),
787  mnIndex(0)
788 {
789  ScTable *pTab = mrDoc.FetchTable(mnTab);
790  ScColumn *pCol = pTab ? pTab->FetchColumn(mnCol) : nullptr;
791  if (pCol)
792  {
793  mbNullCol = false;
795  }
796  else
797  mbNullCol = true;
798 }
799 
801 {
802  return next();
803 }
804 
806 {
807  if (mnIndex >= maEntries.size() || mbNullCol)
808  {
809  while (mnIndex >= maEntries.size() || mbNullCol)
810  {
811  mnIndex = 0;
812  mnCol++;
813  if (mnCol > mrDoc.MaxCol())
814  {
815  mnCol = 0;
816  mnTab++;
817  if (mnTab >= mrDoc.GetTableCount())
818  return nullptr;
819  }
820  ScTable *pTab = mrDoc.FetchTable(mnTab);
821  ScColumn *pCol = pTab ? pTab->FetchColumn(mnCol) : nullptr;
822  if (pCol)
823  {
824  mbNullCol = false;
826  }
827  else
828  mbNullCol = true;
829  }
830  }
831 
832  return &maEntries[mnIndex++];
833 }
834 
835 ScCellIterator::ScCellIterator( ScDocument& rDoc, const ScRange& rRange, SubtotalFlags nSubTotalFlags ) :
836  mrDoc(rDoc),
837  maStartPos(rRange.aStart),
838  maEndPos(rRange.aEnd),
839  mnSubTotalFlags(nSubTotalFlags)
840 {
841  init();
842 }
843 
845 {
846  ++maCurColPos.first;
847  maCurColPos.second = 0;
848 
849  maCurPos.SetRow(maCurColPos.first->position);
850 }
851 
853 {
854  if (maCurColPos.second + 1 < maCurColPos.first->size)
855  {
856  // Move within the same block.
857  ++maCurColPos.second;
858  maCurPos.IncRow();
859  }
860  else
861  // Move to the next block.
862  incBlock();
863 }
864 
865 void ScCellIterator::setPos(size_t nPos)
866 {
867  maCurColPos = getColumn()->maCells.position(maCurColPos.first, nPos);
868  maCurPos.SetRow(nPos);
869 }
870 
872 {
873  return &mrDoc.maTabs[maCurPos.Tab()]->aCol[maCurPos.Col()];
874 }
875 
877 {
878  SCTAB nDocMaxTab = mrDoc.GetTableCount() - 1;
879 
881 
886  if (!ValidTab(maStartPos.Tab(), nDocMaxTab)) maStartPos.SetTab(nDocMaxTab);
887  if (!ValidTab(maEndPos.Tab(), nDocMaxTab)) maEndPos.SetTab(nDocMaxTab);
888 
889  while (maEndPos.Tab() > 0 && !mrDoc.maTabs[maEndPos.Tab()])
890  maEndPos.IncTab(-1); // Only the tables in use
891 
892  if (maStartPos.Tab() > maEndPos.Tab())
894 
895  if (!mrDoc.maTabs[maStartPos.Tab()])
896  {
897  assert(!"Table not found");
898  maStartPos = ScAddress(mrDoc.MaxCol()+1, mrDoc.MaxRow()+1, MAXTAB+1); // -> Abort on GetFirst.
899  }
900  else
901  {
902  maStartPos.SetCol(mrDoc.maTabs[maStartPos.Tab()]->ClampToAllocatedColumns(maStartPos.Col()));
903  }
904 
906 }
907 
909 {
910  const ScColumn* pCol = getColumn();
911 
912  while (true)
913  {
914  bool bNextColumn = maCurColPos.first == pCol->maCells.end();
915  if (!bNextColumn)
916  {
917  if (maCurPos.Row() > maEndPos.Row())
918  bNextColumn = true;
919  }
920 
921  if (bNextColumn)
922  {
923  // Move to the next column.
925  do
926  {
927  maCurPos.IncCol();
929  || maCurPos.Col() > maEndPos.Col())
930  {
932  maCurPos.IncTab();
933  if (maCurPos.Tab() > maEndPos.Tab())
934  {
935  maCurCell.clear();
936  return false; // Over and out
937  }
938  }
939  pCol = getColumn();
940  }
941  while (pCol->IsEmptyData());
942 
943  maCurColPos = pCol->maCells.position(maCurPos.Row());
944  }
945 
946  if (maCurColPos.first->type == sc::element_type_empty)
947  {
948  incBlock();
949  continue;
950  }
951 
952  SCROW nLastRow;
953  // Skip all filtered or hidden rows, depending on mSubTotalFlags
955  pCol->GetDoc().RowFiltered(maCurPos.Row(), maCurPos.Tab(), nullptr, &nLastRow) ) ||
957  pCol->GetDoc().RowHidden(maCurPos.Row(), maCurPos.Tab(), nullptr, &nLastRow) ) )
958  {
959  setPos(nLastRow+1);
960  continue;
961  }
962 
963  if (maCurColPos.first->type == sc::element_type_formula)
964  {
966  {
967  ScFormulaCell* pCell = sc::formula_block::at(*maCurColPos.first->data, maCurColPos.second);
968  // Skip formula cells with Subtotal formulae or errors, depending on mnSubTotalFlags
969  if ( ( ( mnSubTotalFlags & SubtotalFlags::IgnoreNestedStAg ) && pCell->IsSubTotal() ) ||
970  ( ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) && pCell->GetErrCode() != FormulaError::NONE ) )
971  {
972  incPos();
973  continue;
974  }
975  }
976  }
977 
979  return true;
980  }
981  return false;
982 }
983 
985 {
986  return maCurCell.getString(&mrDoc);
987 }
988 
990 {
991  ScCellValue aRet;
992  aRet.meType = maCurCell.meType;
993 
994  switch (maCurCell.meType)
995  {
996  case CELLTYPE_STRING:
998  break;
999  case CELLTYPE_EDIT:
1000  aRet.mpEditText = maCurCell.mpEditText->Clone().release();
1001  break;
1002  case CELLTYPE_VALUE:
1003  aRet.mfValue = maCurCell.mfValue;
1004  break;
1005  case CELLTYPE_FORMULA:
1006  aRet.mpFormula = maCurCell.mpFormula->Clone();
1007  break;
1008  default:
1009  ;
1010  }
1011 
1012  return aRet;
1013 }
1014 
1016 {
1017  return maCurCell.hasString();
1018 }
1019 
1021 {
1022  return maCurCell.isEmpty();
1023 }
1024 
1026 {
1027  ScRefCellValue aOther(mrDoc, rPos);
1028  return maCurCell.equalsWithoutFormat(aOther);
1029 }
1030 
1032 {
1033  if (!ValidTab(maCurPos.Tab()))
1034  return false;
1035 
1036  maCurPos = maStartPos;
1037  const ScColumn* pCol = getColumn();
1038 
1039  maCurColPos = pCol->maCells.position(maCurPos.Row());
1040  return getCurrent();
1041 }
1042 
1044 {
1045  incPos();
1046  return getCurrent();
1047 }
1048 
1050  const ScQueryParam& rParam, bool bMod ) :
1051  maParam(rParam),
1052  rDoc( rDocument ),
1053  mrContext( rContext ),
1054  nTab( nTable),
1055  nStopOnMismatch( nStopOnMismatchDisabled ),
1056  nTestEqualCondition( nTestEqualConditionDisabled ),
1057  bAdvanceQuery( false ),
1058  bIgnoreMismatchOnLeadingStrings( false )
1059 {
1060  nCol = maParam.nCol1;
1061  nRow = maParam.nRow1;
1062  SCSIZE i;
1063  if (!bMod) // Or else it's already inserted
1064  return;
1065 
1067  for (i = 0; (i < nCount) && (maParam.GetEntry(i).bDoQuery); ++i)
1068  {
1069  ScQueryEntry& rEntry = maParam.GetEntry(i);
1070  ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
1071  sal_uInt32 nIndex = 0;
1072  bool bNumber = mrContext.GetFormatTable()->IsNumberFormat(
1073  rItem.maString.getString(), nIndex, rItem.mfVal);
1075  }
1076 }
1077 
1079 {
1080  nRow = maParam.nRow1;
1082  ++nRow;
1083  const ScColumn& rCol = rDoc.maTabs[nTab]->CreateColumnIfNotExists(nCol);
1084  maCurPos = rCol.maCells.position(nRow);
1085 }
1086 
1088 {
1089  if (maCurPos.second + 1 < maCurPos.first->size)
1090  {
1091  // Move within the same block.
1092  ++maCurPos.second;
1093  ++nRow;
1094  }
1095  else
1096  // Move to the next block.
1097  IncBlock();
1098 }
1099 
1101 {
1102  ++maCurPos.first;
1103  maCurPos.second = 0;
1104 
1105  nRow = maCurPos.first->position;
1106 }
1107 
1109 {
1110  assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
1111  const ScQueryEntry& rEntry = maParam.GetEntry(0);
1112  const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
1113 
1114  SCCOLROW nFirstQueryField = rEntry.nField;
1115  bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1116  rItem.meType != ScQueryEntry::ByString;
1117  bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1119  ((maParam.bByRow && nRow == maParam.nRow1) ||
1120  (!maParam.bByRow && nCol == maParam.nCol1));
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) )
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 
1511  ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
1512  while (true)
1513  {
1514  bool bNextColumn = maCurPos.first == pCol->maCells.end();
1515  if (!bNextColumn)
1516  {
1517  if (nRow > maParam.nRow2)
1518  bNextColumn = true;
1519  }
1520 
1521  if (bNextColumn)
1522  {
1523  do
1524  {
1525  ++nCol;
1526  if (nCol > maParam.nCol2 || nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
1527  return count; // Over and out
1529  pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
1530  }
1531  while (!rItem.mbMatchEmpty && pCol->IsEmptyData());
1532 
1533  InitPos();
1534  }
1535 
1536  if (maCurPos.first->type == sc::element_type_empty)
1537  {
1538  if (rItem.mbMatchEmpty && bSingleQueryItem)
1539  {
1540  // This shortcut, instead of determining if any SC_OR query
1541  // exists or this query is SC_AND'ed (which wouldn't make
1542  // sense, but..) and evaluating them in ValidQuery(), is
1543  // possible only because the interpreter is the only caller
1544  // that sets mbMatchEmpty and there is only one item in those
1545  // cases.
1546  // XXX this would have to be reworked if other filters used it
1547  // in different manners and evaluation would have to be done in
1548  // ValidQuery().
1549  count++;
1550  IncPos();
1551  continue;
1552  }
1553  else
1554  {
1555  IncBlock();
1556  continue;
1557  }
1558  }
1559 
1560  ScRefCellValue aCell = sc::toRefCell(maCurPos.first, maCurPos.second);
1561 
1562  if ( rDoc.maTabs[nTab]->ValidQuery( nRow, maParam,
1563  (nCol == static_cast<SCCOL>(rEntry.nField) ? &aCell : nullptr),
1564  nullptr,
1565  &mrContext) )
1566  {
1567  if (aCell.isEmpty())
1568  return count;
1569  count++;
1570  IncPos();
1571  continue;
1572  }
1573  else
1574  IncPos();
1575  }
1576  return count;
1577 }
1578 
1580 {
1581  SCSIZE nEntries = maParam.GetEntryCount();
1582  for ( SCSIZE j = 0; j < nEntries; j++ )
1583  {
1584  ScQueryEntry& rEntry = maParam.GetEntry( j );
1585  if ( rEntry.bDoQuery )
1586  {
1587  if ( rEntry.nField < rDoc.MaxCol() )
1588  rEntry.nField++;
1589  else
1590  {
1591  OSL_FAIL( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
1592  }
1593  }
1594  else
1595  break; // for
1596  }
1597 }
1598 
1599 namespace {
1600 
1610 class NonEmptyCellIndexer
1611 {
1612  typedef std::map<size_t, sc::CellStoreType::const_iterator> BlockMapType;
1613 
1614  BlockMapType maBlockMap;
1615 
1616  const sc::CellStoreType& mrCells;
1617 
1618  size_t mnLowIndex;
1619  size_t mnHighIndex;
1620 
1621  bool mbValid;
1622 
1623 public:
1624 
1625  typedef std::pair<ScRefCellValue, SCROW> CellType;
1626 
1633  NonEmptyCellIndexer(
1634  const sc::CellStoreType& rCells, SCROW nStartRow, SCROW nEndRow, bool bSkipTopStrBlock ) :
1635  mrCells(rCells), mnLowIndex(0), mnHighIndex(0), mbValid(true)
1636  {
1637  if (nEndRow < nStartRow)
1638  {
1639  mbValid = false;
1640  return;
1641  }
1642 
1643  // Find the low position.
1644 
1645  sc::CellStoreType::const_position_type aLoPos = mrCells.position(nStartRow);
1646  if (aLoPos.first->type == sc::element_type_empty)
1647  incBlock(aLoPos);
1648 
1649  if (aLoPos.first == rCells.end())
1650  {
1651  mbValid = false;
1652  return;
1653  }
1654 
1655  if (bSkipTopStrBlock)
1656  {
1657  // Skip all leading string or empty blocks.
1658  while (aLoPos.first->type == sc::element_type_string ||
1659  aLoPos.first->type == sc::element_type_edittext ||
1660  aLoPos.first->type == sc::element_type_empty)
1661  {
1662  incBlock(aLoPos);
1663  if (aLoPos.first == rCells.end())
1664  {
1665  mbValid = false;
1666  return;
1667  }
1668  }
1669  }
1670 
1671  SCROW nFirstRow = aLoPos.first->position;
1672  SCROW nLastRow = aLoPos.first->position + aLoPos.first->size - 1;
1673 
1674  if (nFirstRow > nEndRow)
1675  {
1676  // Both start and end row positions are within the leading skipped
1677  // blocks.
1678  mbValid = false;
1679  return;
1680  }
1681 
1682  // Calculate the index of the low position.
1683  if (nFirstRow < nStartRow)
1684  mnLowIndex = nStartRow - nFirstRow;
1685  else
1686  {
1687  // Start row is within the skipped block(s). Set it to the first
1688  // element of the low block.
1689  mnLowIndex = 0;
1690  }
1691 
1692  if (nEndRow < nLastRow)
1693  {
1694  assert(nEndRow >= nFirstRow);
1695  mnHighIndex = nEndRow - nFirstRow;
1696 
1697  maBlockMap.emplace(aLoPos.first->size, aLoPos.first);
1698  return;
1699  }
1700 
1701  // Find the high position.
1702 
1703  sc::CellStoreType::const_position_type aHiPos = mrCells.position(aLoPos.first, nEndRow);
1704  if (aHiPos.first->type == sc::element_type_empty)
1705  {
1706  // Move to the last position of the previous block.
1707  decBlock(aHiPos);
1708 
1709  // Check the row position of the end of the previous block, and make sure it's valid.
1710  SCROW nBlockEndRow = aHiPos.first->position + aHiPos.first->size - 1;
1711  if (nBlockEndRow < nStartRow)
1712  {
1713  mbValid = false;
1714  return;
1715  }
1716  }
1717 
1718  // Tag the start and end blocks, and all blocks in between in order
1719  // but skip all empty blocks.
1720 
1721  size_t nPos = 0;
1722  sc::CellStoreType::const_iterator itBlk = aLoPos.first;
1723  while (itBlk != aHiPos.first)
1724  {
1725  if (itBlk->type == sc::element_type_empty)
1726  {
1727  ++itBlk;
1728  continue;
1729  }
1730 
1731  nPos += itBlk->size;
1732  maBlockMap.emplace(nPos, itBlk);
1733  ++itBlk;
1734 
1735  if (itBlk->type == sc::element_type_empty)
1736  ++itBlk;
1737 
1738  assert(itBlk != mrCells.end());
1739  }
1740 
1741  assert(itBlk == aHiPos.first);
1742  nPos += itBlk->size;
1743  maBlockMap.emplace(nPos, itBlk);
1744 
1745  // Calculate the high index.
1746  BlockMapType::const_reverse_iterator ri = maBlockMap.rbegin();
1747  mnHighIndex = ri->first;
1748  mnHighIndex -= ri->second->size;
1749  mnHighIndex += aHiPos.second;
1750  }
1751 
1752  sc::CellStoreType::const_position_type getPosition( size_t nIndex ) const
1753  {
1754  assert(mbValid);
1755  assert(mnLowIndex <= nIndex);
1756  assert(nIndex <= mnHighIndex);
1757 
1758  sc::CellStoreType::const_position_type aRet(mrCells.end(), 0);
1759 
1760  BlockMapType::const_iterator it = maBlockMap.upper_bound(nIndex);
1761  if (it == maBlockMap.end())
1762  return aRet;
1763 
1764  sc::CellStoreType::const_iterator itBlk = it->second;
1765  size_t nBlkIndex = it->first - itBlk->size; // index of the first element of the block.
1766  assert(nBlkIndex <= nIndex);
1767  assert(nIndex < it->first);
1768 
1769  size_t nOffset = nIndex - nBlkIndex;
1770  aRet.first = itBlk;
1771  aRet.second = nOffset;
1772  return aRet;
1773  }
1774 
1775  CellType getCell( size_t nIndex ) const
1776  {
1777  std::pair<ScRefCellValue, SCROW> aRet;
1778  aRet.second = -1;
1779 
1780  sc::CellStoreType::const_position_type aPos = getPosition(nIndex);
1781  if (aPos.first == mrCells.end())
1782  return aRet;
1783 
1784  aRet.first = sc::toRefCell(aPos.first, aPos.second);
1785  aRet.second = aPos.first->position + aPos.second;
1786  return aRet;
1787  }
1788 
1789  size_t getLowIndex() const { return mnLowIndex; }
1790 
1791  size_t getHighIndex() const { return mnHighIndex; }
1792 
1793  bool isValid() const { return mbValid; }
1794 };
1795 
1796 }
1797 
1799 {
1800  // TODO: This will be extremely slow with mdds::multi_type_vector.
1801 
1802  assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
1803  nCol = maParam.nCol1;
1804 
1805  if (nCol >= rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
1806  return false;
1807 
1808  ScColumn* pCol = &(rDoc.maTabs[nTab])->aCol[nCol];
1809  if (pCol->IsEmptyData())
1810  return false;
1811 
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;
1836  ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, rDoc);
1837  sal_Int32 nTmp = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
1838  if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
1839  (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
1840  (rEntry.eOp == SC_EQUAL && nTmp != 0))
1841  ++nRow;
1842  }
1843  }
1844 
1845  NonEmptyCellIndexer aIndexer(pCol->maCells, nRow, maParam.nRow2, bAllStringIgnore);
1846  if (!aIndexer.isValid())
1847  return false;
1848 
1849  size_t nLo = aIndexer.getLowIndex();
1850  size_t nHi = aIndexer.getHighIndex();
1851  NonEmptyCellIndexer::CellType aCellData;
1852 
1853  // Bookkeeping values for breaking up the binary search in case the data
1854  // range isn't strictly sorted.
1855  size_t nLastInRange = nLo;
1856  size_t nFirstLastInRange = nLastInRange;
1857  double fLastInRangeValue = bLessEqual ?
1858  -(::std::numeric_limits<double>::max()) :
1859  ::std::numeric_limits<double>::max();
1860  OUString aLastInRangeString;
1861  if (!bLessEqual)
1862  aLastInRangeString = OUString(u'\xFFFF');
1863 
1864  aCellData = aIndexer.getCell(nLastInRange);
1865  aCell = aCellData.first;
1866  if (aCell.hasString())
1867  {
1868  sal_uInt32 nFormat = pCol->GetNumberFormat(mrContext, aCellData.second);
1869  OUString aStr;
1870  ScCellFormat::GetInputString(aCell, nFormat, aStr, rFormatter, rDoc);
1871  aLastInRangeString = aStr;
1872  }
1873  else
1874  {
1875  switch (aCell.meType)
1876  {
1877  case CELLTYPE_VALUE :
1878  fLastInRangeValue = aCell.mfValue;
1879  break;
1880  case CELLTYPE_FORMULA :
1881  fLastInRangeValue = aCell.mpFormula->GetValue();
1882  break;
1883  default:
1884  {
1885  // added to avoid warnings
1886  }
1887  }
1888  }
1889 
1890  sal_Int32 nRes = 0;
1891  bool bFound = false;
1892  bool bDone = false;
1893  while (nLo <= nHi && !bDone)
1894  {
1895  size_t nMid = (nLo+nHi)/2;
1896  size_t i = nMid;
1897 
1898  aCellData = aIndexer.getCell(i);
1899  aCell = aCellData.first;
1900  bool bStr = aCell.hasString();
1901  nRes = 0;
1902 
1903  // compares are content<query:-1, content>query:1
1904  // Cell value comparison similar to ScTable::ValidQuery()
1905  if (!bStr && !bByString)
1906  {
1907  double nCellVal;
1908  switch (aCell.meType)
1909  {
1910  case CELLTYPE_VALUE :
1911  case CELLTYPE_FORMULA :
1912  nCellVal = aCell.getValue();
1913  break;
1914  default:
1915  nCellVal = 0.0;
1916  }
1917  if ((nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(
1918  nCellVal, rItem.mfVal))
1919  {
1920  nRes = -1;
1921  if (bLessEqual)
1922  {
1923  if (fLastInRangeValue < nCellVal)
1924  {
1925  fLastInRangeValue = nCellVal;
1926  nLastInRange = i;
1927  }
1928  else if (fLastInRangeValue > nCellVal)
1929  {
1930  // not strictly sorted, continue with GetThis()
1931  nLastInRange = nFirstLastInRange;
1932  bDone = true;
1933  }
1934  }
1935  }
1936  else if ((nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(
1937  nCellVal, rItem.mfVal))
1938  {
1939  nRes = 1;
1940  if (!bLessEqual)
1941  {
1942  if (fLastInRangeValue > nCellVal)
1943  {
1944  fLastInRangeValue = nCellVal;
1945  nLastInRange = i;
1946  }
1947  else if (fLastInRangeValue < nCellVal)
1948  {
1949  // not strictly sorted, continue with GetThis()
1950  nLastInRange = nFirstLastInRange;
1951  bDone = true;
1952  }
1953  }
1954  }
1955  }
1956  else if (bStr && bByString)
1957  {
1958  OUString aCellStr;
1959  sal_uInt32 nFormat = pCol->GetNumberFormat(mrContext, aCellData.second);
1960  ScCellFormat::GetInputString(aCell, nFormat, aCellStr, rFormatter, rDoc);
1961 
1962  nRes = pCollator->compareString(aCellStr, rEntry.GetQueryItem().maString.getString());
1963  if (nRes < 0 && bLessEqual)
1964  {
1965  sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1966  aCellStr);
1967  if (nTmp < 0)
1968  {
1969  aLastInRangeString = aCellStr;
1970  nLastInRange = i;
1971  }
1972  else if (nTmp > 0)
1973  {
1974  // not strictly sorted, continue with GetThis()
1975  nLastInRange = nFirstLastInRange;
1976  bDone = true;
1977  }
1978  }
1979  else if (nRes > 0 && !bLessEqual)
1980  {
1981  sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1982  aCellStr);
1983  if (nTmp > 0)
1984  {
1985  aLastInRangeString = aCellStr;
1986  nLastInRange = i;
1987  }
1988  else if (nTmp < 0)
1989  {
1990  // not strictly sorted, continue with GetThis()
1991  nLastInRange = nFirstLastInRange;
1992  bDone = true;
1993  }
1994  }
1995  }
1996  else if (!bStr && bByString)
1997  {
1998  nRes = -1; // numeric < string
1999  if (bLessEqual)
2000  nLastInRange = i;
2001  }
2002  else // if (bStr && !bByString)
2003  {
2004  nRes = 1; // string > numeric
2005  if (!bLessEqual)
2006  nLastInRange = i;
2007  }
2008  if (nRes < 0)
2009  {
2010  if (bLessEqual)
2011  nLo = nMid + 1;
2012  else // assumed to be SC_GREATER_EQUAL
2013  {
2014  if (nMid > 0)
2015  nHi = nMid - 1;
2016  else
2017  bDone = true;
2018  }
2019  }
2020  else if (nRes > 0)
2021  {
2022  if (bLessEqual)
2023  {
2024  if (nMid > 0)
2025  nHi = nMid - 1;
2026  else
2027  bDone = true;
2028  }
2029  else // assumed to be SC_GREATER_EQUAL
2030  nLo = nMid + 1;
2031  }
2032  else
2033  {
2034  nLo = i;
2035  bDone = bFound = true;
2036  }
2037  }
2038 
2039  if (!bFound)
2040  {
2041  // If all hits didn't result in a moving limit there's something
2042  // strange, e.g. data range not properly sorted, or only identical
2043  // values encountered, which doesn't mean there aren't any others in
2044  // between... leave it to GetThis(). The condition for this would be
2045  // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
2046  // Else, in case no exact match was found, we step back for a
2047  // subsequent GetThis() to find the last in range. Effectively this is
2048  // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
2049  nLo = nLastInRange;
2050  }
2051 
2052  aCellData = aIndexer.getCell(nLo);
2053  if (nLo <= nHi && aCellData.second <= maParam.nRow2)
2054  {
2055  nRow = aCellData.second;
2056  maCurPos = aIndexer.getPosition(nLo);
2057  return true;
2058  }
2059  else
2060  {
2061  nRow = maParam.nRow2 + 1;
2062  // Set current position to the last possible row.
2063  maCurPos.first = pCol->maCells.end();
2064  --maCurPos.first;
2065  maCurPos.second = maCurPos.first->size - 1;
2066  return false;
2067  }
2068 }
2069 
2071  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
2072  rDoc( rDocument ),
2073  mnTab( nTable ),
2074  nStartCol( nCol1 ),
2075  nEndCol( nCol2 ),
2076  nStartRow( nRow1 ),
2077  nEndRow( nRow2 ),
2078  mnCol( nCol1 ),
2079  mnRow( nRow1 ),
2080  mbMore( false )
2081 {
2082  assert(mnTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
2083 
2084  nEndCol = rDoc.maTabs[mnTab]->ClampToAllocatedColumns(nEndCol);
2085  if (nEndCol < nStartCol) // E.g., somewhere completely outside allocated area
2086  nEndCol = nStartCol - 1; // Empty
2087 
2088  maColPositions.reserve( nEndCol-nStartCol+1 );
2089 
2090  SetTab( mnTab );
2091 }
2092 
2094 {
2095 }
2096 
2098 {
2099  mbMore = false;
2100  mnTab = nTabP;
2101  mnRow = nStartRow;
2102  mnCol = nStartCol;
2103  maColPositions.resize(0);
2104 
2105  // Set the start position in each column.
2106  for (SCCOL i = nStartCol; i <= nEndCol; ++i)
2107  {
2108  ScColumn* pCol = &rDoc.maTabs[mnTab]->aCol[i];
2109  ColParam aParam;
2110  aParam.maPos = pCol->maCells.position(nStartRow).first;
2111  aParam.maEnd = pCol->maCells.end();
2112  aParam.mnCol = i;
2113 
2114  // find first non-empty element.
2115  while (aParam.maPos != aParam.maEnd) {
2116  if (aParam.maPos->type == sc::element_type_empty)
2117  ++aParam.maPos;
2118  else
2119  {
2120  maColPositions.push_back( aParam );
2121  break;
2122  }
2123  }
2124  }
2125 
2126  if (maColPositions.empty())
2127  return;
2128 
2129  maColPos = maColPositions.begin();
2130  mbMore = true;
2131  SkipInvalid();
2132 }
2133 
2135 {
2136  if (!mbMore)
2137  {
2138  debugiter("no more !\n");
2139  return nullptr;
2140  }
2141 
2142  // Return the current non-empty cell, and move the cursor to the next one.
2143  ColParam& r = *maColPos;
2144 
2145  rCol = mnCol = r.mnCol;
2146  rRow = mnRow;
2147  debugiter("return col %d row %d\n", (int)rCol, (int)rRow);
2148 
2149  size_t nOffset = static_cast<size_t>(mnRow) - r.maPos->position;
2150  maCurCell = sc::toRefCell(r.maPos, nOffset);
2151  Advance();
2152  debugiter("advance to: col %d row %d\n", (int)maColPos->mnCol, (int)mnRow);
2153 
2154  return &maCurCell;
2155 }
2156 
2158 {
2159  rCol = mnCol;
2160  rRow = mnRow;
2161  return mbMore;
2162 }
2163 
2164 // Skip any invalid / empty cells across the current row,
2165 // we only advance the cursor if the current entry is invalid.
2166 // if we return true we have a valid cursor (or hit the end)
2168 {
2169  assert (mbMore);
2170  assert (maColPos != maColPositions.end());
2171 
2172  // Find the next non-empty cell in the current row.
2173  while( maColPos != maColPositions.end() )
2174  {
2175  ColParam& r = *maColPos;
2176  assert (r.maPos != r.maEnd);
2177 
2178  size_t nRow = static_cast<size_t>(mnRow);
2179 
2180  if (nRow >= r.maPos->position)
2181  {
2182  if (nRow < r.maPos->position + r.maPos->size)
2183  {
2184  mnCol = maColPos->mnCol;
2185  debugiter("found valid cell at column %d, row %d\n",
2186  (int)mnCol, (int)mnRow);
2187  assert(r.maPos->type != sc::element_type_empty);
2188  return true;
2189  }
2190  else
2191  {
2192  bool bMoreBlocksInColumn = false;
2193  // This block is behind the current row position. Advance the block.
2194  for (++r.maPos; r.maPos != r.maEnd; ++r.maPos)
2195  {
2196  if (nRow < r.maPos->position + r.maPos->size &&
2197  r.maPos->type != sc::element_type_empty)
2198  {
2199  bMoreBlocksInColumn = true;
2200  break;
2201  }
2202  }
2203  if (!bMoreBlocksInColumn)
2204  {
2205  debugiter("remove column %d at row %d\n",
2206  (int)maColPos->mnCol, (int)nRow);
2207  maColPos = maColPositions.erase(maColPos);
2208  if (maColPositions.empty())
2209  {
2210  debugiter("no more columns\n");
2211  mbMore = false;
2212  }
2213  }
2214  else
2215  {
2216  debugiter("advanced column %d to block starting row %d, retrying\n",
2217  (int)maColPos->mnCol, r.maPos->position);
2218  }
2219  }
2220  }
2221  else
2222  {
2223  debugiter("skip empty cells at column %d, row %d\n",
2224  (int)maColPos->mnCol, (int)nRow);
2225  ++maColPos;
2226  }
2227  }
2228 
2229  // No more columns with anything interesting in them ?
2230  if (maColPositions.empty())
2231  {
2232  debugiter("no more live columns left - done\n");
2233  mbMore = false;
2234  return true;
2235  }
2236 
2237  return false;
2238 }
2239 
2242 {
2243  size_t nNextRow = rDoc.MaxRow()+1;
2244 
2245  for (const ColParam& r : maColPositions)
2246  {
2247  assert(o3tl::make_unsigned(mnRow) <= r.maPos->position);
2248  nNextRow = std::min (nNextRow, static_cast<size_t>(r.maPos->position));
2249  }
2250 
2251  SCROW nRow = std::max(static_cast<SCROW>(nNextRow), mnRow);
2252  debugiter("Next non empty row is %d\n", (int) nRow);
2253  return nRow;
2254 }
2255 
2257 {
2258  assert (mbMore);
2259  assert (maColPos != maColPositions.end());
2260 
2261  ++maColPos;
2262 
2263  SkipInvalid();
2264 }
2265 
2267 {
2268  if (maColPos == maColPositions.end() ||
2269  !SkipInvalidInRow())
2270  {
2271  mnRow++;
2272 
2273  if (mnRow > nEndRow)
2274  {
2275  mbMore = false;
2276  return;
2277  }
2278 
2279  maColPos = maColPositions.begin();
2280  debugiter("moving to next row\n");
2281  if (SkipInvalidInRow())
2282  {
2283  debugiter("moved to valid cell in next row (or end)\n");
2284  return;
2285  }
2286 
2288  maColPos = maColPositions.begin();
2289  bool bCorrect = SkipInvalidInRow();
2290  assert (bCorrect); (void) bCorrect;
2291  }
2292 
2293  if (mnRow > nEndRow)
2294  mbMore = false;
2295 }
2296 
2298  const ScRange& rRange ) :
2299  rDoc( rDocument ),
2300  nEndTab( rRange.aEnd.Tab() ),
2301  bCalcAsShown( rDocument.GetDocOptions().IsCalcAsShown() )
2302 {
2303  SCCOL nStartCol = rRange.aStart.Col();
2304  SCROW nStartRow = rRange.aStart.Row();
2305  SCTAB nStartTab = rRange.aStart.Tab();
2306  SCCOL nEndCol = rRange.aEnd.Col();
2307  SCROW nEndRow = rRange.aEnd.Row();
2308  PutInOrder( nStartCol, nEndCol);
2309  PutInOrder( nStartRow, nEndRow);
2310  PutInOrder( nStartTab, nEndTab );
2311 
2312  if (!rDoc.ValidCol(nStartCol)) nStartCol = rDoc.MaxCol();
2313  if (!rDoc.ValidCol(nEndCol)) nEndCol = rDoc.MaxCol();
2314  if (!rDoc.ValidRow(nStartRow)) nStartRow = rDoc.MaxRow();
2315  if (!rDoc.ValidRow(nEndRow)) nEndRow = rDoc.MaxRow();
2316  if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
2317  if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
2318 
2319  nCurCol = nStartCol;
2320  nCurRow = nStartRow;
2321  nCurTab = nStartTab;
2322 
2323  nNumFormat = 0; // Will be initialized in GetNumberFormat()
2324  pAttrArray = nullptr;
2325  nAttrEndRow = 0;
2326 
2327  pCellIter.reset( new ScHorizontalCellIterator( rDoc, nStartTab, nStartCol,
2328  nStartRow, nEndCol, nEndRow ) );
2329 }
2330 
2332 {
2333 }
2334 
2336 {
2337  bool bFound = false;
2338  while ( !bFound )
2339  {
2340  ScRefCellValue* pCell = pCellIter->GetNext( nCurCol, nCurRow );
2341  while ( !pCell )
2342  {
2343  if ( nCurTab < nEndTab )
2344  {
2345  pCellIter->SetTab( ++nCurTab);
2346  pCell = pCellIter->GetNext( nCurCol, nCurRow );
2347  }
2348  else
2349  return false;
2350  }
2351  switch (pCell->meType)
2352  {
2353  case CELLTYPE_VALUE:
2354  {
2355  rValue = pCell->mfValue;
2356  rErr = FormulaError::NONE;
2357  if ( bCalcAsShown )
2358  {
2359  ScColumn* pCol = &rDoc.maTabs[nCurTab]->aCol[nCurCol];
2361  nAttrEndRow, pCol->pAttrArray.get(), nCurRow, rDoc );
2362  rValue = rDoc.RoundValueAsShown( rValue, nNumFormat );
2363  }
2364  bFound = true;
2365  }
2366  break;
2367  case CELLTYPE_FORMULA:
2368  {
2369  rErr = pCell->mpFormula->GetErrCode();
2370  if (rErr != FormulaError::NONE || pCell->mpFormula->IsValue())
2371  {
2372  rValue = pCell->mpFormula->GetValue();
2373  bFound = true;
2374  }
2375  }
2376  break;
2377  case CELLTYPE_STRING :
2378  case CELLTYPE_EDIT :
2379  break;
2380  default: ; // nothing
2381  }
2382  }
2383  return bFound;
2384 }
2385 
2387  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
2388  rDoc( rDocument ),
2389  nTab( nTable ),
2390  nStartCol( nCol1 ),
2391  nStartRow( nRow1 ),
2392  nEndCol( nCol2 ),
2393  nEndRow( nRow2 )
2394 {
2395  assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
2396  assert(rDoc.maTabs[nTab]);
2397 
2398  nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
2399 
2400  nRow = nStartRow;
2401  nCol = nStartCol;
2402  bRowEmpty = false;
2403 
2404  pIndices.reset( new SCSIZE[nEndCol-nStartCol+1] );
2405  pNextEnd.reset( new SCROW[nEndCol-nStartCol+1] );
2406  pHorizEnd.reset( new SCCOL[nEndCol-nStartCol+1] );
2407  ppPatterns.reset( new const ScPatternAttr*[nEndCol-nStartCol+1] );
2408 
2409  InitForNextRow(true);
2410 }
2411 
2413 {
2414 }
2415 
2417 {
2418  bool bEmpty = true;
2419  nMinNextEnd = rDoc.MaxRow();
2420  SCCOL nThisHead = 0;
2421 
2422  for (SCCOL i=nStartCol; i<=nEndCol; i++)
2423  {
2424  SCCOL nPos = i - nStartCol;
2425  if ( bInitialization || pNextEnd[nPos] < nRow )
2426  {
2427  const ScAttrArray* pArray = rDoc.maTabs[nTab]->aCol[i].pAttrArray.get();
2428  assert(pArray);
2429 
2430  SCSIZE nIndex;
2431  if (bInitialization)
2432  {
2433  if ( pArray->Count() )
2434  pArray->Search( nStartRow, nIndex );
2435  else
2436  nIndex = 0;
2437  pIndices[nPos] = nIndex;
2438  pHorizEnd[nPos] = rDoc.MaxCol()+1; // only for assert()
2439  }
2440  else
2441  nIndex = ++pIndices[nPos];
2442 
2443  if ( !nIndex && !pArray->Count() )
2444  {
2445  pNextEnd[nPos] = rDoc.MaxRow();
2446  assert( pNextEnd[nPos] >= nRow && "Sequence out of order" );
2447  ppPatterns[nPos] = nullptr;
2448  }
2449  else if ( nIndex < pArray->Count() )
2450  {
2451  const ScPatternAttr* pPattern = pArray->mvData[nIndex].pPattern;
2452  SCROW nThisEnd = pArray->mvData[nIndex].nEndRow;
2453 
2454  if ( IsDefaultItem( pPattern ) )
2455  pPattern = nullptr;
2456  else
2457  bEmpty = false; // Found attributes
2458 
2459  pNextEnd[nPos] = nThisEnd;
2460  assert( pNextEnd[nPos] >= nRow && "Sequence out of order" );
2461  ppPatterns[nPos] = pPattern;
2462  }
2463  else
2464  {
2465  assert(!"AttrArray does not range to MAXROW");
2466  pNextEnd[nPos] = rDoc.MaxRow();
2467  ppPatterns[nPos] = nullptr;
2468  }
2469  }
2470  else if ( ppPatterns[nPos] )
2471  bEmpty = false; // Area not at the end yet
2472 
2473  if ( nMinNextEnd > pNextEnd[nPos] )
2474  nMinNextEnd = pNextEnd[nPos];
2475 
2476  // store positions of ScHorizontalAttrIterator elements (minimizing expensive ScPatternAttr comparisons)
2477  if (i > nStartCol && ppPatterns[nThisHead] != ppPatterns[nPos])
2478  {
2479  pHorizEnd[nThisHead] = i - 1;
2480  nThisHead = nPos; // start position of the next horizontal group
2481  }
2482  }
2483 
2484  if (bEmpty)
2485  nRow = nMinNextEnd; // Skip until end of next section
2486  else
2487  pHorizEnd[nThisHead] = nEndCol; // set the end position of the last horizontal group, too
2488  bRowEmpty = bEmpty;
2489 }
2490 
2492 {
2493  if ( !ppPatterns[nCol-nStartCol] ) // Skip default items
2494  {
2495  assert( pHorizEnd[nCol-nStartCol] < rDoc.MaxCol()+1 && "missing stored data" );
2496  nCol = pHorizEnd[nCol-nStartCol] + 1;
2497  if ( nCol > nEndCol )
2498  return false;
2499  }
2500 
2501  return true;
2502 }
2503 
2505 {
2506  assert(nTab < rDoc.GetTableCount() && "index out of bounds, FIX IT");
2507  for (;;)
2508  {
2509  if ( !bRowEmpty && nCol <= nEndCol && InitForNextAttr() )
2510  {
2511  const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
2512  rRow = nRow;
2513  rCol1 = nCol;
2514  assert( pHorizEnd[nCol-nStartCol] < rDoc.MaxCol()+1 && "missing stored data" );
2515  nCol = pHorizEnd[nCol-nStartCol];
2516  rCol2 = nCol;
2517  ++nCol; // Count up for next call
2518  return pPat; // Found it!
2519  }
2520 
2521  // Next row
2522  ++nRow;
2523  if ( nRow > nEndRow ) // Already at the end?
2524  return nullptr; // Found nothing
2525  nCol = nStartCol; // Start at the left again
2526 
2527  if ( bRowEmpty || nRow > nMinNextEnd )
2528  InitForNextRow(false);
2529  }
2530 }
2531 
2532 static bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2533 {
2534  return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
2535 }
2536 
2538  SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2539  : aCellIter( rDocument, nTable, nCol1, nRow1, nCol2, nRow2 )
2540  , aAttrIter( rDocument, nTable, nCol1, nRow1, nCol2, nRow2 )
2541  , nNextCol( nCol1 )
2542  , nNextRow( nRow1 )
2543  , nCellCol( 0 )
2544  , nCellRow( 0 )
2545  , nAttrCol1( 0 )
2546  , nAttrCol2( 0 )
2547  , nAttrRow( 0 )
2548  , nFoundStartCol( 0 )
2549  , nFoundEndCol( 0 )
2550  , nFoundRow( 0 )
2551  , pFoundPattern( nullptr )
2552 {
2555 }
2556 
2558 {
2559 }
2560 
2562 {
2563  // Forward iterators
2566 
2567  while (pCell && pCell->isEmpty())
2569 
2572 
2573  if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
2574  nAttrCol1 = nNextCol;
2575 
2576  // Find next area
2577  bool bFound = true;
2578  bool bUseCell = false;
2579 
2580  if ( pCell && pPattern )
2581  {
2582  if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // Only attributes at the beginning?
2583  {
2584  maFoundCell.clear();
2586  nFoundRow = nAttrRow;
2588  if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // Area also contains cell?
2589  nFoundEndCol = nCellCol - 1; // Only until right before the cell
2590  else
2591  nFoundEndCol = nAttrCol2; // Everything
2592  }
2593  else
2594  {
2595  bUseCell = true;
2596  if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attributes on the cell?
2598  else
2599  pFoundPattern = nullptr;
2600  }
2601  }
2602  else if ( pCell ) // Just a cell -> take over right away
2603  {
2604  pFoundPattern = nullptr;
2605  bUseCell = true; // Cell position
2606  }
2607  else if ( pPattern ) // Just attributes -> take over right away
2608  {
2609  maFoundCell.clear();
2611  nFoundRow = nAttrRow;
2614  }
2615  else // Nothing
2616  bFound = false;
2617 
2618  if ( bUseCell ) // Cell position
2619  {
2620  if (pCell)
2621  maFoundCell = *pCell;
2622  else
2623  maFoundCell.clear();
2624 
2625  nFoundRow = nCellRow;
2627  }
2628 
2629  if (bFound)
2630  {
2631  nNextRow = nFoundRow;
2632  nNextCol = nFoundEndCol + 1;
2633  }
2634 
2635  return bFound;
2636 }
2637 
2639  SCCOL nCol1, SCROW nRow1,
2640  SCCOL nCol2, SCROW nRow2) :
2641  rDoc( rDocument ),
2642  nTab( nTable ),
2643  nEndCol( nCol2 ),
2644  nStartRow( nRow1 ),
2645  nEndRow( nRow2 ),
2646  nCol( nCol1 )
2647 {
2648  if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab]
2649  && nCol < rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
2650  {
2651  nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
2652  pColIter = rDoc.maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2653  }
2654 }
2655 
2657 {
2658 }
2659 
2661 {
2662  while ( pColIter )
2663  {
2664  const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2665  if ( pPattern )
2666  {
2667  rCol = nCol;
2668  return pPattern;
2669  }
2670 
2671  ++nCol;
2672  if ( nCol <= nEndCol )
2673  pColIter = rDoc.maTabs[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2674  else
2675  pColIter.reset();
2676  }
2677  return nullptr; // Nothing anymore
2678 }
2679 
2681  mnTab(nTab), maRanges(nMaxRow)
2682 {
2683 }
2684 
2685 ScDocRowHeightUpdater::ScDocRowHeightUpdater(ScDocument& rDoc, OutputDevice* pOutDev, double fPPTX, double fPPTY, const vector<TabRanges>* pTabRangesArray) :
2686  mrDoc(rDoc), mpOutDev(pOutDev), mfPPTX(fPPTX), mfPPTY(fPPTY), mpTabRangesArray(pTabRangesArray)
2687 {
2688 }
2689 
2691 {
2692  if (!mpTabRangesArray || mpTabRangesArray->empty())
2693  {
2694  // No ranges defined. Update all rows in all tables.
2695  updateAll();
2696  return;
2697  }
2698 
2699  sal_uLong nCellCount = 0;
2700  for (const auto& rTabRanges : *mpTabRangesArray)
2701  {
2702  const SCTAB nTab = rTabRanges.mnTab;
2703  if (!ValidTab(nTab) || nTab >= mrDoc.GetTableCount() || !mrDoc.maTabs[nTab])
2704  continue;
2705 
2707  ScFlatBoolRowSegments::RangeIterator aRangeItr(rTabRanges.maRanges);
2708  for (bool bFound = aRangeItr.getFirst(aData); bFound; bFound = aRangeItr.getNext(aData))
2709  {
2710  if (!aData.mbValue)
2711  continue;
2712 
2713  nCellCount += mrDoc.maTabs[nTab]->GetWeightedCount(aData.mnRow1, aData.mnRow2);
2714  }
2715  }
2716 
2717  ScProgress aProgress(mrDoc.GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING), nCellCount, true);
2718 
2719  Fraction aZoom(1, 1);
2720  sal_uLong nProgressStart = 0;
2721  for (const auto& rTabRanges : *mpTabRangesArray)
2722  {
2723  const SCTAB nTab = rTabRanges.mnTab;
2724  if (!ValidTab(nTab) || nTab >= mrDoc.GetTableCount() || !mrDoc.maTabs[nTab])
2725  continue;
2726 
2727  sc::RowHeightContext aCxt(mrDoc.MaxRow(), mfPPTX, mfPPTY, aZoom, aZoom, mpOutDev);
2729  ScFlatBoolRowSegments::RangeIterator aRangeItr(rTabRanges.maRanges);
2730  for (bool bFound = aRangeItr.getFirst(aData); bFound; bFound = aRangeItr.getNext(aData))
2731  {
2732  if (!aData.mbValue)
2733  continue;
2734 
2735  mrDoc.maTabs[nTab]->SetOptimalHeight(
2736  aCxt, aData.mnRow1, aData.mnRow2, true, &aProgress, nProgressStart);
2737 
2738  nProgressStart += mrDoc.maTabs[nTab]->GetWeightedCount(aData.mnRow1, aData.mnRow2);
2739  }
2740  }
2741 }
2742 
2744 {
2745  sal_uInt32 nCellCount = 0;
2746  for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab)
2747  {
2748  if (!ValidTab(nTab) || !mrDoc.maTabs[nTab])
2749  continue;
2750 
2751  nCellCount += mrDoc.maTabs[nTab]->GetWeightedCount();
2752  }
2753 
2754  ScProgress aProgress(mrDoc.GetDocumentShell(), ScResId(STR_PROGRESS_HEIGHTING), nCellCount, true);
2755 
2756  Fraction aZoom(1, 1);
2757  sc::RowHeightContext aCxt(mrDoc.MaxRow(), mfPPTX, mfPPTY, aZoom, aZoom, mpOutDev);
2758  sal_uLong nProgressStart = 0;
2759  for (SCTAB nTab = 0; nTab < mrDoc.GetTableCount(); ++nTab)
2760  {
2761  if (!ValidTab(nTab) || !mrDoc.maTabs[nTab])
2762  continue;
2763 
2764  mrDoc.maTabs[nTab]->SetOptimalHeight(aCxt, 0, mrDoc.MaxRow(), true, &aProgress, nProgressStart);
2765  nProgressStart += mrDoc.maTabs[nTab]->GetWeightedCount();
2766  }
2767 }
2768 
2770  SCCOL nCol1, SCROW nRow1,
2771  SCCOL nCol2, SCROW nRow2) :
2772  rDoc( rDocument ),
2773  nTab( nTable ),
2774  nEndCol( nCol2 ),
2775  nStartRow( nRow1 ),
2776  nEndRow( nRow2 ),
2777  nIterStartCol( nCol1 ),
2778  nIterEndCol( nCol1 )
2779 {
2780  if ( ValidTab(nTab) && nTab < rDoc.GetTableCount() && rDoc.maTabs[nTab]
2781  && nCol1 < rDoc.maTabs[nTab]->GetAllocatedColumnsCount())
2782  {
2783  nEndCol = rDoc.maTabs[nTab]->ClampToAllocatedColumns(nEndCol);
2784  pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2785  while ( nIterEndCol < nEndCol &&
2786  rDoc.maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2787  rDoc.maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2788  ++nIterEndCol;
2789  }
2790  else
2791  pColIter = nullptr;
2792 }
2793 
2795 {
2796 }
2797 
2799 {
2800  if (pColIter)
2801  {
2802  SCROW nNextRow = pColIter->GetNextRow();
2803  pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
2804  }
2805 }
2806 
2808  SCROW& rRow1, SCROW& rRow2 )
2809 {
2810  while ( pColIter )
2811  {
2812  const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2813  if ( pPattern )
2814  {
2815  rCol1 = nIterStartCol;
2816  rCol2 = nIterEndCol;
2817  return pPattern;
2818  }
2819 
2821  if ( nIterStartCol <= nEndCol )
2822  {
2824  pColIter = rDoc.maTabs[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2825  while ( nIterEndCol < nEndCol &&
2826  rDoc.maTabs[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2827  rDoc.maTabs[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2828  ++nIterEndCol;
2829  }
2830  else
2831  pColIter.reset();
2832  }
2833  return nullptr; // Nothing anymore
2834 }
2835 
2837  mrBreaks(rBreaks),
2838  maItr(rBreaks.begin()), maEnd(rBreaks.end())
2839 {
2840 }
2841 
2843 {
2844  maItr = mrBreaks.begin();
2845  return maItr == maEnd ? NOT_FOUND : *maItr;
2846 }
2847 
2849 {
2850  ++maItr;
2851  return maItr == maEnd ? NOT_FOUND : *maItr;
2852 }
2853 
2854 /* 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:101
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:2537
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:80
const size_t count(pCandidateA->getBorderLines().size())
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:984
bool isValidQuery(SCROW mnRow, const ScMatrix &rMat) const
Definition: dociter.cxx:617
ScAddress aStart
Definition: address.hxx:499
static void GetInputString(const ScRefCellValue &rCell, sal_uInt32 nFormat, OUString &rString, SvNumberFormatter &rFormatter, const ScDocument &rDoc, bool bFiltering=false)
Definition: cellform.cxx:118
std::unique_ptr< ScAttrArray > pAttrArray
Definition: column.hxx:130
ScRefCellValue * GetNext(SCCOL &rCol, SCROW &rRow)
Definition: dociter.cxx:2134
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
ScDocument & GetDoc() const
Definition: column.hxx:183
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:2685
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:71
DataAccessMatrix(ScDBQueryParamMatrix *pParam)
Definition: dociter.cxx:529
ScTable * FetchTable(SCTAB nTab)
Definition: document.cxx:2497
ScDocument & rDoc
Definition: dociter.hxx:397
rtl_uString * getDataIgnoreCase()
bool isEmpty() const
Definition: cellvalue.cxx:670
ScColumn * FetchColumn(SCCOL nCol)
Definition: table2.cxx:1089
ScFormulaCell * Clone() const
virtual bool getFirst(Value &rValue) override
Definition: dociter.cxx:486
const ScInterpreterContext & mrContext
Definition: dociter.hxx:377
sal_uIntPtr sal_uLong
bool GetPos(SCCOL &rCol, SCROW &rRow)
Definition: dociter.cxx:2157
bool equalsWithoutFormat(const ScAddress &rPos) const
Definition: dociter.cxx:1025
ScRefCellValue maCurCell
Definition: dociter.hxx:457
::std::set< SCROW >::const_iterator maEnd
Definition: dociter.hxx:587
sal_Int64 n
QueryItemsType & GetQueryItems()
Definition: queryentry.hxx:65
bool bTextAsZero
Definition: dociter.hxx:69
bool getCurrent()
Definition: dociter.cxx:908
std::unique_ptr< ScAttrIterator > pColIter
Definition: dociter.hxx:404
static SC_DLLPUBLIC CollatorWrapper * GetCollator()
Definition: global.cxx:1028
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:778
std::vector< sc::FormulaGroupEntry > maEntries
Definition: dociter.hxx:195
bool IsEmptyData() const
Definition: column2.cxx:1200
double mfValue
Definition: cellvalue.hxx:39
SCCOLROW nField
Definition: queryentry.hxx:51
ScAddress aEnd
Definition: address.hxx:500
bool hasString() const
Definition: dociter.cxx:1015
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:341
SubtotalFlags mnSubTotalFlags
Definition: dociter.hxx:217
mdds::multi_type_vector< CellFunc, CellStoreEvent > CellStoreType
ScQueryCellIterator(ScDocument &rDocument, const ScInterpreterContext &rContext, SCTAB nTable, const ScQueryParam &aParam, bool bMod)
Definition: dociter.cxx:1049
static const sc::CellStoreType * GetColumnCellStore(ScDocument &rDoc, SCTAB nTab, SCCOL nCol)
Definition: dociter.cxx:324
bool getNext(RangeData &rRange)
ScAddress maEndPos
Definition: dociter.hxx:213
DataAccessInternal(ScDBQueryParamInternal *pParam, ScDocument &rDoc, const ScInterpreterContext &rContext)
Definition: dociter.cxx:348
std::unique_ptr< SCSIZE[]> pIndices
Definition: dociter.hxx:516
NONE
double GetDouble(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3054
ScFormulaGroupIterator(ScDocument &rDoc)
Definition: dociter.cxx:783
::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:249
const ScColumn * getColumn() const
Definition: dociter.cxx:871
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:2097
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:871
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
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:313
ScMatrixRef mpMatrix
Definition: queryparam.hxx:197
double GetValue()
bool hasString() const
Definition: cellvalue.cxx:617
FormulaError GetErrCode()
TableContainer maTabs
Definition: document.hxx:374
int nCount
PositionType maCurColPos
Definition: dociter.hxx:216
SC_DLLPUBLIC SCSIZE GetEntryCount() const
Definition: queryparam.cxx:119
SCROW GetRow() const
Definition: dociter.cxx:130
sc::CellStoreType maCells
Definition: column.hxx:128
SC_DLLPUBLIC const ScQueryEntry & GetEntry(SCSIZE n) const
Definition: queryparam.cxx:124
SCCOL GetCol() const
Definition: dociter.hxx:307
void InitPos()
Initialize position for new column.
Definition: dociter.cxx:1078
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:3089
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:2769
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:2145
bool GetNext(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:2335
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:92
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:870
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:440
void AdvanceQueryParamEntryField()
Definition: dociter.cxx:1579
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:3069
SC_DLLPUBLIC bool RowFiltered(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4491
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:873
void setPos(size_t nPos)
Definition: dociter.cxx:865
sc::FormulaGroupEntry * next()
Definition: dociter.cxx:805
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:153
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
OUString ScResId(const char *pId)
Definition: scdll.cxx:89
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:156
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1255
SCROW FindNextNonEmptyRow()
Find the next row that has some real content in one of its columns.
Definition: dociter.cxx:2241
sal_uInt32 nNumFmtIndex
Definition: dociter.hxx:59
bool GetFirst(Value &rValue)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:773
TabRanges(SCTAB nTab, SCROW nMaxRow)
Definition: dociter.cxx:2680
sc::CellStoreType::const_position_type PositionType
Definition: dociter.hxx:269
static CollatorWrapper * GetCaseCollator()
Definition: global.cxx:1038
ScHorizontalAttrIterator(ScDocument &rDocument, SCTAB nTable, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: dociter.cxx:2386
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:835
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:218
rtl_uString * getData()
svl::SharedString maString
Definition: queryentry.hxx:40
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:1020
ScHorizontalCellIterator(ScDocument &rDocument, SCTAB nTable, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: dociter.cxx:2070
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
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:874
bool IsSubTotal() const
PositionType maCurPos
Definition: dociter.hxx:374
sc::CellStoreType::const_iterator maPos
Definition: dociter.hxx:441
ScDocument & mrDoc
Definition: dociter.hxx:211
static const ScAttrArray * GetAttrArrayByCol(ScDocument &rDoc, SCTAB nTab, SCCOL nCol)
Definition: dociter.cxx:334
bool IsEmpty(SCSIZE nC, SCSIZE nR) const
Definition: scmatrix.cxx:3099
ScAddress maStartPos
Definition: dociter.hxx:60
bool GetFirst(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:286
void InitForNextRow(bool bInitialization)
Definition: dociter.cxx:2416
CellType
Definition: global.hxx:280
sc::FormulaGroupEntry * first()
Definition: dociter.cxx:800
const mdds::mtv::element_t element_type_edittext
Definition: mtvelements.hxx:48
#define debugiter(...)
Definition: dociter.cxx:58
void InitPos()
Initialize position for new column.
Definition: dociter.cxx:1470
ScHorizontalValueIterator(ScDocument &rDocument, const ScRange &rRange)
Definition: dociter.cxx:2297
virtual bool getNext(Value &rValue) override
Definition: dociter.cxx:576
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:2807
SvNumFormatType GetNumberFormatType(sal_uInt32 nFIndex) const
void * p
QPRO_FUNC_TYPE nType
Definition: qproform.cxx:400
const ScPatternAttr * GetNext(SCCOL &rCol, SCROW &rRow1, SCROW &rRow2)
Definition: dociter.cxx:2660
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:6043
double getValue()
Definition: cellvalue.cxx:632
ScHorizontalAttrIterator aAttrIter
Definition: dociter.hxx:541
EditTextObject * mpEditText
Definition: cellvalue.hxx:41
ScQueryConnect eConnect
Definition: queryentry.hxx:53
void GetCurNumFmtInfo(const ScInterpreterContext &rContext, SvNumFormatType &nType, sal_uInt32 &nIndex)
Definition: dociter.cxx:271
bool GetNext(double &rValue, FormulaError &rErr)
Does NOT reset rValue if no value found!
Definition: dociter.cxx:310
ScCellValue getCellValue() const
Definition: dociter.cxx:989
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4421
ScRefCellValue * pCell
Definition: dociter.hxx:548
ScRefCellValue toRefCell(const sc::CellStoreType::const_iterator &itPos, size_t nOffset)
std::vector< Item > QueryItemsType
Definition: queryentry.hxx:48
virtual bool getCurrent(Value &rValue) override
Definition: dociter.cxx:543
const ScPatternAttr * GetNext(SCCOL &rCol1, SCCOL &rCol2, SCROW &rRow)
Definition: dociter.cxx:2504
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:1056
ScDocAttrIterator(ScDocument &rDocument, SCTAB nTable, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: dociter.cxx:2638
virtual bool getCurrent(Value &rValue) override
Definition: dociter.cxx:383
void incPos()
Definition: dociter.cxx:852
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:2836
ScDocument & mrDoc
Definition: dociter.hxx:615
std::unique_ptr< EditTextObject > Clone() const
ScQueryOp eOp
Definition: queryentry.hxx:52
ScHorizontalCellIterator aCellIter
Definition: dociter.hxx:540
SCCOL GetAllocatedColumnsCount() const
Definition: table.hxx:1091
const mdds::mtv::element_t element_type_string
Definition: mtvelements.hxx:47
void incBlock()
Definition: dociter.cxx:844
::std::unique_ptr< DataAccess > mpData
Definition: dociter.hxx:177
virtual bool getNext(Value &rValue) override
Definition: dociter.cxx:499
void IncBlock()
Definition: dociter.cxx:137
ScDBQueryDataIterator(ScDocument &rDocument, const ScInterpreterContext &rContext, std::unique_ptr< ScDBQueryParamBase > pParam)
Definition: dociter.cxx:754
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:32
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:3129
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:2532
ScDocument & mrDoc
Definition: dociter.hxx:55
bool IsDefaultItem(const SfxPoolItem *pItem)
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo