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