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->SetFreeFlying(true);
405  pFCell1->StartListeningTo( *mpDoc );
406  }
407 
408  if ( pFormula2 && !pFCell2 && !bRelRef2 )
409  {
410  // pFCell2 will hold a flat-copied ScTokenArray sharing ref-counted
411  // code tokens with pFormula2
412  pFCell2.reset( new ScFormulaCell(*mpDoc, rPos, *pFormula2) );
413  pFCell2->SetFreeFlying(true);
414  pFCell2->StartListeningTo( *mpDoc );
415  }
416 }
417 
419 {
420  // The bit SC_COND_NOBLANKS is set if blanks are not ignored
421  // (only of valid)
422  if (bSet)
424  else
426 }
427 
432 {
433  pFCell1.reset();
434  pFCell2.reset();
435 }
436 
438 {
439  // First parse the formula source position if it was stored as text
440  if ( !aSrcString.isEmpty() )
441  {
442  ScAddress aNew;
443  /* XML is always in OOo:A1 format, although R1C1 would be more amenable
444  * to compression */
445  if ( aNew.Parse( aSrcString, *mpDoc ) & ScRefFlags::VALID )
446  aSrcPos = aNew;
447  // if the position is invalid, there isn't much we can do at this time
448  aSrcString.clear();
449  }
450 
451  // Convert the text tokens that were created during XML import into real tokens.
455 
456  // Importing ocDde/ocWebservice?
457  if (pFormula1)
459  if (pFormula2)
461 }
462 
463 void ScConditionEntry::SetSrcString( const OUString& rNew )
464 {
465  // aSrcString is only evaluated in CompileXML
466  SAL_WARN_IF( !mpDoc->IsImportingXML(), "sc", "SetSrcString is only valid for XML import" );
467 
468  aSrcString = rNew;
469 }
470 
472 {
473  pFormula1.reset();
474  if( rArray.GetLen() > 0 )
475  {
476  pFormula1.reset( new ScTokenArray( rArray ) );
478  }
479 
480  StartListening();
481 }
482 
484 {
485  pFormula2.reset();
486  if( rArray.GetLen() > 0 )
487  {
488  pFormula2.reset( new ScTokenArray( rArray ) );
490  }
491 
492  StartListening();
493 }
494 
496 {
497  if(pCondFormat)
499  ScAddress aOldSrcPos = aSrcPos;
500  bool bChangedPos = false;
501  if (rCxt.meMode == URM_INSDEL && rCxt.maRange.In(aSrcPos))
502  {
503  ScAddress aErrorPos( ScAddress::UNINITIALIZED );
504  if (!aSrcPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta, aErrorPos))
505  {
506  assert(!"can't move ScConditionEntry");
507  }
508  bChangedPos = aSrcPos != aOldSrcPos;
509  }
510 
511  if (pFormula1)
512  {
513  sc::RefUpdateResult aRes;
514  switch (rCxt.meMode)
515  {
516  case URM_INSDEL:
517  aRes = pFormula1->AdjustReferenceOnShift(rCxt, aOldSrcPos);
518  break;
519  case URM_MOVE:
520  aRes = pFormula1->AdjustReferenceOnMove(rCxt, aOldSrcPos, aSrcPos);
521  break;
522  default:
523  ;
524  }
525 
526  if (aRes.mbReferenceModified || bChangedPos)
527  pFCell1.reset(); // is created again in IsValid
528  }
529 
530  if (pFormula2)
531  {
532  sc::RefUpdateResult aRes;
533  switch (rCxt.meMode)
534  {
535  case URM_INSDEL:
536  aRes = pFormula2->AdjustReferenceOnShift(rCxt, aOldSrcPos);
537  break;
538  case URM_MOVE:
539  aRes = pFormula2->AdjustReferenceOnMove(rCxt, aOldSrcPos, aSrcPos);
540  break;
541  default:
542  ;
543  }
544 
545  if (aRes.mbReferenceModified || bChangedPos)
546  pFCell2.reset(); // is created again in IsValid
547  }
548 
549  StartListening();
550 }
551 
553 {
554  if (pFormula1)
555  {
556  pFormula1->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
557  pFCell1.reset();
558  }
559 
560  if (pFormula2)
561  {
562  pFormula2->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
563  pFCell2.reset();
564  }
565 
567 }
568 
570 {
571  if (pFormula1)
572  {
573  pFormula1->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
574  pFCell1.reset();
575  }
576 
577  if (pFormula2)
578  {
579  pFormula2->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
580  pFCell2.reset();
581  }
582 
584  StartListening();
585 }
586 
588 {
589  if (pFormula1)
590  {
591  pFormula1->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
592  pFCell1.reset();
593  }
594 
595  if (pFormula2)
596  {
597  pFormula2->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
598  pFCell2.reset();
599  }
600 
601  StartListening();
602 }
603 
604 static bool lcl_IsEqual( const std::unique_ptr<ScTokenArray>& pArr1, const std::unique_ptr<ScTokenArray>& pArr2 )
605 {
606  // We only compare the non-RPN array
607  if ( pArr1 && pArr2 )
608  return pArr1->EqualTokens( pArr2.get() );
609  else
610  return !pArr1 && !pArr2; // Both 0? -> the same
611 }
612 
613 // virtual
614 bool ScConditionEntry::IsEqual( const ScFormatEntry& rOther, bool bIgnoreSrcPos ) const
615 {
616  if (GetType() != rOther.GetType())
617  return false;
618 
619  const ScConditionEntry& r = static_cast<const ScConditionEntry&>(rOther);
620 
621  bool bEq = (eOp == r.eOp && nOptions == r.nOptions &&
624 
625  if (!bIgnoreSrcPos)
626  {
627  // for formulas, the reference positions must be compared, too
628  // (including aSrcString, for inserting the entries during XML import)
629  if ( bEq && ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
630  bEq = false;
631  }
632 
633  // If not formulas, compare values
634  if ( bEq && !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
635  bEq = false;
636  if ( bEq && !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
637  bEq = false;
638 
639  return bEq;
640 }
641 
643 {
644  // Create formula cells
645  // Note: New Broadcaster (Note cells) may be inserted into the document!
646  if ( ( pFormula1 && !pFCell1 ) || ( pFormula2 && !pFCell2 ) )
647  MakeCells( rPos );
648 
649  // Evaluate formulas
650  bool bDirty = false; // 1 and 2 separate?
651 
652  std::unique_ptr<ScFormulaCell> pTemp1;
653  ScFormulaCell* pEff1 = pFCell1.get();
654  if ( bRelRef1 )
655  {
656  pTemp1.reset(pFormula1 ? new ScFormulaCell(*mpDoc, rPos, *pFormula1) : new ScFormulaCell(*mpDoc, rPos));
657  pEff1 = pTemp1.get();
658  pEff1->SetFreeFlying(true);
659  }
660  if ( pEff1 )
661  {
662  if (!pEff1->IsRunning()) // Don't create 522
663  {
664  //TODO: Query Changed instead of Dirty!
665  if (pEff1->GetDirty() && !bRelRef1 && mpDoc->GetAutoCalc())
666  bDirty = true;
667  if (pEff1->IsValue())
668  {
669  bIsStr1 = false;
670  nVal1 = pEff1->GetValue();
671  aStrVal1.clear();
672  }
673  else
674  {
675  bIsStr1 = true;
676  aStrVal1 = pEff1->GetString().getString();
677  nVal1 = 0.0;
678  }
679  }
680  }
681  pTemp1.reset();
682 
683  std::unique_ptr<ScFormulaCell> pTemp2;
684  ScFormulaCell* pEff2 = pFCell2.get(); //@ 1!=2
685  if ( bRelRef2 )
686  {
687  pTemp2.reset(pFormula2 ? new ScFormulaCell(*mpDoc, rPos, *pFormula2) : new ScFormulaCell(*mpDoc, rPos));
688  pEff2 = pTemp2.get();
689  pEff2->SetFreeFlying(true);
690  }
691  if ( pEff2 )
692  {
693  if (!pEff2->IsRunning()) // Don't create 522
694  {
695  if (pEff2->GetDirty() && !bRelRef2 && mpDoc->GetAutoCalc())
696  bDirty = true;
697  if (pEff2->IsValue())
698  {
699  bIsStr2 = false;
700  nVal2 = pEff2->GetValue();
701  aStrVal2.clear();
702  }
703  else
704  {
705  bIsStr2 = true;
706  aStrVal2 = pEff2->GetString().getString();
707  nVal2 = 0.0;
708  }
709  }
710  }
711  pTemp2.reset();
712 
713  // If IsRunning, the last values remain
714  if (bDirty && !bFirstRun)
715  {
716  // Repaint everything for dependent formats
717  DataChanged();
718  }
719 
720  bFirstRun = false;
721 }
722 
723 static bool lcl_GetCellContent( ScRefCellValue& rCell, bool bIsStr1, double& rArg, OUString& rArgStr,
724  const ScDocument* pDoc )
725 {
726 
727  if (rCell.isEmpty())
728  return !bIsStr1;
729 
730  bool bVal = true;
731 
732  switch (rCell.meType)
733  {
734  case CELLTYPE_VALUE:
735  rArg = rCell.mfValue;
736  break;
737  case CELLTYPE_FORMULA:
738  {
739  bVal = rCell.mpFormula->IsValue();
740  if (bVal)
741  rArg = rCell.mpFormula->GetValue();
742  else
743  rArgStr = rCell.mpFormula->GetString().getString();
744  }
745  break;
746  case CELLTYPE_STRING:
747  case CELLTYPE_EDIT:
748  bVal = false;
749  if (rCell.meType == CELLTYPE_STRING)
750  rArgStr = rCell.mpString->getString();
751  else if (rCell.mpEditText)
752  rArgStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc);
753  break;
754  default:
755  ;
756  }
757 
758  return bVal;
759 }
760 
762 {
763  if(mpCache)
764  return;
765 
766  const ScRangeList& rRanges = pCondFormat->GetRange();
767  mpCache.reset(new ScConditionEntryCache);
768  size_t nListCount = rRanges.size();
769  for( size_t i = 0; i < nListCount; i++ )
770  {
771  const ScRange & rRange = rRanges[i];
772  SCROW nRow = rRange.aEnd.Row();
773  SCCOL nCol = rRange.aEnd.Col();
774  SCCOL nColStart = rRange.aStart.Col();
775  SCROW nRowStart = rRange.aStart.Row();
776  SCTAB nTab = rRange.aStart.Tab();
777 
778  // temporary fix to workaround slow duplicate entry
779  // conditions, prevent to use a whole row
780  if(nRow == MAXROW)
781  {
782  bool bShrunk = false;
783  mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
784  nCol, nRow, false);
785  }
786 
787  for( SCROW r = nRowStart; r <= nRow; r++ )
788  for( SCCOL c = nColStart; c <= nCol; c++ )
789  {
790  ScRefCellValue aCell(*mpDoc, ScAddress(c, r, nTab));
791  if (aCell.isEmpty())
792  continue;
793 
794  double nVal = 0.0;
795  OUString aStr;
796  if (!lcl_GetCellContent(aCell, false, nVal, aStr, mpDoc))
797  {
798  std::pair<ScConditionEntryCache::StringCacheType::iterator, bool> aResult =
799  mpCache->maStrings.emplace(aStr, 1);
800 
801  if(!aResult.second)
802  aResult.first->second++;
803  }
804  else
805  {
806  std::pair<ScConditionEntryCache::ValueCacheType::iterator, bool> aResult =
807  mpCache->maValues.emplace(nVal, 1);
808 
809  if(!aResult.second)
810  aResult.first->second++;
811 
812  ++(mpCache->nValueItems);
813  }
814  }
815  }
816 }
817 
818 bool ScConditionEntry::IsDuplicate( double nArg, const OUString& rStr ) const
819 {
820  FillCache();
821 
822  if(rStr.isEmpty())
823  {
824  ScConditionEntryCache::ValueCacheType::iterator itr = mpCache->maValues.find(nArg);
825  if(itr == mpCache->maValues.end())
826  return false;
827  else
828  {
829  return itr->second > 1;
830  }
831  }
832  else
833  {
834  ScConditionEntryCache::StringCacheType::iterator itr = mpCache->maStrings.find(rStr);
835  if(itr == mpCache->maStrings.end())
836  return false;
837  else
838  {
839  return itr->second > 1;
840  }
841  }
842 }
843 
844 bool ScConditionEntry::IsTopNElement( double nArg ) const
845 {
846  FillCache();
847 
848  if(mpCache->nValueItems <= nVal1)
849  return true;
850 
851  size_t nCells = 0;
852  for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
853  itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
854  {
855  if(nCells >= nVal1)
856  return false;
857  if(itr->first <= nArg)
858  return true;
859  nCells += itr->second;
860  }
861 
862  return true;
863 }
864 
865 bool ScConditionEntry::IsBottomNElement( double nArg ) const
866 {
867  FillCache();
868 
869  if(mpCache->nValueItems <= nVal1)
870  return true;
871 
872  size_t nCells = 0;
873  for(const auto& [rVal, rCount] : mpCache->maValues)
874  {
875  if(nCells >= nVal1)
876  return false;
877  if(rVal >= nArg)
878  return true;
879  nCells += rCount;
880  }
881 
882  return true;
883 }
884 
885 bool ScConditionEntry::IsTopNPercent( double nArg ) const
886 {
887  FillCache();
888 
889  size_t nCells = 0;
890  size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
891  for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
892  itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
893  {
894  if(nCells >= nLimitCells)
895  return false;
896  if(itr->first <= nArg)
897  return true;
898  nCells += itr->second;
899  }
900 
901  return true;
902 }
903 
904 bool ScConditionEntry::IsBottomNPercent( double nArg ) const
905 {
906  FillCache();
907 
908  size_t nCells = 0;
909  size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
910  for(const auto& [rVal, rCount] : mpCache->maValues)
911  {
912  if(nCells >= nLimitCells)
913  return false;
914  if(rVal >= nArg)
915  return true;
916  nCells += rCount;
917  }
918 
919  return true;
920 }
921 
922 bool ScConditionEntry::IsBelowAverage( double nArg, bool bEqual ) const
923 {
924  FillCache();
925 
926  double nSum = std::accumulate(mpCache->maValues.begin(), mpCache->maValues.end(), double(0),
927  [](const double& rSum, const ScConditionEntryCache::ValueCacheType::value_type& rEntry) {
928  return rSum + rEntry.first * rEntry.second; });
929 
930  if(bEqual)
931  return (nArg <= nSum/mpCache->nValueItems);
932  else
933  return (nArg < nSum/mpCache->nValueItems);
934 }
935 
936 bool ScConditionEntry::IsAboveAverage( double nArg, bool bEqual ) const
937 {
938  FillCache();
939 
940  double nSum = std::accumulate(mpCache->maValues.begin(), mpCache->maValues.end(), double(0),
941  [](const double& rSum, const ScConditionEntryCache::ValueCacheType::value_type& rEntry) {
942  return rSum + rEntry.first * rEntry.second; });
943 
944  if(bEqual)
945  return (nArg >= nSum/mpCache->nValueItems);
946  else
947  return (nArg > nSum/mpCache->nValueItems);
948 }
949 
950 bool ScConditionEntry::IsError( const ScAddress& rPos ) const
951 {
952  ScRefCellValue rCell(*mpDoc, rPos);
953 
954  if (rCell.meType == CELLTYPE_FORMULA)
955  {
956  if (rCell.mpFormula->GetErrCode() != FormulaError::NONE)
957  return true;
958  }
959 
960  return false;
961 }
962 
963 bool ScConditionEntry::IsValid( double nArg, const ScAddress& rPos ) const
964 {
965  // Interpret must already have been called
966  if ( bIsStr1 )
967  {
968  switch( eOp )
969  {
974  break;
976  return true;
977  default:
978  return false;
979  }
980  }
981 
983  if ( bIsStr2 )
984  return false;
985 
986  double nComp1 = nVal1; // Copy, so that it can be changed
987  double nComp2 = nVal2;
988 
990  if ( nComp1 > nComp2 )
991  {
992  // Right order for value range
993  double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp;
994  }
995 
996  // All corner cases need to be tested with ::rtl::math::approxEqual!
997  bool bValid = false;
998  switch (eOp)
999  {
1000  case ScConditionMode::NONE:
1001  break; // Always sal_False
1003  bValid = ::rtl::math::approxEqual( nArg, nComp1 );
1004  break;
1006  bValid = !::rtl::math::approxEqual( nArg, nComp1 );
1007  break;
1009  bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1010  break;
1012  bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1013  break;
1014  case ScConditionMode::Less:
1015  bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1016  break;
1018  bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1019  break;
1021  bValid = ( nArg >= nComp1 && nArg <= nComp2 ) ||
1022  ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 );
1023  break;
1025  bValid = ( nArg < nComp1 || nArg > nComp2 ) &&
1026  !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 );
1027  break;
1030  if( pCondFormat )
1031  {
1032  bValid = IsDuplicate( nArg, OUString() );
1034  bValid = !bValid;
1035  }
1036  break;
1038  bValid = nComp1 != 0.0;
1039  break;
1041  bValid = IsTopNElement( nArg );
1042  break;
1044  bValid = IsBottomNElement( nArg );
1045  break;
1047  bValid = IsTopNPercent( nArg );
1048  break;
1050  bValid = IsBottomNPercent( nArg );
1051  break;
1055  break;
1059  break;
1062  bValid = IsError( rPos );
1063  if( eOp == ScConditionMode::NoError )
1064  bValid = !bValid;
1065  break;
1067  if(aStrVal1.isEmpty())
1068  {
1069  OUString aStr = OUString::number(nVal1);
1070  OUString aStr2 = OUString::number(nArg);
1071  bValid = aStr2.startsWith(aStr);
1072  }
1073  else
1074  {
1075  OUString aStr2 = OUString::number(nArg);
1076  bValid = aStr2.startsWith(aStrVal1);
1077  }
1078  break;
1080  if(aStrVal1.isEmpty())
1081  {
1082  OUString aStr = OUString::number(nVal1);
1083  OUString aStr2 = OUString::number(nArg);
1084  bValid = aStr2.endsWith(aStr);
1085  }
1086  else
1087  {
1088  OUString aStr2 = OUString::number(nArg);
1089  bValid = aStr2.endsWith(aStrVal1);
1090  }
1091  break;
1094  if(aStrVal1.isEmpty())
1095  {
1096  OUString aStr = OUString::number(nVal1);
1097  OUString aStr2 = OUString::number(nArg);
1098  bValid = aStr2.indexOf(aStr) != -1;
1099  }
1100  else
1101  {
1102  OUString aStr2 = OUString::number(nArg);
1103  bValid = aStr2.indexOf(aStrVal1) != -1;
1104  }
1105 
1107  bValid = !bValid;
1108  break;
1109  default:
1110  SAL_WARN("sc", "unknown operation at ScConditionEntry");
1111  break;
1112  }
1113  return bValid;
1114 }
1115 
1116 bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos ) const
1117 {
1118  bool bValid = false;
1119  // Interpret must already have been called
1120  if ( eOp == ScConditionMode::Direct ) // Formula is independent from the content
1121  return nVal1 != 0.0;
1122 
1124  {
1125  if( pCondFormat && !rArg.isEmpty() )
1126  {
1127  bValid = IsDuplicate( 0.0, rArg );
1129  bValid = !bValid;
1130  return bValid;
1131  }
1132  }
1133 
1134  // If number contains condition, always false, except for "not equal".
1136  return ( eOp == ScConditionMode::NotEqual );
1138  if ( !bIsStr2 )
1139  return false;
1140 
1141  OUString aUpVal1( aStrVal1 ); //TODO: As a member? (Also set in Interpret)
1142  OUString aUpVal2( aStrVal2 );
1143 
1145  if (ScGlobal::GetCollator().compareString( aUpVal1, aUpVal2 ) > 0)
1146  {
1147  // Right order for value range
1148  OUString aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
1149  }
1150 
1151  switch ( eOp )
1152  {
1155  rArg, aUpVal1 ) == 0);
1156  break;
1159  rArg, aUpVal1 ) != 0);
1160  break;
1167  return false;
1170  bValid = IsError( rPos );
1172  bValid = !bValid;
1173  break;
1175  bValid = rArg.startsWith(aUpVal1);
1176  break;
1178  bValid = rArg.endsWith(aUpVal1);
1179  break;
1182  bValid = rArg.indexOf(aUpVal1) != -1;
1184  bValid = !bValid;
1185  break;
1186  default:
1187  {
1188  sal_Int32 nCompare = ScGlobal::GetCollator().compareString(
1189  rArg, aUpVal1 );
1190  switch ( eOp )
1191  {
1193  bValid = ( nCompare > 0 );
1194  break;
1196  bValid = ( nCompare >= 0 );
1197  break;
1198  case ScConditionMode::Less:
1199  bValid = ( nCompare < 0 );
1200  break;
1202  bValid = ( nCompare <= 0 );
1203  break;
1206  // Test for NOTBETWEEN:
1207  bValid = ( nCompare < 0 ||
1209  aUpVal2 ) > 0 );
1210  if ( eOp == ScConditionMode::Between )
1211  bValid = !bValid;
1212  break;
1213  // ScConditionMode::Direct already handled above
1214  default:
1215  SAL_WARN("sc", "unknown operation in ScConditionEntry");
1216  bValid = false;
1217  break;
1218  }
1219  }
1220  }
1221  return bValid;
1222 }
1223 
1224 bool ScConditionEntry::IsCellValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
1225 {
1226  const_cast<ScConditionEntry*>(this)->Interpret(rPos); // Evaluate formula
1227 
1228  if ( eOp == ScConditionMode::Direct )
1229  return nVal1 != 0.0;
1230 
1231  double nArg = 0.0;
1232  OUString aArgStr;
1233  bool bVal = lcl_GetCellContent( rCell, bIsStr1, nArg, aArgStr, mpDoc );
1234  if (bVal)
1235  return IsValid( nArg, rPos );
1236  else
1237  return IsValidStr( aArgStr, rPos );
1238 }
1239 
1240 OUString ScConditionEntry::GetExpression( const ScAddress& rCursor, sal_uInt16 nIndex,
1241  sal_uInt32 nNumFmt,
1242  const FormulaGrammar::Grammar eGrammar ) const
1243 {
1244  assert( nIndex <= 1);
1245  OUString aRet;
1246 
1247  if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 )
1249 
1250  if ( nIndex==0 )
1251  {
1252  if ( pFormula1 )
1253  {
1254  ScCompiler aComp(*mpDoc, rCursor, *pFormula1, eGrammar);
1255  OUStringBuffer aBuffer;
1256  aComp.CreateStringFromTokenArray( aBuffer );
1257  aRet = aBuffer.makeStringAndClear();
1258  }
1259  else if (bIsStr1)
1260  {
1261  aRet = "\"" + aStrVal1 + "\"";
1262  }
1263  else
1264  mpDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet);
1265  }
1266  else if ( nIndex==1 )
1267  {
1268  if ( pFormula2 )
1269  {
1270  ScCompiler aComp(*mpDoc, rCursor, *pFormula2, eGrammar);
1271  OUStringBuffer aBuffer;
1272  aComp.CreateStringFromTokenArray( aBuffer );
1273  aRet = aBuffer.makeStringAndClear();
1274  }
1275  else if (bIsStr2)
1276  {
1277  aRet = "\"" + aStrVal2 + "\"";
1278  }
1279  else
1280  mpDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet);
1281  }
1282 
1283  return aRet;
1284 }
1285 
1286 std::unique_ptr<ScTokenArray> ScConditionEntry::CreateFlatCopiedTokenArray( sal_uInt16 nIndex ) const
1287 {
1288  assert(nIndex <= 1);
1289  std::unique_ptr<ScTokenArray> pRet;
1290 
1291  if ( nIndex==0 )
1292  {
1293  if ( pFormula1 )
1294  pRet.reset(new ScTokenArray( *pFormula1 ));
1295  else
1296  {
1297  pRet.reset(new ScTokenArray(*mpDoc));
1298  if (bIsStr1)
1299  {
1301  pRet->AddString(rSPool.intern(aStrVal1));
1302  }
1303  else
1304  pRet->AddDouble( nVal1 );
1305  }
1306  }
1307  else if ( nIndex==1 )
1308  {
1309  if ( pFormula2 )
1310  pRet.reset(new ScTokenArray( *pFormula2 ));
1311  else
1312  {
1313  pRet.reset(new ScTokenArray(*mpDoc));
1314  if (bIsStr2)
1315  {
1317  pRet->AddString(rSPool.intern(aStrVal2));
1318  }
1319  else
1320  pRet->AddDouble( nVal2 );
1321  }
1322  }
1323 
1324  return pRet;
1325 }
1326 
1332 {
1333  SCTAB nMinTab = aSrcPos.Tab();
1334  SCTAB nMaxTab = nMinTab;
1335 
1336  for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1337  {
1338  ScTokenArray* pFormula = nPass ? pFormula2.get() : pFormula1.get();
1339  if (pFormula)
1340  {
1341  for ( auto t: pFormula->References() )
1342  {
1343  ScSingleRefData& rRef1 = *t->GetSingleRef();
1344  ScAddress aAbs = rRef1.toAbs(*mpDoc, aSrcPos);
1345  if (!rRef1.IsTabDeleted())
1346  {
1347  if (aAbs.Tab() < nMinTab)
1348  nMinTab = aAbs.Tab();
1349  if (aAbs.Tab() > nMaxTab)
1350  nMaxTab = aAbs.Tab();
1351  }
1352  if ( t->GetType() == svDoubleRef )
1353  {
1354  ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
1355  aAbs = rRef2.toAbs(*mpDoc, aSrcPos);
1356  if (!rRef2.IsTabDeleted())
1357  {
1358  if (aAbs.Tab() < nMinTab)
1359  nMinTab = aAbs.Tab();
1360  if (aAbs.Tab() > nMaxTab)
1361  nMaxTab = aAbs.Tab();
1362  }
1363  }
1364  }
1365  }
1366  }
1367 
1368  ScAddress aValidPos = aSrcPos;
1369  SCTAB nTabCount = mpDoc->GetTableCount();
1370  if ( nMaxTab >= nTabCount && nMinTab > 0 )
1371  aValidPos.SetTab( aSrcPos.Tab() - nMinTab ); // so the lowest tab ref will be on 0
1372 
1373  if ( aValidPos.Tab() >= nTabCount )
1374  aValidPos.SetTab( nTabCount - 1 ); // ensure a valid position even if some references will be invalid
1375 
1376  return aValidPos;
1377 }
1378 
1380 {
1381  //FIXME: Nothing so far
1382 }
1383 
1385 {
1386  bool bAllMarked = false;
1387  for (sal_uInt16 nPass = 0; !bAllMarked && nPass < 2; nPass++)
1388  {
1389  ScTokenArray* pFormula = nPass ? pFormula2.get() : pFormula1.get();
1390  if (pFormula)
1391  bAllMarked = mpDoc->MarkUsedExternalReferences(*pFormula, aSrcPos);
1392  }
1393  return bAllMarked;
1394 }
1395 
1397 {
1398  return new ScConditionEntry(*pDoc, *this);
1399 }
1400 
1401 ScConditionMode ScConditionEntry::GetModeFromApi(css::sheet::ConditionOperator nOperation)
1402 {
1404  switch (static_cast<sal_Int32>(nOperation))
1405  {
1406  case css::sheet::ConditionOperator2::EQUAL:
1407  eMode = ScConditionMode::Equal;
1408  break;
1409  case css::sheet::ConditionOperator2::LESS:
1410  eMode = ScConditionMode::Less;
1411  break;
1412  case css::sheet::ConditionOperator2::GREATER:
1413  eMode = ScConditionMode::Greater;
1414  break;
1415  case css::sheet::ConditionOperator2::LESS_EQUAL:
1416  eMode = ScConditionMode::EqLess;
1417  break;
1418  case css::sheet::ConditionOperator2::GREATER_EQUAL:
1420  break;
1421  case css::sheet::ConditionOperator2::NOT_EQUAL:
1422  eMode = ScConditionMode::NotEqual;
1423  break;
1424  case css::sheet::ConditionOperator2::BETWEEN:
1425  eMode = ScConditionMode::Between;
1426  break;
1427  case css::sheet::ConditionOperator2::NOT_BETWEEN:
1429  break;
1431  eMode = ScConditionMode::Direct;
1432  break;
1433  case css::sheet::ConditionOperator2::DUPLICATE:
1435  break;
1436  case css::sheet::ConditionOperator2::NOT_DUPLICATE:
1438  break;
1439  default:
1440  break;
1441  }
1442  return eMode;
1443 }
1444 
1446 {
1447  mpCache.reset();
1448 }
1449 
1451 {
1452  mpCache.reset();
1453 }
1454 
1456 {
1457  return mpListener->NeedsRepaint();
1458 }
1459 
1461  const OUString& rExpr1, const OUString& rExpr2,
1462  ScDocument& rDocument, const ScAddress& rPos,
1463  const OUString& rStyle,
1464  const OUString& rExprNmsp1, const OUString& rExprNmsp2,
1465  FormulaGrammar::Grammar eGrammar1,
1466  FormulaGrammar::Grammar eGrammar2,
1467  ScFormatEntry::Type eType ) :
1468  ScConditionEntry( eOper, rExpr1, rExpr2, rDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, eType ),
1469  aStyleName( rStyle ),
1470  eCondFormatType( eType )
1471 {
1472 }
1473 
1475  const ScTokenArray* pArr1, const ScTokenArray* pArr2,
1476  ScDocument& rDocument, const ScAddress& rPos,
1477  const OUString& rStyle ) :
1478  ScConditionEntry( eOper, pArr1, pArr2, rDocument, rPos ),
1479  aStyleName( rStyle )
1480 {
1481 }
1482 
1484  ScConditionEntry( r ),
1485  aStyleName( r.aStyleName ),
1486  eCondFormatType( r.eCondFormatType)
1487 {
1488 }
1489 
1491  ScConditionEntry( rDocument, r ),
1492  aStyleName( r.aStyleName ),
1493  eCondFormatType( r.eCondFormatType)
1494 {
1495 }
1496 
1497 // virtual
1498 bool ScCondFormatEntry::IsEqual( const ScFormatEntry& r, bool bIgnoreSrcPos ) const
1499 {
1500  return ScConditionEntry::IsEqual(r, bIgnoreSrcPos) &&
1501  (aStyleName == static_cast<const ScCondFormatEntry&>(r).aStyleName);
1502 }
1503 
1505 {
1506 }
1507 
1509 {
1510  if ( pCondFormat )
1512 }
1513 
1515 {
1516  return new ScCondFormatEntry( *pDoc, *this );
1517 }
1518 
1520 {
1521  if (pFCell1 || pFCell2)
1522  {
1523  if (pFCell1)
1524  pFCell1->SetDirty();
1525  if (pFCell2)
1526  pFCell2->SetDirty();
1528  }
1529 }
1530 
1532  : ScFormatEntry( pDoc )
1533  , meType(condformat::TODAY)
1534 {
1535 }
1536 
1538  ScFormatEntry( pDoc ),
1539  meType( rFormat.meType ),
1540  maStyleName( rFormat.maStyleName )
1541 {
1542 }
1543 
1545 {
1546  ScRefCellValue rCell(*mpDoc, rPos);
1547 
1548  if (!rCell.hasNumeric())
1549  // non-numerical cell.
1550  return false;
1551 
1552  if( !mpCache )
1553  mpCache.reset( new Date( Date::SYSTEM ) );
1554 
1555  const Date& rActDate = *mpCache;
1556  SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
1557  sal_Int32 nCurrentDate = rActDate - pFormatter->GetNullDate();
1558 
1559  double nVal = rCell.getValue();
1560  sal_Int32 nCellDate = static_cast<sal_Int32>(::rtl::math::approxFloor(nVal));
1561  Date aCellDate = pFormatter->GetNullDate();
1562  aCellDate.AddDays(nCellDate);
1563 
1564  switch(meType)
1565  {
1566  case condformat::TODAY:
1567  if( nCurrentDate == nCellDate )
1568  return true;
1569  break;
1570  case condformat::TOMORROW:
1571  if( nCurrentDate == nCellDate -1 )
1572  return true;
1573  break;
1574  case condformat::YESTERDAY:
1575  if( nCurrentDate == nCellDate + 1)
1576  return true;
1577  break;
1578  case condformat::LAST7DAYS:
1579  if( nCurrentDate >= nCellDate && nCurrentDate - 7 < nCellDate )
1580  return true;
1581  break;
1582  case condformat::LASTWEEK:
1583  {
1584  const DayOfWeek eDay = rActDate.GetDayOfWeek();
1585  if( eDay != SUNDAY )
1586  {
1587  Date aBegin(rActDate - (8 + static_cast<sal_Int32>(eDay)));
1588  Date aEnd(rActDate - (2 + static_cast<sal_Int32>(eDay)));
1589  return aCellDate.IsBetween( aBegin, aEnd );
1590  }
1591  else
1592  {
1593  Date aBegin(rActDate - 8);
1594  Date aEnd(rActDate - 1);
1595  return aCellDate.IsBetween( aBegin, aEnd );
1596  }
1597  }
1598  break;
1599  case condformat::THISWEEK:
1600  {
1601  const DayOfWeek eDay = rActDate.GetDayOfWeek();
1602  if( eDay != SUNDAY )
1603  {
1604  Date aBegin(rActDate - (1 + static_cast<sal_Int32>(eDay)));
1605  Date aEnd(rActDate + (5 - static_cast<sal_Int32>(eDay)));
1606  return aCellDate.IsBetween( aBegin, aEnd );
1607  }
1608  else
1609  {
1610  Date aEnd( rActDate + 6);
1611  return aCellDate.IsBetween( rActDate, aEnd );
1612  }
1613  }
1614  break;
1615  case condformat::NEXTWEEK:
1616  {
1617  const DayOfWeek eDay = rActDate.GetDayOfWeek();
1618  if( eDay != SUNDAY )
1619  {
1620  return aCellDate.IsBetween( rActDate + (6 - static_cast<sal_Int32>(eDay)),
1621  rActDate + (12 - static_cast<sal_Int32>(eDay)) );
1622  }
1623  else
1624  {
1625  return aCellDate.IsBetween( rActDate + 7, rActDate + 13 );
1626  }
1627  }
1628  break;
1629  case condformat::LASTMONTH:
1630  if( rActDate.GetMonth() == 1 )
1631  {
1632  if( aCellDate.GetMonth() == 12 && rActDate.GetYear() == aCellDate.GetNextYear() )
1633  return true;
1634  }
1635  else if( rActDate.GetYear() == aCellDate.GetYear() )
1636  {
1637  if( rActDate.GetMonth() == aCellDate.GetMonth() + 1)
1638  return true;
1639  }
1640  break;
1641  case condformat::THISMONTH:
1642  if( rActDate.GetYear() == aCellDate.GetYear() )
1643  {
1644  if( rActDate.GetMonth() == aCellDate.GetMonth() )
1645  return true;
1646  }
1647  break;
1648  case condformat::NEXTMONTH:
1649  if( rActDate.GetMonth() == 12 )
1650  {
1651  if( aCellDate.GetMonth() == 1 && rActDate.GetYear() == aCellDate.GetYear() - 1 )
1652  return true;
1653  }
1654  else if( rActDate.GetYear() == aCellDate.GetYear() )
1655  {
1656  if( rActDate.GetMonth() == aCellDate.GetMonth() - 1)
1657  return true;
1658  }
1659  break;
1660  case condformat::LASTYEAR:
1661  if( rActDate.GetYear() == aCellDate.GetNextYear() )
1662  return true;
1663  break;
1664  case condformat::THISYEAR:
1665  if( rActDate.GetYear() == aCellDate.GetYear() )
1666  return true;
1667  break;
1668  case condformat::NEXTYEAR:
1669  if( rActDate.GetYear() == aCellDate.GetYear() - 1 )
1670  return true;
1671  break;
1672  }
1673 
1674  return false;
1675 }
1676 
1678 {
1679  meType = eType;
1680 }
1681 
1682 void ScCondDateFormatEntry::SetStyleName( const OUString& rStyleName )
1683 {
1684  maStyleName = rStyleName;
1685 }
1686 
1688 {
1689  return new ScCondDateFormatEntry( pDoc, *this );
1690 }
1691 
1693 {
1694  mpCache.reset();
1695 }
1696 
1698 {
1699  mpCache.reset();
1700 }
1701 
1702 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
1703  pDoc( pDocument ),
1704  nKey( nNewKey )
1705 {
1706 }
1707 
1708 std::unique_ptr<ScConditionalFormat> ScConditionalFormat::Clone(ScDocument* pNewDoc) const
1709 {
1710  // Real copy of the formula (for Ref Undo/between documents)
1711  if (!pNewDoc)
1712  pNewDoc = pDoc;
1713 
1714  std::unique_ptr<ScConditionalFormat> pNew(new ScConditionalFormat(nKey, pNewDoc));
1715  pNew->SetRange( maRanges ); // prerequisite for listeners
1716 
1717  for (const auto& rxEntry : maEntries)
1718  {
1719  ScFormatEntry* pNewEntry = rxEntry->Clone(pNewDoc);
1720  pNew->maEntries.push_back( std::unique_ptr<ScFormatEntry>(pNewEntry) );
1721  pNewEntry->SetParent(pNew.get());
1722  }
1723 
1724  return pNew;
1725 }
1726 
1727 bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r, bool bIgnoreSrcPos ) const
1728 {
1729  if( size() != r.size())
1730  return false;
1731 
1732  //TODO: Test for same entries in reverse order?
1733  if (! std::equal(maEntries.begin(), maEntries.end(), r.maEntries.begin(),
1734  [&bIgnoreSrcPos](const std::unique_ptr<ScFormatEntry>& p1, const std::unique_ptr<ScFormatEntry>& p2) -> bool
1735  {
1736  return p1->IsEqual(*p2, bIgnoreSrcPos);
1737  }))
1738  return false;
1739 
1740  // right now don't check for same range
1741  // we only use this method to merge same conditional formats from
1742  // old ODF data structure
1743  return true;
1744 }
1745 
1747 {
1748  maRanges = rRanges;
1749  SAL_WARN_IF(maRanges.empty(), "sc", "the conditional format range is empty! will result in a crash later!");
1750 }
1751 
1753 {
1754  maEntries.push_back( std::unique_ptr<ScFormatEntry>(pNew));
1755  pNew->SetParent(this);
1756 }
1757 
1759 {
1760  if (n < maEntries.size())
1761  {
1762  maEntries.erase(maEntries.begin() + n);
1763  DoRepaint();
1764  }
1765 }
1766 
1768 {
1769  return maEntries.empty();
1770 }
1771 
1773 {
1774  return maEntries.size();
1775 }
1776 
1778 {
1779  return pDoc;
1780 }
1781 
1783 {
1784 }
1785 
1786 const ScFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const
1787 {
1788  if ( nPos < size() )
1789  return maEntries[nPos].get();
1790  else
1791  return nullptr;
1792 }
1793 
1794 OUString ScConditionalFormat::GetCellStyle( ScRefCellValue& rCell, const ScAddress& rPos ) const
1795 {
1796  for (const auto& rxEntry : maEntries)
1797  {
1798  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
1799  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
1800  {
1801  const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*rxEntry);
1802  if (rEntry.IsCellValid(rCell, rPos))
1803  return rEntry.GetStyle();
1804  }
1805  else if(rxEntry->GetType() == ScFormatEntry::Type::Date)
1806  {
1807  const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*rxEntry);
1808  if (rEntry.IsValid( rPos ))
1809  return rEntry.GetStyleName();
1810  }
1811  }
1812 
1813  return OUString();
1814 }
1815 
1817 {
1819  for(const auto& rxEntry : maEntries)
1820  {
1821  if( (rxEntry->GetType() == ScFormatEntry::Type::Condition ||
1822  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition) &&
1823  aData.aStyleName.isEmpty())
1824  {
1825  const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*rxEntry);
1826  if (rEntry.IsCellValid(rCell, rPos))
1827  aData.aStyleName = rEntry.GetStyle();
1828  }
1829  else if(rxEntry->GetType() == ScFormatEntry::Type::Colorscale && !aData.mxColorScale)
1830  {
1831  const ScColorScaleFormat& rEntry = static_cast<const ScColorScaleFormat&>(*rxEntry);
1832  aData.mxColorScale = rEntry.GetColor(rPos);
1833  }
1834  else if(rxEntry->GetType() == ScFormatEntry::Type::Databar && !aData.pDataBar)
1835  {
1836  const ScDataBarFormat& rEntry = static_cast<const ScDataBarFormat&>(*rxEntry);
1837  aData.pDataBar = rEntry.GetDataBarInfo(rPos);
1838  }
1839  else if(rxEntry->GetType() == ScFormatEntry::Type::Iconset && !aData.pIconSet)
1840  {
1841  const ScIconSetFormat& rEntry = static_cast<const ScIconSetFormat&>(*rxEntry);
1842  aData.pIconSet = rEntry.GetIconSetInfo(rPos);
1843  }
1844  else if(rxEntry->GetType() == ScFormatEntry::Type::Date && aData.aStyleName.isEmpty())
1845  {
1846  const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*rxEntry);
1847  if ( rEntry.IsValid( rPos ) )
1848  aData.aStyleName = rEntry.GetStyleName();
1849  }
1850  }
1851  return aData;
1852 }
1853 
1855 {
1856  // all conditional format cells
1858 }
1859 
1861 {
1862  for(auto& rxEntry : maEntries)
1863  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
1864  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
1865  static_cast<ScCondFormatEntry&>(*rxEntry).CompileAll();
1866 }
1867 
1869 {
1870  for(auto& rxEntry : maEntries)
1871  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
1872  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
1873  static_cast<ScCondFormatEntry&>(*rxEntry).CompileXML();
1874 }
1875 
1877 {
1878  if (rCxt.meMode == URM_COPY && bCopyAsMove)
1879  {
1880  // ScConditionEntry::UpdateReference() obtains its aSrcPos from
1881  // maRanges and does not update it on URM_COPY, but it's needed later
1882  // for the moved position, so update maRanges beforehand.
1884  for (auto& rxEntry : maEntries)
1885  rxEntry->UpdateReference(rCxt);
1886  }
1887  else
1888  {
1889  for (auto& rxEntry : maEntries)
1890  rxEntry->UpdateReference(rCxt);
1891  maRanges.UpdateReference(rCxt.meMode, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
1892  }
1893 }
1894 
1895 void ScConditionalFormat::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
1896 {
1897  maRanges.InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
1898 }
1899 
1900 void ScConditionalFormat::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
1901 {
1902  maRanges.InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
1903 }
1904 
1906 {
1907  for (size_t i = 0, n = maRanges.size(); i < n; ++i)
1908  {
1909  // We assume that the start and end sheet indices are equal.
1910  ScRange & rRange = maRanges[i];
1911  SCTAB nTab = rRange.aStart.Tab();
1912 
1913  if (nTab < rCxt.mnInsertPos)
1914  // Unaffected.
1915  continue;
1916 
1917  rRange.aStart.IncTab(rCxt.mnSheets);
1918  rRange.aEnd.IncTab(rCxt.mnSheets);
1919  }
1920 
1921  for (auto& rxEntry : maEntries)
1922  rxEntry->UpdateInsertTab(rCxt);
1923 }
1924 
1926 {
1927  for (size_t i = 0, n = maRanges.size(); i < n; ++i)
1928  {
1929  // We assume that the start and end sheet indices are equal.
1930  ScRange & rRange = maRanges[i];
1931  SCTAB nTab = rRange.aStart.Tab();
1932 
1933  if (nTab < rCxt.mnDeletePos)
1934  // Left of the deleted sheet(s). Unaffected.
1935  continue;
1936 
1937  if (nTab <= rCxt.mnDeletePos+rCxt.mnSheets-1)
1938  {
1939  // On the deleted sheet(s).
1940  rRange.aStart.SetTab(-1);
1941  rRange.aEnd.SetTab(-1);
1942  continue;
1943  }
1944 
1945  // Right of the deleted sheet(s). Adjust the sheet indices.
1946  rRange.aStart.IncTab(-1*rCxt.mnSheets);
1947  rRange.aEnd.IncTab(-1*rCxt.mnSheets);
1948  }
1949 
1950  for (auto& rxEntry : maEntries)
1951  rxEntry->UpdateDeleteTab(rCxt);
1952 }
1953 
1955 {
1956  size_t n = maRanges.size();
1957  SCTAB nMinTab = std::min<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
1958  SCTAB nMaxTab = std::max<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
1959  for(size_t i = 0; i < n; ++i)
1960  {
1961  ScRange & rRange = maRanges[i];
1962  SCTAB nTab = rRange.aStart.Tab();
1963  if(nTab < nMinTab || nTab > nMaxTab)
1964  {
1965  continue;
1966  }
1967 
1968  if (nTab == rCxt.mnOldPos)
1969  {
1970  rRange.aStart.SetTab(rCxt.mnNewPos);
1971  rRange.aEnd.SetTab(rCxt.mnNewPos);
1972  continue;
1973  }
1974 
1975  if (rCxt.mnNewPos < rCxt.mnOldPos)
1976  {
1977  rRange.aStart.IncTab();
1978  rRange.aEnd.IncTab();
1979  }
1980  else
1981  {
1982  rRange.aStart.IncTab(-1);
1983  rRange.aEnd.IncTab(-1);
1984  }
1985  }
1986 
1987  for (auto& rxEntry : maEntries)
1988  rxEntry->UpdateMoveTab(rCxt);
1989 }
1990 
1991 void ScConditionalFormat::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
1992 {
1993  if (maRanges.empty())
1994  return;
1995 
1996  SCTAB nTab = maRanges[0].aStart.Tab();
1997  maRanges.DeleteArea( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
1998 }
1999 
2000 void ScConditionalFormat::RenameCellStyle(std::u16string_view rOld, const OUString& rNew)
2001 {
2002  for(const auto& rxEntry : maEntries)
2003  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
2004  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
2005  {
2006  ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*rxEntry);
2007  if(rFormat.GetStyle() == rOld)
2008  rFormat.UpdateStyleName( rNew );
2009  }
2010 }
2011 
2013 {
2014  bool bAllMarked = false;
2015  for(const auto& rxEntry : maEntries)
2016  if(rxEntry->GetType() == ScFormatEntry::Type::Condition ||
2017  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
2018  {
2019  const ScCondFormatEntry& rFormat = static_cast<const ScCondFormatEntry&>(*rxEntry);
2020  bAllMarked = rFormat.MarkUsedExternalReferences();
2021  if (bAllMarked)
2022  break;
2023  }
2024 
2025  return bAllMarked;
2026 }
2027 
2029 {
2030  for(auto& rxEntry : maEntries)
2031  {
2032  rxEntry->startRendering();
2033  }
2034 }
2035 
2037 {
2038  for(auto& rxEntry : maEntries)
2039  {
2040  rxEntry->endRendering();
2041  }
2042 }
2043 
2045 {
2046  for(const auto& rxEntry : maEntries)
2047  {
2048  if (rxEntry->GetType() == ScFormatEntry::Type::Condition ||
2049  rxEntry->GetType() == ScFormatEntry::Type::ExtCondition)
2050  {
2051  ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*rxEntry);
2052  rFormat.CalcAll();
2053  }
2054  }
2055 }
2056 
2058 {
2059  for(const auto& rxFormat : rList)
2060  InsertNew( rxFormat->Clone() );
2061 }
2062 
2064 {
2065  for(const auto& rxFormat : rList)
2066  InsertNew( rxFormat->Clone(&rDoc) );
2067 }
2068 
2069 void ScConditionalFormatList::InsertNew( std::unique_ptr<ScConditionalFormat> pNew )
2070 {
2071  m_ConditionalFormats.insert(std::move(pNew));
2072 }
2073 
2075 {
2076  auto itr = m_ConditionalFormats.find(nKey);
2077  if (itr != m_ConditionalFormats.end())
2078  return itr->get();
2079 
2080  SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2081  return nullptr;
2082 }
2083 
2085 {
2086  auto itr = m_ConditionalFormats.find(nKey);
2087  if (itr != m_ConditionalFormats.end())
2088  return itr->get();
2089 
2090  SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2091  return nullptr;
2092 }
2093 
2095 {
2096  for (auto const& it : m_ConditionalFormats)
2097  {
2098  it->CompileAll();
2099  }
2100 }
2101 
2103 {
2104  for (auto const& it : m_ConditionalFormats)
2105  {
2106  it->CompileXML();
2107  }
2108 }
2109 
2111 {
2112  for (auto const& it : m_ConditionalFormats)
2113  {
2114  it->UpdateReference(rCxt);
2115  }
2116 
2117  if (rCxt.meMode == URM_INSDEL)
2118  {
2119  // need to check which must be deleted
2120  CheckAllEntries();
2121  }
2122 }
2123 
2124 void ScConditionalFormatList::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
2125 {
2126  for (auto const& it : m_ConditionalFormats)
2127  {
2128  it->InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
2129  }
2130 }
2131 
2132 void ScConditionalFormatList::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
2133 {
2134  for (auto const& it : m_ConditionalFormats)
2135  {
2136  it->InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
2137  }
2138 }
2139 
2141 {
2142  for (auto const& it : m_ConditionalFormats)
2143  {
2144  it->UpdateInsertTab(rCxt);
2145  }
2146 }
2147 
2149 {
2150  for (auto const& it : m_ConditionalFormats)
2151  {
2152  it->UpdateDeleteTab(rCxt);
2153  }
2154 }
2155 
2157 {
2158  for (auto const& it : m_ConditionalFormats)
2159  {
2160  it->UpdateMoveTab(rCxt);
2161  }
2162 }
2163 
2164 void ScConditionalFormatList::RenameCellStyle( std::u16string_view rOld, const OUString& rNew )
2165 {
2166  for (auto const& it : m_ConditionalFormats)
2167  {
2168  it->RenameCellStyle(rOld, rNew);
2169  }
2170 }
2171 
2173 {
2174  bool bValid = true;
2175 
2176  // need to check which must be deleted
2177  iterator itr = m_ConditionalFormats.begin();
2178  while(itr != m_ConditionalFormats.end())
2179  {
2180  if ((*itr)->GetRange().empty())
2181  {
2182  bValid = false;
2183  if (rLink.IsSet())
2184  rLink.Call(itr->get());
2185  itr = m_ConditionalFormats.erase(itr);
2186  }
2187  else
2188  ++itr;
2189  }
2190 
2191  return bValid;
2192 }
2193 
2194 void ScConditionalFormatList::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2195 {
2196  for (auto& rxFormat : m_ConditionalFormats)
2197  rxFormat->DeleteArea( nCol1, nRow1, nCol2, nRow2 );
2198 
2199  CheckAllEntries();
2200 }
2201 
2203 {
2204  return m_ConditionalFormats.begin();
2205 }
2206 
2208 {
2209  return m_ConditionalFormats.begin();
2210 }
2211 
2213 {
2214  return m_ConditionalFormats.end();
2215 }
2216 
2218 {
2219  return m_ConditionalFormats.end();
2220 }
2221 
2223 {
2224  ScRangeList aRange;
2225  for (auto& itr: m_ConditionalFormats)
2226  {
2227  const ScRangeList& rRange = itr->GetRange();
2228  for (size_t i = 0, n = rRange.size(); i < n; ++i)
2229  {
2230  aRange.Join(rRange[i]);
2231  }
2232  }
2233  return aRange;
2234 }
2235 
2237 {
2238  ScRangeList aRange = GetCombinedRange();
2239  ScMarkData aMark(rDoc.GetSheetLimits());
2240  aMark.MarkFromRangeList(aRange, true);
2241  sal_uInt16 const pItems[2] = { sal_uInt16(ATTR_CONDITIONAL),0};
2242  rDoc.ClearSelectionItems(pItems, aMark);
2243 }
2244 
2246 {
2247  for (auto& itr: m_ConditionalFormats)
2248  {
2249  const ScRangeList& rRange = itr->GetRange();
2250  if (rRange.empty())
2251  continue;
2252 
2253  SCTAB nTab = rRange.front().aStart.Tab();
2254  rDoc.AddCondFormatData(rRange, nTab, itr->GetKey());
2255  }
2256 }
2257 
2259 {
2260  return m_ConditionalFormats.size();
2261 }
2262 
2264 {
2265  return m_ConditionalFormats.empty();
2266 }
2267 
2269 {
2270  auto itr = m_ConditionalFormats.find(nIndex);
2271  if (itr != end())
2272  m_ConditionalFormats.erase(itr);
2273 }
2274 
2276 {
2277  for (auto const& it : m_ConditionalFormats)
2278  {
2279  it->startRendering();
2280  }
2281 }
2282 
2284 {
2285  for (auto const& it : m_ConditionalFormats)
2286  {
2287  it->endRendering();
2288  }
2289 }
2290 
2292 {
2293  m_ConditionalFormats.clear();
2294 }
2295 
2297 {
2298  if (m_ConditionalFormats.empty())
2299  return 0;
2300  return (*m_ConditionalFormats.rbegin())->GetKey();
2301 }
2302 
2304 {
2305  for (const auto& aEntry : m_ConditionalFormats)
2306  {
2307  aEntry->CalcAll();
2308  }
2309 
2310 }
2311 
2313 
2315 
2317 
2318 
2319 /* 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:1450
void ClearSelectionItems(const sal_uInt16 *pWhich, const ScMarkData &rMark)
Definition: document.cxx:5929
static void UpdateInsertTab(ScAddress &rAddr, const sc::RefUpdateInsertTabContext &rCxt)
Definition: rangeutl.cxx:1052
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:1504
SC_DLLPUBLIC svl::SharedStringPool & GetSharedStringPool()
Definition: documen2.cxx:566
virtual void DataChanged() const override
Definition: conditio.cxx:1508
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
void AddEntry(ScFormatEntry *pNew)
Definition: conditio.cxx:1752
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:1900
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:2069
bool GetDirty() const
sal_uIntPtr sal_uLong
void SetFormula1(const ScTokenArray &rArray)
Definition: conditio.cxx:471
void Interpret(const ScAddress &rPos)
Definition: conditio.cxx:642
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:4630
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:552
bool MarkUsedExternalReferences() const
Definition: conditio.cxx:1384
void StartListening()
Definition: conditio.cxx:154
bool IsClipOrUndo() const
Definition: document.hxx:1532
bool IsValid(const ScAddress &rPos) const
Definition: conditio.cxx:1544
bool IsBelowAverage(double nArg, bool bEqual) const
Definition: conditio.cxx:922
ScRange Combine() const
Definition: rangelst.cxx:1119
ScAddress aEnd
Definition: address.hxx:500
virtual double GetDouble() const
virtual void DataChanged() const
Definition: conditio.cxx:1379
OpCode GetOpCode() const
void UpdateReference(sc::RefUpdateContext &rCxt, bool bCopyAsMove=false)
Definition: conditio.cxx:1876
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:2074
bool IsCellValid(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1224
void CreateStringFromTokenArray(OUString &rFormula)
void RenameCellStyle(std::u16string_view rOld, const OUString &rNew)
Definition: conditio.cxx:2000
void MarkFromRangeList(const ScRangeList &rList, bool bReset)
Definition: markdata.cxx:333
ocRow
ScConditionalFormat(sal_uInt32 nNewKey, ScDocument *pDocument)
Definition: conditio.cxx:1702
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:454
void UpdateDeleteTab(sc::RefUpdateDeleteTabContext &rCxt)
Definition: conditio.cxx:2148
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:587
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:963
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:463
sal_uInt32 getMaxKey() const
Definition: conditio.cxx:2296
SC_DLLPUBLIC SCTAB GetTableCount() const
Definition: document.cxx:314
std::optional< Color > GetColor(const ScAddress &rAddr) const
Definition: colorscale.cxx:587
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:431
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:2172
const SCROW MAXROW
Definition: address.hxx:68
virtual const ScSingleRefData * GetSingleRef() const
std::unique_ptr< ScDataBarInfo > GetDataBarInfo(const ScAddress &rAddr) const
Definition: colorscale.cxx:834
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:2124
ScConditionMode
Definition: conditio.hxx:60
void UpdateReference(sc::RefUpdateContext &rCxt)
Definition: conditio.cxx:2110
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:2236
ConditionalFormatContainer m_ConditionalFormats
Definition: conditio.hxx:630
void MarkUsedExternalReferences()
Definition: documen3.cxx:637
size_t size() const
Definition: conditio.cxx:1772
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:865
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:1331
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:1498
std::unique_ptr< ScFormulaListener > mpListener
Definition: conditio.hxx:327
void SetRange(const ScRangeList &rRanges)
Definition: conditio.cxx:1746
const ScFormatEntry * GetEntry(sal_uInt16 nPos) const
Definition: conditio.cxx:1786
void SetTab(SCTAB nTabP)
Definition: address.hxx:282
bool IsTopNElement(double nArg) const
Definition: conditio.cxx:844
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:484
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:2245
UpdateRefMode meMode
update mode - insert/delete, copy, or move.
virtual ScFormatEntry * Clone(ScDocument *pDoc) const override
Definition: conditio.cxx:1514
void addTokenArray(const ScTokenArray *pTokens, const ScRange &rRange)
Definition: colorscale.cxx:112
bool IsValidStr(const OUString &rArg, const ScAddress &rPos) const
Definition: conditio.cxx:1116
void CalcAll()
Forced recalculation of formulas.
Definition: conditio.cxx:2303
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:1240
sal_Int16 SCCOL
Definition: types.hxx:21
bool IsValid(double nArg, const ScAddress &rPos) const
Definition: conditio.cxx:963
ocSheet
ocPush
condformat::ScCondFormatDateType meType
Definition: conditio.hxx:531
size_t size() const
Definition: conditio.cxx:2258
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:614
void UpdateInsertTab(sc::RefUpdateInsertTabContext &rCxt)
Definition: conditio.cxx:1905
size_t size() const
Definition: rangelst.hxx:89
bool NeedsRepaint() const
Definition: conditio.cxx:1455
ScSingleRefData Ref2
Definition: refdata.hxx:125
ConditionalFormatContainer::iterator iterator
Definition: conditio.hxx:665
bool IsDuplicate(double nArg, const OUString &rStr) const
Definition: conditio.cxx:818
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:1758
SUNDAY
bool EqualEntries(const ScConditionalFormat &r, bool bIgnoreSrcPos=false) const
Definition: conditio.cxx:1727
void AddDays(sal_Int32 nAddDays)
virtual ScFormatEntry * Clone(ScDocument *pDoc) const =0
void SetIgnoreBlank(bool bSet)
Definition: conditio.cxx:418
bool IsRowRel() const
Definition: refdata.hxx:67
bool IsRunning() const
void UpdateDeleteTab(sc::RefUpdateDeleteTabContext &rCxt)
Definition: conditio.cxx:1925
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:483
void UpdateStyleName(const OUString &rNew)
Definition: conditio.hxx:474
bool IsError(const ScAddress &rPos) const
Definition: conditio.cxx:950
void UpdateMoveTab(sc::RefUpdateMoveTabContext &rCxt)
Definition: conditio.cxx:1954
virtual void UpdateReference(sc::RefUpdateContext &rCxt) override
Definition: conditio.cxx:495
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:1697
const svl::SharedString & GetString()
SCCOL Col() const
Definition: address.hxx:266
void SetFreeFlying(bool b)
XPropertyListType t
virtual void UpdateDeleteTab(sc::RefUpdateDeleteTabContext &rCxt) override
Definition: conditio.cxx:569
SC_DLLPUBLIC bool Move(SCCOL nDeltaX, SCROW nDeltaY, SCTAB nDeltaZ, ScAddress &rErrorPos, const ScDocument *pDocument=nullptr)
Definition: address.cxx:2325
virtual ScFormatEntry * Clone(ScDocument *pDoc) const override
Definition: conditio.cxx:1396
ScCondFormatEntry(ScConditionMode eOper, const OUString &rExpr1, const OUString &rExpr2, ScDocument &rDocument, const ScAddress &rPos, const OUString &rStyle, const OUString &rExprNmsp1=OUString(), const OUString &rExprNmsp2=OUString(), formula::FormulaGrammar::Grammar eGrammar1=formula::FormulaGrammar::GRAM_DEFAULT, formula::FormulaGrammar::Grammar eGrammar2=formula::FormulaGrammar::GRAM_DEFAULT, Type eType=Type::Condition)
svDoubleRef
CellType meType
Definition: cellvalue.hxx:105
ScCondFormatData GetData(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1816
ScCondDateFormatEntry(ScDocument *pDoc)
Definition: conditio.cxx:1531
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:1895
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:2222
void DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
Definition: conditio.cxx:1991
static SC_DLLPUBLIC CollatorWrapper & GetCollator()
case-insensitive collator
Definition: global.cxx:1044
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:2012
static void UpdateDeleteTab(ScAddress &rAddr, const sc::RefUpdateDeleteTabContext &rCxt)
Definition: rangeutl.cxx:1060
virtual ScFormatEntry * Clone(ScDocument *pDoc) const override
Definition: conditio.cxx:1687
void UpdateInsertTab(sc::RefUpdateInsertTabContext &rCxt)
Definition: conditio.cxx:2140
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:604
bool IsAboveAverage(double nArg, bool bEqual) const
Definition: conditio.cxx:936
static bool lcl_GetCellContent(ScRefCellValue &rCell, bool bIsStr1, double &rArg, OUString &rArgStr, const ScDocument *pDoc)
Definition: conditio.cxx:723
void SetDateType(condformat::ScCondFormatDateType eType)
Definition: conditio.cxx:1677
constexpr TypedWhichId< ScCondFormatItem > ATTR_CONDITIONAL(154)
void RenameCellStyle(std::u16string_view rOld, const OUString &rNew)
Definition: conditio.cxx:2164
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
static SC_DLLPUBLIC OUString GetString(const EditTextObject &rEditText, const ScDocument *pDoc)
Retrieves string with paragraphs delimited by new lines (' ').
Definition: editutil.cxx:118
virtual Type GetType() const =0
bool IsTopNPercent(double nArg) const
Definition: conditio.cxx:885
void erase(sal_uLong nIndex)
Definition: conditio.cxx:2268
static ScConditionMode GetModeFromApi(css::sheet::ConditionOperator nOperator)
Definition: conditio.cxx:1401
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:1445
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:1549
std::unique_ptr< ScTokenArray > CreateFlatCopiedTokenArray(sal_uInt16 nPos) const
Create a flat copy using ScTokenArray copy-ctor with shared tokens.
Definition: conditio.cxx:1286
virtual void SetParent(ScConditionalFormat *pNew) override
Definition: conditio.cxx:167
ScConditionalFormat * pCondFormat
Definition: conditio.hxx:414
OUString GetCellStyle(ScRefCellValue &rCell, const ScAddress &rPos) const
Definition: conditio.cxx:1794
bool IsBottomNPercent(double nArg) const
Definition: conditio.cxx:904
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:1692
bool IsEmpty() const
Definition: conditio.cxx:1767
StackVar GetType() const
OUString aStyleName
Definition: conditio.hxx:221
void UpdateMoveTab(sc::RefUpdateMoveTabContext &rCxt)
Definition: conditio.cxx:2156
RedlineType meType
aStr
OUString aStrVal2
Definition: conditio.hxx:310
std::unique_ptr< ScConditionalFormat > Clone(ScDocument *pNewDoc=nullptr) const
Definition: conditio.cxx:1708
void FillCache() const
Definition: conditio.cxx:761
const formula::FormulaGrammar::Grammar eTempGrammar1
Definition: conditio.hxx:313
void SetStyleName(const OUString &rStyleName)
Definition: conditio.cxx:1682
#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:4821
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:2194
std::unique_ptr< ScFormulaCell > pFCell2
Definition: conditio.hxx:323
ScDocument * GetDocument()
Definition: conditio.cxx:1777
void InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColStart, SCSIZE nSize)
Definition: conditio.cxx:2132