Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / conditio.cxx
blob1a9f8698f7608cb5fbfe98f899932bb475836a03
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"
45 using namespace formula;
46 //------------------------------------------------------------------------
48 ScFormatEntry::ScFormatEntry(ScDocument* pDoc):
49 mpDoc(pDoc)
53 bool ScFormatEntry::operator==( const ScFormatEntry& r ) const
55 if(GetType() != r.GetType())
56 return false;
58 switch(GetType())
60 case condformat::CONDITION:
61 return static_cast<const ScCondFormatEntry&>(*this) == static_cast<const ScCondFormatEntry&>(r);
62 default:
63 // TODO: implement also this case
64 // actually return false for these cases is not that bad
65 // as soon as databar and color scale are tested we need
66 // to think about the range
67 return false;
71 void ScFormatEntry::startRendering()
75 void ScFormatEntry::endRendering()
79 static bool lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, sal_uInt16 nRecursion = 0 )
81 if (pFormula)
83 pFormula->Reset();
84 FormulaToken* t;
85 for( t = pFormula->Next(); t; t = pFormula->Next() )
87 switch( t->GetType() )
89 case svDoubleRef:
91 ScSingleRefData& rRef2 = static_cast<ScToken*>(t)->GetDoubleRef().Ref2;
92 if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
93 return true;
95 // fall through
97 case svSingleRef:
99 ScSingleRefData& rRef1 = static_cast<ScToken*>(t)->GetSingleRef();
100 if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
101 return true;
103 break;
105 case svIndex:
107 if( t->GetOpCode() == ocName ) // DB areas always absolute
108 if( ScRangeData* pRangeData = pDoc->GetRangeName()->findByIndex( t->GetIndex() ) )
109 if( (nRecursion < 42) && lcl_HasRelRef( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
110 return true;
112 break;
114 // #i34474# function result dependent on cell position
115 case svByte:
117 switch( t->GetOpCode() )
119 case ocRow: // ROW() returns own row index
120 case ocColumn: // COLUMN() returns own column index
121 case ocTable: // SHEET() returns own sheet index
122 case ocCell: // CELL() may return own cell address
123 return true;
124 // break;
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 erzeugt flache Kopie
170 if (r.pFormula1)
171 pFormula1 = new ScTokenArray( *r.pFormula1 );
172 if (r.pFormula2)
173 pFormula2 = new ScTokenArray( *r.pFormula2 );
175 // Formelzellen werden erst bei IsValid angelegt
178 ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntry& r ) :
179 ScFormatEntry(pDocument),
180 eOp(r.eOp),
181 nOptions(r.nOptions),
182 nVal1(r.nVal1),
183 nVal2(r.nVal2),
184 aStrVal1(r.aStrVal1),
185 aStrVal2(r.aStrVal2),
186 aStrNmsp1(r.aStrNmsp1),
187 aStrNmsp2(r.aStrNmsp2),
188 eTempGrammar1(r.eTempGrammar1),
189 eTempGrammar2(r.eTempGrammar2),
190 bIsStr1(r.bIsStr1),
191 bIsStr2(r.bIsStr2),
192 pFormula1(NULL),
193 pFormula2(NULL),
194 aSrcPos(r.aSrcPos),
195 aSrcString(r.aSrcString),
196 pFCell1(NULL),
197 pFCell2(NULL),
198 bRelRef1(r.bRelRef1),
199 bRelRef2(r.bRelRef2),
200 bFirstRun(true),
201 pCondFormat(r.pCondFormat)
203 // echte Kopie der Formeln (fuer Ref-Undo)
205 if (r.pFormula1)
206 pFormula1 = r.pFormula1->Clone();
207 if (r.pFormula2)
208 pFormula2 = r.pFormula2->Clone();
210 // Formelzellen werden erst bei IsValid angelegt
211 //! im Clipboard nicht - dann vorher interpretieren !!!
214 ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
215 const OUString& rExpr1, const OUString& rExpr2, ScDocument* pDocument, const ScAddress& rPos,
216 const OUString& rExprNmsp1, const OUString& rExprNmsp2,
217 FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) :
218 ScFormatEntry(pDocument),
219 eOp(eOper),
220 nOptions(0),
221 nVal1(0.0),
222 nVal2(0.0),
223 aStrNmsp1(rExprNmsp1),
224 aStrNmsp2(rExprNmsp2),
225 eTempGrammar1(eGrammar1),
226 eTempGrammar2(eGrammar2),
227 bIsStr1(false),
228 bIsStr2(false),
229 pFormula1(NULL),
230 pFormula2(NULL),
231 aSrcPos(rPos),
232 pFCell1(NULL),
233 pFCell2(NULL),
234 bRelRef1(false),
235 bRelRef2(false),
236 bFirstRun(true),
237 pCondFormat(NULL)
239 Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, false );
241 // Formelzellen werden erst bei IsValid angelegt
244 ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
245 const ScTokenArray* pArr1, const ScTokenArray* pArr2,
246 ScDocument* pDocument, const ScAddress& rPos ) :
247 ScFormatEntry(pDocument),
248 eOp(eOper),
249 nOptions(0),
250 nVal1(0.0),
251 nVal2(0.0),
252 eTempGrammar1(FormulaGrammar::GRAM_DEFAULT),
253 eTempGrammar2(FormulaGrammar::GRAM_DEFAULT),
254 bIsStr1(false),
255 bIsStr2(false),
256 pFormula1(NULL),
257 pFormula2(NULL),
258 aSrcPos(rPos),
259 pFCell1(NULL),
260 pFCell2(NULL),
261 bRelRef1(false),
262 bRelRef2(false),
263 bFirstRun(true),
264 pCondFormat(NULL)
266 if ( pArr1 )
268 pFormula1 = new ScTokenArray( *pArr1 );
269 if ( pFormula1->GetLen() == 1 )
271 // einzelne (konstante Zahl) ?
272 FormulaToken* pToken = pFormula1->First();
273 if ( pToken->GetOpCode() == ocPush )
275 if ( pToken->GetType() == svDouble )
277 nVal1 = pToken->GetDouble();
278 DELETEZ(pFormula1); // nicht als Formel merken
280 else if ( pToken->GetType() == svString )
282 bIsStr1 = true;
283 aStrVal1 = pToken->GetString().getString();
284 DELETEZ(pFormula1); // nicht als Formel merken
288 bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
290 if ( pArr2 )
292 pFormula2 = new ScTokenArray( *pArr2 );
293 if ( pFormula2->GetLen() == 1 )
295 // einzelne (konstante Zahl) ?
296 FormulaToken* pToken = pFormula2->First();
297 if ( pToken->GetOpCode() == ocPush )
299 if ( pToken->GetType() == svDouble )
301 nVal2 = pToken->GetDouble();
302 DELETEZ(pFormula2); // nicht als Formel merken
304 else if ( pToken->GetType() == svString )
306 bIsStr2 = true;
307 aStrVal2 = pToken->GetString().getString();
308 DELETEZ(pFormula2); // nicht als Formel merken
312 bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
315 // formula cells are created at IsValid
318 ScConditionEntry::~ScConditionEntry()
320 delete pFCell1;
321 delete pFCell2;
323 delete pFormula1;
324 delete pFormula2;
327 void ScConditionEntry::Compile( const OUString& rExpr1, const OUString& rExpr2,
328 const OUString& rExprNmsp1, const OUString& rExprNmsp2,
329 FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2, bool bTextToReal )
331 if ( !rExpr1.isEmpty() || !rExpr2.isEmpty() )
333 ScCompiler aComp( mpDoc, aSrcPos );
335 if ( !rExpr1.isEmpty() )
337 aComp.SetGrammar( eGrammar1 );
338 if ( mpDoc->IsImportingXML() && !bTextToReal )
340 // temporary formula string as string tokens
341 //! merge with lcl_ScDocFunc_CreateTokenArrayXML
342 pFormula1 = new ScTokenArray;
343 pFormula1->AddStringXML( rExpr1 );
344 // bRelRef1 is set when the formula is compiled again (CompileXML)
346 else
348 pFormula1 = aComp.CompileString( rExpr1, rExprNmsp1 );
349 if ( pFormula1->GetLen() == 1 )
351 // einzelne (konstante Zahl) ?
352 FormulaToken* pToken = pFormula1->First();
353 if ( pToken->GetOpCode() == ocPush )
355 if ( pToken->GetType() == svDouble )
357 nVal1 = pToken->GetDouble();
358 DELETEZ(pFormula1); // nicht als Formel merken
360 else if ( pToken->GetType() == svString )
362 bIsStr1 = true;
363 aStrVal1 = pToken->GetString().getString();
364 DELETEZ(pFormula1); // nicht als Formel merken
368 bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
372 if ( !rExpr2.isEmpty() )
374 aComp.SetGrammar( eGrammar2 );
375 if ( mpDoc->IsImportingXML() && !bTextToReal )
377 // temporary formula string as string tokens
378 //! merge with lcl_ScDocFunc_CreateTokenArrayXML
379 pFormula2 = new ScTokenArray;
380 pFormula2->AddStringXML( rExpr2 );
381 // bRelRef2 is set when the formula is compiled again (CompileXML)
383 else
385 pFormula2 = aComp.CompileString( rExpr2, rExprNmsp2 );
386 if ( pFormula2->GetLen() == 1 )
388 // einzelne (konstante Zahl) ?
389 FormulaToken* pToken = pFormula2->First();
390 if ( pToken->GetOpCode() == ocPush )
392 if ( pToken->GetType() == svDouble )
394 nVal2 = pToken->GetDouble();
395 DELETEZ(pFormula2); // nicht als Formel merken
397 else if ( pToken->GetType() == svString )
399 bIsStr2 = true;
400 aStrVal2 = pToken->GetString().getString();
401 DELETEZ(pFormula2); // nicht als Formel merken
405 bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
411 void ScConditionEntry::MakeCells( const ScAddress& rPos ) // Formelzellen anlegen
413 if ( !mpDoc->IsClipOrUndo() ) // nie im Clipboard rechnen!
415 if ( pFormula1 && !pFCell1 && !bRelRef1 )
417 pFCell1 = new ScFormulaCell(mpDoc, rPos, *pFormula1);
418 pFCell1->StartListeningTo( mpDoc );
421 if ( pFormula2 && !pFCell2 && !bRelRef2 )
423 pFCell2 = new ScFormulaCell(mpDoc, rPos, *pFormula2);
424 pFCell2->StartListeningTo( mpDoc );
429 void ScConditionEntry::SetIgnoreBlank(bool bSet)
431 // Das Bit SC_COND_NOBLANKS wird gesetzt, wenn Blanks nicht ignoriert werden
432 // (nur bei Gueltigkeit)
434 if (bSet)
435 nOptions &= ~SC_COND_NOBLANKS;
436 else
437 nOptions |= SC_COND_NOBLANKS;
440 void ScConditionEntry::CompileAll()
442 // Formelzellen loeschen, dann wird beim naechsten IsValid neu kompiliert
444 DELETEZ(pFCell1);
445 DELETEZ(pFCell2);
448 void ScConditionEntry::CompileXML()
450 // First parse the formula source position if it was stored as text
452 if ( !aSrcString.isEmpty() )
454 ScAddress aNew;
455 /* XML is always in OOo:A1 format, although R1C1 would be more amenable
456 * to compression */
457 if ( aNew.Parse( aSrcString, mpDoc ) & SCA_VALID )
458 aSrcPos = aNew;
459 // if the position is invalid, there isn't much we can do at this time
460 aSrcString = OUString();
463 // Convert the text tokens that were created during XML import into real tokens.
465 Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar1),
466 GetExpression(aSrcPos, 1, 0, eTempGrammar2),
467 aStrNmsp1, aStrNmsp2, eTempGrammar1, eTempGrammar2, true );
470 void ScConditionEntry::SetSrcString( const OUString& rNew )
472 // aSrcString is only evaluated in CompileXML
473 SAL_WARN_IF( !mpDoc->IsImportingXML(), "sc", "SetSrcString is only valid for XML import" );
475 aSrcString = rNew;
478 void ScConditionEntry::SetFormula1( const ScTokenArray& rArray )
480 DELETEZ( pFormula1 );
481 if( rArray.GetLen() > 0 )
483 pFormula1 = new ScTokenArray( rArray );
484 bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
488 void ScConditionEntry::SetFormula2( const ScTokenArray& rArray )
490 DELETEZ( pFormula2 );
491 if( rArray.GetLen() > 0 )
493 pFormula2 = new ScTokenArray( rArray );
494 bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
498 void ScConditionEntry::UpdateReference( sc::RefUpdateContext& rCxt )
500 if(pCondFormat)
501 aSrcPos = pCondFormat->GetRange().Combine().aStart;
502 ScAddress aOldSrcPos = aSrcPos;
503 bool bChangedPos = false;
504 if (rCxt.meMode == URM_INSDEL && rCxt.maRange.In(aSrcPos))
506 aSrcPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
507 bChangedPos = aSrcPos != aOldSrcPos;
510 if (pFormula1)
512 sc::RefUpdateResult aRes = pFormula1->AdjustReferenceInName(rCxt, aOldSrcPos);
513 if (aRes.mbReferenceModified || bChangedPos)
514 DELETEZ(pFCell1); // is created again in IsValid
516 if (pFormula2)
518 sc::RefUpdateResult aRes = pFormula2->AdjustReferenceInName(rCxt, aOldSrcPos);
519 if (aRes.mbReferenceModified || bChangedPos)
520 DELETEZ(pFCell2); // is created again in IsValid
524 void ScConditionEntry::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
526 if (pFormula1)
528 pFormula1->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
529 DELETEZ(pFCell1);
532 if (pFormula2)
534 pFormula2->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
535 DELETEZ(pFCell2);
539 void ScConditionEntry::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
541 if (pFormula1)
543 pFormula1->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
544 DELETEZ(pFCell1);
547 if (pFormula2)
549 pFormula2->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
550 DELETEZ(pFCell2);
554 void ScConditionEntry::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
556 if (pFormula1)
558 pFormula1->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
559 DELETEZ(pFCell1);
562 if (pFormula2)
564 pFormula2->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
565 DELETEZ(pFCell2);
569 //! als Vergleichsoperator ans TokenArray ???
571 static bool lcl_IsEqual( const ScTokenArray* pArr1, const ScTokenArray* pArr2 )
573 // verglichen wird nur das nicht-RPN Array
575 if ( pArr1 && pArr2 )
577 sal_uInt16 nLen = pArr1->GetLen();
578 if ( pArr2->GetLen() != nLen )
579 return false;
581 FormulaToken** ppToken1 = pArr1->GetArray();
582 FormulaToken** ppToken2 = pArr2->GetArray();
583 for (sal_uInt16 i=0; i<nLen; i++)
585 if ( ppToken1[i] != ppToken2[i] &&
586 !(*ppToken1[i] == *ppToken2[i]) )
587 return false; // Unterschied
589 return true; // alle Eintraege gleich
591 else
592 return !pArr1 && !pArr2; // beide 0 -> gleich
595 int ScConditionEntry::operator== ( const ScConditionEntry& r ) const
597 bool bEq = (eOp == r.eOp && nOptions == r.nOptions &&
598 lcl_IsEqual( pFormula1, r.pFormula1 ) &&
599 lcl_IsEqual( pFormula2, r.pFormula2 ));
600 if (bEq)
602 // for formulas, the reference positions must be compared, too
603 // (including aSrcString, for inserting the entries during XML import)
604 if ( ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
605 bEq = false;
607 // wenn keine Formeln, Werte vergleichen
608 if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
609 bEq = false;
610 if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
611 bEq = false;
614 return bEq;
617 void ScConditionEntry::Interpret( const ScAddress& rPos )
619 // Formelzellen anlegen
620 // dabei koennen neue Broadcaster (Note-Zellen) ins Dokument eingefuegt werden !!!!
622 if ( ( pFormula1 && !pFCell1 ) || ( pFormula2 && !pFCell2 ) )
623 MakeCells( rPos );
625 // Formeln auswerten
627 bool bDirty = false; //! 1 und 2 getrennt ???
629 ScFormulaCell* pTemp1 = NULL;
630 ScFormulaCell* pEff1 = pFCell1;
631 if ( bRelRef1 )
633 pTemp1 = pFormula1 ? new ScFormulaCell(mpDoc, rPos, *pFormula1) : new ScFormulaCell(mpDoc, rPos);
634 pEff1 = pTemp1;
636 if ( pEff1 )
638 if (!pEff1->IsRunning()) // keine 522 erzeugen
640 //! Changed statt Dirty abfragen !!!
641 if (pEff1->GetDirty() && !bRelRef1 && mpDoc->GetAutoCalc())
642 bDirty = true;
643 if (pEff1->IsValue())
645 bIsStr1 = false;
646 nVal1 = pEff1->GetValue();
647 aStrVal1 = OUString();
649 else
651 bIsStr1 = true;
652 aStrVal1 = pEff1->GetString().getString();
653 nVal1 = 0.0;
657 delete pTemp1;
659 ScFormulaCell* pTemp2 = NULL;
660 ScFormulaCell* pEff2 = pFCell2; //@ 1!=2
661 if ( bRelRef2 )
663 pTemp2 = pFormula2 ? new ScFormulaCell(mpDoc, rPos, *pFormula2) : new ScFormulaCell(mpDoc, rPos);
664 pEff2 = pTemp2;
666 if ( pEff2 )
668 if (!pEff2->IsRunning()) // keine 522 erzeugen
670 if (pEff2->GetDirty() && !bRelRef2 && mpDoc->GetAutoCalc())
671 bDirty = true;
672 if (pEff2->IsValue())
674 bIsStr2 = false;
675 nVal2 = pEff2->GetValue();
676 aStrVal2 = OUString();
678 else
680 bIsStr2 = true;
681 aStrVal2 = pEff2->GetString().getString();
682 nVal2 = 0.0;
686 delete pTemp2;
688 // wenn IsRunning, bleiben die letzten Werte erhalten
690 if (bDirty && !bFirstRun)
692 // bei bedingten Formaten neu painten
694 DataChanged( NULL ); // alles
697 bFirstRun = false;
700 static bool lcl_GetCellContent( ScRefCellValue& rCell, bool bIsStr1, double& rArg, OUString& rArgStr,
701 const ScDocument* pDoc )
704 if (rCell.isEmpty())
705 return !bIsStr1;
707 bool bVal = true;
709 switch (rCell.meType)
711 case CELLTYPE_VALUE:
712 rArg = rCell.mfValue;
713 break;
714 case CELLTYPE_FORMULA:
716 bVal = rCell.mpFormula->IsValue();
717 if (bVal)
718 rArg = rCell.mpFormula->GetValue();
719 else
720 rArgStr = rCell.mpFormula->GetString().getString();
722 break;
723 case CELLTYPE_STRING:
724 case CELLTYPE_EDIT:
725 bVal = false;
726 if (rCell.meType == CELLTYPE_STRING)
727 rArgStr = rCell.mpString->getString();
728 else if (rCell.mpEditText)
729 rArgStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc);
730 break;
731 default:
735 return bVal;
738 void ScConditionEntry::FillCache() const
740 if(!mpCache)
742 const ScRangeList& rRanges = pCondFormat->GetRange();
743 mpCache.reset(new ScConditionEntryCache);
744 size_t nListCount = rRanges.size();
745 for( size_t i = 0; i < nListCount; i++ )
747 const ScRange *aRange = rRanges[i];
748 SCROW nRow = aRange->aEnd.Row();
749 SCCOL nCol = aRange->aEnd.Col();
750 SCCOL nColStart = aRange->aStart.Col();
751 SCROW nRowStart = aRange->aStart.Row();
752 SCTAB nTab = aRange->aStart.Tab();
754 // temporary fix to workaorund slow duplicate entry
755 // conditions, prevent to use a whole row
756 if(nRow == MAXROW)
758 bool bShrunk = false;
759 mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
760 nCol, nRow, false);
763 for( SCROW r = nRowStart; r <= nRow; r++ )
764 for( SCCOL c = nColStart; c <= nCol; c++ )
766 ScRefCellValue aCell;
767 aCell.assign(*mpDoc, ScAddress(c, r, nTab));
768 if (aCell.isEmpty())
769 continue;
771 double nVal = 0.0;
772 OUString aStr;
773 if (!lcl_GetCellContent(aCell, false, nVal, aStr, mpDoc))
775 std::pair<ScConditionEntryCache::StringCacheType::iterator, bool> aResult =
776 mpCache->maStrings.insert(
777 ScConditionEntryCache::StringCacheType::value_type(aStr, 1));
779 if(!aResult.second)
780 aResult.first->second++;
782 else
784 std::pair<ScConditionEntryCache::ValueCacheType::iterator, bool> aResult =
785 mpCache->maValues.insert(
786 ScConditionEntryCache::ValueCacheType::value_type(nVal, 1));
788 if(!aResult.second)
789 aResult.first->second++;
791 ++(mpCache->nValueItems);
798 bool ScConditionEntry::IsDuplicate( double nArg, const OUString& rStr ) const
800 FillCache();
802 if(rStr.isEmpty())
804 ScConditionEntryCache::ValueCacheType::iterator itr = mpCache->maValues.find(nArg);
805 if(itr == mpCache->maValues.end())
806 return false;
807 else
809 if(itr->second > 1)
810 return true;
811 else
812 return false;
815 else
817 ScConditionEntryCache::StringCacheType::iterator itr = mpCache->maStrings.find(rStr);
818 if(itr == mpCache->maStrings.end())
819 return false;
820 else
822 if(itr->second > 1)
823 return true;
824 else
825 return false;
830 bool ScConditionEntry::IsTopNElement( double nArg ) const
832 FillCache();
834 if(mpCache->nValueItems <= nVal1)
835 return true;
837 size_t nCells = 0;
838 for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
839 itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
841 if(nCells >= nVal1)
842 return false;
843 if(itr->first <= nArg)
844 return true;
845 nCells += itr->second;
848 return true;
851 bool ScConditionEntry::IsBottomNElement( double nArg ) const
853 FillCache();
855 if(mpCache->nValueItems <= nVal1)
856 return true;
858 size_t nCells = 0;
859 for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
860 itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
862 if(nCells >= nVal1)
863 return false;
864 if(itr->first >= nArg)
865 return true;
866 nCells += itr->second;
869 return true;
872 bool ScConditionEntry::IsTopNPercent( double nArg ) const
874 FillCache();
876 size_t nCells = 0;
877 size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
878 for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
879 itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
881 if(nCells >= nLimitCells)
882 return false;
883 if(itr->first <= nArg)
884 return true;
885 nCells += itr->second;
888 return true;
891 bool ScConditionEntry::IsBottomNPercent( double nArg ) const
893 FillCache();
895 size_t nCells = 0;
896 size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
897 for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
898 itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
900 if(nCells >= nLimitCells)
901 return false;
902 if(itr->first >= nArg)
903 return true;
904 nCells += itr->second;
907 return true;
910 bool ScConditionEntry::IsBelowAverage( double nArg, bool bEqual ) const
912 FillCache();
914 double nSum = 0;
915 for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
916 itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
918 nSum += itr->first * itr->second;
921 if(bEqual)
922 return (nArg <= nSum/mpCache->nValueItems);
923 else
924 return (nArg < nSum/mpCache->nValueItems);
927 bool ScConditionEntry::IsAboveAverage( double nArg, bool bEqual ) const
929 FillCache();
931 double nSum = 0;
932 for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
933 itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
935 nSum += itr->first * itr->second;
938 if(bEqual)
939 return (nArg >= nSum/mpCache->nValueItems);
940 else
941 return (nArg > nSum/mpCache->nValueItems);
944 bool ScConditionEntry::IsError( const ScAddress& rPos ) const
946 switch (mpDoc->GetCellType(rPos))
948 case CELLTYPE_VALUE:
949 return false;
950 case CELLTYPE_FORMULA:
952 ScFormulaCell* pFormulaCell = const_cast<ScFormulaCell*>(mpDoc->GetFormulaCell(rPos));
953 if(pFormulaCell->GetErrCode())
954 return true;
956 case CELLTYPE_STRING:
957 case CELLTYPE_EDIT:
958 return false;
959 default:
960 break;
962 return false;
965 bool ScConditionEntry::IsValid( double nArg, const ScAddress& rPos ) const
967 // Interpret muss schon gerufen sein
969 if ( bIsStr1 )
971 switch( eOp )
973 case SC_COND_BEGINS_WITH:
974 case SC_COND_ENDS_WITH:
975 case SC_COND_CONTAINS_TEXT:
976 case SC_COND_NOT_CONTAINS_TEXT:
977 break;
978 case SC_COND_NOTEQUAL:
979 return true;
980 default:
981 return false;
985 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
986 if ( bIsStr2 )
987 return false;
989 double nComp1 = nVal1; // Kopie, damit vertauscht werden kann
990 double nComp2 = nVal2;
992 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
993 if ( nComp1 > nComp2 )
995 // richtige Reihenfolge fuer Wertebereich
996 double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp;
999 // Alle Grenzfaelle muessen per ::rtl::math::approxEqual getestet werden!
1001 bool bValid = false;
1002 switch (eOp)
1004 case SC_COND_NONE:
1005 break; // immer sal_False;
1006 case SC_COND_EQUAL:
1007 bValid = ::rtl::math::approxEqual( nArg, nComp1 );
1008 break;
1009 case SC_COND_NOTEQUAL:
1010 bValid = !::rtl::math::approxEqual( nArg, nComp1 );
1011 break;
1012 case SC_COND_GREATER:
1013 bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1014 break;
1015 case SC_COND_EQGREATER:
1016 bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1017 break;
1018 case SC_COND_LESS:
1019 bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1020 break;
1021 case SC_COND_EQLESS:
1022 bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1023 break;
1024 case SC_COND_BETWEEN:
1025 bValid = ( nArg >= nComp1 && nArg <= nComp2 ) ||
1026 ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 );
1027 break;
1028 case SC_COND_NOTBETWEEN:
1029 bValid = ( nArg < nComp1 || nArg > nComp2 ) &&
1030 !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 );
1031 break;
1032 case SC_COND_DUPLICATE:
1033 case SC_COND_NOTDUPLICATE:
1034 if( pCondFormat )
1036 bValid = IsDuplicate( nArg, OUString() );
1037 if( eOp == SC_COND_NOTDUPLICATE )
1038 bValid = !bValid;
1040 break;
1041 case SC_COND_DIRECT:
1042 bValid = !::rtl::math::approxEqual( nComp1, 0.0 );
1043 break;
1044 case SC_COND_TOP10:
1045 bValid = IsTopNElement( nArg );
1046 break;
1047 case SC_COND_BOTTOM10:
1048 bValid = IsBottomNElement( nArg );
1049 break;
1050 case SC_COND_TOP_PERCENT:
1051 bValid = IsTopNPercent( nArg );
1052 break;
1053 case SC_COND_BOTTOM_PERCENT:
1054 bValid = IsBottomNPercent( nArg );
1055 break;
1056 case SC_COND_ABOVE_AVERAGE:
1057 case SC_COND_ABOVE_EQUAL_AVERAGE:
1058 bValid = IsAboveAverage( nArg, eOp == SC_COND_ABOVE_EQUAL_AVERAGE );
1059 break;
1060 case SC_COND_BELOW_AVERAGE:
1061 case SC_COND_BELOW_EQUAL_AVERAGE:
1062 bValid = IsBelowAverage( nArg, eOp == SC_COND_BELOW_EQUAL_AVERAGE );
1063 break;
1064 case SC_COND_ERROR:
1065 case SC_COND_NOERROR:
1066 bValid = IsError( rPos );
1067 if( eOp == SC_COND_NOERROR )
1068 bValid = !bValid;
1069 break;
1070 case SC_COND_BEGINS_WITH:
1071 if(aStrVal1.isEmpty())
1073 OUString aStr = OUString::number(nVal1);
1074 OUString aStr2 = OUString::number(nArg);
1075 bValid = aStr2.startsWith(aStr);
1077 else
1079 OUString aStr2 = OUString::number(nArg);
1080 bValid = aStr2.startsWith(aStrVal1);
1082 break;
1083 case SC_COND_ENDS_WITH:
1084 if(aStrVal1.isEmpty())
1086 OUString aStr = OUString::number(nVal1);
1087 OUString aStr2 = OUString::number(nArg);
1088 bValid = aStr2.endsWith(aStr) == 0;
1090 else
1092 OUString aStr2 = OUString::number(nArg);
1093 bValid = aStr2.endsWith(aStrVal1) == 0;
1095 break;
1096 case SC_COND_CONTAINS_TEXT:
1097 case SC_COND_NOT_CONTAINS_TEXT:
1098 if(aStrVal1.isEmpty())
1100 OUString aStr = OUString::number(nVal1);
1101 OUString aStr2 = OUString::number(nArg);
1102 bValid = aStr2.indexOf(aStr) != -1;
1104 else
1106 OUString aStr2 = OUString::number(nArg);
1107 bValid = aStr2.indexOf(aStrVal1) != -1;
1110 if( eOp == SC_COND_NOT_CONTAINS_TEXT )
1111 bValid = !bValid;
1112 break;
1113 default:
1114 SAL_WARN("sc", "unknown operation at ScConditionEntry");
1115 break;
1117 return bValid;
1120 bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos ) const
1122 bool bValid = false;
1123 // Interpret muss schon gerufen sein
1125 if ( eOp == SC_COND_DIRECT ) // Formel ist unabhaengig vom Inhalt
1126 return !::rtl::math::approxEqual( nVal1, 0.0 );
1128 if ( eOp == SC_COND_DUPLICATE || eOp == SC_COND_NOTDUPLICATE )
1130 if( pCondFormat && !rArg.isEmpty() )
1132 bValid = IsDuplicate( 0.0, rArg );
1133 if( eOp == SC_COND_NOTDUPLICATE )
1134 bValid = !bValid;
1135 return bValid;
1139 // If number contains condition, always false, except for "not equal".
1141 if ( !bIsStr1 && (eOp != SC_COND_ERROR && eOp != SC_COND_NOERROR) )
1142 return ( eOp == SC_COND_NOTEQUAL );
1143 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1144 if ( !bIsStr2 )
1145 return false;
1147 OUString aUpVal1( aStrVal1 ); //! als Member? (dann auch in Interpret setzen)
1148 OUString aUpVal2( aStrVal2 );
1150 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1151 if (ScGlobal::GetCollator()->compareString( aUpVal1, aUpVal2 ) > 0)
1153 // richtige Reihenfolge fuer Wertebereich
1154 OUString aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
1157 switch ( eOp )
1159 case SC_COND_EQUAL:
1160 bValid = (ScGlobal::GetCollator()->compareString(
1161 rArg, aUpVal1 ) == 0);
1162 break;
1163 case SC_COND_NOTEQUAL:
1164 bValid = (ScGlobal::GetCollator()->compareString(
1165 rArg, aUpVal1 ) != 0);
1166 break;
1167 case SC_COND_TOP_PERCENT:
1168 case SC_COND_BOTTOM_PERCENT:
1169 case SC_COND_TOP10:
1170 case SC_COND_BOTTOM10:
1171 case SC_COND_ABOVE_AVERAGE:
1172 case SC_COND_BELOW_AVERAGE:
1173 return false;
1174 case SC_COND_ERROR:
1175 case SC_COND_NOERROR:
1176 bValid = IsError( rPos );
1177 if(eOp == SC_COND_NOERROR)
1178 bValid = !bValid;
1179 break;
1180 case SC_COND_BEGINS_WITH:
1181 bValid = rArg.startsWith(aUpVal1);
1182 break;
1183 case SC_COND_ENDS_WITH:
1184 bValid = rArg.endsWith(aUpVal1);
1185 break;
1186 case SC_COND_CONTAINS_TEXT:
1187 case SC_COND_NOT_CONTAINS_TEXT:
1188 bValid = rArg.indexOf(aUpVal1) != -1;
1189 if(eOp == SC_COND_NOT_CONTAINS_TEXT)
1190 bValid = !bValid;
1191 break;
1192 default:
1194 sal_Int32 nCompare = ScGlobal::GetCollator()->compareString(
1195 rArg, aUpVal1 );
1196 switch ( eOp )
1198 case SC_COND_GREATER:
1199 bValid = ( nCompare > 0 );
1200 break;
1201 case SC_COND_EQGREATER:
1202 bValid = ( nCompare >= 0 );
1203 break;
1204 case SC_COND_LESS:
1205 bValid = ( nCompare < 0 );
1206 break;
1207 case SC_COND_EQLESS:
1208 bValid = ( nCompare <= 0 );
1209 break;
1210 case SC_COND_BETWEEN:
1211 case SC_COND_NOTBETWEEN:
1212 // Test auf NOTBETWEEN:
1213 bValid = ( nCompare < 0 ||
1214 ScGlobal::GetCollator()->compareString( rArg,
1215 aUpVal2 ) > 0 );
1216 if ( eOp == SC_COND_BETWEEN )
1217 bValid = !bValid;
1218 break;
1219 // SC_COND_DIRECT schon oben abgefragt
1220 default:
1221 SAL_WARN("sc", "unbekannte Operation bei ScConditionEntry");
1222 bValid = false;
1223 break;
1227 return bValid;
1230 bool ScConditionEntry::IsCellValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
1232 ((ScConditionEntry*)this)->Interpret(rPos); // Formeln auswerten
1234 double nArg = 0.0;
1235 OUString aArgStr;
1236 bool bVal = lcl_GetCellContent( rCell, bIsStr1, nArg, aArgStr, mpDoc );
1237 if (bVal)
1238 return IsValid( nArg, rPos );
1239 else
1240 return IsValidStr( aArgStr, rPos );
1243 OUString ScConditionEntry::GetExpression( const ScAddress& rCursor, sal_uInt16 nIndex,
1244 sal_uLong nNumFmt,
1245 const FormulaGrammar::Grammar eGrammar ) const
1247 assert( nIndex <= 1);
1248 OUString aRet;
1250 if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 )
1251 nNumFmt = mpDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US );
1253 if ( nIndex==0 )
1255 if ( pFormula1 )
1257 ScCompiler aComp(mpDoc, rCursor, *pFormula1);
1258 aComp.SetGrammar(eGrammar);
1259 OUStringBuffer aBuffer;
1260 aComp.CreateStringFromTokenArray( aBuffer );
1261 aRet = aBuffer.makeStringAndClear();
1263 else if (bIsStr1)
1265 aRet = "\"";
1266 aRet += aStrVal1;
1267 aRet += "\"";
1269 else
1270 mpDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet);
1272 else if ( nIndex==1 )
1274 if ( pFormula2 )
1276 ScCompiler aComp(mpDoc, rCursor, *pFormula2);
1277 aComp.SetGrammar(eGrammar);
1278 OUStringBuffer aBuffer;
1279 aComp.CreateStringFromTokenArray( aBuffer );
1280 aRet = aBuffer.makeStringAndClear();
1282 else if (bIsStr2)
1284 aRet = "\"";
1285 aRet += aStrVal2;
1286 aRet += "\"";
1288 else
1289 mpDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet);
1292 return aRet;
1295 ScTokenArray* ScConditionEntry::CreateTokenArry( sal_uInt16 nIndex ) const
1297 assert(nIndex <= 1);
1298 ScTokenArray* pRet = NULL;
1299 ScAddress aAddr;
1301 if ( nIndex==0 )
1303 if ( pFormula1 )
1304 pRet = new ScTokenArray( *pFormula1 );
1305 else
1307 pRet = new ScTokenArray();
1308 if (bIsStr1)
1309 pRet->AddString( aStrVal1 );
1310 else
1311 pRet->AddDouble( nVal1 );
1314 else if ( nIndex==1 )
1316 if ( pFormula2 )
1317 pRet = new ScTokenArray( *pFormula2 );
1318 else
1320 pRet = new ScTokenArray();
1321 if (bIsStr2)
1322 pRet->AddString( aStrVal2 );
1323 else
1324 pRet->AddDouble( nVal2 );
1328 return pRet;
1331 void ScConditionEntry::SourceChanged( const ScAddress& rChanged )
1333 for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1335 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1336 if (pFormula)
1338 pFormula->Reset();
1339 ScToken* t;
1340 while ( ( t = static_cast<ScToken*>(pFormula->GetNextReference()) ) != NULL )
1342 SingleDoubleRefProvider aProv( *t );
1343 if ( aProv.Ref1.IsColRel() || aProv.Ref1.IsRowRel() || aProv.Ref1.IsTabRel() ||
1344 aProv.Ref2.IsColRel() || aProv.Ref2.IsRowRel() || aProv.Ref2.IsTabRel() )
1346 // absolut muss getroffen sein, relativ bestimmt Bereich
1348 bool bHit = true;
1349 SCsCOL nCol1;
1350 SCsROW nRow1;
1351 SCsTAB nTab1;
1352 SCsCOL nCol2;
1353 SCsROW nRow2;
1354 SCsTAB nTab2;
1356 if ( aProv.Ref1.IsColRel() )
1357 nCol2 = rChanged.Col() - aProv.Ref1.Col();
1358 else
1360 bHit &= (rChanged.Col() >= aProv.Ref1.Col());
1361 nCol2 = MAXCOL;
1363 if ( aProv.Ref1.IsRowRel() )
1364 nRow2 = rChanged.Row() - aProv.Ref1.Row();
1365 else
1367 bHit &= ( rChanged.Row() >= aProv.Ref1.Row() );
1368 nRow2 = MAXROW;
1370 if ( aProv.Ref1.IsTabRel() )
1371 nTab2 = rChanged.Tab() - aProv.Ref1.Tab();
1372 else
1374 bHit &= (rChanged.Tab() >= aProv.Ref1.Tab());
1375 nTab2 = MAXTAB;
1378 if ( aProv.Ref2.IsColRel() )
1379 nCol1 = rChanged.Col() - aProv.Ref2.Col();
1380 else
1382 bHit &= ( rChanged.Col() <= aProv.Ref2.Col() );
1383 nCol1 = 0;
1385 if ( aProv.Ref2.IsRowRel() )
1386 nRow1 = rChanged.Row() - aProv.Ref2.Row();
1387 else
1389 bHit &= (rChanged.Row() <= aProv.Ref2.Row());
1390 nRow1 = 0;
1392 if ( aProv.Ref2.IsTabRel() )
1393 nTab1 = rChanged.Tab() - aProv.Ref2.Tab();
1394 else
1396 bHit &= (rChanged.Tab() <= aProv.Ref2.Tab());
1397 nTab1 = 0;
1400 if ( bHit )
1402 //! begrenzen
1404 ScRange aPaint( nCol1,nRow1,nTab1, nCol2,nRow2,nTab2 );
1406 // kein Paint, wenn es nur die Zelle selber ist
1407 if ( aPaint.IsValid() && (aPaint.aStart != rChanged || aPaint.aEnd != rChanged ))
1408 DataChanged( &aPaint );
1416 ScAddress ScConditionEntry::GetValidSrcPos() const
1418 // return a position that's adjusted to allow textual representation of expressions if possible
1420 SCTAB nMinTab = aSrcPos.Tab();
1421 SCTAB nMaxTab = nMinTab;
1423 for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1425 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1426 if (pFormula)
1428 pFormula->Reset();
1429 ScToken* t;
1430 while ( ( t = static_cast<ScToken*>(pFormula->GetNextReference()) ) != NULL )
1432 ScSingleRefData& rRef1 = t->GetSingleRef();
1433 ScAddress aAbs = rRef1.toAbs(aSrcPos);
1434 if (!rRef1.IsTabDeleted())
1436 if (aAbs.Tab() < nMinTab)
1437 nMinTab = aAbs.Tab();
1438 if (aAbs.Tab() > nMaxTab)
1439 nMaxTab = aAbs.Tab();
1441 if ( t->GetType() == svDoubleRef )
1443 ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
1444 aAbs = rRef2.toAbs(aSrcPos);
1445 if (!rRef2.IsTabDeleted())
1447 if (aAbs.Tab() < nMinTab)
1448 nMinTab = aAbs.Tab();
1449 if (aAbs.Tab() > nMaxTab)
1450 nMaxTab = aAbs.Tab();
1457 ScAddress aValidPos = aSrcPos;
1458 SCTAB nTabCount = mpDoc->GetTableCount();
1459 if ( nMaxTab >= nTabCount && nMinTab > 0 )
1460 aValidPos.SetTab( aSrcPos.Tab() - nMinTab ); // so the lowest tab ref will be on 0
1462 if ( aValidPos.Tab() >= nTabCount )
1463 aValidPos.SetTab( nTabCount - 1 ); // ensure a valid position even if some references will be invalid
1465 return aValidPos;
1468 void ScConditionEntry::DataChanged( const ScRange* /* pModified */ ) const
1470 // nix
1473 bool ScConditionEntry::MarkUsedExternalReferences() const
1475 bool bAllMarked = false;
1476 for (sal_uInt16 nPass = 0; !bAllMarked && nPass < 2; nPass++)
1478 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1479 if (pFormula)
1480 bAllMarked = mpDoc->MarkUsedExternalReferences(*pFormula, aSrcPos);
1482 return bAllMarked;
1485 ScFormatEntry* ScConditionEntry::Clone(ScDocument* pDoc) const
1487 return new ScConditionEntry(pDoc, *this);
1490 ScConditionMode ScConditionEntry::GetModeFromApi(sal_Int32 nOperation)
1492 ScConditionMode eMode = SC_COND_NONE;
1493 switch (nOperation)
1495 case com::sun::star::sheet::ConditionOperator2::EQUAL:
1496 eMode = SC_COND_EQUAL;
1497 break;
1498 case com::sun::star::sheet::ConditionOperator2::LESS:
1499 eMode = SC_COND_LESS;
1500 break;
1501 case com::sun::star::sheet::ConditionOperator2::GREATER:
1502 eMode = SC_COND_GREATER;
1503 break;
1504 case com::sun::star::sheet::ConditionOperator2::LESS_EQUAL:
1505 eMode = SC_COND_EQLESS;
1506 break;
1507 case com::sun::star::sheet::ConditionOperator2::GREATER_EQUAL:
1508 eMode = SC_COND_EQGREATER;
1509 break;
1510 case com::sun::star::sheet::ConditionOperator2::NOT_EQUAL:
1511 eMode = SC_COND_NOTEQUAL;
1512 break;
1513 case com::sun::star::sheet::ConditionOperator2::BETWEEN:
1514 eMode = SC_COND_BETWEEN;
1515 break;
1516 case com::sun::star::sheet::ConditionOperator2::NOT_BETWEEN:
1517 eMode = SC_COND_NOTBETWEEN;
1518 break;
1519 case com::sun::star::sheet::ConditionOperator2::FORMULA:
1520 eMode = SC_COND_DIRECT;
1521 break;
1522 case com::sun::star::sheet::ConditionOperator2::DUPLICATE:
1523 eMode = SC_COND_DUPLICATE;
1524 break;
1525 case com::sun::star::sheet::ConditionOperator2::NOT_DUPLICATE:
1526 eMode = SC_COND_NOTDUPLICATE;
1527 break;
1528 default:
1529 break;
1531 return eMode;
1534 void ScConditionEntry::startRendering()
1536 mpCache.reset();
1539 void ScConditionEntry::endRendering()
1541 mpCache.reset();
1544 //------------------------------------------------------------------------
1546 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
1547 const OUString& rExpr1, const OUString& rExpr2,
1548 ScDocument* pDocument, const ScAddress& rPos,
1549 const OUString& rStyle,
1550 const OUString& rExprNmsp1, const OUString& rExprNmsp2,
1551 FormulaGrammar::Grammar eGrammar1,
1552 FormulaGrammar::Grammar eGrammar2 ) :
1553 ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ),
1554 aStyleName( rStyle )
1558 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
1559 const ScTokenArray* pArr1, const ScTokenArray* pArr2,
1560 ScDocument* pDocument, const ScAddress& rPos,
1561 const OUString& rStyle ) :
1562 ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos ),
1563 aStyleName( rStyle )
1567 ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry& r ) :
1568 ScConditionEntry( r ),
1569 aStyleName( r.aStyleName )
1573 ScCondFormatEntry::ScCondFormatEntry( ScDocument* pDocument, const ScCondFormatEntry& r ) :
1574 ScConditionEntry( pDocument, r ),
1575 aStyleName( r.aStyleName )
1579 int ScCondFormatEntry::operator== ( const ScCondFormatEntry& r ) const
1581 return ScConditionEntry::operator==( r ) &&
1582 aStyleName == r.aStyleName;
1585 ScCondFormatEntry::~ScCondFormatEntry()
1589 void ScCondFormatEntry::DataChanged( const ScRange* pModified ) const
1591 if ( pCondFormat )
1592 pCondFormat->DoRepaint( pModified );
1595 ScFormatEntry* ScCondFormatEntry::Clone( ScDocument* pDoc ) const
1597 return new ScCondFormatEntry( pDoc, *this );
1600 //------------------------------------------------------------------------
1602 ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument* pDoc ):
1603 ScFormatEntry( pDoc )
1607 ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument* pDoc, const ScCondDateFormatEntry& rFormat ):
1608 ScFormatEntry( pDoc ),
1609 meType( rFormat.meType ),
1610 maStyleName( rFormat.maStyleName )
1614 bool ScCondDateFormatEntry::IsValid( const ScAddress& rPos ) const
1616 CellType eCellType = mpDoc->GetCellType(rPos);
1618 if (eCellType == CELLTYPE_NONE)
1619 // empty cell.
1620 return false;
1622 if (eCellType != CELLTYPE_VALUE && eCellType != CELLTYPE_FORMULA)
1623 // non-numerical cell.
1624 return false;
1626 if( !mpCache )
1627 mpCache.reset( new Date( Date::SYSTEM ) );
1629 const Date& rActDate = *mpCache;
1630 SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
1631 long nCurrentDate = rActDate - *(pFormatter->GetNullDate());
1633 double nVal = mpDoc->GetValue(rPos);
1634 long nCellDate = (long) ::rtl::math::approxFloor(nVal);
1635 Date aCellDate = *(pFormatter->GetNullDate());
1636 aCellDate += (long) ::rtl::math::approxFloor(nVal);
1638 switch(meType)
1640 case condformat::TODAY:
1641 if( nCurrentDate == nCellDate )
1642 return true;
1643 break;
1644 case condformat::TOMORROW:
1645 if( nCurrentDate == nCellDate -1 )
1646 return true;
1647 break;
1648 case condformat::YESTERDAY:
1649 if( nCurrentDate == nCellDate + 1)
1650 return true;
1651 break;
1652 case condformat::LAST7DAYS:
1653 if( nCurrentDate >= nCellDate && nCurrentDate - 7 < nCellDate )
1654 return true;
1655 break;
1656 case condformat::LASTWEEK:
1657 if( rActDate.GetDayOfWeek() != SUNDAY )
1659 Date aBegin(rActDate - 8 - static_cast<long>(rActDate.GetDayOfWeek()));
1660 Date aEnd(rActDate - 2 -static_cast<long>(rActDate.GetDayOfWeek()));
1661 return aCellDate.IsBetween( aBegin, aEnd );
1663 else
1665 Date aBegin(rActDate - 8);
1666 Date aEnd(rActDate - 1);
1667 return aCellDate.IsBetween( aBegin, aEnd );
1669 break;
1670 case condformat::THISWEEK:
1671 if( rActDate.GetDayOfWeek() != SUNDAY )
1673 Date aBegin(rActDate - 1 - static_cast<long>(rActDate.GetDayOfWeek()));
1674 Date aEnd(rActDate + 5 - static_cast<long>(rActDate.GetDayOfWeek()));
1675 return aCellDate.IsBetween( aBegin, aEnd );
1677 else
1679 Date aEnd( rActDate + 6);
1680 return aCellDate.IsBetween( rActDate, aEnd );
1682 break;
1683 case condformat::NEXTWEEK:
1684 if( rActDate.GetDayOfWeek() != SUNDAY )
1686 return aCellDate.IsBetween( rActDate + 6 - static_cast<long>(rActDate.GetDayOfWeek()), rActDate + 12 - static_cast<long>(rActDate.GetDayOfWeek()) );
1688 else
1690 return aCellDate.IsBetween( rActDate + 7, rActDate + 13 );
1692 break;
1693 case condformat::LASTMONTH:
1694 if( rActDate.GetMonth() == 1 )
1696 if( aCellDate.GetMonth() == 12 && rActDate.GetYear() == aCellDate.GetYear() + 1 )
1697 return true;
1699 else if( rActDate.GetYear() == aCellDate.GetYear() )
1701 if( rActDate.GetMonth() == aCellDate.GetMonth() + 1)
1702 return true;
1704 break;
1705 case condformat::THISMONTH:
1706 if( rActDate.GetYear() == aCellDate.GetYear() )
1708 if( rActDate.GetMonth() == aCellDate.GetMonth() )
1709 return true;
1711 break;
1712 case condformat::NEXTMONTH:
1713 if( rActDate.GetMonth() == 12 )
1715 if( aCellDate.GetMonth() == 1 && rActDate.GetYear() == aCellDate.GetYear() - 1 )
1716 return true;
1718 else if( rActDate.GetYear() == aCellDate.GetYear() )
1720 if( rActDate.GetMonth() == aCellDate.GetMonth() - 1)
1721 return true;
1723 break;
1724 case condformat::LASTYEAR:
1725 if( rActDate.GetYear() == aCellDate.GetYear() + 1 )
1726 return true;
1727 break;
1728 case condformat::THISYEAR:
1729 if( rActDate.GetYear() == aCellDate.GetYear() )
1730 return true;
1731 break;
1732 case condformat::NEXTYEAR:
1733 if( rActDate.GetYear() == aCellDate.GetYear() - 1 )
1734 return true;
1735 break;
1738 return false;
1741 void ScCondDateFormatEntry::SetDateType( condformat::ScCondFormatDateType eType )
1743 meType = eType;
1746 condformat::ScCondFormatDateType ScCondDateFormatEntry::GetDateType() const
1748 return meType;
1751 const OUString& ScCondDateFormatEntry::GetStyleName() const
1753 return maStyleName;
1756 void ScCondDateFormatEntry::SetStyleName( const OUString& rStyleName )
1758 maStyleName = rStyleName;
1761 ScFormatEntry* ScCondDateFormatEntry::Clone( ScDocument* pDoc ) const
1763 return new ScCondDateFormatEntry( pDoc, *this );
1766 bool ScCondDateFormatEntry::operator==( const ScFormatEntry& r ) const
1768 if(r.GetType() != condformat::DATE)
1769 return false;
1771 const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(r);
1773 if(rEntry.meType != meType)
1774 return false;
1776 return rEntry.maStyleName == maStyleName;
1779 void ScCondDateFormatEntry::startRendering()
1781 mpCache.reset();
1784 void ScCondDateFormatEntry::endRendering()
1786 mpCache.reset();
1789 //------------------------------------------------------------------------
1791 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
1792 pDoc( pDocument ),
1793 nKey( nNewKey )
1797 ScConditionalFormat* ScConditionalFormat::Clone(ScDocument* pNewDoc) const
1799 // echte Kopie der Formeln (fuer Ref-Undo / zwischen Dokumenten)
1801 if (!pNewDoc)
1802 pNewDoc = pDoc;
1804 ScConditionalFormat* pNew = new ScConditionalFormat(nKey, pNewDoc);
1806 for (CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1808 ScFormatEntry* pNewEntry = itr->Clone(pNewDoc);
1809 pNew->maEntries.push_back( pNewEntry );
1810 pNewEntry->SetParent(pNew);
1812 pNew->AddRange( maRanges );
1814 return pNew;
1817 bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const
1819 if( size() != r.size())
1820 return false;
1822 //! auf gleiche Eintraege in anderer Reihenfolge testen ???
1824 for (sal_uInt16 i=0; i<size(); i++)
1825 if ( ! (maEntries == r.maEntries ) )
1826 return false;
1828 // right now don't check for same range
1829 // we only use this method to merge same conditional formats from
1830 // old ODF data structure
1831 return true;
1834 void ScConditionalFormat::AddRange( const ScRangeList& rRanges )
1836 maRanges = rRanges;
1839 void ScConditionalFormat::AddEntry( ScFormatEntry* pNew )
1841 maEntries.push_back(pNew);
1842 pNew->SetParent(this);
1845 bool ScConditionalFormat::IsEmpty() const
1847 return maEntries.empty();
1850 size_t ScConditionalFormat::size() const
1852 return maEntries.size();
1855 ScConditionalFormat::~ScConditionalFormat()
1859 const ScFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const
1861 if ( nPos < size() )
1862 return &maEntries[nPos];
1863 else
1864 return NULL;
1867 const OUString& ScConditionalFormat::GetCellStyle( ScRefCellValue& rCell, const ScAddress& rPos ) const
1869 for (CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1871 if(itr->GetType() == condformat::CONDITION)
1873 const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*itr);
1874 if (rEntry.IsCellValid(rCell, rPos))
1875 return rEntry.GetStyle();
1877 else if(itr->GetType() == condformat::DATE)
1879 const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*itr);
1880 if (rEntry.IsValid( rPos ))
1881 return rEntry.GetStyleName();
1885 return EMPTY_OUSTRING;
1888 ScCondFormatData ScConditionalFormat::GetData( ScRefCellValue& rCell, const ScAddress& rPos ) const
1890 ScCondFormatData aData;
1891 for(CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1893 if(itr->GetType() == condformat::CONDITION && aData.aStyleName.isEmpty())
1895 const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*itr);
1896 if (rEntry.IsCellValid(rCell, rPos))
1897 aData.aStyleName = rEntry.GetStyle();
1899 else if(itr->GetType() == condformat::COLORSCALE && !aData.pColorScale)
1901 const ScColorScaleFormat& rEntry = static_cast<const ScColorScaleFormat&>(*itr);
1902 aData.pColorScale = rEntry.GetColor(rPos);
1904 else if(itr->GetType() == condformat::DATABAR && !aData.pDataBar)
1906 const ScDataBarFormat& rEntry = static_cast<const ScDataBarFormat&>(*itr);
1907 aData.pDataBar = rEntry.GetDataBarInfo(rPos);
1909 else if(itr->GetType() == condformat::ICONSET && !aData.pIconSet)
1911 const ScIconSetFormat& rEntry = static_cast<const ScIconSetFormat&>(*itr);
1912 aData.pIconSet = rEntry.GetIconSetInfo(rPos);
1914 else if(itr->GetType() == condformat::DATE && aData.aStyleName.isEmpty())
1916 const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*itr);
1917 if ( rEntry.IsValid( rPos ) )
1918 aData.aStyleName = rEntry.GetStyleName();
1921 return aData;
1924 void ScConditionalFormat::DoRepaint( const ScRange* pModified )
1926 if(pModified)
1928 if(maRanges.Intersects(*pModified))
1929 pDoc->RepaintRange(*pModified);
1931 else
1933 // all conditional format cells
1934 pDoc->RepaintRange( maRanges );
1938 void ScConditionalFormat::CompileAll()
1940 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1941 if(itr->GetType() == condformat::CONDITION)
1942 static_cast<ScCondFormatEntry&>(*itr).CompileAll();
1945 void ScConditionalFormat::CompileXML()
1947 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1948 if(itr->GetType() == condformat::CONDITION)
1949 static_cast<ScCondFormatEntry&>(*itr).CompileXML();
1952 void ScConditionalFormat::UpdateReference( sc::RefUpdateContext& rCxt, bool bCopyAsMove )
1954 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1955 itr->UpdateReference(rCxt);
1957 if (rCxt.meMode == URM_COPY && bCopyAsMove)
1958 maRanges.UpdateReference(URM_MOVE, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
1959 else
1960 maRanges.UpdateReference(rCxt.meMode, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
1963 void ScConditionalFormat::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
1965 maRanges.InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
1968 void ScConditionalFormat::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
1970 maRanges.InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
1973 void ScConditionalFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
1975 for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
1976 it->UpdateInsertTab(rCxt);
1979 void ScConditionalFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
1981 for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
1982 it->UpdateDeleteTab(rCxt);
1985 void ScConditionalFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
1987 size_t n = maRanges.size();
1988 SCTAB nMinTab = std::min<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
1989 SCTAB nMaxTab = std::max<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
1990 for(size_t i = 0; i < n; ++i)
1992 ScRange* pRange = maRanges[i];
1993 SCTAB nTab = pRange->aStart.Tab();
1994 if(nTab < nMinTab || nTab > nMaxTab)
1996 continue;
1999 if (nTab == rCxt.mnOldPos)
2001 pRange->aStart.SetTab(rCxt.mnNewPos);
2002 pRange->aEnd.SetTab(rCxt.mnNewPos);
2003 continue;
2006 if (rCxt.mnNewPos < rCxt.mnOldPos)
2008 pRange->aStart.IncTab();
2009 pRange->aEnd.IncTab();
2011 else
2013 pRange->aStart.IncTab(-1);
2014 pRange->aEnd.IncTab(-1);
2018 for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
2019 it->UpdateMoveTab(rCxt);
2022 void ScConditionalFormat::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2024 SCTAB nTab = maRanges[0]->aStart.Tab();
2025 maRanges.DeleteArea( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
2028 void ScConditionalFormat::RenameCellStyle(const OUString& rOld, const OUString& rNew)
2030 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2031 if(itr->GetType() == condformat::CONDITION)
2033 ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*itr);
2034 if(rFormat.GetStyle() == rOld)
2035 rFormat.UpdateStyleName( rNew );
2039 void ScConditionalFormat::SourceChanged( const ScAddress& rAddr )
2041 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2043 condformat::ScFormatEntryType eEntryType = itr->GetType();
2044 if( eEntryType == condformat::CONDITION)
2046 ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*itr);
2047 rFormat.SourceChanged( rAddr );
2049 else if( eEntryType == condformat::COLORSCALE ||
2050 eEntryType == condformat::DATABAR ||
2051 eEntryType == condformat::ICONSET )
2053 ScColorFormat& rFormat = static_cast<ScColorFormat&>(*itr);
2054 if(rFormat.NeedsRepaint())
2056 // we need to repaint the whole range anyway
2057 DoRepaint(NULL);
2058 return;
2064 bool ScConditionalFormat::MarkUsedExternalReferences() const
2066 bool bAllMarked = false;
2067 for(CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end() && !bAllMarked; ++itr)
2068 if(itr->GetType() == condformat::CONDITION)
2070 const ScCondFormatEntry& rFormat = static_cast<const ScCondFormatEntry&>(*itr);
2071 bAllMarked = rFormat.MarkUsedExternalReferences();
2074 return bAllMarked;
2077 void ScConditionalFormat::startRendering()
2079 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2081 itr->startRendering();
2085 void ScConditionalFormat::endRendering()
2087 for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2089 itr->endRendering();
2093 //------------------------------------------------------------------------
2095 ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList& rList)
2097 for(const_iterator itr = rList.begin(); itr != rList.end(); ++itr)
2098 InsertNew( itr->Clone() );
2101 ScConditionalFormatList::ScConditionalFormatList(ScDocument* pDoc, const ScConditionalFormatList& rList)
2103 for(const_iterator itr = rList.begin(); itr != rList.end(); ++itr)
2104 InsertNew( itr->Clone(pDoc) );
2107 void ScConditionalFormatList::InsertNew( ScConditionalFormat* pNew )
2109 maConditionalFormats.insert(pNew);
2112 bool ScConditionalFormatList::operator==( const ScConditionalFormatList& r ) const
2114 // fuer Ref-Undo - interne Variablen werden nicht verglichen
2116 sal_uInt16 nCount = size();
2117 bool bEqual = ( nCount == r.size() );
2118 const_iterator locIterator = begin();
2119 for(const_iterator itr = r.begin(); itr != r.end() && bEqual; ++itr, ++locIterator)
2120 if ( !locIterator->EqualEntries(*itr) ) // Eintraege unterschiedlich ?
2121 bEqual = false;
2123 return bEqual;
2126 ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey )
2128 //! binaer suchen
2130 for( iterator itr = begin(); itr != end(); ++itr)
2131 if (itr->GetKey() == nKey)
2132 return &(*itr);
2134 SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2135 return NULL;
2138 const ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey ) const
2140 //! binaer suchen
2142 for ( const_iterator itr = begin(); itr != end(); ++itr)
2143 if (itr->GetKey() == nKey)
2144 return &(*itr);
2146 SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2147 return NULL;
2150 void ScConditionalFormatList::CompileAll()
2152 for( iterator itr = begin(); itr != end(); ++itr)
2153 itr->CompileAll();
2156 void ScConditionalFormatList::CompileXML()
2158 for( iterator itr = begin(); itr != end(); ++itr)
2159 itr->CompileXML();
2162 void ScConditionalFormatList::UpdateReference( sc::RefUpdateContext& rCxt )
2164 for( iterator itr = begin(); itr != end(); ++itr)
2165 itr->UpdateReference(rCxt);
2167 if (rCxt.meMode == URM_INSDEL)
2169 // need to check which must be deleted
2170 iterator itr = begin();
2171 while(itr != end())
2173 if(itr->GetRange().empty())
2174 maConditionalFormats.erase(itr++);
2175 else
2176 ++itr;
2181 void ScConditionalFormatList::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
2183 for(iterator it = begin(), itEnd = end(); it != itEnd; ++it)
2184 it->InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
2187 void ScConditionalFormatList::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
2189 for(iterator it = begin(), itEnd = end(); it != itEnd; ++it)
2190 it->InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
2193 void ScConditionalFormatList::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
2195 for (iterator it = begin(); it != end(); ++it)
2196 it->UpdateInsertTab(rCxt);
2199 void ScConditionalFormatList::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
2201 for (iterator it = begin(); it != end(); ++it)
2202 it->UpdateDeleteTab(rCxt);
2205 void ScConditionalFormatList::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
2207 for (iterator it = begin(); it != end(); ++it)
2208 it->UpdateMoveTab(rCxt);
2211 void ScConditionalFormatList::RenameCellStyle( const OUString& rOld, const OUString& rNew )
2213 for( iterator itr = begin(); itr != end(); ++itr)
2214 itr->RenameCellStyle(rOld,rNew);
2217 bool ScConditionalFormatList::CheckAllEntries()
2219 bool bValid = true;
2221 // need to check which must be deleted
2222 iterator itr = begin();
2223 while(itr != end())
2225 if(itr->GetRange().empty())
2227 bValid = false;
2228 maConditionalFormats.erase(itr++);
2230 else
2231 ++itr;
2234 return bValid;
2237 void ScConditionalFormatList::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2239 for( iterator itr = begin(); itr != end(); ++itr)
2240 itr->DeleteArea( nCol1, nRow1, nCol2, nRow2 );
2242 CheckAllEntries();
2245 void ScConditionalFormatList::SourceChanged( const ScAddress& rAddr )
2247 for( iterator itr = begin(); itr != end(); ++itr)
2248 itr->SourceChanged( rAddr );
2251 ScConditionalFormatList::iterator ScConditionalFormatList::begin()
2253 return maConditionalFormats.begin();
2256 ScConditionalFormatList::const_iterator ScConditionalFormatList::begin() const
2258 return maConditionalFormats.begin();
2261 ScConditionalFormatList::iterator ScConditionalFormatList::end()
2263 return maConditionalFormats.end();
2266 ScConditionalFormatList::const_iterator ScConditionalFormatList::end() const
2268 return maConditionalFormats.end();
2271 size_t ScConditionalFormatList::size() const
2273 return maConditionalFormats.size();
2276 void ScConditionalFormatList::erase( sal_uLong nIndex )
2278 for( iterator itr = begin(); itr != end(); ++itr )
2280 if( itr->GetKey() == nIndex )
2282 maConditionalFormats.erase(itr);
2283 break;
2288 void ScConditionalFormatList::startRendering()
2290 for(iterator itr = begin(); itr != end(); ++itr)
2292 itr->startRendering();
2296 void ScConditionalFormatList::endRendering()
2298 for(iterator itr = begin(); itr != end(); ++itr)
2300 itr->endRendering();
2304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */