LibreOffice Module sc (master)  1
conditio.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 <scitems.hxx>
21 #include <svl/numformat.hxx>
22 #include <svl/zforlist.hxx>
23 #include <rtl/math.hxx>
24 #include <sal/log.hxx>
26 
27 #include <com/sun/star/sheet/ConditionOperator2.hpp>
28 
29 #include <attrib.hxx>
30 #include <conditio.hxx>
31 #include <formulacell.hxx>
32 #include <document.hxx>
33 #include <compiler.hxx>
34 #include <rangelst.hxx>
35 #include <rangenam.hxx>
36 #include <rangeutl.hxx>
37 #include <colorscale.hxx>
38 #include <cellvalue.hxx>
39 #include <editutil.hxx>
40 #include <tokenarray.hxx>
41 #include <fillinfo.hxx>
42 #include <refupdatecontext.hxx>
43 #include <formula/errorcodes.hxx>
44 #include <svl/sharedstring.hxx>
45 #include <svl/sharedstringpool.hxx>
46 #include <memory>
47 #include <numeric>
48 
49 using namespace formula;
50 
52  mpDoc(pDoc)
53 {
54 }
55 
57 {
58  return IsEqual(r, false);
59 }
60 
61 // virtual
62 bool ScFormatEntry::IsEqual( const ScFormatEntry& /*r*/, bool /*bIgnoreSrcPos*/ ) const
63 {
64  // By default, return false; this makes sense for all cases except ScConditionEntry
65  // As soon as databar and color scale are tested we need to think about the range
66  return false;
67 }
68 
70 {
71 }
72 
74 {
75 }
76 
77 static bool lcl_HasRelRef( ScDocument* pDoc, const ScTokenArray* pFormula, sal_uInt16 nRecursion = 0 )
78 {
79  if (pFormula)
80  {
81  FormulaTokenArrayPlainIterator aIter( *pFormula );
82  FormulaToken* t;
83  for( t = aIter.Next(); t; t = aIter.Next() )
84  {
85  switch( t->GetType() )
86  {
87  case svDoubleRef:
88  {
89  ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
90  if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
91  return true;
92  [[fallthrough]];
93  }
94 
95  case svSingleRef:
96  {
97  ScSingleRefData& rRef1 = *t->GetSingleRef();
98  if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
99  return true;
100  }
101  break;
102 
103  case svIndex:
104  {
105  if( t->GetOpCode() == ocName ) // DB areas always absolute
106  if( ScRangeData* pRangeData = pDoc->FindRangeNameBySheetAndIndex( t->GetSheet(), t->GetIndex()) )
107  if( (nRecursion < 42) && lcl_HasRelRef( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
108  return true;
109  }
110  break;
111 
112  // #i34474# function result dependent on cell position
113  case svByte:
114  {
115  switch( t->GetOpCode() )
116  {
117  case ocRow: // ROW() returns own row index
118  case ocColumn: // COLUMN() returns own column index
119  case ocSheet: // SHEET() returns own sheet index
120  case ocCell: // CELL() may return own cell address
121  return true;
122  default:
123  {
124  // added to avoid warnings
125  }
126  }
127  }
128  break;
129 
130  default:
131  {
132  // added to avoid warnings
133  }
134  }
135  }
136  }
137  return false;
138 }
139 
140 namespace {
141 
142 void start_listen_to(ScFormulaListener& rListener, const ScTokenArray* pTokens, const ScRangeList& rRangeList)
143 {
144  size_t n = rRangeList.size();
145  for (size_t i = 0; i < n; ++i)
146  {
147  const ScRange & rRange = rRangeList[i];
148  rListener.addTokenArray(pTokens, rRange);
149  }
150 }
151 
152 }
153 
155 {
156  if (!pCondFormat)
157  return;
158 
159  const ScRangeList& rRanges = pCondFormat->GetRange();
160  mpListener->stopListening();
161  start_listen_to(*mpListener, pFormula1.get(), rRanges);
162  start_listen_to(*mpListener, pFormula2.get(), rRanges);
163 
164  mpListener->setCallback([&]() { pCondFormat->DoRepaint();});
165 }
166 
168 {
169  pCondFormat = pParent;
170  StartListening();
171 }
172 
174  ScFormatEntry(r.mpDoc),
175  eOp(r.eOp),
176  nOptions(r.nOptions),
177  nVal1(r.nVal1),
178  nVal2(r.nVal2),
179  aStrVal1(r.aStrVal1),
180  aStrVal2(r.aStrVal2),
181  aStrNmsp1(r.aStrNmsp1),
182  aStrNmsp2(r.aStrNmsp2),
183  eTempGrammar1(r.eTempGrammar1),
184  eTempGrammar2(r.eTempGrammar2),
185  bIsStr1(r.bIsStr1),
186  bIsStr2(r.bIsStr2),
187  aSrcPos(r.aSrcPos),
188  aSrcString(r.aSrcString),
189  bRelRef1(r.bRelRef1),
190  bRelRef2(r.bRelRef2),
191  bFirstRun(true),
192  mpListener(new ScFormulaListener(*r.mpDoc)),
193  eConditionType( r.eConditionType ),
194  pCondFormat(r.pCondFormat)
195 {
196  // ScTokenArray copy ctor creates a flat copy
197  if (r.pFormula1)
198  pFormula1.reset( new ScTokenArray( *r.pFormula1 ) );
199  if (r.pFormula2)
200  pFormula2.reset( new ScTokenArray( *r.pFormula2 ) );
201 
202  StartListening();
203  // Formula cells are created at IsValid
204 }
205 
207  ScFormatEntry(&rDocument),
208  eOp(r.eOp),
209  nOptions(r.nOptions),
210  nVal1(r.nVal1),
211  nVal2(r.nVal2),
212  aStrVal1(r.aStrVal1),
213  aStrVal2(r.aStrVal2),
214  aStrNmsp1(r.aStrNmsp1),
215  aStrNmsp2(r.aStrNmsp2),
216  eTempGrammar1(r.eTempGrammar1),
217  eTempGrammar2(r.eTempGrammar2),
218  bIsStr1(r.bIsStr1),
219  bIsStr2(r.bIsStr2),
220  aSrcPos(r.aSrcPos),
221  aSrcString(r.aSrcString),
222  bRelRef1(r.bRelRef1),
223  bRelRef2(r.bRelRef2),
224  bFirstRun(true),
225  mpListener(new ScFormulaListener(rDocument)),
226  eConditionType( r.eConditionType),
227  pCondFormat(r.pCondFormat)
228 {
229  // Real copy of the formulas (for Ref Undo)
230  if (r.pFormula1)
231  pFormula1 = r.pFormula1->Clone();
232  if (r.pFormula2)
233  pFormula2 = r.pFormula2->Clone();
234 
235  // Formula cells are created at IsValid
236  // TODO: But not in the Clipboard! So interpret beforehand!
237 }
238 
240  const OUString& rExpr1, const OUString& rExpr2, ScDocument& rDocument, const ScAddress& rPos,
241  const OUString& rExprNmsp1, const OUString& rExprNmsp2,
243  Type eType ) :
244  ScFormatEntry(&rDocument),
245  eOp(eOper),
246  nOptions(0),
247  nVal1(0.0),
248  nVal2(0.0),
249  aStrNmsp1(rExprNmsp1),
250  aStrNmsp2(rExprNmsp2),
251  eTempGrammar1(eGrammar1),
252  eTempGrammar2(eGrammar2),
253  bIsStr1(false),
254  bIsStr2(false),
255  aSrcPos(rPos),
256  bRelRef1(false),
257  bRelRef2(false),
258  bFirstRun(true),
259  mpListener(new ScFormulaListener(rDocument)),
260  eConditionType(eType),
261  pCondFormat(nullptr)
262 {
263  Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, false );
264 
265  // Formula cells are created at IsValid
266 }
267 
269  const ScTokenArray* pArr1, const ScTokenArray* pArr2,
270  ScDocument& rDocument, const ScAddress& rPos ) :
271  ScFormatEntry(&rDocument),
272  eOp(eOper),
273  nOptions(0),
274  nVal1(0.0),
275  nVal2(0.0),
276  eTempGrammar1(FormulaGrammar::GRAM_DEFAULT),
277  eTempGrammar2(FormulaGrammar::GRAM_DEFAULT),
278  bIsStr1(false),
279  bIsStr2(false),
280  aSrcPos(rPos),
281  bRelRef1(false),
282  bRelRef2(false),
283  bFirstRun(true),
284  mpListener(new ScFormulaListener(rDocument)),
285  eConditionType(ScFormatEntry::Type::Condition),
286  pCondFormat(nullptr)
287 {
288  if ( pArr1 )
289  {
290  pFormula1.reset( new ScTokenArray( *pArr1 ) );
293  }
294  if ( pArr2 )
295  {
296  pFormula2.reset( new ScTokenArray( *pArr2 ) );
299  }
300 
301  StartListening();
302 
303  // Formula cells are created at IsValid
304 }
305 
307 {
308 }
309 
310 void ScConditionEntry::SimplifyCompiledFormula( std::unique_ptr<ScTokenArray>& rFormula,
311  double& rVal,
312  bool& rIsStr,
313  OUString& rStrVal )
314 {
315  if ( rFormula->GetLen() != 1 )
316  return;
317 
318  // Single (constant number)?
319  FormulaToken* pToken = rFormula->FirstToken();
320  if ( pToken->GetOpCode() != ocPush )
321  return;
322 
323  if ( pToken->GetType() == svDouble )
324  {
325  rVal = pToken->GetDouble();
326  rFormula.reset(); // Do not remember as formula
327  }
328  else if ( pToken->GetType() == svString )
329  {
330  rIsStr = true;
331  rStrVal = pToken->GetString().getString();
332  rFormula.reset(); // Do not remember as formula
333  }
334 }
335 
337 {
338  eOp = eMode;
339 }
340 
341 void ScConditionEntry::Compile( const OUString& rExpr1, const OUString& rExpr2,
342  const OUString& rExprNmsp1, const OUString& rExprNmsp2,
343  FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2, bool bTextToReal )
344 {
345  if ( !rExpr1.isEmpty() || !rExpr2.isEmpty() )
346  {
347  ScCompiler aComp( *mpDoc, aSrcPos );
348 
349  if ( !rExpr1.isEmpty() )
350  {
351  pFormula1.reset();
352  aComp.SetGrammar( eGrammar1 );
353  if ( mpDoc->IsImportingXML() && !bTextToReal )
354  {
355  // temporary formula string as string tokens
356  pFormula1.reset( new ScTokenArray(*mpDoc) );
357  pFormula1->AssignXMLString( rExpr1, rExprNmsp1 );
358  // bRelRef1 is set when the formula is compiled again (CompileXML)
359  }
360  else
361  {
362  pFormula1 = aComp.CompileString( rExpr1, rExprNmsp1 );
365  }
366  }
367 
368  if ( !rExpr2.isEmpty() )
369  {
370  pFormula2.reset();
371  aComp.SetGrammar( eGrammar2 );
372  if ( mpDoc->IsImportingXML() && !bTextToReal )
373  {
374  // temporary formula string as string tokens
375  pFormula2.reset( new ScTokenArray(*mpDoc) );
376  pFormula2->AssignXMLString( rExpr2, rExprNmsp2 );
377  // bRelRef2 is set when the formula is compiled again (CompileXML)
378  }
379  else
380  {
381  pFormula2 = aComp.CompileString( rExpr2, rExprNmsp2 );
384  }
385  }
386  }
387 
388  StartListening();
389 }
390 
395 {
396  if ( mpDoc->IsClipOrUndo() ) // Never calculate in the Clipboard!
397  return;
398 
399  if ( pFormula1 && !pFCell1 && !bRelRef1 )
400  {
401  // pFCell1 will hold a flat-copied ScTokenArray sharing ref-counted
402  // code tokens with pFormula1
403  pFCell1.reset( new ScFormulaCell(*mpDoc, rPos, *pFormula1) );
404  pFCell1->StartListeningTo( *mpDoc );
405  }
406 
407  if ( pFormula2 && !pFCell2 && !bRelRef2 )
408  {
409  // pFCell2 will hold a flat-copied ScTokenArray sharing ref-counted
410  // code tokens with pFormula2
411  pFCell2.reset( new ScFormulaCell(*mpDoc, rPos, *pFormula2) );
412  pFCell2->StartListeningTo( *mpDoc );
413  }
414 }
415 
417 {
418  // The bit SC_COND_NOBLANKS is set if blanks are not ignored
419  // (only of valid)
420  if (bSet)
422  else
424 }
425 
430 {
431  pFCell1.reset();
432  pFCell2.reset();
433 }
434 
436 {
437  // First parse the formula source position if it was stored as text
438  if ( !aSrcString.isEmpty() )
439  {
440  ScAddress aNew;
441  /* XML is always in OOo:A1 format, although R1C1 would be more amenable
442  * to compression */
443  if ( aNew.Parse( aSrcString, *mpDoc ) & ScRefFlags::VALID )
444  aSrcPos = aNew;
445  // if the position is invalid, there isn't much we can do at this time
446  aSrcString.clear();
447  }
448 
449  // Convert the text tokens that were created during XML import into real tokens.
453 
454  // Importing ocDde/ocWebservice?
455  if (pFormula1)
457  if (pFormula2)
459 }
460 
461 void ScConditionEntry::SetSrcString( const OUString& rNew )
462 {
463  // aSrcString is only evaluated in CompileXML
464  SAL_WARN_IF( !mpDoc->IsImportingXML(), "sc", "SetSrcString is only valid for XML import" );
465 
466  aSrcString = rNew;
467 }
468 
470 {
471  pFormula1.reset();
472  if( rArray.GetLen() > 0 )
473  {
474  pFormula1.reset( new ScTokenArray( rArray ) );
476  }
477 
478  StartListening();
479 }
480 
482 {
483  pFormula2.reset();
484  if( rArray.GetLen() > 0 )
485  {
486  pFormula2.reset( new ScTokenArray( rArray ) );
488  }
489 
490  StartListening();
491 }
492 
494 {
495  if(pCondFormat)
497  ScAddress aOldSrcPos = aSrcPos;
498  bool bChangedPos = false;
499  if (rCxt.meMode == URM_INSDEL && rCxt.maRange.In(aSrcPos))
500  {
501  ScAddress aErrorPos( ScAddress::UNINITIALIZED );
502  if (!aSrcPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos))
503  {
504  assert(!"can't move ScConditionEntry");
505  }
506  bChangedPos = aSrcPos != aOldSrcPos;
507  }
508 
509  if (pFormula1)
510  {
511  sc::RefUpdateResult aRes;
512  switch (rCxt.meMode)
513  {
514  case URM_INSDEL:
515  aRes = pFormula1->AdjustReferenceOnShift(rCxt, aOldSrcPos);
516  break;
517  case URM_MOVE:
518  aRes = pFormula1->AdjustReferenceOnMove(rCxt, aOldSrcPos, aSrcPos);
519  break;
520  default:
521  ;
522  }
523 
524  if (aRes.mbReferenceModified || bChangedPos)
525  pFCell1.reset(); // is created again in IsValid
526  }
527 
528  if (pFormula2)
529  {
530  sc::RefUpdateResult aRes;
531  switch (rCxt.meMode)
532  {
533  case URM_INSDEL:
534  aRes = pFormula2->AdjustReferenceOnShift(rCxt, aOldSrcPos);
535  break;
536  case URM_MOVE:
537  aRes = pFormula2->AdjustReferenceOnMove(rCxt, aOldSrcPos, aSrcPos);
538  break;
539  default:
540  ;
541  }
542 
543  if (aRes.mbReferenceModified || bChangedPos)
544  pFCell2.reset(); // is created again in IsValid
545  }
546 
547  StartListening();
548 }
549 
551 {
552  if (pFormula1)
553  {
554  pFormula1->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
555  pFCell1.reset();
556  }
557 
558  if (pFormula2)
559  {
560  pFormula2->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
561  pFCell2.reset();
562  }
563 
565 }
566 
568 {
569  if (pFormula1)
570  {
571  pFormula1->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
572  pFCell1.reset();
573  }
574 
575  if (pFormula2)
576  {
577  pFormula2->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
578  pFCell2.reset();
579  }
580 
582  StartListening();
583 }
584 
586 {
587  if (pFormula1)
588  {
589  pFormula1->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
590  pFCell1.reset();
591  }
592 
593  if (pFormula2)
594  {
595  pFormula2->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
596  pFCell2.reset();
597  }
598 
599  StartListening();
600 }
601 
602 static bool lcl_IsEqual( const std::unique_ptr<ScTokenArray>& pArr1, const std::unique_ptr<ScTokenArray>& pArr2 )
603 {
604  // We only compare the non-RPN array
605  if ( pArr1 && pArr2 )
606  return pArr1->EqualTokens( pArr2.get() );
607  else
608  return !pArr1 && !pArr2; // Both 0? -> the same
609 }
610 
611 // virtual
612 bool ScConditionEntry::IsEqual( const ScFormatEntry& rOther, bool bIgnoreSrcPos ) const
613 {
614  if (GetType() != rOther.GetType())
615  return false;
616 
617  const ScConditionEntry& r = static_cast<const ScConditionEntry&>(rOther);
618 
619  bool bEq = (eOp == r.eOp && nOptions == r.nOptions &&
622 
623  if (!bIgnoreSrcPos)
624  {
625  // for formulas, the reference positions must be compared, too
626  // (including aSrcString, for inserting the entries during XML import)
627  if ( bEq && ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
628  bEq = false;
629  }
630 
631  // If not formulas, compare values
632  if ( bEq && !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
633  bEq = false;
634  if ( bEq && !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
635  bEq = false;
636 
637  return bEq;
638 }
639 
641 {
642  // Create formula cells
643  // Note: New Broadcaster (Note cells) may be inserted into the document!
644  if ( ( pFormula1 && !pFCell1 ) || ( pFormula2 && !pFCell2 ) )
645  MakeCells( rPos );
646 
647  // Evaluate formulas
648  bool bDirty = false; // 1 and 2 separate?
649 
650  std::unique_ptr<ScFormulaCell> pTemp1;
651  ScFormulaCell* pEff1 = pFCell1.get();
652  if ( bRelRef1 )
653  {
654  pTemp1.reset(pFormula1 ? new ScFormulaCell(*mpDoc, rPos, *pFormula1) : new ScFormulaCell(*mpDoc, rPos));
655  pEff1 = pTemp1.get();
656  }
657  if ( pEff1 )
658  {
659  if (!pEff1->IsRunning()) // Don't create 522
660  {
661  //TODO: Query Changed instead of Dirty!
662  if (pEff1->GetDirty() && !bRelRef1 && mpDoc->GetAutoCalc())
663  bDirty = true;
664  if (pEff1->IsValue())
665  {
666  bIsStr1 = false;
667  nVal1 = pEff1->GetValue();
668  aStrVal1.clear();
669  }
670  else
671  {
672  bIsStr1 = true;
673  aStrVal1 = pEff1->GetString().getString();
674  nVal1 = 0.0;
675  }
676  }
677  }
678  pTemp1.reset();
679 
680  std::unique_ptr<ScFormulaCell> pTemp2;
681  ScFormulaCell* pEff2 = pFCell2.get(); //@ 1!=2
682  if ( bRelRef2 )
683  {
684  pTemp2.reset(pFormula2 ? new ScFormulaCell(*mpDoc, rPos, *pFormula2) : new ScFormulaCell(*mpDoc, rPos));
685  pEff2 = pTemp2.get();
686  }
687  if ( pEff2 )
688  {
689  if (!pEff2->IsRunning()) // Don't create 522
690  {
691  if (pEff2->GetDirty() && !bRelRef2 && mpDoc->GetAutoCalc())
692  bDirty = true;
693  if (pEff2->IsValue())
694  {
695  bIsStr2 = false;
696  nVal2 = pEff2->GetValue();
697  aStrVal2.clear();
698  }
699  else
700  {
701  bIsStr2 = true;
702  aStrVal2 = pEff2->GetString().getString();
703  nVal2 = 0.0;
704  }
705  }
706  }
707  pTemp2.reset();
708 
709  // If IsRunning, the last values remain
710  if (bDirty && !bFirstRun)
711  {
712  // Repaint everything for dependent formats
713  DataChanged();
714  }
715 
716  bFirstRun = false;
717 }
718 
719 static bool lcl_GetCellContent( ScRefCellValue& rCell, bool bIsStr1, double& rArg, OUString& rArgStr,
720  const ScDocument* pDoc )
721 {
722 
723  if (rCell.isEmpty())
724  return !bIsStr1;
725 
726  bool bVal = true;
727 
728  switch (rCell.meType)
729  {
730  case CELLTYPE_VALUE:
731  rArg = rCell.mfValue;
732  break;
733  case CELLTYPE_FORMULA:
734  {
735  bVal = rCell.mpFormula->IsValue();
736  if (bVal)
737  rArg = rCell.mpFormula->GetValue();
738  else
739  rArgStr = rCell.mpFormula->GetString().getString();
740  }
741  break;
742  case CELLTYPE_STRING:
743  case CELLTYPE_EDIT:
744  bVal = false;
745  if (rCell.meType == CELLTYPE_STRING)
746  rArgStr = rCell.mpString->getString();
747  else if (rCell.mpEditText)
748  rArgStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc);
749  break;
750  default:
751  ;
752  }
753 
754  return bVal;
755 }
756 
758 {
759  if(mpCache)
760  return;
761 
762  const ScRangeList& rRanges = pCondFormat->GetRange();
763  mpCache.reset(new ScConditionEntryCache);
764  size_t nListCount = rRanges.size();
765  for( size_t i = 0; i < nListCount; i++ )
766  {
767  const ScRange & rRange = rRanges[i];
768  SCROW nRow = rRange.aEnd.Row();
769  SCCOL nCol = rRange.aEnd.Col();
770  SCCOL nColStart = rRange.aStart.Col();
771  SCROW nRowStart = rRange.aStart.Row();
772  SCTAB nTab = rRange.aStart.Tab();
773 
774  // temporary fix to workaround slow duplicate entry
775  // conditions, prevent to use a whole row
776  if(nRow == MAXROW)
777  {
778  bool bShrunk = false;
779  mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
780  nCol, nRow, false);
781  }
782 
783  for( SCROW r = nRowStart; r <= nRow; r++ )
784  for( SCCOL c = nColStart; c <= nCol; c++ )
785  {
786  ScRefCellValue aCell(*mpDoc, ScAddress(c, r, nTab));
787  if (aCell.isEmpty())
788  continue;
789 
790  double nVal = 0.0;
791  OUString aStr;
792  if (!lcl_GetCellContent(aCell, false, nVal, aStr, mpDoc))
793  {
794  std::pair<ScConditionEntryCache::StringCacheType::iterator, bool> aResult =
795  mpCache->maStrings.emplace(aStr, 1);
796 
797  if(!aResult.second)
798  aResult.first->second++;
799  }
800  else
801  {
802  std::pair<ScConditionEntryCache::ValueCacheType::iterator, bool> aResult =
803  mpCache->maValues.emplace(nVal, 1);
804 
805  if(!aResult.second)
806  aResult.first->second++;
807 
808  ++(mpCache->nValueItems);
809  }
810  }
811  }
812 }
813 
814 bool ScConditionEntry::IsDuplicate( double nArg, const OUString& rStr ) const
815 {
816  FillCache();
817 
818  if(rStr.isEmpty())
819  {
820  ScConditionEntryCache::ValueCacheType::iterator itr = mpCache->maValues.find(nArg);
821  if(itr == mpCache->maValues.end())
822  return false;
823  else
824  {
825  return itr->second > 1;
826  }
827  }
828  else
829  {
830  ScConditionEntryCache::StringCacheType::iterator itr = mpCache->maStrings.find(rStr);
831  if(itr == mpCache->maStrings.end())
832  return false;
833  else
834  {
835  return itr->second > 1;
836  }
837  }
838 }
839 
840 bool ScConditionEntry::IsTopNElement( double nArg ) const
841 {
842  FillCache();
843 
844  if(mpCache->nValueItems <= nVal1)
845  return true;
846 
847  size_t nCells = 0;
848  for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
849  itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
850  {
851  if(nCells >= nVal1)
852  return false;
853  if(itr->first <= nArg)
854  return true;
855  nCells += itr->second;
856  }
857 
858  return true;
859 }
860 
861 bool ScConditionEntry::IsBottomNElement( double nArg ) const
862 {
863  FillCache();
864 
865  if(mpCache->nValueItems <= nVal1)
866  return true;
867 
868  size_t nCells = 0;
869  for(const auto& [rVal, rCount] : mpCache->maValues)
870  {
871  if(nCells >= nVal1)
872  return false;
873  if(rVal >= nArg)
874  return true;
875  nCells += rCount;
876  }
877 
878  return true;
879 }
880 
881 bool ScConditionEntry::IsTopNPercent( double nArg ) const
882 {
883  FillCache();
884 
885  size_t nCells = 0;
886  size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
887  for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
888  itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
889  {
890  if(nCells >= nLimitCells)
891  return false;
892  if(itr->first <= nArg)
893  return true;
894  nCells += itr->second;
895  }
896 
897  return true;
898 }
899 
900 bool ScConditionEntry::IsBottomNPercent( double nArg ) const
901 {
902  FillCache();
903 
904  size_t nCells = 0;
905  size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
906  for(const auto& [rVal, rCount] : mpCache->maValues)
907  {
908  if(nCells >= nLimitCells)
909  return false;
910  if(rVal >= nArg)
911  return true;
912  nCells += rCount;
913  }
914 
915  return true;
916 }
917 
918 bool ScConditionEntry::IsBelowAverage( double nArg, bool bEqual ) const
919 {
920  FillCache();
921 
922  double nSum = std::accumulate(mpCache->maValues.begin(), mpCache->maValues.end(), double(0),
923  [](const double& rSum, const ScConditionEntryCache::ValueCacheType::value_type& rEntry) {
924  return rSum + rEntry.first * rEntry.second; });
925 
926  if(bEqual)
927  return (nArg <= nSum/mpCache->nValueItems);
928  else
929  return (nArg < nSum/mpCache->nValueItems);
930 }
931 
932 bool ScConditionEntry::IsAboveAverage( double nArg, bool bEqual ) const
933 {
934  FillCache();
935 
936  double nSum = std::accumulate(mpCache->maValues.begin(), mpCache->maValues.end(), double(0),
937  [](const double& rSum, const ScConditionEntryCache::ValueCacheType::value_type& rEntry) {
938  return rSum + rEntry.first * rEntry.second; });
939 
940  if(bEqual)
941  return (nArg >= nSum/mpCache->nValueItems);
942  else
943  return (nArg > nSum/mpCache->nValueItems);
944 }
945 
946 bool ScConditionEntry::IsError( const ScAddress& rPos ) const
947 {
948  ScRefCellValue rCell(*mpDoc, rPos);
949 
950  if (rCell.meType == CELLTYPE_FORMULA)
951  {
952  if (rCell.mpFormula->GetErrCode() != FormulaError::NONE)
953  return true;
954  }
955 
956  return false;
957 }
958 
959 bool ScConditionEntry::IsValid( double nArg, const ScAddress& rPos ) const
960 {
961  // Interpret must already have been called
962  if ( bIsStr1 )
963  {
964  switch( eOp )
965  {
970  break;
972  return true;
973  default:
974  return false;
975  }
976  }
977 
979  if ( bIsStr2 )
980  return false;
981 
982  double nComp1 = nVal1; // Copy, so that it can be changed
983  double nComp2 = nVal2;
984 
986  if ( nComp1 > nComp2 )
987  {
988  // Right order for value range
989  double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp;
990  }
991 
992  // All corner cases need to be tested with ::rtl::math::approxEqual!
993  bool bValid = false;
994  switch (eOp)
995  {
997  break; // Always sal_False
999  bValid = ::rtl::math::approxEqual( nArg, nComp1 );
1000  break;
1002  bValid = !::rtl::math::approxEqual( nArg, nComp1 );
1003  break;
1005  bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1006  break;
1008  bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1009  break;
1010  case ScConditionMode::Less:
1011  bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1012  break;
1014  bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1015  break;
1017  bValid = ( nArg >= nComp1 && nArg <= nComp2 ) ||
1018  ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 );
1019  break;
1021  bValid = ( nArg < nComp1 || nArg > nComp2 ) &&
1022  !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 );
1023  break;
1026  if( pCondFormat )
1027  {
1028  bValid = IsDuplicate( nArg, OUString() );
1030  bValid = !bValid;
1031  }
1032  break;
1034  bValid = nComp1 != 0.0;
1035  break;
1037  bValid = IsTopNElement( nArg );
1038  break;
1040  bValid = IsBottomNElement( nArg );
1041  break;
1043  bValid = IsTopNPercent( nArg );
1044  break;
1046  bValid = IsBottomNPercent( nArg );
1047  break;
1051  break;
1055  break;
1058  bValid = IsError( rPos );
1059  if( eOp == ScConditionMode::NoError )
1060  bValid = !bValid;
1061  break;
1063  if(aStrVal1.isEmpty())
1064  {
1065  OUString aStr = OUString::number(nVal1);
1066  OUString aStr2 = OUString::number(nArg);
1067  bValid = aStr2.startsWith(aStr);
1068  }
1069  else
1070  {
1071  OUString aStr2 = OUString::number(nArg);
1072  bValid = aStr2.startsWith(aStrVal1);
1073  }
1074  break;
1076  if(aStrVal1.isEmpty())
1077  {
1078  OUString aStr = OUString::number(nVal1);
1079  OUString aStr2 = OUString::number(nArg);
1080  bValid = aStr2.endsWith(aStr);
1081  }
1082  else
1083  {
1084  OUString aStr2 = OUString::number(nArg);
1085  bValid = aStr2.endsWith(aStrVal1);
1086  }
1087  break;
1090  if(aStrVal1.isEmpty())
1091  {
1092  OUString aStr = OUString::number(nVal1);
1093  OUString aStr2 = OUString::number(nArg);
1094  bValid = aStr2.indexOf(aStr) != -1;
1095  }
1096  else
1097  {
1098  OUString aStr2 = OUString::number(nArg);
1099  bValid = aStr2.indexOf(aStrVal1) != -1;
1100  }
1101 
1103  bValid = !bValid;
1104  break;
1105  default:
1106  SAL_WARN("sc", "unknown operation at ScConditionEntry");
1107  break;
1108  }
1109  return bValid;
1110 }
1111 
1112 bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos ) const
1113 {
1114  bool bValid = false;
1115  // Interpret must already have been called
1116  if ( eOp == ScConditionMode::Direct ) // Formula is independent from the content
1117  return nVal1 != 0.0;
1118 
1120  {
1121  if( pCondFormat && !rArg.isEmpty() )
1122  {
1123  bValid = IsDuplicate( 0.0, rArg );
1125  bValid = !bValid;
1126  return bValid;
1127  }
1128  }
1129 
1130  // If number contains condition, always false, except for "not equal".
1132  return ( eOp == ScConditionMode::NotEqual );
1134  if ( !bIsStr2 )
1135  return false;
1136 
1137  OUString aUpVal1( aStrVal1 ); //TODO: As a member? (Also set in Interpret)
1138  OUString aUpVal2( aStrVal2 );
1139 
1141  if (ScGlobal::GetCollator().compareString( aUpVal1, aUpVal2 ) > 0)
1142  {
1143  // Right order for value range
1144  OUString aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
1145  }
1146 
1147  switch ( eOp )
1148  {
1151  rArg, aUpVal1 ) == 0);
1152  break;
1155  rArg, aUpVal1 ) != 0);
1156  break;
1163  return false;
1166  bValid = IsError( rPos );
1168  bValid = !bValid;
1169  break;
1171  bValid = rArg.startsWith(aUpVal1);
1172  break;
1174  bValid = rArg.endsWith(aUpVal1);
1175  break;
1178  bValid = rArg.indexOf(aUpVal1) != -1;
1180  bValid = !bValid;
1181  break;
1182  default:
1183  {
1184  sal_Int32 nCompare = ScGlobal::GetCollator().compareString(
1185  rArg, aUpVal1 );
1186  switch ( eOp )
1187  {
1189  bValid = ( nCompare > 0 );
1190  break;
1192  bValid = ( nCompare >= 0 );
1193  break;
1194  case ScConditionMode::Less:
1195  bValid = ( nCompare < 0 );
1196  break;
1198  bValid = ( nCompare <= 0 );
1199  break;
1202  // Test for NOTBETWEEN:
1203  bValid = ( nCompare < 0 ||
1205  aUpVal2 ) > 0 );
1206  if ( eOp == ScConditionMode::Between )
1207  bValid = !bValid;
1208  break;
1209  // ScConditionMode::Direct already handled above
1210  default:
1211  SAL_WARN("sc", "unknown operation in ScConditionEntry");
1212  bValid = false;
1213  break;
1214  }
1215  }
1216  }
1217  return bValid;
1218 }
1219 
1220 bool ScConditionEntry::IsCellValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
1221 {
1222  const_cast<ScConditionEntry*>(this)->Interpret(rPos); // Evaluate formula
1223 
1224  if ( eOp == ScConditionMode::Direct )
1225  return nVal1 != 0.0;
1226 
1227  double nArg = 0.0;
1228  OUString aArgStr;
1229  bool bVal = lcl_GetCellContent( rCell, bIsStr1, nArg, aArgStr, mpDoc );
1230  if (bVal)
1231  return IsValid( nArg, rPos );
1232  else
1233  return IsValidStr( aArgStr, rPos );
1234 }
1235 
1236 OUString ScConditionEntry::GetExpression( const ScAddress& rCursor, sal_uInt16 nIndex,
1237  sal_uInt32 nNumFmt,
1238  const FormulaGrammar::Grammar eGrammar ) const
1239 {
1240  assert( nIndex <= 1);
1241  OUString aRet;
1242 
1243  if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 )
1245 
1246  if ( nIndex==0 )
1247  {
1248  if ( pFormula1 )
1249  {
1250  ScCompiler aComp(*mpDoc, rCursor, *pFormula1, eGrammar);
1251  OUStringBuffer aBuffer;
1252  aComp.CreateStringFromTokenArray( aBuffer );
1253  aRet = aBuffer.makeStringAndClear();
1254  }
1255  else if (bIsStr1)
1256  {
1257  aRet = "\"" + aStrVal1 + "\"";
1258  }
1259  else
1260  mpDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet);
1261  }
1262  else if ( nIndex==1 )
1263  {
1264  if ( pFormula2 )
1265  {
1266  ScCompiler aComp(*mpDoc, rCursor, *pFormula2, eGrammar);
1267  OUStringBuffer aBuffer;
1268  aComp.CreateStringFromTokenArray( aBuffer );
1269  aRet = aBuffer.makeStringAndClear();
1270  }
1271  else if (bIsStr2)
1272  {
1273  aRet = "\"" + aStrVal2 + "\"";
1274  }
1275  else
1276  mpDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet);
1277  }
1278 
1279  return aRet;
1280 }
1281 
1282 std::unique_ptr<ScTokenArray> ScConditionEntry::CreateFlatCopiedTokenArray( sal_uInt16 nIndex ) const
1283 {
1284  assert(nIndex <= 1);
1285  std::unique_ptr<ScTokenArray> pRet;
1286 
1287  if ( nIndex==0 )
1288  {
1289  if ( pFormula1 )
1290  pRet.reset(new ScTokenArray( *pFormula1 ));
1291  else
1292  {
1293  pRet.reset(new ScTokenArray(*mpDoc));
1294  if (bIsStr1)
1295  {
1297  pRet->AddString(rSPool.intern(aStrVal1));
1298  }
1299  else
1300  pRet->AddDouble( nVal1 );
1301  }
1302  }
1303  else if ( nIndex==1 )
1304  {
1305  if ( pFormula2 )
1306  pRet.reset(new ScTokenArray( *pFormula2 ));
1307  else
1308  {
1309  pRet.reset(new ScTokenArray(*mpDoc));
1310  if (bIsStr2)
1311  {
1313  pRet->AddString(rSPool.intern(aStrVal2));
1314  }
1315  else
1316  pRet->AddDouble( nVal2 );
1317  }
1318  }
1319 
1320  return pRet;
1321 }
1322 
1328 {
1329  SCTAB nMinTab = aSrcPos.Tab();
1330  SCTAB nMaxTab = nMinTab;
1331 
1332  for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1333  {
1334  ScTokenArray* pFormula = nPass ? pFormula2.get() : pFormula1.get();
1335  if (pFormula)
1336  {
1337  for ( auto t: pFormula->References() )
1338  {
1339  ScSingleRefData& rRef1 = *t->GetSingleRef();
1340  ScAddress aAbs = rRef1.toAbs(*mpDoc, aSrcPos);
1341  if (!rRef1.IsTabDeleted())
1342  {
1343  if (aAbs.Tab() < nMinTab)
1344  nMinTab = aAbs.Tab();
1345  if (aAbs.Tab() > nMaxTab)
1346  nMaxTab = aAbs.Tab();
1347  }
1348  if ( t->GetType() == svDoubleRef )
1349  {
1350  ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
1351  aAbs = rRef2.toAbs(*mpDoc, aSrcPos);
1352  if (!rRef2.IsTabDeleted())
1353  {
1354  if (aAbs.Tab() < nMinTab)
1355  nMinTab = aAbs.Tab();
1356  if (aAbs.Tab() > nMaxTab)
1357  nMaxTab = aAbs.Tab();
1358  }
1359  }
1360  }
1361  }
1362  }
1363 
1364  ScAddress aValidPos = aSrcPos;
1365  SCTAB nTabCount = mpDoc->GetTableCount();
1366  if ( nMaxTab >= nTabCount && nMinTab > 0 )
1367  aValidPos.SetTab( aSrcPos.Tab() - nMinTab ); // so the lowest tab ref will be on 0
1368 
1369  if ( aValidPos.Tab() >= nTabCount )
1370  aValidPos.SetTab( nTabCount - 1 ); // ensure a valid position even if some references will be invalid
1371 
1372  return aValidPos;
1373 }
1374 
1376 {
1377  //FIXME: Nothing so far
1378 }
1379 
1381 {
1382  bool bAllMarked = false;
1383  for (sal_uInt16 nPass = 0; !bAllMarked && nPass < 2; nPass++)
1384  {
1385  ScTokenArray* pFormula = nPass ? pFormula2.get() : pFormula1.get();
1386  if (pFormula)
1387  bAllMarked = mpDoc->MarkUsedExternalReferences(*pFormula, aSrcPos);
1388  }
1389  return bAllMarked;
1390 }
1391 
1393 {
1394  return new ScConditionEntry(*pDoc, *this);
1395 }
1396 
1397 ScConditionMode ScConditionEntry::GetModeFromApi(css::sheet::ConditionOperator nOperation)
1398 {
1400  switch (static_cast<sal_Int32>(nOperation))
1401  {
1402  case css::sheet::ConditionOperator2::EQUAL:
1403  eMode = ScConditionMode::Equal;
1404  break;
1405  case css::sheet::ConditionOperator2::LESS:
1406  eMode = ScConditionMode::Less;
1407  break;
1408  case css::sheet::ConditionOperator2::GREATER:
1409  eMode = ScConditionMode::Greater;
1410  break;
1411  case css::sheet::ConditionOperator2::LESS_EQUAL:
1412  eMode = ScConditionMode::EqLess;
1413  break;
1414  case css::sheet::ConditionOperator2::GREATER_EQUAL:
1416  break;
1417  case css::sheet::ConditionOperator2::NOT_EQUAL:
1418  eMode = ScConditionMode::NotEqual;
1419  break;
1420  case css::sheet::ConditionOperator2::BETWEEN:
1421  eMode = ScConditionMode::Between;
1422  break;
1423  case css::sheet::ConditionOperator2::NOT_BETWEEN:
1425  break;
1427  eMode = ScConditionMode::Direct;
1428  break;
1429  case css::sheet::ConditionOperator2::DUPLICATE:
1431  break;
1432  case css::sheet::ConditionOperator2::NOT_DUPLICATE:
1434  break;
1435  default:
1436  break;
1437  }
1438  return eMode;
1439 }
1440 
1442 {
1443  mpCache.reset();
1444 }
1445 
1447 {
1448  mpCache.reset();
1449 }
1450 
1452 {
1453  return mpListener->NeedsRepaint();
1454 }
1455 
1457  const OUString& rExpr1, const OUString& rExpr2,
1458  ScDocument& rDocument, const ScAddress& rPos,
1459  const OUString& rStyle,
1460  const OUString& rExprNmsp1, const OUString& rExprNmsp2,
1461  FormulaGrammar::Grammar eGrammar1,
1462  FormulaGrammar::Grammar eGrammar2,
1463  ScFormatEntry::Type eType ) :
1464  ScConditionEntry( eOper, rExpr1, rExpr2, rDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, eType ),
1465  aStyleName( rStyle ),
1466  eCondFormatType( eType )
1467 {
1468 }
1469 
1471  const ScTokenArray* pArr1, const ScTokenArray* pArr2,
1472  ScDocument& rDocument, const ScAddress& rPos,
1473  const OUString& rStyle ) :
1474  ScConditionEntry( eOper, pArr1, pArr2, rDocument, rPos ),
1475  aStyleName( rStyle )
1476 {
1477 }
1478 
1480  ScConditionEntry( r ),
1481  aStyleName( r.aStyleName ),
1482  eCondFormatType( r.eCondFormatType)
1483 {
1484 }
1485 
1487  ScConditionEntry( rDocument, r ),
1488  aStyleName( r.aStyleName ),
1489  eCondFormatType( r.eCondFormatType)
1490 {
1491 }
1492 
1493 // virtual
1494 bool ScCondFormatEntry::IsEqual( const ScFormatEntry& r, bool bIgnoreSrcPos ) const
1495 {
1496  return ScConditionEntry::IsEqual(r, bIgnoreSrcPos) &&
1497  (aStyleName == static_cast<const ScCondFormatEntry&>(r).aStyleName);
1498 }
1499 
1501 {
1502 }
1503 
1505 {
1506  if ( pCondFormat )
1508 }
1509 
1511 {
1512  return new ScCondFormatEntry( *pDoc, *this );
1513 }
1514 
1516 {
1517  if (pFCell1 || pFCell2)
1518  {
1519  if (pFCell1)
1520  pFCell1->SetDirty();
1521  if (pFCell2)
1522  pFCell2->SetDirty();
1524  }
1525 }
1526 
1528  : ScFormatEntry( pDoc )
1529  , meType(condformat::TODAY)
1530 {
1531 }
1532 
1534  ScFormatEntry( pDoc ),
1535  meType( rFormat.meType ),
1536  maStyleName( rFormat.maStyleName )
1537 {
1538 }
1539 
1541 {
1542  ScRefCellValue rCell(*mpDoc, rPos);
1543 
1544  if (!rCell.hasNumeric())
1545  // non-numerical cell.
1546  return false;
1547 
1548  if( !mpCache )
1549  mpCache.reset( new Date( Date::SYSTEM ) );
1550 
1551  const Date& rActDate = *mpCache;
1552  SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
1553  sal_Int32 nCurrentDate = rActDate - pFormatter->GetNullDate();
1554 
1555  double nVal = rCell.getValue();
1556  sal_Int32 nCellDate = static_cast<sal_Int32>(::rtl::math::approxFloor(nVal));
1557  Date aCellDate = pFormatter->GetNullDate();
1558  aCellDate.AddDays(nCellDate);
1559 
1560  switch(meType)
1561  {
1562  case condformat::TODAY:
1563  if( nCurrentDate == nCellDate )
1564  return true;
1565  break;
1566  case condformat::TOMORROW:
1567  if( nCurrentDate == nCellDate -1 )
1568  return true;
1569  break;
1570  case condformat::YESTERDAY:
1571  if( nCurrentDate == nCellDate + 1)
1572  return true;
1573  break;
1574  case condformat::LAST7DAYS:
1575  if( nCurrentDate >= nCellDate && nCurrentDate - 7 < nCellDate )
1576  return true;
1577  break;
1578  case condformat::LASTWEEK:
1579  {
1580  const DayOfWeek eDay = rActDate.GetDayOfWeek();
1581  if( eDay != SUNDAY )
1582  {
1583  Date aBegin(rActDate - (8 + static_cast<sal_Int32>(eDay)));
1584  Date aEnd(rActDate - (2 + static_cast<sal_Int32>(eDay)));
1585  return aCellDate.IsBetween( aBegin, aEnd );
1586  }
1587  else
1588  {
1589  Date aBegin(rActDate - 8);
1590  Date aEnd(rActDate - 1);
1591  return aCellDate.IsBetween( aBegin, aEnd );
1592  }
1593  }
1594  break;
1595  case condformat::THISWEEK:
1596  {
1597  const DayOfWeek eDay = rActDate.GetDayOfWeek();
1598  if( eDay != SUNDAY )
1599  {
1600  Date aBegin(rActDate - (1 + static_cast<sal_Int32>(eDay)));
1601  Date aEnd(rActDate + (5 - static_cast<sal_Int32>(eDay)));
1602  return aCellDate.IsBetween( aBegin, aEnd );
1603  }
1604  else
1605  {
1606  Date aEnd( rActDate + 6);
1607  return aCellDate.IsBetween( rActDate, aEnd );
1608  }
1609  }
1610  break;
1611  case condformat::NEXTWEEK:
1612  {
1613  const DayOfWeek eDay = rActDate.GetDayOfWeek();
1614  if( eDay != SUNDAY )
1615  {
1616  return aCellDate.IsBetween( rActDate + (6 - static_cast<sal_Int32>(eDay)),
1617  rActDate + (12 - static_cast<sal_Int32>(eDay)) );
1618  }
1619  else
1620  {
1621  return aCellDate.IsBetween( rActDate + 7, rActDate + 13 );
1622  }
1623  }
1624  break;
1625  case condformat::LASTMONTH:
1626  if( rActDate.GetMonth() == 1 )
1627  {
1628  if( aCellDate.GetMonth() == 12 && rActDate.GetYear() == aCellDate.GetNextYear() )
1629  return true;
1630  }
1631  else if( rActDate.GetYear() == aCellDate.GetYear() )
1632  {
1633  if( rActDate.GetMonth() == aCellDate.GetMonth() + 1)
1634  return true;
1635  }
1636  break;
1637  case condformat::THISMONTH:
1638  if( rActDate.GetYear() == aCellDate.GetYear() )
1639  {
1640  if( rActDate.GetMonth() == aCellDate.GetMonth() )
1641  return true;
1642  }
1643  break;
1644  case condformat::NEXTMONTH:
1645  if( rActDate.GetMonth() == 12 )
1646  {
1647  if( aCellDate.GetMonth() == 1 && rActDate.GetYear() == aCellDate.GetYear() - 1 )
1648  return true;
1649  }
1650  else if( rActDate.GetYear() == aCellDate.GetYear() )
1651  {
1652  if( rActDate.GetMonth() == aCellDate.GetMonth() - 1)
1653  return true;
1654  }
1655  break;
1656  case condformat::LASTYEAR:
1657  if( rActDate.GetYear() == aCellDate.GetNextYear() )
1658  return true;
1659  break;
1660  case condformat::THISYEAR:
1661  if( rActDate.GetYear() == aCellDate.GetYear() )
1662  return true;
1663  break;
1664  case condformat::NEXTYEAR:
1665  if( rActDate.GetYear() == aCellDate.GetYear() - 1 )
1666  return true;
1667  break;
1668  }
1669 
1670  return false;
1671 }
1672 
1674 {
1675  meType = eType;
1676 }
1677 
1678 void ScCondDateFormatEntry::SetStyleName( const OUString& rStyleName )
1679 {
1680  maStyleName = rStyleName;
1681 }
1682 
1684 {
1685  return new ScCondDateFormatEntry( pDoc, *this );
1686 }
1687 
1689 {
1690  mpCache.reset();
1691 }
1692 
1694 {
1695  mpCache.reset();
1696 }
1697 
1698 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
1699  pDoc( pDocument ),
1700  nKey( nNewKey )
1701 {
1702 }
1703 
1704 std::unique_ptr<ScConditionalFormat> ScConditionalFormat::Clone(ScDocument* pNewDoc) const
1705 {
1706  // Real copy of the formula (for Ref Undo/between documents)
1707  if (!pNewDoc)
1708  pNewDoc = pDoc;
1709 
1710  std::unique_ptr<ScConditionalFormat> pNew(new ScConditionalFormat(nKey, pNewDoc));
1711  pNew->SetRange( maRanges ); // prerequisite for listeners
1712 
1713  for (const auto& rxEntry : maEntries)
1714  {
1715  ScFormatEntry* pNewEntry = rxEntry->Clone(pNewDoc);
1716  pNew->maEntries.push_back( std::unique_ptr<ScFormatEntry>(pNewEntry) );
1717  pNewEntry->SetParent(pNew.get());
1718  }
1719 
1720  return pNew;
1721 }
1722 
1723 bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r, bool bIgnoreSrcPos ) const
1724 {
1725  if( size() != r.size())
1726  return false;
1727 
1728  //TODO: Test for same entries in reverse order?
1729  if (! std::equal(maEntries.begin(), maEntries.end(), r.maEntries.begin(),
1730  [&bIgnoreSrcPos](const std::unique_ptr<ScFormatEntry>& p1, const std::unique_ptr<ScFormatEntry>& p2) -> bool
1731  {
1732  return p1->IsEqual(*p2, bIgnoreSrcPos);
1733  }))
1734  return false;
1735 
1736  // right now don't check for same range
1737  // we only use this method to merge same conditional formats from
1738  // old ODF data structure
1739  return true;
1740 }
1741 
1743 {
1744  maRanges = rRanges;
1745  SAL_WARN_IF(maRanges.empty(), "sc", "the conditional format range is empty! will result in a crash later!");
1746 }
1747 
1749 {
1750  maEntries.push_back( std::unique_ptr<ScFormatEntry>(pNew));
1751  pNew->SetParent(this);
1752 }
1753 
1755 {
1756  if (n < maEntries.size())
1757  {
1758  maEntries.erase(maEntries.begin() + n);
1759  DoRepaint();
1760  }
1761 }
1762 
1764 {
1765  return maEntries.empty();
1766 }
1767 
1769 {
1770  return maEntries.size();
1771 }
1772 
1774 {
1775  return pDoc;
1776 }
1777 
1779 {
1780 }
1781 
1782 const ScFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const
1783 {
1784  if ( nPos < size() )
1785  return maEntries[nPos].get();
1786  else
1787  return nullptr;
1788 }
1789 
1790 const OUString& ScConditionalFormat::GetCellStyle( ScRefCellValue& rCell, const ScAddress& rPos ) const
1791 {
1792  for (const auto& rxEntry : maEntries)
1793  {
1794  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
1795  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
1796  {
1797  const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*rxEntry);
1798  if (rEntry.IsCellValid(rCell, rPos))
1799  return rEntry.GetStyle();
1800  }
1801  else if(rxEntry->GetType() == ScFormatEntry::Type::Date)
1802  {
1803  const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*rxEntry);
1804  if (rEntry.IsValid( rPos ))
1805  return rEntry.GetStyleName();
1806  }
1807  }
1808 
1809  return EMPTY_OUSTRING;
1810 }
1811 
1813 {
1815  for(const auto& rxEntry : maEntries)
1816  {
1817  if( (rxEntry->GetType() == ScFormatEntry::Type::Condition ||
1818  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition) &&
1819  aData.aStyleName.isEmpty())
1820  {
1821  const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*rxEntry);
1822  if (rEntry.IsCellValid(rCell, rPos))
1823  aData.aStyleName = rEntry.GetStyle();
1824  }
1825  else if(rxEntry->GetType() == ScFormatEntry::Type::Colorscale && !aData.mxColorScale)
1826  {
1827  const ScColorScaleFormat& rEntry = static_cast<const ScColorScaleFormat&>(*rxEntry);
1828  aData.mxColorScale = rEntry.GetColor(rPos);
1829  }
1830  else if(rxEntry->GetType() == ScFormatEntry::Type::Databar && !aData.pDataBar)
1831  {
1832  const ScDataBarFormat& rEntry = static_cast<const ScDataBarFormat&>(*rxEntry);
1833  aData.pDataBar = rEntry.GetDataBarInfo(rPos);
1834  }
1835  else if(rxEntry->GetType() == ScFormatEntry::Type::Iconset && !aData.pIconSet)
1836  {
1837  const ScIconSetFormat& rEntry = static_cast<const ScIconSetFormat&>(*rxEntry);
1838  aData.pIconSet = rEntry.GetIconSetInfo(rPos);
1839  }
1840  else if(rxEntry->GetType() == ScFormatEntry::Type::Date && aData.aStyleName.isEmpty())
1841  {
1842  const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*rxEntry);
1843  if ( rEntry.IsValid( rPos ) )
1844  aData.aStyleName = rEntry.GetStyleName();
1845  }
1846  }
1847  return aData;
1848 }
1849 
1851 {
1852  // all conditional format cells
1854 }
1855 
1857 {
1858  for(auto& rxEntry : maEntries)
1859  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
1860  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
1861  static_cast<ScCondFormatEntry&>(*rxEntry).CompileAll();
1862 }
1863 
1865 {
1866  for(auto& rxEntry : maEntries)
1867  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
1868  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
1869  static_cast<ScCondFormatEntry&>(*rxEntry).CompileXML();
1870 }
1871 
1873 {
1874  if (rCxt.meMode == URM_COPY && bCopyAsMove)
1875  {
1876  // ScConditionEntry::UpdateReference() obtains its aSrcPos from
1877  // maRanges and does not update it on URM_COPY, but it's needed later
1878  // for the moved position, so update maRanges beforehand.
1880  for (auto& rxEntry : maEntries)
1881  rxEntry->UpdateReference(rCxt);
1882  }
1883  else
1884  {
1885  for (auto& rxEntry : maEntries)
1886  rxEntry->UpdateReference(rCxt);
1887  maRanges.UpdateReference(rCxt.meMode, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
1888  }
1889 }
1890 
1891 void ScConditionalFormat::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
1892 {
1893  maRanges.InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
1894 }
1895 
1896 void ScConditionalFormat::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
1897 {
1898  maRanges.InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
1899 }
1900 
1902 {
1903  for (size_t i = 0, n = maRanges.size(); i < n; ++i)
1904  {
1905  // We assume that the start and end sheet indices are equal.
1906  ScRange & rRange = maRanges[i];
1907  SCTAB nTab = rRange.aStart.Tab();
1908 
1909  if (nTab < rCxt.mnInsertPos)
1910  // Unaffected.
1911  continue;
1912 
1913  rRange.aStart.IncTab(rCxt.mnSheets);
1914  rRange.aEnd.IncTab(rCxt.mnSheets);
1915  }
1916 
1917  for (auto& rxEntry : maEntries)
1918  rxEntry->UpdateInsertTab(rCxt);
1919 }
1920 
1922 {
1923  for (size_t i = 0, n = maRanges.size(); i < n; ++i)
1924  {
1925  // We assume that the start and end sheet indices are equal.
1926  ScRange & rRange = maRanges[i];
1927  SCTAB nTab = rRange.aStart.Tab();
1928 
1929  if (nTab < rCxt.mnDeletePos)
1930  // Left of the deleted sheet(s). Unaffected.
1931  continue;
1932 
1933  if (nTab <= rCxt.mnDeletePos+rCxt.mnSheets-1)
1934  {
1935  // On the deleted sheet(s).
1936  rRange.aStart.SetTab(-1);
1937  rRange.aEnd.SetTab(-1);
1938  continue;
1939  }
1940 
1941  // Right of the deleted sheet(s). Adjust the sheet indices.
1942  rRange.aStart.IncTab(-1*rCxt.mnSheets);
1943  rRange.aEnd.IncTab(-1*rCxt.mnSheets);
1944  }
1945 
1946  for (auto& rxEntry : maEntries)
1947  rxEntry->UpdateDeleteTab(rCxt);
1948 }
1949 
1951 {
1952  size_t n = maRanges.size();
1953  SCTAB nMinTab = std::min<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
1954  SCTAB nMaxTab = std::max<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
1955  for(size_t i = 0; i < n; ++i)
1956  {
1957  ScRange & rRange = maRanges[i];
1958  SCTAB nTab = rRange.aStart.Tab();
1959  if(nTab < nMinTab || nTab > nMaxTab)
1960  {
1961  continue;
1962  }
1963 
1964  if (nTab == rCxt.mnOldPos)
1965  {
1966  rRange.aStart.SetTab(rCxt.mnNewPos);
1967  rRange.aEnd.SetTab(rCxt.mnNewPos);
1968  continue;
1969  }
1970 
1971  if (rCxt.mnNewPos < rCxt.mnOldPos)
1972  {
1973  rRange.aStart.IncTab();
1974  rRange.aEnd.IncTab();
1975  }
1976  else
1977  {
1978  rRange.aStart.IncTab(-1);
1979  rRange.aEnd.IncTab(-1);
1980  }
1981  }
1982 
1983  for (auto& rxEntry : maEntries)
1984  rxEntry->UpdateMoveTab(rCxt);
1985 }
1986 
1987 void ScConditionalFormat::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1988 {
1989  if (maRanges.empty())
1990  return;
1991 
1992  SCTAB nTab = maRanges[0].aStart.Tab();
1993  maRanges.DeleteArea( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
1994 }
1995 
1996 void ScConditionalFormat::RenameCellStyle(std::u16string_view rOld, const OUString& rNew)
1997 {
1998  for(const auto& rxEntry : maEntries)
1999  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
2000  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
2001  {
2002  ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*rxEntry);
2003  if(rFormat.GetStyle() == rOld)
2004  rFormat.UpdateStyleName( rNew );
2005  }
2006 }
2007 
2009 {
2010  bool bAllMarked = false;
2011  for(const auto& rxEntry : maEntries)
2012  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
2013  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
2014  {
2015  const ScCondFormatEntry& rFormat = static_cast<const ScCondFormatEntry&>(*rxEntry);
2016  bAllMarked = rFormat.MarkUsedExternalReferences();
2017  if (bAllMarked)
2018  break;
2019  }
2020 
2021  return bAllMarked;
2022 }
2023 
2025 {
2026  for(auto& rxEntry : maEntries)
2027  {
2028  rxEntry->startRendering();
2029  }
2030 }
2031 
2033 {
2034  for(auto& rxEntry : maEntries)
2035  {
2036  rxEntry->endRendering();
2037  }
2038 }
2039 
2041 {
2042  for(const auto& rxEntry : maEntries)
2043  {
2044  if (rxEntry->GetType() == ScFormatEntry::Type::Condition ||
2045  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
2046  {
2047  ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*rxEntry);
2048  rFormat.CalcAll();
2049  }
2050  }
2051 }
2052 
2054 {
2055  for(const auto& rxFormat : rList)
2056  InsertNew( rxFormat->Clone() );
2057 }
2058 
2060 {
2061  for(const auto& rxFormat : rList)
2062  InsertNew( rxFormat->Clone(&rDoc) );
2063 }
2064 
2065 void ScConditionalFormatList::InsertNew( std::unique_ptr<ScConditionalFormat> pNew )
2066 {
2067  m_ConditionalFormats.insert(std::move(pNew));
2068 }
2069 
2071 {
2072  auto itr = m_ConditionalFormats.find(nKey);
2073  if (itr != m_ConditionalFormats.end())
2074  return itr->get();
2075 
2076  SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2077  return nullptr;
2078 }
2079 
2081 {
2082  auto itr = m_ConditionalFormats.find(nKey);
2083  if (itr != m_ConditionalFormats.end())
2084  return itr->get();
2085 
2086  SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2087  return nullptr;
2088 }
2089 
2091 {
2092  for (auto const& it : m_ConditionalFormats)
2093  {
2094  it->CompileAll();
2095  }
2096 }
2097 
2099 {
2100  for (auto const& it : m_ConditionalFormats)
2101  {
2102  it->CompileXML();
2103  }
2104 }
2105 
2107 {
2108  for (auto const& it : m_ConditionalFormats)
2109  {
2110  it->UpdateReference(rCxt);
2111  }
2112 
2113  if (rCxt.meMode == URM_INSDEL)
2114  {
2115  // need to check which must be deleted
2116  CheckAllEntries();
2117  }
2118 }
2119 
2120 void ScConditionalFormatList::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
2121 {
2122  for (auto const& it : m_ConditionalFormats)
2123  {
2124  it->InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
2125  }
2126 }
2127 
2128 void ScConditionalFormatList::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
2129 {
2130  for (auto const& it : m_ConditionalFormats)
2131  {
2132  it->InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
2133  }
2134 }
2135 
2137 {
2138  for (auto const& it : m_ConditionalFormats)
2139  {
2140  it->UpdateInsertTab(rCxt);
2141  }
2142 }
2143 
2145 {
2146  for (auto const& it : m_ConditionalFormats)
2147  {
2148  it->UpdateDeleteTab(rCxt);
2149  }
2150 }
2151 
2153 {
2154  for (auto const& it : m_ConditionalFormats)
2155  {
2156  it->UpdateMoveTab(rCxt);
2157  }
2158 }
2159 
2160 void ScConditionalFormatList::RenameCellStyle( std::u16string_view rOld, const OUString& rNew )
2161 {
2162  for (auto const& it : m_ConditionalFormats)
2163  {
2164  it->RenameCellStyle(rOld, rNew);
2165  }
2166 }
2167 
2169 {
2170  bool bValid = true;
2171 
2172  // need to check which must be deleted
2173  iterator itr = m_ConditionalFormats.begin();
2174  while(itr != m_ConditionalFormats.end())
2175  {
2176  if ((*itr)->GetRange().empty())
2177  {
2178  bValid = false;
2179  if (rLink.IsSet())
2180  rLink.Call(itr->get());
2181  itr = m_ConditionalFormats.erase(itr);
2182  }
2183  else
2184  ++itr;
2185  }
2186 
2187  return bValid;
2188 }
2189 
2190 void ScConditionalFormatList::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2191 {
2192  for (auto& rxFormat : m_ConditionalFormats)
2193  rxFormat->DeleteArea( nCol1, nRow1, nCol2, nRow2 );
2194 
2195  CheckAllEntries();
2196 }
2197 
2199 {
2200  return m_ConditionalFormats.begin();
2201 }
2202 
2204 {
2205  return m_ConditionalFormats.begin();
2206 }
2207 
2209 {
2210  return m_ConditionalFormats.end();
2211 }
2212 
2214 {
2215  return m_ConditionalFormats.end();
2216 }
2217 
2219 {
2220  ScRangeList aRange;
2221  for (auto& itr: m_ConditionalFormats)
2222  {
2223  const ScRangeList& rRange = itr->GetRange();
2224  for (size_t i = 0, n = rRange.size(); i < n; ++i)
2225  {
2226  aRange.Join(rRange[i]);
2227  }
2228  }
2229  return aRange;
2230 }
2231 
2233 {
2234  ScRangeList aRange = GetCombinedRange();
2235  ScMarkData aMark(rDoc.GetSheetLimits());
2236  aMark.MarkFromRangeList(aRange, true);
2237  sal_uInt16 const pItems[2] = { sal_uInt16(ATTR_CONDITIONAL),0};
2238  rDoc.ClearSelectionItems(pItems, aMark);
2239 }
2240 
2242 {
2243  for (auto& itr: m_ConditionalFormats)
2244  {
2245  const ScRangeList& rRange = itr->GetRange();
2246  if (rRange.empty())
2247  continue;
2248 
2249  SCTAB nTab = rRange.front().aStart.Tab();
2250  rDoc.AddCondFormatData(rRange, nTab, itr->GetKey());
2251  }
2252 }
2253 
2255 {
2256  return m_ConditionalFormats.size();
2257 }
2258 
2260 {
2261  return m_ConditionalFormats.empty();
2262 }
2263 
2265 {
2266  auto itr = m_ConditionalFormats.find(nIndex);
2267  if (itr != end())
2268  m_ConditionalFormats.erase(itr);
2269 }
2270 
2272 {
2273  for (auto const& it : m_ConditionalFormats)
2274  {
2275  it->startRendering();
2276  }
2277 }
2278 
2280 {
2281  for (auto const& it : m_ConditionalFormats)
2282  {
2283  it->endRendering();
2284  }
2285 }
2286 
2288 {
2289  m_ConditionalFormats.clear();
2290 }
2291 
2293 {
2294  if (m_ConditionalFormats.empty())
2295  return 0;
2296  return (*m_ConditionalFormats.rbegin())->GetKey();
2297 }
2298 
2300 {
2301  for (const auto& aEntry : m_ConditionalFormats)
2302  {
2303  aEntry->CalcAll();
2304  }
2305 
2306 }
2307 
2309 
2311 
2313 
2314 
2315 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsTabRel() const
Definition: refdata.hxx:69
svString
Type
void SetOperation(ScConditionMode eMode)
Definition: conditio.cxx:336
sal_Int16 GetNextYear() const
bool UpdateReference(UpdateRefMode, const ScDocument *, const ScRange &rWhere, SCCOL nDx, SCROW nDy, SCTAB nDz)
Definition: rangelst.cxx:369
SCROW mnRowDelta
Amount and direction of movement in the row direction.
virtual void endRendering() override
Definition: conditio.cxx:1446
void ClearSelectionItems(const sal_uInt16 *pWhich, const ScMarkData &rMark)
Definition: document.cxx:5946
static void UpdateInsertTab(ScAddress &rAddr, const sc::RefUpdateInsertTabContext &rCxt)
Definition: rangeutl.cxx:1044
void SetGrammar(const formula::FormulaGrammar::Grammar eGrammar)
Definition: compiler.cxx:228
bool IsTabDeleted() const
Definition: refdata.hxx:86
OUString getString() const
ScAddress aStart
Definition: address.hxx:499
ocCell
SharedString intern(const OUString &rStr)
virtual ~ScCondFormatEntry() override
Definition: conditio.cxx:1500
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:566
virtual void DataChanged() const override
Definition: conditio.cxx:1504
todo: It should be possible to have MarkArrays for each table, in order to enable "search all" across...
Definition: markdata.hxx:42
DayOfWeek GetDayOfWeek() const
sal_Int32 compareString(const OUString &s1, const OUString &s2) const
#define EMPTY_OUSTRING
Definition: global.hxx:214
void AddEntry(ScFormatEntry *pNew)
Definition: conditio.cxx:1748
void IncTab(SCTAB nDelta=1)
Definition: address.hxx:307
ocName
SCROW Row() const
Definition: address.hxx:261
#define LANGUAGE_ENGLISH_US
void InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColStart, SCSIZE nSize)
Definition: conditio.cxx:1896
Single reference (one address) into the sheet.
Definition: refdata.hxx:29
std::unique_ptr< ScTokenArray > pFormula2
Definition: conditio.hxx:318
OUString aStrVal1
Definition: conditio.hxx:309
std::unique_ptr< ScConditionEntryCache > mpCache
Definition: conditio.hxx:444
bool isEmpty() const
Definition: cellvalue.cxx:670
ScAddress toAbs(const ScSheetLimits &rLimits, const ScAddress &rPos) const
Definition: refdata.cxx:193
void InsertNew(std::unique_ptr< ScConditionalFormat > pNew)
Definition: conditio.cxx:2065
bool GetDirty() const
sal_uIntPtr sal_uLong
void SetFormula1(const ScTokenArray &rArray)
Definition: conditio.cxx:469
void Interpret(const ScAddress &rPos)
Definition: conditio.cxx:640
bool IsBetween(const Date &rFrom, const Date &rTo) const
Context for reference update during shifting, moving or copying of cell ranges.
sal_Int64 n
std::unique_ptr< ScTokenArray > CompileString(const OUString &rFormula)
Tokenize formula expression string into an array of tokens.
Definition: compiler.cxx:4624
ScRangeList maRanges
Definition: conditio.hxx:545
const OUString & GetStyle() const
Definition: conditio.hxx:473
std::optional< Color > mxColorScale
Definition: conditio.hxx:218
virtual void UpdateInsertTab(sc::RefUpdateInsertTabContext &rCxt) override
Definition: conditio.cxx:550
bool MarkUsedExternalReferences() const
Definition: conditio.cxx:1380
void StartListening()
Definition: conditio.cxx:154
bool IsClipOrUndo() const
Definition: document.hxx:1532
bool IsValid(const ScAddress &rPos) const
Definition: conditio.cxx:1540
bool IsBelowAverage(double nArg, bool bEqual) const
Definition: conditio.cxx:918
ScRange Combine() const
Definition: rangelst.cxx:1111
ScAddress aEnd
Definition: address.hxx:500
virtual double GetDouble() const
virtual void DataChanged() const
Definition: conditio.cxx:1375
OpCode GetOpCode() const
void UpdateReference(sc::RefUpdateContext &rCxt, bool bCopyAsMove=false)
Definition: conditio.cxx:1872
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:103
ScCondFormatDateType
Definition: conditio.hxx:484
ScConditionalFormat * GetFormat(sal_uInt32 nKey)
Definition: conditio.cxx:2070
bool IsCellValid(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1220
void CreateStringFromTokenArray(OUString &rFormula)
void RenameCellStyle(std::u16string_view rOld, const OUString &rNew)
Definition: conditio.cxx:1996
void MarkFromRangeList(const ScRangeList &rList, bool bReset)
Definition: markdata.cxx:333
ocRow
ScConditionalFormat(sal_uInt32 nNewKey, ScDocument *pDocument)
Definition: conditio.cxx:1698
virtual void endRendering()
Definition: conditio.cxx:73
virtual sal_Int16 GetSheet() const
std::vector< std::unique_ptr< ScFormatEntry > > maEntries
Definition: conditio.hxx:544
virtual ~ScConditionEntry() override
Definition: conditio.cxx:306
void InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
Definition: rangelst.cxx:446
void UpdateDeleteTab(sc::RefUpdateDeleteTabContext &rCxt)
Definition: conditio.cxx:2144
const ScRangeList & GetRange() const
Definition: conditio.hxx:559
void RepaintRange(const ScRange &rRange)
Definition: documen8.cxx:691
ScConditionMode eOp
Definition: conditio.hxx:305
SC_DLLPUBLIC void CheckLinkFormulaNeedingCheck(const ScTokenArray &rCode)
Check token array and set link check if ocDde/ocWebservice is contained.
Definition: documen8.cxx:1156
virtual void UpdateMoveTab(sc::RefUpdateMoveTabContext &rCxt) override
Definition: conditio.cxx:585
bool DeleteArea(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2)
For now this method assumes that nTab1 == nTab2 The algorithm will be much more complicated if nTab1 ...
Definition: rangelst.cxx:955
const EditTextObject * mpEditText
Definition: cellvalue.hxx:109
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
void SetSrcString(const OUString &rNew)
Definition: conditio.cxx:461
sal_uInt32 getMaxKey() const
Definition: conditio.cxx:2292
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:314
std::optional< Color > GetColor(const ScAddress &rAddr) const
Definition: colorscale.cxx:588
sal_uInt16 GetMonth() const
OUString aSrcString
Definition: conditio.hxx:321
const OUString aStrNmsp1
Definition: conditio.hxx:311
double GetValue()
void CompileAll()
Delete formula cells, so we re-compile at the next IsValid.
Definition: conditio.cxx:429
FormulaError GetErrCode()
sal_uInt32 GetStandardIndex(LanguageType eLnge=LANGUAGE_DONTKNOW)
IntrinsicAnimationEventHandlerSharedPtr mpListener
bool CheckAllEntries(const Link< ScConditionalFormat *, void > &rLink=Link< ScConditionalFormat *, void >())
Checks that all cond formats have a non empty range.
Definition: conditio.cxx:2168
const SCROW MAXROW
Definition: address.hxx:68
virtual const ScSingleRefData * GetSingleRef() const
std::unique_ptr< ScDataBarInfo > GetDataBarInfo(const ScAddress &rAddr) const
Definition: colorscale.cxx:835
ScAddress aSrcPos
Definition: conditio.hxx:319
svDouble
ConditionalFormatContainer::const_iterator const_iterator
Definition: conditio.hxx:666
void InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowStart, SCSIZE nSize)
Definition: conditio.cxx:2120
ScConditionMode
Definition: conditio.hxx:60
void UpdateReference(sc::RefUpdateContext &rCxt)
Definition: conditio.cxx:2106
Mode eMode
ScFormulaCell * mpFormula
Definition: cellvalue.hxx:110
SCTAB Tab() const
Definition: address.hxx:270
bool IsColRel() const
Definition: refdata.hxx:65
OUString aStyleName
Definition: conditio.hxx:450
void RemoveFromDocument(ScDocument &rDoc) const
Definition: conditio.cxx:2232
ConditionalFormatContainer m_ConditionalFormats
Definition: conditio.hxx:630
void MarkUsedExternalReferences()
Definition: documen3.cxx:637
size_t size() const
Definition: conditio.cxx:1768
bool ShrinkToUsedDataArea(bool &o_bShrunk, SCTAB nTab, SCCOL &rStartCol, SCROW &rStartRow, SCCOL &rEndCol, SCROW &rEndRow, bool bColumnsOnly, bool bStickyTopRow=false, bool bStickyLeftCol=false, ScDataAreaExtras *pDataAreaExtras=nullptr) const
Shrink a range to only include used data area.
Definition: document.cxx:1063
sal_uInt16 GetLen() const
bool IsBottomNElement(double nArg) const
Definition: conditio.cxx:861
virtual void SetParent(ScConditionalFormat *pNew)=0
bool empty() const
Definition: rangelst.hxx:88
void Compile(const OUString &rExpr1, const OUString &rExpr2, const OUString &rExprNmsp1, const OUString &rExprNmsp2, formula::FormulaGrammar::Grammar eGrammar1, formula::FormulaGrammar::Grammar eGrammar2, bool bTextToReal)
Definition: conditio.cxx:341
ScAddress GetValidSrcPos() const
Return a position that's adjusted to allow textual representation of expressions if possible...
Definition: conditio.cxx:1327
constexpr OUStringLiteral aData
sal_Int16 GetYear() const
bool operator==(const ScFormatEntry &) const
Definition: conditio.cxx:56
bool IsEqual(const ScFormatEntry &r, bool bIgnoreSrcPos) const override
Definition: conditio.cxx:1494
std::unique_ptr< ScFormulaListener > mpListener
Definition: conditio.hxx:327
void SetRange(const ScRangeList &rRanges)
Definition: conditio.cxx:1742
const ScFormatEntry * GetEntry(sal_uInt16 nPos) const
Definition: conditio.cxx:1782
void SetTab(SCTAB nTabP)
Definition: address.hxx:282
bool IsTopNElement(double nArg) const
Definition: conditio.cxx:840
std::unique_ptr< ScFormulaCell > pFCell1
Definition: conditio.hxx:322
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:441
bool IsImportingXML() const
Definition: document.hxx:2150
void InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
Definition: rangelst.cxx:476
virtual const ScComplexRefData * GetDoubleRef() const
virtual bool IsEqual(const ScFormatEntry &, bool bIgnoreSrcPos) const
Definition: conditio.cxx:62
int i
std::unique_ptr< ScIconSetInfo > pIconSet
Definition: conditio.hxx:220
void AddToDocument(ScDocument &rDoc) const
Definition: conditio.cxx:2241
UpdateRefMode meMode
update mode - insert/delete, copy, or move.
virtual ScFormatEntry * Clone(ScDocument *pDoc) const override
Definition: conditio.cxx:1510
void addTokenArray(const ScTokenArray *pTokens, const ScRange &rRange)
Definition: colorscale.cxx:112
bool IsValidStr(const OUString &rArg, const ScAddress &rPos) const
Definition: conditio.cxx:1112
void CalcAll()
Forced recalculation of formulas.
Definition: conditio.cxx:2299
const svl::SharedString * mpString
Definition: cellvalue.hxx:108
OUString GetExpression(const ScAddress &rCursor, sal_uInt16 nPos, sal_uInt32 nNumFmt=0, const formula::FormulaGrammar::Grammar eGrammar=formula::FormulaGrammar::GRAM_DEFAULT) const
Definition: conditio.cxx:1236
sal_Int16 SCCOL
Definition: types.hxx:21
bool IsValid(double nArg, const ScAddress &rPos) const
Definition: conditio.cxx:959
ocSheet
ocPush
condformat::ScCondFormatDateType meType
Definition: conditio.hxx:531
size_t size() const
Definition: conditio.cxx:2254
virtual Type GetType() const override
Definition: conditio.hxx:399
ScSheetLimits & GetSheetLimits() const
Definition: document.hxx:873
svIndex
bool IsEqual(const ScFormatEntry &r, bool bIgnoreSrcPos) const override
Definition: conditio.cxx:612
void UpdateInsertTab(sc::RefUpdateInsertTabContext &rCxt)
Definition: conditio.cxx:1901
size_t size() const
Definition: rangelst.hxx:89
bool NeedsRepaint() const
Definition: conditio.cxx:1451
ScSingleRefData Ref2
Definition: refdata.hxx:125
ConditionalFormatContainer::iterator iterator
Definition: conditio.hxx:665
bool IsDuplicate(double nArg, const OUString &rStr) const
Definition: conditio.cxx:814
ScConditionEntry(ScConditionMode eOper, const OUString &rExpr1, const OUString &rExpr2, ScDocument &rDocument, const ScAddress &rPos, const OUString &rExprNmsp1, const OUString &rExprNmsp2, formula::FormulaGrammar::Grammar eGrammar1, formula::FormulaGrammar::Grammar eGrammar2, Type eType=Type::Condition)
svByte
void GetInputLineString(const double &fOutNumber, sal_uInt32 nFIndex, OUString &rOutString, bool bFiltering=false)
ScFormatEntry(ScDocument *pDoc)
Definition: conditio.cxx:51
void RemoveEntry(size_t nIndex)
Definition: conditio.cxx:1754
SUNDAY
bool EqualEntries(const ScConditionalFormat &r, bool bIgnoreSrcPos=false) const
Definition: conditio.cxx:1723
void AddDays(sal_Int32 nAddDays)
virtual ScFormatEntry * Clone(ScDocument *pDoc) const =0
void SetIgnoreBlank(bool bSet)
Definition: conditio.cxx:416
bool IsRowRel() const
Definition: refdata.hxx:67
bool IsRunning() const
void UpdateDeleteTab(sc::RefUpdateDeleteTabContext &rCxt)
Definition: conditio.cxx:1921
bool hasNumeric() const
Definition: cellvalue.cxx:622
const OUString aStrNmsp2
Definition: conditio.hxx:312
bool In(const ScAddress &) const
is Address& in Range?
Definition: address.hxx:732
void SetFormula2(const ScTokenArray &rArray)
Definition: conditio.cxx:481
void UpdateStyleName(const OUString &rNew)
Definition: conditio.hxx:474
bool IsError(const ScAddress &rPos) const
Definition: conditio.cxx:946
void UpdateMoveTab(sc::RefUpdateMoveTabContext &rCxt)
Definition: conditio.cxx:1950
virtual void UpdateReference(sc::RefUpdateContext &rCxt) override
Definition: conditio.cxx:493
ScRange maRange
Range of cells that are about to be moved for insert/delete/move modes.
ScDocument * pDoc
Definition: conditio.hxx:541
virtual sal_uInt16 GetIndex() const
svSingleRef
virtual void endRendering() override
Definition: conditio.cxx:1693
const svl::SharedString & GetString()
SCCOL Col() const
Definition: address.hxx:266
XPropertyListType t
const OUString & GetCellStyle(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1790
virtual void UpdateDeleteTab(sc::RefUpdateDeleteTabContext &rCxt) override
Definition: conditio.cxx:567
SC_DLLPUBLIC bool Move(SCCOL nDeltaX, SCROW nDeltaY, SCTAB nDeltaZ, ScAddress &rErrorPos, const ScDocument *pDocument=nullptr)
Definition: address.cxx:2324
virtual ScFormatEntry * Clone(ScDocument *pDoc) const override
Definition: conditio.cxx:1392
svDoubleRef
CellType meType
Definition: cellvalue.hxx:105
ScCondFormatData GetData(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1812
ScCondDateFormatEntry(ScDocument *pDoc)
Definition: conditio.cxx:1527
sal_Int32 SCROW
Definition: types.hxx:17
std::unique_ptr< Date > mpCache
Definition: conditio.hxx:533
void InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowStart, SCSIZE nSize)
Definition: conditio.cxx:1891
std::unique_ptr< char[]> aBuffer
std::unique_ptr< ScTokenArray > pFormula1
Definition: conditio.hxx:317
#define SAL_WARN_IF(condition, area, stream)
ScRangeList GetCombinedRange() const
Definition: conditio.cxx:2218
void DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: conditio.cxx:1987
static SC_DLLPUBLIC CollatorWrapper & GetCollator()
case-insensitive collator
Definition: global.cxx:1047
void Join(const ScRange &, bool bIsInList=false)
Definition: rangelst.cxx:164
DayOfWeek
const OUString & GetStyleName() const
Definition: conditio.hxx:514
std::unique_ptr< ScDataBarInfo > pDataBar
Definition: conditio.hxx:219
SCTAB mnTabDelta
Amount and direction of movement in the sheet direction.
virtual const svl::SharedString & GetString() const
bool MarkUsedExternalReferences() const
Definition: conditio.cxx:2008
static void UpdateDeleteTab(ScAddress &rAddr, const sc::RefUpdateDeleteTabContext &rCxt)
Definition: rangeutl.cxx:1052
virtual ScFormatEntry * Clone(ScDocument *pDoc) const override
Definition: conditio.cxx:1683
void UpdateInsertTab(sc::RefUpdateInsertTabContext &rCxt)
Definition: conditio.cxx:2136
const formula::FormulaGrammar::Grammar eTempGrammar2
Definition: conditio.hxx:314
static bool lcl_IsEqual(const std::unique_ptr< ScTokenArray > &pArr1, const std::unique_ptr< ScTokenArray > &pArr2)
Definition: conditio.cxx:602
bool IsAboveAverage(double nArg, bool bEqual) const
Definition: conditio.cxx:932
static bool lcl_GetCellContent(ScRefCellValue &rCell, bool bIsStr1, double &rArg, OUString &rArgStr, const ScDocument *pDoc)
Definition: conditio.cxx:719
void SetDateType(condformat::ScCondFormatDateType eType)
Definition: conditio.cxx:1673
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
void RenameCellStyle(std::u16string_view rOld, const OUString &rNew)
Definition: conditio.cxx:2160
double getValue()
Definition: cellvalue.cxx:632
sal_uInt16 nOptions
Definition: conditio.hxx:306
bool mbReferenceModified
This flag indicates whether any reference in the token array has been modified.
virtual void startRendering()
Definition: conditio.cxx:69
ScDocument * mpDoc
Definition: conditio.hxx:256
static bool lcl_HasRelRef(ScDocument *pDoc, const ScTokenArray *pFormula, sal_uInt16 nRecursion=0)
Definition: conditio.cxx:77
static void SimplifyCompiledFormula(std::unique_ptr< ScTokenArray > &rFormula, double &rVal, bool &rIsStr, OUString &rStrVal)
Definition: conditio.cxx:310
ScCondFormatEntry(ScConditionMode eOper, const OUString &rExpr1, const OUString &rExpr2, ScDocument &rDocument, const ScAddress &rPos, const OUString &rStyle, const OUString &rExprNmsp1=EMPTY_OUSTRING, const OUString &rExprNmsp2=EMPTY_OUSTRING, formula::FormulaGrammar::Grammar eGrammar1=formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::Grammar eGrammar2=formula::FormulaGrammar::GRAM_DEFAULT, Type eType=Type::Condition)
static SC_DLLPUBLIC OUString GetString(const EditTextObject &rEditText, const ScDocument *pDoc)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:113
virtual Type GetType() const =0
bool IsTopNPercent(double nArg) const
Definition: conditio.cxx:881
void erase(sal_uLong nIndex)
Definition: conditio.cxx:2264
static ScConditionMode GetModeFromApi(css::sheet::ConditionOperator nOperator)
Definition: conditio.cxx:1397
ScRange & front()
Definition: rangelst.hxx:92
#define SAL_WARN(area, stream)
std::unique_ptr< ScIconSetInfo > GetIconSetInfo(const ScAddress &rAddr) const
virtual void startRendering() override
Definition: conditio.cxx:1441
SC_DLLPUBLIC ScRefFlags Parse(const OUString &, const ScDocument &, const Details &rDetails=detailsOOOa1, ExternalInfo *pExtInfo=nullptr, const css::uno::Sequence< css::sheet::ExternalLinkInfo > *pExternalLinks=nullptr, sal_Int32 *pSheetEndPos=nullptr, const OUString *pErrRef=nullptr)
Definition: address.cxx:1548
std::unique_ptr< ScTokenArray > CreateFlatCopiedTokenArray(sal_uInt16 nPos) const
Create a flat copy using ScTokenArray copy-ctor with shared tokens.
Definition: conditio.cxx:1282
virtual void SetParent(ScConditionalFormat *pNew) override
Definition: conditio.cxx:167
ScConditionalFormat * pCondFormat
Definition: conditio.hxx:414
bool IsBottomNPercent(double nArg) const
Definition: conditio.cxx:900
ScRangeData * FindRangeNameBySheetAndIndex(SCTAB nTab, sal_uInt16 nIndex) const
Find a named expression / range name in either global or a local scope.
Definition: documen3.cxx:269
SCCOL mnColDelta
Amount and direction of movement in the column direction.
const Date & GetNullDate() const
virtual void startRendering() override
Definition: conditio.cxx:1688
bool IsEmpty() const
Definition: conditio.cxx:1763
StackVar GetType() const
OUString aStyleName
Definition: conditio.hxx:221
void UpdateMoveTab(sc::RefUpdateMoveTabContext &rCxt)
Definition: conditio.cxx:2152
RedlineType meType
aStr
OUString aStrVal2
Definition: conditio.hxx:310
std::unique_ptr< ScConditionalFormat > Clone(ScDocument *pNewDoc=nullptr) const
Definition: conditio.cxx:1704
void FillCache() const
Definition: conditio.cxx:757
const formula::FormulaGrammar::Grammar eTempGrammar1
Definition: conditio.hxx:313
void SetStyleName(const OUString &rStyleName)
Definition: conditio.cxx:1678
#define SC_COND_NOBLANKS
Definition: conditio.hxx:58
sal_Int16 SCTAB
Definition: types.hxx:22
void MakeCells(const ScAddress &rPos)
Create formula cells.
Definition: conditio.cxx:394
SC_DLLPUBLIC void AddCondFormatData(const ScRangeList &rRange, SCTAB nTab, sal_uInt32 nIndex)
Definition: document.cxx:4838
FormulaTokenArrayReferencesRange References() const
ocColumn
SC_DLLPUBLIC bool GetAutoCalc() const
Definition: document.hxx:1360
void DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: conditio.cxx:2190
std::unique_ptr< ScFormulaCell > pFCell2
Definition: conditio.hxx:323
ScDocument * GetDocument()
Definition: conditio.cxx:1773
void InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColStart, SCSIZE nSize)
Definition: conditio.cxx:2128