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