fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / conditio.cxx
blobd4408d9a5d4c4dff657e71adc2dcd549d4bd3891
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "scitems.hxx"
21 #include <sfx2/objsh.hxx>
22 #include <svl/itemset.hxx>
23 #include <svl/zforlist.hxx>
24 #include <rtl/math.hxx>
25 #include <unotools/collatorwrapper.hxx>
27 #include <com/sun/star/sheet/ConditionOperator2.hpp>
29 #include "conditio.hxx"
30 #include "formulacell.hxx"
31 #include "document.hxx"
32 #include "hints.hxx"
33 #include "compiler.hxx"
34 #include "rechead.hxx"
35 #include "rangelst.hxx"
36 #include "stlpool.hxx"
37 #include "rangenam.hxx"
38 #include "colorscale.hxx"
39 #include "cellvalue.hxx"
40 #include "editutil.hxx"
41 #include "tokenarray.hxx"
42 #include "refupdatecontext.hxx"
43 #include <svl/sharedstring.hxx>
44 #include <svl/sharedstringpool.hxx>
45 #include <boost/scoped_ptr.hpp>
47 using namespace formula;
49 ScFormatEntry::ScFormatEntry(ScDocument* pDoc):
50 mpDoc(pDoc)
54 bool ScFormatEntry::operator==( const ScFormatEntry& r ) const
56 if(GetType() != r.GetType())
57 return false;
59 switch(GetType())
61 case condformat::CONDITION:
62 return static_cast<const ScCondFormatEntry&>(*this) == static_cast<const ScCondFormatEntry&>(r);
63 default:
64 // TODO: implement also this case
65 // actually return false for these cases is not that bad
66 // as soon as databar and color scale are tested we need
67 // to think about the range
68 return false;
72 void ScFormatEntry::startRendering()
76 void ScFormatEntry::endRendering()
80 static bool lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, sal_uInt16 nRecursion = 0 )
82 if (pFormula)
84 pFormula->Reset();
85 FormulaToken* t;
86 for( t = pFormula->Next(); t; t = pFormula->Next() )
88 switch( t->GetType() )
90 case svDoubleRef:
92 ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
93 if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
94 return true;
96 // fall through
98 case svSingleRef:
100 ScSingleRefData& rRef1 = *t->GetSingleRef();
101 if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
102 return true;
104 break;
106 case svIndex:
108 if( t->GetOpCode() == ocName ) // DB areas always absolute
109 if( ScRangeData* pRangeData = pDoc->GetRangeName()->findByIndex( t->GetIndex() ) )
110 if( (nRecursion < 42) && lcl_HasRelRef( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
111 return true;
113 break;
115 // #i34474# function result dependent on cell position
116 case svByte:
118 switch( t->GetOpCode() )
120 case ocRow: // ROW() returns own row index
121 case ocColumn: // COLUMN() returns own column index
122 case ocSheet: // SHEET() returns own sheet index
123 case ocCell: // CELL() may return own cell address
124 return true;
125 default:
127 // added to avoid warnings
131 break;
133 default:
135 // added to avoid warnings
140 return false;
143 ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) :
144 ScFormatEntry(r.mpDoc),
145 eOp(r.eOp),
146 nOptions(r.nOptions),
147 nVal1(r.nVal1),
148 nVal2(r.nVal2),
149 aStrVal1(r.aStrVal1),
150 aStrVal2(r.aStrVal2),
151 aStrNmsp1(r.aStrNmsp1),
152 aStrNmsp2(r.aStrNmsp2),
153 eTempGrammar1(r.eTempGrammar1),
154 eTempGrammar2(r.eTempGrammar2),
155 bIsStr1(r.bIsStr1),
156 bIsStr2(r.bIsStr2),
157 pFormula1(NULL),
158 pFormula2(NULL),
159 aSrcPos(r.aSrcPos),
160 aSrcString(r.aSrcString),
161 pFCell1(NULL),
162 pFCell2(NULL),
163 bRelRef1(r.bRelRef1),
164 bRelRef2(r.bRelRef2),
165 bFirstRun(true),
166 pCondFormat(r.pCondFormat)
168 // ScTokenArray copy ctor creates a flat copy
169 if (r.pFormula1)
170 pFormula1 = new ScTokenArray( *r.pFormula1 );
171 if (r.pFormula2)
172 pFormula2 = new ScTokenArray( *r.pFormula2 );
174 // Formula cells are created at IsValid
177 ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntry& r ) :
178 ScFormatEntry(pDocument),
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 pFormula1(NULL),
192 pFormula2(NULL),
193 aSrcPos(r.aSrcPos),
194 aSrcString(r.aSrcString),
195 pFCell1(NULL),
196 pFCell2(NULL),
197 bRelRef1(r.bRelRef1),
198 bRelRef2(r.bRelRef2),
199 bFirstRun(true),
200 pCondFormat(r.pCondFormat)
202 // Real copy of the formulas (for Ref Undo)
203 if (r.pFormula1)
204 pFormula1 = r.pFormula1->Clone();
205 if (r.pFormula2)
206 pFormula2 = r.pFormula2->Clone();
208 // Formula cells are created at IsValid
209 // TODO: But not in the Clipboard! So interpret beforehand!
212 ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
213 const OUString& rExpr1, const OUString& rExpr2, ScDocument* pDocument, const ScAddress& rPos,
214 const OUString& rExprNmsp1, const OUString& rExprNmsp2,
215 FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) :
216 ScFormatEntry(pDocument),
217 eOp(eOper),
218 nOptions(0),
219 nVal1(0.0),
220 nVal2(0.0),
221 aStrNmsp1(rExprNmsp1),
222 aStrNmsp2(rExprNmsp2),
223 eTempGrammar1(eGrammar1),
224 eTempGrammar2(eGrammar2),
225 bIsStr1(false),
226 bIsStr2(false),
227 pFormula1(NULL),
228 pFormula2(NULL),
229 aSrcPos(rPos),
230 pFCell1(NULL),
231 pFCell2(NULL),
232 bRelRef1(false),
233 bRelRef2(false),
234 bFirstRun(true),
235 pCondFormat(NULL)
237 Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, false );
239 // Formula cells are created at IsValid
242 ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
243 const ScTokenArray* pArr1, const ScTokenArray* pArr2,
244 ScDocument* pDocument, const ScAddress& rPos ) :
245 ScFormatEntry(pDocument),
246 eOp(eOper),
247 nOptions(0),
248 nVal1(0.0),
249 nVal2(0.0),
250 eTempGrammar1(FormulaGrammar::GRAM_DEFAULT),
251 eTempGrammar2(FormulaGrammar::GRAM_DEFAULT),
252 bIsStr1(false),
253 bIsStr2(false),
254 pFormula1(NULL),
255 pFormula2(NULL),
256 aSrcPos(rPos),
257 pFCell1(NULL),
258 pFCell2(NULL),
259 bRelRef1(false),
260 bRelRef2(false),
261 bFirstRun(true),
262 pCondFormat(NULL)
264 if ( pArr1 )
266 pFormula1 = new ScTokenArray( *pArr1 );
267 if ( pFormula1->GetLen() == 1 )
269 // Single (constant number)?
270 FormulaToken* pToken = pFormula1->First();
271 if ( pToken->GetOpCode() == ocPush )
273 if ( pToken->GetType() == svDouble )
275 nVal1 = pToken->GetDouble();
276 DELETEZ(pFormula1); // Do not remember as formula
278 else if ( pToken->GetType() == svString )
280 bIsStr1 = true;
281 aStrVal1 = pToken->GetString().getString();
282 DELETEZ(pFormula1); // Do not remember as formula
286 bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
288 if ( pArr2 )
290 pFormula2 = new ScTokenArray( *pArr2 );
291 if ( pFormula2->GetLen() == 1 )
293 // Single (constant number)?
294 FormulaToken* pToken = pFormula2->First();
295 if ( pToken->GetOpCode() == ocPush )
297 if ( pToken->GetType() == svDouble )
299 nVal2 = pToken->GetDouble();
300 DELETEZ(pFormula2); // Do not remember as formula
302 else if ( pToken->GetType() == svString )
304 bIsStr2 = true;
305 aStrVal2 = pToken->GetString().getString();
306 DELETEZ(pFormula2); // Do not remember as formula
310 bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
313 // Formula cells are created at IsValid
316 ScConditionEntry::~ScConditionEntry()
318 delete pFCell1;
319 delete pFCell2;
321 delete pFormula1;
322 delete pFormula2;
325 void ScConditionEntry::SetOperation(ScConditionMode eMode)
327 eOp = eMode;
330 void ScConditionEntry::Compile( const OUString& rExpr1, const OUString& rExpr2,
331 const OUString& rExprNmsp1, const OUString& rExprNmsp2,
332 FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2, bool bTextToReal )
334 if ( !rExpr1.isEmpty() || !rExpr2.isEmpty() )
336 ScCompiler aComp( mpDoc, aSrcPos );
338 if ( !rExpr1.isEmpty() )
340 delete pFormula1;
341 aComp.SetGrammar( eGrammar1 );
342 if ( mpDoc->IsImportingXML() && !bTextToReal )
344 // temporary formula string as string tokens
345 //TODO: merge with lcl_ScDocFunc_CreateTokenArrayXML
346 pFormula1 = new ScTokenArray;
347 pFormula1->AddStringXML( rExpr1 );
348 // bRelRef1 is set when the formula is compiled again (CompileXML)
350 else
352 pFormula1 = aComp.CompileString( rExpr1, rExprNmsp1 );
353 if ( pFormula1->GetLen() == 1 )
355 // Single (constant number)?
356 FormulaToken* pToken = pFormula1->First();
357 if ( pToken->GetOpCode() == ocPush )
359 if ( pToken->GetType() == svDouble )
361 nVal1 = pToken->GetDouble();
362 DELETEZ(pFormula1); // Do not remember as formula
364 else if ( pToken->GetType() == svString )
366 bIsStr1 = true;
367 aStrVal1 = pToken->GetString().getString();
368 DELETEZ(pFormula1); // Do not remember as formula
372 bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
376 if ( !rExpr2.isEmpty() )
378 delete pFormula2;
379 aComp.SetGrammar( eGrammar2 );
380 if ( mpDoc->IsImportingXML() && !bTextToReal )
382 // temporary formula string as string tokens
383 //TODO: merge with lcl_ScDocFunc_CreateTokenArrayXML
384 pFormula2 = new ScTokenArray;
385 pFormula2->AddStringXML( rExpr2 );
386 // bRelRef2 is set when the formula is compiled again (CompileXML)
388 else
390 pFormula2 = aComp.CompileString( rExpr2, rExprNmsp2 );
391 if ( pFormula2->GetLen() == 1 )
393 // Sigle (constant number)?
394 FormulaToken* pToken = pFormula2->First();
395 if ( pToken->GetOpCode() == ocPush )
397 if ( pToken->GetType() == svDouble )
399 nVal2 = pToken->GetDouble();
400 DELETEZ(pFormula2); // Do not remember as formula
402 else if ( pToken->GetType() == svString )
404 bIsStr2 = true;
405 aStrVal2 = pToken->GetString().getString();
406 DELETEZ(pFormula2); // Do not remember as formula
410 bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
417 * Create formula cells
419 void ScConditionEntry::MakeCells( const ScAddress& rPos )
421 if ( !mpDoc->IsClipOrUndo() ) // Never calculate in the Clipboard!
423 if ( pFormula1 && !pFCell1 && !bRelRef1 )
425 pFCell1 = new ScFormulaCell(mpDoc, rPos, *pFormula1);
426 pFCell1->StartListeningTo( mpDoc );
429 if ( pFormula2 && !pFCell2 && !bRelRef2 )
431 pFCell2 = new ScFormulaCell(mpDoc, rPos, *pFormula2);
432 pFCell2->StartListeningTo( mpDoc );
437 void ScConditionEntry::SetIgnoreBlank(bool bSet)
439 // The bit SC_COND_NOBLANKS is set if blanks are not ignored
440 // (only of valid)
441 if (bSet)
442 nOptions &= ~SC_COND_NOBLANKS;
443 else
444 nOptions |= SC_COND_NOBLANKS;
448 * Delete formula cells, so we re-complile at the next IsValid
450 void ScConditionEntry::CompileAll()
452 DELETEZ(pFCell1);
453 DELETEZ(pFCell2);
456 void ScConditionEntry::CompileXML()
458 // First parse the formula source position if it was stored as text
459 if ( !aSrcString.isEmpty() )
461 ScAddress aNew;
462 /* XML is always in OOo:A1 format, although R1C1 would be more amenable
463 * to compression */
464 if ( aNew.Parse( aSrcString, mpDoc ) & SCA_VALID )
465 aSrcPos = aNew;
466 // if the position is invalid, there isn't much we can do at this time
467 aSrcString.clear();
470 // Convert the text tokens that were created during XML import into real tokens.
471 Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar1),
472 GetExpression(aSrcPos, 1, 0, eTempGrammar2),
473 aStrNmsp1, aStrNmsp2, eTempGrammar1, eTempGrammar2, true );
476 void ScConditionEntry::SetSrcString( const OUString& rNew )
478 // aSrcString is only evaluated in CompileXML
479 SAL_WARN_IF( !mpDoc->IsImportingXML(), "sc", "SetSrcString is only valid for XML import" );
481 aSrcString = rNew;
484 void ScConditionEntry::SetFormula1( const ScTokenArray& rArray )
486 DELETEZ( pFormula1 );
487 if( rArray.GetLen() > 0 )
489 pFormula1 = new ScTokenArray( rArray );
490 bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
494 void ScConditionEntry::SetFormula2( const ScTokenArray& rArray )
496 DELETEZ( pFormula2 );
497 if( rArray.GetLen() > 0 )
499 pFormula2 = new ScTokenArray( rArray );
500 bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
504 void ScConditionEntry::UpdateReference( sc::RefUpdateContext& rCxt )
506 if(pCondFormat)
507 aSrcPos = pCondFormat->GetRange().Combine().aStart;
508 ScAddress aOldSrcPos = aSrcPos;
509 bool bChangedPos = false;
510 if (rCxt.meMode == URM_INSDEL && rCxt.maRange.In(aSrcPos))
512 aSrcPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
513 bChangedPos = aSrcPos != aOldSrcPos;
516 if (pFormula1)
518 sc::RefUpdateResult aRes;
519 switch (rCxt.meMode)
521 case URM_INSDEL:
522 aRes = pFormula1->AdjustReferenceOnShift(rCxt, aOldSrcPos);
523 break;
524 case URM_MOVE:
525 aRes = pFormula1->AdjustReferenceOnMove(rCxt, aOldSrcPos, aSrcPos);
526 break;
527 default:
531 if (aRes.mbReferenceModified || bChangedPos)
532 DELETEZ(pFCell1); // is created again in IsValid
535 if (pFormula2)
537 sc::RefUpdateResult aRes;
538 switch (rCxt.meMode)
540 case URM_INSDEL:
541 aRes = pFormula2->AdjustReferenceOnShift(rCxt, aOldSrcPos);
542 break;
543 case URM_MOVE:
544 aRes = pFormula2->AdjustReferenceOnMove(rCxt, aOldSrcPos, aSrcPos);
545 break;
546 default:
550 if (aRes.mbReferenceModified || bChangedPos)
551 DELETEZ(pFCell2); // is created again in IsValid
555 void ScConditionEntry::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
557 if (pFormula1)
559 pFormula1->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
560 DELETEZ(pFCell1);
563 if (pFormula2)
565 pFormula2->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
566 DELETEZ(pFCell2);
570 void ScConditionEntry::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
572 if (pFormula1)
574 pFormula1->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
575 DELETEZ(pFCell1);
578 if (pFormula2)
580 pFormula2->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
581 DELETEZ(pFCell2);
585 void ScConditionEntry::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
587 if (pFormula1)
589 pFormula1->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
590 DELETEZ(pFCell1);
593 if (pFormula2)
595 pFormula2->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
596 DELETEZ(pFCell2);
600 //FIXME: Make this a comparison operator at the TokenArray?
601 static bool lcl_IsEqual( const ScTokenArray* pArr1, const ScTokenArray* pArr2 )
603 // We only compare the non-RPN array
604 if ( pArr1 && pArr2 )
606 sal_uInt16 nLen = pArr1->GetLen();
607 if ( pArr2->GetLen() != nLen )
608 return false;
610 FormulaToken** ppToken1 = pArr1->GetArray();
611 FormulaToken** ppToken2 = pArr2->GetArray();
612 for (sal_uInt16 i=0; i<nLen; i++)
614 if ( ppToken1[i] != ppToken2[i] &&
615 !(*ppToken1[i] == *ppToken2[i]) )
616 return false; // Difference
618 return true; // All entries are the same
620 else
621 return !pArr1 && !pArr2; // Both 0? -> the same
624 bool ScConditionEntry::operator== ( const ScConditionEntry& r ) const
626 bool bEq = (eOp == r.eOp && nOptions == r.nOptions &&
627 lcl_IsEqual( pFormula1, r.pFormula1 ) &&
628 lcl_IsEqual( pFormula2, r.pFormula2 ));
629 if (bEq)
631 // for formulas, the reference positions must be compared, too
632 // (including aSrcString, for inserting the entries during XML import)
633 if ( ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
634 bEq = false;
636 // If not formulas, compare values
637 if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
638 bEq = false;
639 if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
640 bEq = false;
643 return bEq;
646 void ScConditionEntry::Interpret( const ScAddress& rPos )
648 // Create formula cells
649 // Note: New Broadcaster (Note cells) may be inserted into the document!
650 if ( ( pFormula1 && !pFCell1 ) || ( pFormula2 && !pFCell2 ) )
651 MakeCells( rPos );
653 // Evaluate formulas
654 bool bDirty = false; // 1 and 2 separate?
656 boost::scoped_ptr<ScFormulaCell> pTemp1;
657 ScFormulaCell* pEff1 = pFCell1;
658 if ( bRelRef1 )
660 pTemp1.reset(pFormula1 ? new ScFormulaCell(mpDoc, rPos, *pFormula1) : new ScFormulaCell(mpDoc, rPos));
661 pEff1 = pTemp1.get();
663 if ( pEff1 )
665 if (!pEff1->IsRunning()) // Don't create 522
667 //TODO: Query Changed instead of Dirty!
668 if (pEff1->GetDirty() && !bRelRef1 && mpDoc->GetAutoCalc())
669 bDirty = true;
670 if (pEff1->IsValue())
672 bIsStr1 = false;
673 nVal1 = pEff1->GetValue();
674 aStrVal1.clear();
676 else
678 bIsStr1 = true;
679 aStrVal1 = pEff1->GetString().getString();
680 nVal1 = 0.0;
684 pTemp1.reset();
686 boost::scoped_ptr<ScFormulaCell> pTemp2;
687 ScFormulaCell* pEff2 = pFCell2; //@ 1!=2
688 if ( bRelRef2 )
690 pTemp2.reset(pFormula2 ? new ScFormulaCell(mpDoc, rPos, *pFormula2) : new ScFormulaCell(mpDoc, rPos));
691 pEff2 = pTemp2.get();
693 if ( pEff2 )
695 if (!pEff2->IsRunning()) // Don't create 522
697 if (pEff2->GetDirty() && !bRelRef2 && mpDoc->GetAutoCalc())
698 bDirty = true;
699 if (pEff2->IsValue())
701 bIsStr2 = false;
702 nVal2 = pEff2->GetValue();
703 aStrVal2.clear();
705 else
707 bIsStr2 = true;
708 aStrVal2 = pEff2->GetString().getString();
709 nVal2 = 0.0;
713 pTemp2.reset();
715 // If IsRunning, the last values remain
716 if (bDirty && !bFirstRun)
718 // Repaint everything for dependent formats
719 DataChanged( NULL );
722 bFirstRun = false;
725 static bool lcl_GetCellContent( ScRefCellValue& rCell, bool bIsStr1, double& rArg, OUString& rArgStr,
726 const ScDocument* pDoc )
729 if (rCell.isEmpty())
730 return !bIsStr1;
732 bool bVal = true;
734 switch (rCell.meType)
736 case CELLTYPE_VALUE:
737 rArg = rCell.mfValue;
738 break;
739 case CELLTYPE_FORMULA:
741 bVal = rCell.mpFormula->IsValue();
742 if (bVal)
743 rArg = rCell.mpFormula->GetValue();
744 else
745 rArgStr = rCell.mpFormula->GetString().getString();
747 break;
748 case CELLTYPE_STRING:
749 case CELLTYPE_EDIT:
750 bVal = false;
751 if (rCell.meType == CELLTYPE_STRING)
752 rArgStr = rCell.mpString->getString();
753 else if (rCell.mpEditText)
754 rArgStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc);
755 break;
756 default:
760 return bVal;
763 void ScConditionEntry::FillCache() const
765 if(!mpCache)
767 const ScRangeList& rRanges = pCondFormat->GetRange();
768 mpCache.reset(new ScConditionEntryCache);
769 size_t nListCount = rRanges.size();
770 for( size_t i = 0; i < nListCount; i++ )
772 const ScRange *aRange = rRanges[i];
773 SCROW nRow = aRange->aEnd.Row();
774 SCCOL nCol = aRange->aEnd.Col();
775 SCCOL nColStart = aRange->aStart.Col();
776 SCROW nRowStart = aRange->aStart.Row();
777 SCTAB nTab = aRange->aStart.Tab();
779 // temporary fix to workaorund slow duplicate entry
780 // conditions, prevent to use a whole row
781 if(nRow == MAXROW)
783 bool bShrunk = false;
784 mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
785 nCol, nRow, false);
788 for( SCROW r = nRowStart; r <= nRow; r++ )
789 for( SCCOL c = nColStart; c <= nCol; c++ )
791 ScRefCellValue aCell;
792 aCell.assign(*mpDoc, ScAddress(c, r, nTab));
793 if (aCell.isEmpty())
794 continue;
796 double nVal = 0.0;
797 OUString aStr;
798 if (!lcl_GetCellContent(aCell, false, nVal, aStr, mpDoc))
800 std::pair<ScConditionEntryCache::StringCacheType::iterator, bool> aResult =
801 mpCache->maStrings.insert(
802 ScConditionEntryCache::StringCacheType::value_type(aStr, 1));
804 if(!aResult.second)
805 aResult.first->second++;
807 else
809 std::pair<ScConditionEntryCache::ValueCacheType::iterator, bool> aResult =
810 mpCache->maValues.insert(
811 ScConditionEntryCache::ValueCacheType::value_type(nVal, 1));
813 if(!aResult.second)
814 aResult.first->second++;
816 ++(mpCache->nValueItems);
823 bool ScConditionEntry::IsDuplicate( double nArg, const OUString& rStr ) const
825 FillCache();
827 if(rStr.isEmpty())
829 ScConditionEntryCache::ValueCacheType::iterator itr = mpCache->maValues.find(nArg);
830 if(itr == mpCache->maValues.end())
831 return false;
832 else
834 if(itr->second > 1)
835 return true;
836 else
837 return false;
840 else
842 ScConditionEntryCache::StringCacheType::iterator itr = mpCache->maStrings.find(rStr);
843 if(itr == mpCache->maStrings.end())
844 return false;
845 else
847 if(itr->second > 1)
848 return true;
849 else
850 return false;
855 bool ScConditionEntry::IsTopNElement( double nArg ) const
857 FillCache();
859 if(mpCache->nValueItems <= nVal1)
860 return true;
862 size_t nCells = 0;
863 for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
864 itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
866 if(nCells >= nVal1)
867 return false;
868 if(itr->first <= nArg)
869 return true;
870 nCells += itr->second;
873 return true;
876 bool ScConditionEntry::IsBottomNElement( double nArg ) const
878 FillCache();
880 if(mpCache->nValueItems <= nVal1)
881 return true;
883 size_t nCells = 0;
884 for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
885 itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
887 if(nCells >= nVal1)
888 return false;
889 if(itr->first >= nArg)
890 return true;
891 nCells += itr->second;
894 return true;
897 bool ScConditionEntry::IsTopNPercent( double nArg ) const
899 FillCache();
901 size_t nCells = 0;
902 size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
903 for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
904 itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
906 if(nCells >= nLimitCells)
907 return false;
908 if(itr->first <= nArg)
909 return true;
910 nCells += itr->second;
913 return true;
916 bool ScConditionEntry::IsBottomNPercent( double nArg ) const
918 FillCache();
920 size_t nCells = 0;
921 size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
922 for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
923 itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
925 if(nCells >= nLimitCells)
926 return false;
927 if(itr->first >= nArg)
928 return true;
929 nCells += itr->second;
932 return true;
935 bool ScConditionEntry::IsBelowAverage( double nArg, bool bEqual ) const
937 FillCache();
939 double nSum = 0;
940 for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
941 itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
943 nSum += itr->first * itr->second;
946 if(bEqual)
947 return (nArg <= nSum/mpCache->nValueItems);
948 else
949 return (nArg < nSum/mpCache->nValueItems);
952 bool ScConditionEntry::IsAboveAverage( double nArg, bool bEqual ) const
954 FillCache();
956 double nSum = 0;
957 for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
958 itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
960 nSum += itr->first * itr->second;
963 if(bEqual)
964 return (nArg >= nSum/mpCache->nValueItems);
965 else
966 return (nArg > nSum/mpCache->nValueItems);
969 bool ScConditionEntry::IsError( const ScAddress& rPos ) const
971 switch (mpDoc->GetCellType(rPos))
973 case CELLTYPE_VALUE:
974 return false;
975 case CELLTYPE_FORMULA:
977 ScFormulaCell* pFormulaCell = const_cast<ScFormulaCell*>(mpDoc->GetFormulaCell(rPos));
978 if (pFormulaCell && pFormulaCell->GetErrCode())
979 return true;
981 case CELLTYPE_STRING:
982 case CELLTYPE_EDIT:
983 return false;
984 default:
985 break;
987 return false;
990 bool ScConditionEntry::IsValid( double nArg, const ScAddress& rPos ) const
992 // Interpret must already have been called
993 if ( bIsStr1 )
995 switch( eOp )
997 case SC_COND_BEGINS_WITH:
998 case SC_COND_ENDS_WITH:
999 case SC_COND_CONTAINS_TEXT:
1000 case SC_COND_NOT_CONTAINS_TEXT:
1001 break;
1002 case SC_COND_NOTEQUAL:
1003 return true;
1004 default:
1005 return false;
1009 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1010 if ( bIsStr2 )
1011 return false;
1013 double nComp1 = nVal1; // Copy, so that it can be changed
1014 double nComp2 = nVal2;
1016 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1017 if ( nComp1 > nComp2 )
1019 // Right order for value range
1020 double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp;
1023 // All corner cases need to be tested with ::rtl::math::approxEqual!
1024 bool bValid = false;
1025 switch (eOp)
1027 case SC_COND_NONE:
1028 break; // Always sal_False
1029 case SC_COND_EQUAL:
1030 bValid = ::rtl::math::approxEqual( nArg, nComp1 );
1031 break;
1032 case SC_COND_NOTEQUAL:
1033 bValid = !::rtl::math::approxEqual( nArg, nComp1 );
1034 break;
1035 case SC_COND_GREATER:
1036 bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1037 break;
1038 case SC_COND_EQGREATER:
1039 bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1040 break;
1041 case SC_COND_LESS:
1042 bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1043 break;
1044 case SC_COND_EQLESS:
1045 bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1046 break;
1047 case SC_COND_BETWEEN:
1048 bValid = ( nArg >= nComp1 && nArg <= nComp2 ) ||
1049 ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 );
1050 break;
1051 case SC_COND_NOTBETWEEN:
1052 bValid = ( nArg < nComp1 || nArg > nComp2 ) &&
1053 !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 );
1054 break;
1055 case SC_COND_DUPLICATE:
1056 case SC_COND_NOTDUPLICATE:
1057 if( pCondFormat )
1059 bValid = IsDuplicate( nArg, OUString() );
1060 if( eOp == SC_COND_NOTDUPLICATE )
1061 bValid = !bValid;
1063 break;
1064 case SC_COND_DIRECT:
1065 bValid = !::rtl::math::approxEqual( nComp1, 0.0 );
1066 break;
1067 case SC_COND_TOP10:
1068 bValid = IsTopNElement( nArg );
1069 break;
1070 case SC_COND_BOTTOM10:
1071 bValid = IsBottomNElement( nArg );
1072 break;
1073 case SC_COND_TOP_PERCENT:
1074 bValid = IsTopNPercent( nArg );
1075 break;
1076 case SC_COND_BOTTOM_PERCENT:
1077 bValid = IsBottomNPercent( nArg );
1078 break;
1079 case SC_COND_ABOVE_AVERAGE:
1080 case SC_COND_ABOVE_EQUAL_AVERAGE:
1081 bValid = IsAboveAverage( nArg, eOp == SC_COND_ABOVE_EQUAL_AVERAGE );
1082 break;
1083 case SC_COND_BELOW_AVERAGE:
1084 case SC_COND_BELOW_EQUAL_AVERAGE:
1085 bValid = IsBelowAverage( nArg, eOp == SC_COND_BELOW_EQUAL_AVERAGE );
1086 break;
1087 case SC_COND_ERROR:
1088 case SC_COND_NOERROR:
1089 bValid = IsError( rPos );
1090 if( eOp == SC_COND_NOERROR )
1091 bValid = !bValid;
1092 break;
1093 case SC_COND_BEGINS_WITH:
1094 if(aStrVal1.isEmpty())
1096 OUString aStr = OUString::number(nVal1);
1097 OUString aStr2 = OUString::number(nArg);
1098 bValid = aStr2.startsWith(aStr);
1100 else
1102 OUString aStr2 = OUString::number(nArg);
1103 bValid = aStr2.startsWith(aStrVal1);
1105 break;
1106 case SC_COND_ENDS_WITH:
1107 if(aStrVal1.isEmpty())
1109 OUString aStr = OUString::number(nVal1);
1110 OUString aStr2 = OUString::number(nArg);
1111 bValid = !aStr2.endsWith(aStr);
1113 else
1115 OUString aStr2 = OUString::number(nArg);
1116 bValid = !aStr2.endsWith(aStrVal1);
1118 break;
1119 case SC_COND_CONTAINS_TEXT:
1120 case SC_COND_NOT_CONTAINS_TEXT:
1121 if(aStrVal1.isEmpty())
1123 OUString aStr = OUString::number(nVal1);
1124 OUString aStr2 = OUString::number(nArg);
1125 bValid = aStr2.indexOf(aStr) != -1;
1127 else
1129 OUString aStr2 = OUString::number(nArg);
1130 bValid = aStr2.indexOf(aStrVal1) != -1;
1133 if( eOp == SC_COND_NOT_CONTAINS_TEXT )
1134 bValid = !bValid;
1135 break;
1136 default:
1137 SAL_WARN("sc", "unknown operation at ScConditionEntry");
1138 break;
1140 return bValid;
1143 bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos ) const
1145 bool bValid = false;
1146 // Interpret must already have been called
1147 if ( eOp == SC_COND_DIRECT ) // Formula is independent from the content
1148 return !::rtl::math::approxEqual( nVal1, 0.0 );
1150 if ( eOp == SC_COND_DUPLICATE || eOp == SC_COND_NOTDUPLICATE )
1152 if( pCondFormat && !rArg.isEmpty() )
1154 bValid = IsDuplicate( 0.0, rArg );
1155 if( eOp == SC_COND_NOTDUPLICATE )
1156 bValid = !bValid;
1157 return bValid;
1161 // If number contains condition, always false, except for "not equal".
1162 if ( !bIsStr1 && (eOp != SC_COND_ERROR && eOp != SC_COND_NOERROR) )
1163 return ( eOp == SC_COND_NOTEQUAL );
1164 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1165 if ( !bIsStr2 )
1166 return false;
1168 OUString aUpVal1( aStrVal1 ); //TODO: As a member? (Also set in Interpret)
1169 OUString aUpVal2( aStrVal2 );
1171 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1172 if (ScGlobal::GetCollator()->compareString( aUpVal1, aUpVal2 ) > 0)
1174 // Right order for value range
1175 OUString aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
1178 switch ( eOp )
1180 case SC_COND_EQUAL:
1181 bValid = (ScGlobal::GetCollator()->compareString(
1182 rArg, aUpVal1 ) == 0);
1183 break;
1184 case SC_COND_NOTEQUAL:
1185 bValid = (ScGlobal::GetCollator()->compareString(
1186 rArg, aUpVal1 ) != 0);
1187 break;
1188 case SC_COND_TOP_PERCENT:
1189 case SC_COND_BOTTOM_PERCENT:
1190 case SC_COND_TOP10:
1191 case SC_COND_BOTTOM10:
1192 case SC_COND_ABOVE_AVERAGE:
1193 case SC_COND_BELOW_AVERAGE:
1194 return false;
1195 case SC_COND_ERROR:
1196 case SC_COND_NOERROR:
1197 bValid = IsError( rPos );
1198 if(eOp == SC_COND_NOERROR)
1199 bValid = !bValid;
1200 break;
1201 case SC_COND_BEGINS_WITH:
1202 bValid = rArg.startsWith(aUpVal1);
1203 break;
1204 case SC_COND_ENDS_WITH:
1205 bValid = rArg.endsWith(aUpVal1);
1206 break;
1207 case SC_COND_CONTAINS_TEXT:
1208 case SC_COND_NOT_CONTAINS_TEXT:
1209 bValid = rArg.indexOf(aUpVal1) != -1;
1210 if(eOp == SC_COND_NOT_CONTAINS_TEXT)
1211 bValid = !bValid;
1212 break;
1213 default:
1215 sal_Int32 nCompare = ScGlobal::GetCollator()->compareString(
1216 rArg, aUpVal1 );
1217 switch ( eOp )
1219 case SC_COND_GREATER:
1220 bValid = ( nCompare > 0 );
1221 break;
1222 case SC_COND_EQGREATER:
1223 bValid = ( nCompare >= 0 );
1224 break;
1225 case SC_COND_LESS:
1226 bValid = ( nCompare < 0 );
1227 break;
1228 case SC_COND_EQLESS:
1229 bValid = ( nCompare <= 0 );
1230 break;
1231 case SC_COND_BETWEEN:
1232 case SC_COND_NOTBETWEEN:
1233 // Test for NOTBETWEEN:
1234 bValid = ( nCompare < 0 ||
1235 ScGlobal::GetCollator()->compareString( rArg,
1236 aUpVal2 ) > 0 );
1237 if ( eOp == SC_COND_BETWEEN )
1238 bValid = !bValid;
1239 break;
1240 // SC_COND_DIRECT already handled above
1241 default:
1242 SAL_WARN("sc", "unknown operation in ScConditionEntry");
1243 bValid = false;
1244 break;
1248 return bValid;
1251 bool ScConditionEntry::IsCellValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
1253 const_cast<ScConditionEntry*>(this)->Interpret(rPos); // Evaluate formula
1255 double nArg = 0.0;
1256 OUString aArgStr;
1257 bool bVal = lcl_GetCellContent( rCell, bIsStr1, nArg, aArgStr, mpDoc );
1258 if (bVal)
1259 return IsValid( nArg, rPos );
1260 else
1261 return IsValidStr( aArgStr, rPos );
1264 OUString ScConditionEntry::GetExpression( const ScAddress& rCursor, sal_uInt16 nIndex,
1265 sal_uLong nNumFmt,
1266 const FormulaGrammar::Grammar eGrammar ) const
1268 assert( nIndex <= 1);
1269 OUString aRet;
1271 if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 )
1272 nNumFmt = mpDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US );
1274 if ( nIndex==0 )
1276 if ( pFormula1 )
1278 ScCompiler aComp(mpDoc, rCursor, *pFormula1);
1279 aComp.SetGrammar(eGrammar);
1280 OUStringBuffer aBuffer;
1281 aComp.CreateStringFromTokenArray( aBuffer );
1282 aRet = aBuffer.makeStringAndClear();
1284 else if (bIsStr1)
1286 aRet = "\"";
1287 aRet += aStrVal1;
1288 aRet += "\"";
1290 else
1291 mpDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet);
1293 else if ( nIndex==1 )
1295 if ( pFormula2 )
1297 ScCompiler aComp(mpDoc, rCursor, *pFormula2);
1298 aComp.SetGrammar(eGrammar);
1299 OUStringBuffer aBuffer;
1300 aComp.CreateStringFromTokenArray( aBuffer );
1301 aRet = aBuffer.makeStringAndClear();
1303 else if (bIsStr2)
1305 aRet = "\"";
1306 aRet += aStrVal2;
1307 aRet += "\"";
1309 else
1310 mpDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet);
1313 return aRet;
1316 ScTokenArray* ScConditionEntry::CreateTokenArry( sal_uInt16 nIndex ) const
1318 assert(nIndex <= 1);
1319 ScTokenArray* pRet = NULL;
1320 ScAddress aAddr;
1322 if ( nIndex==0 )
1324 if ( pFormula1 )
1325 pRet = new ScTokenArray( *pFormula1 );
1326 else
1328 pRet = new ScTokenArray();
1329 if (bIsStr1)
1331 svl::SharedStringPool& rSPool = mpDoc->GetSharedStringPool();
1332 pRet->AddString(rSPool.intern(aStrVal1));
1334 else
1335 pRet->AddDouble( nVal1 );
1338 else if ( nIndex==1 )
1340 if ( pFormula2 )
1341 pRet = new ScTokenArray( *pFormula2 );
1342 else
1344 pRet = new ScTokenArray();
1345 if (bIsStr2)
1347 svl::SharedStringPool& rSPool = mpDoc->GetSharedStringPool();
1348 pRet->AddString(rSPool.intern(aStrVal2));
1350 else
1351 pRet->AddDouble( nVal2 );
1355 return pRet;
1358 void ScConditionEntry::SourceChanged( const ScAddress& rChanged )
1360 for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1362 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1363 if (pFormula)
1365 pFormula->Reset();
1366 formula::FormulaToken* t;
1367 while ( ( t = pFormula->GetNextReference() ) != NULL )
1369 SingleDoubleRefProvider aProv( *t );
1370 if ( aProv.Ref1.IsColRel() || aProv.Ref1.IsRowRel() || aProv.Ref1.IsTabRel() ||
1371 aProv.Ref2.IsColRel() || aProv.Ref2.IsRowRel() || aProv.Ref2.IsTabRel() )
1373 // Absolute must be reached, relative determines range
1374 bool bHit = true;
1375 SCsCOL nCol1;
1376 SCsROW nRow1;
1377 SCsTAB nTab1;
1378 SCsCOL nCol2;
1379 SCsROW nRow2;
1380 SCsTAB nTab2;
1382 if ( aProv.Ref1.IsColRel() )
1383 nCol2 = rChanged.Col() - aProv.Ref1.Col();
1384 else
1386 bHit &= (rChanged.Col() >= aProv.Ref1.Col());
1387 nCol2 = MAXCOL;
1389 if ( aProv.Ref1.IsRowRel() )
1390 nRow2 = rChanged.Row() - aProv.Ref1.Row();
1391 else
1393 bHit &= ( rChanged.Row() >= aProv.Ref1.Row() );
1394 nRow2 = MAXROW;
1396 if ( aProv.Ref1.IsTabRel() )
1397 nTab2 = rChanged.Tab() - aProv.Ref1.Tab();
1398 else
1400 bHit &= (rChanged.Tab() >= aProv.Ref1.Tab());
1401 nTab2 = MAXTAB;
1404 if ( aProv.Ref2.IsColRel() )
1405 nCol1 = rChanged.Col() - aProv.Ref2.Col();
1406 else
1408 bHit &= ( rChanged.Col() <= aProv.Ref2.Col() );
1409 nCol1 = 0;
1411 if ( aProv.Ref2.IsRowRel() )
1412 nRow1 = rChanged.Row() - aProv.Ref2.Row();
1413 else
1415 bHit &= (rChanged.Row() <= aProv.Ref2.Row());
1416 nRow1 = 0;
1418 if ( aProv.Ref2.IsTabRel() )
1419 nTab1 = rChanged.Tab() - aProv.Ref2.Tab();
1420 else
1422 bHit &= (rChanged.Tab() <= aProv.Ref2.Tab());
1423 nTab1 = 0;
1426 if ( bHit )
1428 // Limit paint!
1429 ScRange aPaint( nCol1,nRow1,nTab1, nCol2,nRow2,nTab2 );
1431 // No paint if it's the cell itself
1432 if ( aPaint.IsValid() && (aPaint.aStart != rChanged || aPaint.aEnd != rChanged ))
1433 DataChanged( &aPaint );
1442 * Return a position that's adjusted to allow textual representation
1443 * of expressions if possible
1445 ScAddress ScConditionEntry::GetValidSrcPos() const
1447 SCTAB nMinTab = aSrcPos.Tab();
1448 SCTAB nMaxTab = nMinTab;
1450 for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1452 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1453 if (pFormula)
1455 pFormula->Reset();
1456 formula::FormulaToken* t;
1457 while ( ( t = pFormula->GetNextReference() ) != NULL )
1459 ScSingleRefData& rRef1 = *t->GetSingleRef();
1460 ScAddress aAbs = rRef1.toAbs(aSrcPos);
1461 if (!rRef1.IsTabDeleted())
1463 if (aAbs.Tab() < nMinTab)
1464 nMinTab = aAbs.Tab();
1465 if (aAbs.Tab() > nMaxTab)
1466 nMaxTab = aAbs.Tab();
1468 if ( t->GetType() == svDoubleRef )
1470 ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
1471 aAbs = rRef2.toAbs(aSrcPos);
1472 if (!rRef2.IsTabDeleted())
1474 if (aAbs.Tab() < nMinTab)
1475 nMinTab = aAbs.Tab();
1476 if (aAbs.Tab() > nMaxTab)
1477 nMaxTab = aAbs.Tab();
1484 ScAddress aValidPos = aSrcPos;
1485 SCTAB nTabCount = mpDoc->GetTableCount();
1486 if ( nMaxTab >= nTabCount && nMinTab > 0 )
1487 aValidPos.SetTab( aSrcPos.Tab() - nMinTab ); // so the lowest tab ref will be on 0
1489 if ( aValidPos.Tab() >= nTabCount )
1490 aValidPos.SetTab( nTabCount - 1 ); // ensure a valid position even if some references will be invalid
1492 return aValidPos;
1495 void ScConditionEntry::DataChanged( const ScRange* /* pModified */ ) const
1497 //FIXME: Nothing so far
1500 bool ScConditionEntry::MarkUsedExternalReferences() const
1502 bool bAllMarked = false;
1503 for (sal_uInt16 nPass = 0; !bAllMarked && nPass < 2; nPass++)
1505 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1506 if (pFormula)
1507 bAllMarked = mpDoc->MarkUsedExternalReferences(*pFormula, aSrcPos);
1509 return bAllMarked;
1512 ScFormatEntry* ScConditionEntry::Clone(ScDocument* pDoc) const
1514 return new ScConditionEntry(pDoc, *this);
1517 ScConditionMode ScConditionEntry::GetModeFromApi(sal_Int32 nOperation)
1519 ScConditionMode eMode = SC_COND_NONE;
1520 switch (nOperation)
1522 case com::sun::star::sheet::ConditionOperator2::EQUAL:
1523 eMode = SC_COND_EQUAL;
1524 break;
1525 case com::sun::star::sheet::ConditionOperator2::LESS:
1526 eMode = SC_COND_LESS;
1527 break;
1528 case com::sun::star::sheet::ConditionOperator2::GREATER:
1529 eMode = SC_COND_GREATER;
1530 break;
1531 case com::sun::star::sheet::ConditionOperator2::LESS_EQUAL:
1532 eMode = SC_COND_EQLESS;
1533 break;
1534 case com::sun::star::sheet::ConditionOperator2::GREATER_EQUAL:
1535 eMode = SC_COND_EQGREATER;
1536 break;
1537 case com::sun::star::sheet::ConditionOperator2::NOT_EQUAL:
1538 eMode = SC_COND_NOTEQUAL;
1539 break;
1540 case com::sun::star::sheet::ConditionOperator2::BETWEEN:
1541 eMode = SC_COND_BETWEEN;
1542 break;
1543 case com::sun::star::sheet::ConditionOperator2::NOT_BETWEEN:
1544 eMode = SC_COND_NOTBETWEEN;
1545 break;
1546 case com::sun::star::sheet::ConditionOperator2::FORMULA:
1547 eMode = SC_COND_DIRECT;
1548 break;
1549 case com::sun::star::sheet::ConditionOperator2::DUPLICATE:
1550 eMode = SC_COND_DUPLICATE;
1551 break;
1552 case com::sun::star::sheet::ConditionOperator2::NOT_DUPLICATE:
1553 eMode = SC_COND_NOTDUPLICATE;
1554 break;
1555 default:
1556 break;
1558 return eMode;
1561 void ScConditionEntry::startRendering()
1563 mpCache.reset();
1566 void ScConditionEntry::endRendering()
1568 mpCache.reset();
1571 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
1572 const OUString& rExpr1, const OUString& rExpr2,
1573 ScDocument* pDocument, const ScAddress& rPos,
1574 const OUString& rStyle,
1575 const OUString& rExprNmsp1, const OUString& rExprNmsp2,
1576 FormulaGrammar::Grammar eGrammar1,
1577 FormulaGrammar::Grammar eGrammar2 ) :
1578 ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ),
1579 aStyleName( rStyle )
1583 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
1584 const ScTokenArray* pArr1, const ScTokenArray* pArr2,
1585 ScDocument* pDocument, const ScAddress& rPos,
1586 const OUString& rStyle ) :
1587 ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos ),
1588 aStyleName( rStyle )
1592 ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry& r ) :
1593 ScConditionEntry( r ),
1594 aStyleName( r.aStyleName )
1598 ScCondFormatEntry::ScCondFormatEntry( ScDocument* pDocument, const ScCondFormatEntry& r ) :
1599 ScConditionEntry( pDocument, r ),
1600 aStyleName( r.aStyleName )
1604 bool ScCondFormatEntry::operator== ( const ScCondFormatEntry& r ) const
1606 return ScConditionEntry::operator==( r ) &&
1607 aStyleName == r.aStyleName;
1610 ScCondFormatEntry::~ScCondFormatEntry()
1614 void ScCondFormatEntry::DataChanged( const ScRange* pModified ) const
1616 if ( pCondFormat )
1617 pCondFormat->DoRepaint( pModified );
1620 ScFormatEntry* ScCondFormatEntry::Clone( ScDocument* pDoc ) const
1622 return new ScCondFormatEntry( pDoc, *this );
1625 ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument* pDoc )
1626 : ScFormatEntry( pDoc )
1627 , meType(condformat::TODAY)
1631 ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument* pDoc, const ScCondDateFormatEntry& rFormat ):
1632 ScFormatEntry( pDoc ),
1633 meType( rFormat.meType ),
1634 maStyleName( rFormat.maStyleName )
1638 bool ScCondDateFormatEntry::IsValid( const ScAddress& rPos ) const
1640 CellType eCellType = mpDoc->GetCellType(rPos);
1642 if (eCellType == CELLTYPE_NONE)
1643 // empty cell.
1644 return false;
1646 if (eCellType != CELLTYPE_VALUE && eCellType != CELLTYPE_FORMULA)
1647 // non-numerical cell.
1648 return false;
1650 if( !mpCache )
1651 mpCache.reset( new Date( Date::SYSTEM ) );
1653 const Date& rActDate = *mpCache;
1654 SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
1655 long nCurrentDate = rActDate - *(pFormatter->GetNullDate());
1657 double nVal = mpDoc->GetValue(rPos);
1658 long nCellDate = (long) ::rtl::math::approxFloor(nVal);
1659 Date aCellDate = *(pFormatter->GetNullDate());
1660 aCellDate += (long) ::rtl::math::approxFloor(nVal);
1662 switch(meType)
1664 case condformat::TODAY:
1665 if( nCurrentDate == nCellDate )
1666 return true;
1667 break;
1668 case condformat::TOMORROW:
1669 if( nCurrentDate == nCellDate -1 )
1670 return true;
1671 break;
1672 case condformat::YESTERDAY:
1673 if( nCurrentDate == nCellDate + 1)
1674 return true;
1675 break;
1676 case condformat::LAST7DAYS:
1677 if( nCurrentDate >= nCellDate && nCurrentDate - 7 < nCellDate )
1678 return true;
1679 break;
1680 case condformat::LASTWEEK:
1681 if( rActDate.GetDayOfWeek() != SUNDAY )
1683 Date aBegin(rActDate - 8 - static_cast<long>(rActDate.GetDayOfWeek()));
1684 Date aEnd(rActDate - 2 -static_cast<long>(rActDate.GetDayOfWeek()));
1685 return aCellDate.IsBetween( aBegin, aEnd );
1687 else
1689 Date aBegin(rActDate - 8);
1690 Date aEnd(rActDate - 1);
1691 return aCellDate.IsBetween( aBegin, aEnd );
1693 break;
1694 case condformat::THISWEEK:
1695 if( rActDate.GetDayOfWeek() != SUNDAY )
1697 Date aBegin(rActDate - 1 - static_cast<long>(rActDate.GetDayOfWeek()));
1698 Date aEnd(rActDate + 5 - static_cast<long>(rActDate.GetDayOfWeek()));
1699 return aCellDate.IsBetween( aBegin, aEnd );
1701 else
1703 Date aEnd( rActDate + 6);
1704 return aCellDate.IsBetween( rActDate, aEnd );
1706 break;
1707 case condformat::NEXTWEEK:
1708 if( rActDate.GetDayOfWeek() != SUNDAY )
1710 return aCellDate.IsBetween( rActDate + 6 - static_cast<long>(rActDate.GetDayOfWeek()), rActDate + 12 - static_cast<long>(rActDate.GetDayOfWeek()) );
1712 else
1714 return aCellDate.IsBetween( rActDate + 7, rActDate + 13 );
1716 break;
1717 case condformat::LASTMONTH:
1718 if( rActDate.GetMonth() == 1 )
1720 if( aCellDate.GetMonth() == 12 && rActDate.GetYear() == aCellDate.GetYear() + 1 )
1721 return true;
1723 else if( rActDate.GetYear() == aCellDate.GetYear() )
1725 if( rActDate.GetMonth() == aCellDate.GetMonth() + 1)
1726 return true;
1728 break;
1729 case condformat::THISMONTH:
1730 if( rActDate.GetYear() == aCellDate.GetYear() )
1732 if( rActDate.GetMonth() == aCellDate.GetMonth() )
1733 return true;
1735 break;
1736 case condformat::NEXTMONTH:
1737 if( rActDate.GetMonth() == 12 )
1739 if( aCellDate.GetMonth() == 1 && rActDate.GetYear() == aCellDate.GetYear() - 1 )
1740 return true;
1742 else if( rActDate.GetYear() == aCellDate.GetYear() )
1744 if( rActDate.GetMonth() == aCellDate.GetMonth() - 1)
1745 return true;
1747 break;
1748 case condformat::LASTYEAR:
1749 if( rActDate.GetYear() == aCellDate.GetYear() + 1 )
1750 return true;
1751 break;
1752 case condformat::THISYEAR:
1753 if( rActDate.GetYear() == aCellDate.GetYear() )
1754 return true;
1755 break;
1756 case condformat::NEXTYEAR:
1757 if( rActDate.GetYear() == aCellDate.GetYear() - 1 )
1758 return true;
1759 break;
1762 return false;
1765 void ScCondDateFormatEntry::SetDateType( condformat::ScCondFormatDateType eType )
1767 meType = eType;
1770 void ScCondDateFormatEntry::SetStyleName( const OUString& rStyleName )
1772 maStyleName = rStyleName;
1775 ScFormatEntry* ScCondDateFormatEntry::Clone( ScDocument* pDoc ) const
1777 return new ScCondDateFormatEntry( pDoc, *this );
1780 bool ScCondDateFormatEntry::operator==( const ScFormatEntry& r ) const
1782 if(r.GetType() != condformat::DATE)
1783 return false;
1785 const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(r);
1787 if(rEntry.meType != meType)
1788 return false;
1790 return rEntry.maStyleName == maStyleName;
1793 void ScCondDateFormatEntry::startRendering()
1795 mpCache.reset();
1798 void ScCondDateFormatEntry::endRendering()
1800 mpCache.reset();
1803 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
1804 pDoc( pDocument ),
1805 nKey( nNewKey )
1809 ScConditionalFormat* ScConditionalFormat::Clone(ScDocument* pNewDoc) const
1811 // Real copy of the formula (for Ref Undo/between documents)
1812 if (!pNewDoc)
1813 pNewDoc = pDoc;
1815 ScConditionalFormat* pNew = new ScConditionalFormat(nKey, pNewDoc);
1817 for (CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1819 ScFormatEntry* pNewEntry = itr->Clone(pNewDoc);
1820 pNew->maEntries.push_back( pNewEntry );
1821 pNewEntry->SetParent(pNew);
1823 pNew->SetRange( maRanges );
1825 return pNew;
1828 bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const
1830 if( size() != r.size())
1831 return false;
1833 //TODO: Test for same entries in reverse order?
1834 for (sal_uInt16 i=0; i<size(); i++)
1835 if ( ! (maEntries == r.maEntries ) )
1836 return false;
1838 // right now don't check for same range
1839 // we only use this method to merge same conditional formats from
1840 // old ODF data structure
1841 return true;
1844 void ScConditionalFormat::SetRange( const ScRangeList& rRanges )
1846 maRanges = rRanges;
1847 SAL_WARN_IF(maRanges.empty(), "sc", "the conditional format range is empty! will result in a crash later!");
1850 void ScConditionalFormat::AddEntry( ScFormatEntry* pNew )
1852 maEntries.push_back(pNew);
1853 pNew->SetParent(this);
1856 void ScConditionalFormat::RemoveEntry(size_t n)
1858 if (n < maEntries.size())
1860 maEntries.erase(maEntries.begin() + n);
1861 DoRepaint(NULL);
1865 bool ScConditionalFormat::IsEmpty() const
1867 return maEntries.empty();
1870 size_t ScConditionalFormat::size() const
1872 return maEntries.size();
1875 ScConditionalFormat::~ScConditionalFormat()
1879 const ScFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const
1881 if ( nPos < size() )
1882 return &maEntries[nPos];
1883 else
1884 return NULL;
1887 const OUString& ScConditionalFormat::GetCellStyle( ScRefCellValue& rCell, const ScAddress& rPos ) const
1889 for (CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1891 if(itr->GetType() == condformat::CONDITION)
1893 const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*itr);
1894 if (rEntry.IsCellValid(rCell, rPos))
1895 return rEntry.GetStyle();
1897 else if(itr->GetType() == condformat::DATE)
1899 const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*itr);
1900 if (rEntry.IsValid( rPos ))
1901 return rEntry.GetStyleName();
1905 return EMPTY_OUSTRING;
1908 ScCondFormatData ScConditionalFormat::GetData( ScRefCellValue& rCell, const ScAddress& rPos ) const
1910 ScCondFormatData aData;
1911 for(CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1913 if(itr->GetType() == condformat::CONDITION && aData.aStyleName.isEmpty())
1915 const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*itr);
1916 if (rEntry.IsCellValid(rCell, rPos))
1917 aData.aStyleName = rEntry.GetStyle();
1919 else if(itr->GetType() == condformat::COLORSCALE && !aData.pColorScale)
1921 const ScColorScaleFormat& rEntry = static_cast<const ScColorScaleFormat&>(*itr);
1922 aData.pColorScale = rEntry.GetColor(rPos);
1924 else if(itr->GetType() == condformat::DATABAR && !aData.pDataBar)
1926 const ScDataBarFormat& rEntry = static_cast<const ScDataBarFormat&>(*itr);
1927 aData.pDataBar = rEntry.GetDataBarInfo(rPos);
1929 else if(itr->GetType() == condformat::ICONSET && !aData.pIconSet)
1931 const ScIconSetFormat& rEntry = static_cast<const ScIconSetFormat&>(*itr);
1932 aData.pIconSet = rEntry.GetIconSetInfo(rPos);
1934 else if(itr->GetType() == condformat::DATE && aData.aStyleName.isEmpty())
1936 const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*itr);
1937 if ( rEntry.IsValid( rPos ) )
1938 aData.aStyleName = rEntry.GetStyleName();
1941 return aData;
1944 void ScConditionalFormat::DoRepaint( const ScRange* pModified )
1946 if(pModified)
1948 if(maRanges.Intersects(*pModified))
1949 pDoc->RepaintRange(*pModified);
1951 else
1953 // all conditional format cells
1954 pDoc->RepaintRange( maRanges );
1958 void ScConditionalFormat::CompileAll()
1960 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1961 if(itr->GetType() == condformat::CONDITION)
1962 static_cast<ScCondFormatEntry&>(*itr).CompileAll();
1965 void ScConditionalFormat::CompileXML()
1967 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1968 if(itr->GetType() == condformat::CONDITION)
1969 static_cast<ScCondFormatEntry&>(*itr).CompileXML();
1972 void ScConditionalFormat::UpdateReference( sc::RefUpdateContext& rCxt, bool bCopyAsMove )
1974 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1975 itr->UpdateReference(rCxt);
1977 if (rCxt.meMode == URM_COPY && bCopyAsMove)
1978 maRanges.UpdateReference(URM_MOVE, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
1979 else
1980 maRanges.UpdateReference(rCxt.meMode, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
1983 void ScConditionalFormat::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
1985 maRanges.InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
1988 void ScConditionalFormat::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
1990 maRanges.InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
1993 void ScConditionalFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
1995 for (size_t i = 0, n = maRanges.size(); i < n; ++i)
1997 // We assume that the start and end sheet indices are equal.
1998 ScRange* pRange = maRanges[i];
1999 SCTAB nTab = pRange->aStart.Tab();
2001 if (nTab < rCxt.mnInsertPos)
2002 // Unaffected.
2003 continue;
2005 pRange->aStart.IncTab(rCxt.mnSheets);
2006 pRange->aEnd.IncTab(rCxt.mnSheets);
2009 for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
2010 it->UpdateInsertTab(rCxt);
2013 void ScConditionalFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
2015 for (size_t i = 0, n = maRanges.size(); i < n; ++i)
2017 // We assume that the start and end sheet indices are equal.
2018 ScRange* pRange = maRanges[i];
2019 SCTAB nTab = pRange->aStart.Tab();
2021 if (nTab < rCxt.mnDeletePos)
2022 // Left of the deleted sheet(s). Unaffected.
2023 continue;
2025 if (nTab <= rCxt.mnDeletePos+rCxt.mnSheets-1)
2027 // On the deleted sheet(s).
2028 pRange->aStart.SetTab(-1);
2029 pRange->aEnd.SetTab(-1);
2030 continue;
2033 // Right of the deleted sheet(s). Adjust the sheet indices.
2034 pRange->aStart.IncTab(-1*rCxt.mnSheets);
2035 pRange->aEnd.IncTab(-1*rCxt.mnSheets);
2038 for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
2039 it->UpdateDeleteTab(rCxt);
2042 void ScConditionalFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
2044 size_t n = maRanges.size();
2045 SCTAB nMinTab = std::min<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
2046 SCTAB nMaxTab = std::max<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
2047 for(size_t i = 0; i < n; ++i)
2049 ScRange* pRange = maRanges[i];
2050 SCTAB nTab = pRange->aStart.Tab();
2051 if(nTab < nMinTab || nTab > nMaxTab)
2053 continue;
2056 if (nTab == rCxt.mnOldPos)
2058 pRange->aStart.SetTab(rCxt.mnNewPos);
2059 pRange->aEnd.SetTab(rCxt.mnNewPos);
2060 continue;
2063 if (rCxt.mnNewPos < rCxt.mnOldPos)
2065 pRange->aStart.IncTab();
2066 pRange->aEnd.IncTab();
2068 else
2070 pRange->aStart.IncTab(-1);
2071 pRange->aEnd.IncTab(-1);
2075 for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
2076 it->UpdateMoveTab(rCxt);
2079 void ScConditionalFormat::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2081 if (maRanges.empty())
2082 return;
2084 SCTAB nTab = maRanges[0]->aStart.Tab();
2085 maRanges.DeleteArea( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
2088 void ScConditionalFormat::RenameCellStyle(const OUString& rOld, const OUString& rNew)
2090 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2091 if(itr->GetType() == condformat::CONDITION)
2093 ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*itr);
2094 if(rFormat.GetStyle() == rOld)
2095 rFormat.UpdateStyleName( rNew );
2099 void ScConditionalFormat::SourceChanged( const ScAddress& rAddr )
2101 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2103 condformat::ScFormatEntryType eEntryType = itr->GetType();
2104 if( eEntryType == condformat::CONDITION)
2106 ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*itr);
2107 rFormat.SourceChanged( rAddr );
2109 else if( eEntryType == condformat::COLORSCALE ||
2110 eEntryType == condformat::DATABAR ||
2111 eEntryType == condformat::ICONSET )
2113 ScColorFormat& rFormat = static_cast<ScColorFormat&>(*itr);
2114 if(rFormat.NeedsRepaint())
2116 // we need to repaint the whole range anyway
2117 DoRepaint(NULL);
2118 return;
2124 bool ScConditionalFormat::MarkUsedExternalReferences() const
2126 bool bAllMarked = false;
2127 for(CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end() && !bAllMarked; ++itr)
2128 if(itr->GetType() == condformat::CONDITION)
2130 const ScCondFormatEntry& rFormat = static_cast<const ScCondFormatEntry&>(*itr);
2131 bAllMarked = rFormat.MarkUsedExternalReferences();
2134 return bAllMarked;
2137 void ScConditionalFormat::startRendering()
2139 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2141 itr->startRendering();
2145 void ScConditionalFormat::endRendering()
2147 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2149 itr->endRendering();
2153 ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList& rList)
2155 for(const_iterator itr = rList.begin(); itr != rList.end(); ++itr)
2156 InsertNew( itr->Clone() );
2159 ScConditionalFormatList::ScConditionalFormatList(ScDocument* pDoc, const ScConditionalFormatList& rList)
2161 for(const_iterator itr = rList.begin(); itr != rList.end(); ++itr)
2162 InsertNew( itr->Clone(pDoc) );
2165 void ScConditionalFormatList::InsertNew( ScConditionalFormat* pNew )
2167 maConditionalFormats.insert(pNew);
2170 bool ScConditionalFormatList::operator==( const ScConditionalFormatList& r ) const
2172 // For Ref Undo - internal variables are not compared
2173 sal_uInt16 nCount = size();
2174 bool bEqual = ( nCount == r.size() );
2175 const_iterator locIterator = begin();
2176 for(const_iterator itr = r.begin(); itr != r.end() && bEqual; ++itr, ++locIterator)
2177 if ( !locIterator->EqualEntries(*itr) ) // Entries differ?
2178 bEqual = false;
2180 return bEqual;
2183 ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey )
2185 //FIXME: Binary search
2186 for( iterator itr = begin(); itr != end(); ++itr)
2187 if (itr->GetKey() == nKey)
2188 return &(*itr);
2190 SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2191 return NULL;
2194 const ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey ) const
2196 //FIXME: Binary search
2197 for ( const_iterator itr = begin(); itr != end(); ++itr)
2198 if (itr->GetKey() == nKey)
2199 return &(*itr);
2201 SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2202 return NULL;
2205 void ScConditionalFormatList::CompileAll()
2207 for( iterator itr = begin(); itr != end(); ++itr)
2208 itr->CompileAll();
2211 void ScConditionalFormatList::CompileXML()
2213 for( iterator itr = begin(); itr != end(); ++itr)
2214 itr->CompileXML();
2217 void ScConditionalFormatList::UpdateReference( sc::RefUpdateContext& rCxt )
2219 for( iterator itr = begin(); itr != end(); ++itr)
2220 itr->UpdateReference(rCxt);
2222 if (rCxt.meMode == URM_INSDEL)
2224 // need to check which must be deleted
2225 CheckAllEntries();
2229 void ScConditionalFormatList::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
2231 for(iterator it = begin(), itEnd = end(); it != itEnd; ++it)
2232 it->InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
2235 void ScConditionalFormatList::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
2237 for(iterator it = begin(), itEnd = end(); it != itEnd; ++it)
2238 it->InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
2241 void ScConditionalFormatList::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
2243 for (iterator it = begin(); it != end(); ++it)
2244 it->UpdateInsertTab(rCxt);
2247 void ScConditionalFormatList::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
2249 for (iterator it = begin(); it != end(); ++it)
2250 it->UpdateDeleteTab(rCxt);
2253 void ScConditionalFormatList::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
2255 for (iterator it = begin(); it != end(); ++it)
2256 it->UpdateMoveTab(rCxt);
2259 void ScConditionalFormatList::RenameCellStyle( const OUString& rOld, const OUString& rNew )
2261 for( iterator itr = begin(); itr != end(); ++itr)
2262 itr->RenameCellStyle(rOld,rNew);
2265 bool ScConditionalFormatList::CheckAllEntries()
2267 bool bValid = true;
2269 // need to check which must be deleted
2270 iterator itr = begin();
2271 while(itr != end())
2273 if(itr->GetRange().empty())
2275 bValid = false;
2276 maConditionalFormats.erase(itr++);
2278 else
2279 ++itr;
2282 return bValid;
2285 void ScConditionalFormatList::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2287 for( iterator itr = begin(); itr != end(); ++itr)
2288 itr->DeleteArea( nCol1, nRow1, nCol2, nRow2 );
2290 CheckAllEntries();
2293 void ScConditionalFormatList::SourceChanged( const ScAddress& rAddr )
2295 for( iterator itr = begin(); itr != end(); ++itr)
2296 itr->SourceChanged( rAddr );
2299 ScConditionalFormatList::iterator ScConditionalFormatList::begin()
2301 return maConditionalFormats.begin();
2304 ScConditionalFormatList::const_iterator ScConditionalFormatList::begin() const
2306 return maConditionalFormats.begin();
2309 ScConditionalFormatList::iterator ScConditionalFormatList::end()
2311 return maConditionalFormats.end();
2314 ScConditionalFormatList::const_iterator ScConditionalFormatList::end() const
2316 return maConditionalFormats.end();
2319 size_t ScConditionalFormatList::size() const
2321 return maConditionalFormats.size();
2324 bool ScConditionalFormatList::empty() const
2326 return maConditionalFormats.empty();
2329 void ScConditionalFormatList::erase( sal_uLong nIndex )
2331 for( iterator itr = begin(); itr != end(); ++itr )
2333 if( itr->GetKey() == nIndex )
2335 maConditionalFormats.erase(itr);
2336 break;
2341 void ScConditionalFormatList::startRendering()
2343 for(iterator itr = begin(); itr != end(); ++itr)
2345 itr->startRendering();
2349 void ScConditionalFormatList::endRendering()
2351 for(iterator itr = begin(); itr != end(); ++itr)
2353 itr->endRendering();
2357 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */