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