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