1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: conditio.cxx,v $
10 * $Revision: 1.25.30.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 //------------------------------------------------------------------
38 #include "scitems.hxx"
39 #include <sfx2/objsh.hxx>
40 #include <svtools/itemset.hxx>
41 #include <svtools/zforlist.hxx>
42 #include <rtl/math.hxx>
43 #include <unotools/collatorwrapper.hxx>
45 #include "conditio.hxx"
47 #include "document.hxx"
49 #include "compiler.hxx"
50 #include "rechead.hxx"
51 #include "rangelst.hxx"
52 #include "stlpool.hxx"
53 #include "rangenam.hxx"
55 using namespace formula
;
56 //------------------------------------------------------------------------
58 SV_IMPL_OP_PTRARR_SORT( ScConditionalFormats_Impl
, ScConditionalFormatPtr
);
60 //------------------------------------------------------------------------
62 BOOL
lcl_HasRelRef( ScDocument
* pDoc
, ScTokenArray
* pFormula
, USHORT nRecursion
= 0 )
68 for( t
= pFormula
->Next(); t
; t
= pFormula
->Next() )
70 switch( t
->GetType() )
74 ScSingleRefData
& rRef2
= static_cast<ScToken
*>(t
)->GetDoubleRef().Ref2
;
75 if ( rRef2
.IsColRel() || rRef2
.IsRowRel() || rRef2
.IsTabRel() )
82 ScSingleRefData
& rRef1
= static_cast<ScToken
*>(t
)->GetSingleRef();
83 if ( rRef1
.IsColRel() || rRef1
.IsRowRel() || rRef1
.IsTabRel() )
90 if( t
->GetOpCode() == ocName
) // DB areas always absolute
91 if( ScRangeData
* pRangeData
= pDoc
->GetRangeName()->FindIndex( t
->GetIndex() ) )
92 if( (nRecursion
< 42) && lcl_HasRelRef( pDoc
, pRangeData
->GetCode(), nRecursion
+ 1 ) )
97 // #i34474# function result dependent on cell position
100 switch( t
->GetOpCode() )
102 case ocRow
: // ROW() returns own row index
103 case ocColumn
: // COLUMN() returns own column index
104 case ocTable
: // SHEET() returns own sheet index
105 case ocCell
: // CELL() may return own cell address
110 // added to avoid warnings
118 // added to avoid warnings
126 ScConditionEntry::ScConditionEntry( const ScConditionEntry
& r
) :
128 nOptions(r
.nOptions
),
131 aStrVal1(r
.aStrVal1
),
132 aStrVal2(r
.aStrVal2
),
133 aStrNmsp1(r
.aStrNmsp1
),
134 aStrNmsp2(r
.aStrNmsp2
),
135 eTempGrammar1(r
.eTempGrammar1
),
136 eTempGrammar2(r
.eTempGrammar2
),
142 aSrcString(r
.aSrcString
),
146 bRelRef1(r
.bRelRef1
),
147 bRelRef2(r
.bRelRef2
),
150 // ScTokenArray copy ctor erzeugt flache Kopie
153 pFormula1
= new ScTokenArray( *r
.pFormula1
);
155 pFormula2
= new ScTokenArray( *r
.pFormula2
);
157 // Formelzellen werden erst bei IsValid angelegt
160 ScConditionEntry::ScConditionEntry( ScDocument
* pDocument
, const ScConditionEntry
& r
) :
162 nOptions(r
.nOptions
),
165 aStrVal1(r
.aStrVal1
),
166 aStrVal2(r
.aStrVal2
),
167 aStrNmsp1(r
.aStrNmsp1
),
168 aStrNmsp2(r
.aStrNmsp2
),
169 eTempGrammar1(r
.eTempGrammar1
),
170 eTempGrammar2(r
.eTempGrammar2
),
176 aSrcString(r
.aSrcString
),
180 bRelRef1(r
.bRelRef1
),
181 bRelRef2(r
.bRelRef2
),
184 // echte Kopie der Formeln (fuer Ref-Undo)
187 pFormula1
= r
.pFormula1
->Clone();
189 pFormula2
= r
.pFormula2
->Clone();
191 // Formelzellen werden erst bei IsValid angelegt
192 //! im Clipboard nicht - dann vorher interpretieren !!!
195 ScConditionEntry::ScConditionEntry( ScConditionMode eOper
,
196 const String
& rExpr1
, const String
& rExpr2
, ScDocument
* pDocument
, const ScAddress
& rPos
,
197 const String
& rExprNmsp1
, const String
& rExprNmsp2
,
198 FormulaGrammar::Grammar eGrammar1
, FormulaGrammar::Grammar eGrammar2
) :
200 nOptions(0), // spaeter...
203 aStrNmsp1(rExprNmsp1
),
204 aStrNmsp2(rExprNmsp2
),
205 eTempGrammar1(eGrammar1
),
206 eTempGrammar2(eGrammar2
),
219 Compile( rExpr1
, rExpr2
, rExprNmsp1
, rExprNmsp2
, eGrammar1
, eGrammar2
, FALSE
);
221 // Formelzellen werden erst bei IsValid angelegt
224 ScConditionEntry::ScConditionEntry( ScConditionMode eOper
,
225 const ScTokenArray
* pArr1
, const ScTokenArray
* pArr2
,
226 ScDocument
* pDocument
, const ScAddress
& rPos
) :
228 nOptions(0), // spaeter...
231 eTempGrammar1(FormulaGrammar::GRAM_DEFAULT
),
232 eTempGrammar2(FormulaGrammar::GRAM_DEFAULT
),
247 pFormula1
= new ScTokenArray( *pArr1
);
248 if ( pFormula1
->GetLen() == 1 )
250 // einzelne (konstante Zahl) ?
251 FormulaToken
* pToken
= pFormula1
->First();
252 if ( pToken
->GetOpCode() == ocPush
)
254 if ( pToken
->GetType() == svDouble
)
256 nVal1
= pToken
->GetDouble();
257 DELETEZ(pFormula1
); // nicht als Formel merken
259 else if ( pToken
->GetType() == svString
)
262 aStrVal1
= pToken
->GetString();
263 DELETEZ(pFormula1
); // nicht als Formel merken
267 bRelRef1
= lcl_HasRelRef( pDoc
, pFormula1
);
271 pFormula2
= new ScTokenArray( *pArr2
);
272 if ( pFormula2
->GetLen() == 1 )
274 // einzelne (konstante Zahl) ?
275 FormulaToken
* pToken
= pFormula2
->First();
276 if ( pToken
->GetOpCode() == ocPush
)
278 if ( pToken
->GetType() == svDouble
)
280 nVal2
= pToken
->GetDouble();
281 DELETEZ(pFormula2
); // nicht als Formel merken
283 else if ( pToken
->GetType() == svString
)
286 aStrVal2
= pToken
->GetString();
287 DELETEZ(pFormula2
); // nicht als Formel merken
291 bRelRef2
= lcl_HasRelRef( pDoc
, pFormula2
);
294 // formula cells are created at IsValid
297 ScConditionEntry::~ScConditionEntry()
306 void ScConditionEntry::Compile( const String
& rExpr1
, const String
& rExpr2
,
307 const String
& rExprNmsp1
, const String
& rExprNmsp2
,
308 FormulaGrammar::Grammar eGrammar1
, FormulaGrammar::Grammar eGrammar2
, BOOL bTextToReal
)
310 if ( rExpr1
.Len() || rExpr2
.Len() )
312 ScCompiler
aComp( pDoc
, aSrcPos
);
316 aComp
.SetGrammar( eGrammar1
);
317 if ( pDoc
->IsImportingXML() && !bTextToReal
)
319 // temporary formula string as string tokens
320 //! merge with lcl_ScDocFunc_CreateTokenArrayXML
321 pFormula1
= new ScTokenArray
;
322 pFormula1
->AddString( rExpr1
);
323 // bRelRef1 is set when the formula is compiled again (CompileXML)
327 pFormula1
= aComp
.CompileString( rExpr1
, rExprNmsp1
);
328 if ( pFormula1
->GetLen() == 1 )
330 // einzelne (konstante Zahl) ?
331 FormulaToken
* pToken
= pFormula1
->First();
332 if ( pToken
->GetOpCode() == ocPush
)
334 if ( pToken
->GetType() == svDouble
)
336 nVal1
= pToken
->GetDouble();
337 DELETEZ(pFormula1
); // nicht als Formel merken
339 else if ( pToken
->GetType() == svString
)
342 aStrVal1
= pToken
->GetString();
343 DELETEZ(pFormula1
); // nicht als Formel merken
347 bRelRef1
= lcl_HasRelRef( pDoc
, pFormula1
);
353 aComp
.SetGrammar( eGrammar2
);
354 if ( pDoc
->IsImportingXML() && !bTextToReal
)
356 // temporary formula string as string tokens
357 //! merge with lcl_ScDocFunc_CreateTokenArrayXML
358 pFormula2
= new ScTokenArray
;
359 pFormula2
->AddString( rExpr2
);
360 // bRelRef2 is set when the formula is compiled again (CompileXML)
364 pFormula2
= aComp
.CompileString( rExpr2
, rExprNmsp2
);
365 if ( pFormula2
->GetLen() == 1 )
367 // einzelne (konstante Zahl) ?
368 FormulaToken
* pToken
= pFormula2
->First();
369 if ( pToken
->GetOpCode() == ocPush
)
371 if ( pToken
->GetType() == svDouble
)
373 nVal2
= pToken
->GetDouble();
374 DELETEZ(pFormula2
); // nicht als Formel merken
376 else if ( pToken
->GetType() == svString
)
379 aStrVal2
= pToken
->GetString();
380 DELETEZ(pFormula2
); // nicht als Formel merken
384 bRelRef2
= lcl_HasRelRef( pDoc
, pFormula2
);
390 void ScConditionEntry::MakeCells( const ScAddress
& rPos
) // Formelzellen anlegen
392 if ( !pDoc
->IsClipOrUndo() ) // nie im Clipboard rechnen!
394 if ( pFormula1
&& !pFCell1
&& !bRelRef1
)
396 pFCell1
= new ScFormulaCell( pDoc
, rPos
, pFormula1
);
397 pFCell1
->StartListeningTo( pDoc
);
400 if ( pFormula2
&& !pFCell2
&& !bRelRef2
)
402 pFCell2
= new ScFormulaCell( pDoc
, rPos
, pFormula2
);
403 pFCell2
->StartListeningTo( pDoc
);
408 void ScConditionEntry::SetIgnoreBlank(BOOL bSet
)
410 // Das Bit SC_COND_NOBLANKS wird gesetzt, wenn Blanks nicht ignoriert werden
411 // (nur bei Gueltigkeit)
414 nOptions
&= ~SC_COND_NOBLANKS
;
416 nOptions
|= SC_COND_NOBLANKS
;
419 void ScConditionEntry::CompileAll()
421 // Formelzellen loeschen, dann wird beim naechsten IsValid neu kompiliert
427 void ScConditionEntry::CompileXML()
429 // #b4974740# First parse the formula source position if it was stored as text
431 if ( aSrcString
.Len() )
434 /* XML is always in OOo:A1 format, although R1C1 would be more amenable
436 if ( aNew
.Parse( aSrcString
, pDoc
) & SCA_VALID
)
438 // if the position is invalid, there isn't much we can do at this time
442 // Convert the text tokens that were created during XML import into real tokens.
444 Compile( GetExpression(aSrcPos
, 0, 0, eTempGrammar1
),
445 GetExpression(aSrcPos
, 1, 0, eTempGrammar2
),
446 aStrNmsp1
, aStrNmsp2
, eTempGrammar1
, eTempGrammar2
, TRUE
);
449 void ScConditionEntry::SetSrcString( const String
& rNew
)
451 // aSrcString is only evaluated in CompileXML
452 DBG_ASSERT( pDoc
->IsImportingXML(), "SetSrcString is only valid for XML import" );
457 void ScConditionEntry::SetFormula1( const ScTokenArray
& rArray
)
459 DELETEZ( pFormula1
);
460 if( rArray
.GetLen() > 0 )
462 pFormula1
= new ScTokenArray( rArray
);
463 bRelRef1
= lcl_HasRelRef( pDoc
, pFormula1
);
467 void ScConditionEntry::SetFormula2( const ScTokenArray
& rArray
)
469 DELETEZ( pFormula2
);
470 if( rArray
.GetLen() > 0 )
472 pFormula2
= new ScTokenArray( rArray
);
473 bRelRef2
= lcl_HasRelRef( pDoc
, pFormula2
);
477 void lcl_CondUpdateInsertTab( ScTokenArray
& rCode
, SCTAB nInsTab
, SCTAB nPosTab
, BOOL
& rChanged
)
479 // Insert table: only update absolute table references.
480 // (Similar to ScCompiler::UpdateInsertTab with bIsName=TRUE, result is the same as for named ranges)
481 // For deleting, ScCompiler::UpdateDeleteTab is used because of the handling of invalid references.
484 ScToken
* p
= static_cast<ScToken
*>(rCode
.GetNextReference());
487 ScSingleRefData
& rRef1
= p
->GetSingleRef();
488 if ( !rRef1
.IsTabRel() && nInsTab
<= rRef1
.nTab
)
491 rRef1
.nRelTab
= rRef1
.nTab
- nPosTab
;
494 if( p
->GetType() == svDoubleRef
)
496 ScSingleRefData
& rRef2
= p
->GetDoubleRef().Ref2
;
497 if ( !rRef2
.IsTabRel() && nInsTab
<= rRef2
.nTab
)
500 rRef2
.nRelTab
= rRef2
.nTab
- nPosTab
;
504 p
= static_cast<ScToken
*>(rCode
.GetNextReference());
508 void ScConditionEntry::UpdateReference( UpdateRefMode eUpdateRefMode
,
509 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
511 BOOL bInsertTab
= ( eUpdateRefMode
== URM_INSDEL
&& nDz
== 1 );
512 BOOL bDeleteTab
= ( eUpdateRefMode
== URM_INSDEL
&& nDz
== -1 );
514 BOOL bChanged1
= FALSE
;
515 BOOL bChanged2
= FALSE
;
520 lcl_CondUpdateInsertTab( *pFormula1
, rRange
.aStart
.Tab(), aSrcPos
.Tab(), bChanged1
);
523 ScCompiler
aComp( pDoc
, aSrcPos
, *pFormula1
);
524 aComp
.SetGrammar(pDoc
->GetGrammar());
526 aComp
.UpdateDeleteTab( rRange
.aStart
.Tab(), FALSE
, TRUE
, bChanged1
);
528 aComp
.UpdateNameReference( eUpdateRefMode
, rRange
, nDx
, nDy
, nDz
, bChanged1
);
532 DELETEZ(pFCell1
); // is created again in IsValid
537 lcl_CondUpdateInsertTab( *pFormula2
, rRange
.aStart
.Tab(), aSrcPos
.Tab(), bChanged2
);
540 ScCompiler
aComp( pDoc
, aSrcPos
, *pFormula2
);
541 aComp
.SetGrammar(pDoc
->GetGrammar());
543 aComp
.UpdateDeleteTab( rRange
.aStart
.Tab(), FALSE
, TRUE
, bChanged2
);
545 aComp
.UpdateNameReference( eUpdateRefMode
, rRange
, nDx
, nDy
, nDz
, bChanged2
);
549 DELETEZ(pFCell2
); // is created again in IsValid
553 void ScConditionEntry::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
)
557 ScCompiler
aComp( pDoc
, aSrcPos
, *pFormula1
);
558 aComp
.SetGrammar(pDoc
->GetGrammar());
559 aComp
.UpdateMoveTab(nOldPos
, nNewPos
, TRUE
);
564 ScCompiler
aComp( pDoc
, aSrcPos
, *pFormula2
);
565 aComp
.SetGrammar(pDoc
->GetGrammar());
566 aComp
.UpdateMoveTab(nOldPos
, nNewPos
, TRUE
);
571 //! als Vergleichsoperator ans TokenArray ???
573 BOOL
lcl_IsEqual( const ScTokenArray
* pArr1
, const ScTokenArray
* pArr2
)
575 // verglichen wird nur das nicht-UPN Array
577 if ( pArr1
&& pArr2
)
579 USHORT nLen
= pArr1
->GetLen();
580 if ( pArr2
->GetLen() != nLen
)
583 FormulaToken
** ppToken1
= pArr1
->GetArray();
584 FormulaToken
** ppToken2
= pArr2
->GetArray();
585 for (USHORT i
=0; i
<nLen
; i
++)
587 if ( ppToken1
[i
] != ppToken2
[i
] &&
588 !(*ppToken1
[i
] == *ppToken2
[i
]) )
589 return FALSE
; // Unterschied
591 return TRUE
; // alle Eintraege gleich
594 return !pArr1
&& !pArr2
; // beide 0 -> gleich
597 int ScConditionEntry::operator== ( const ScConditionEntry
& r
) const
599 BOOL bEq
= (eOp
== r
.eOp
&& nOptions
== r
.nOptions
&&
600 lcl_IsEqual( pFormula1
, r
.pFormula1
) &&
601 lcl_IsEqual( pFormula2
, r
.pFormula2
));
604 // for formulas, the reference positions must be compared, too
605 // (including aSrcString, for inserting the entries during XML import)
606 if ( ( pFormula1
|| pFormula2
) && ( aSrcPos
!= r
.aSrcPos
|| aSrcString
!= r
.aSrcString
) )
609 // wenn keine Formeln, Werte vergleichen
610 if ( !pFormula1
&& ( nVal1
!= r
.nVal1
|| aStrVal1
!= r
.aStrVal1
|| bIsStr1
!= r
.bIsStr1
) )
612 if ( !pFormula2
&& ( nVal2
!= r
.nVal2
|| aStrVal2
!= r
.aStrVal2
|| bIsStr2
!= r
.bIsStr2
) )
619 void ScConditionEntry::Interpret( const ScAddress
& rPos
)
621 // Formelzellen anlegen
622 // dabei koennen neue Broadcaster (Note-Zellen) ins Dokument eingefuegt werden !!!!
624 if ( ( pFormula1
&& !pFCell1
) || ( pFormula2
&& !pFCell2
) )
629 BOOL bDirty
= FALSE
; //! 1 und 2 getrennt ???
631 ScFormulaCell
* pTemp1
= NULL
;
632 ScFormulaCell
* pEff1
= pFCell1
;
635 pTemp1
= new ScFormulaCell( pDoc
, rPos
, pFormula1
); // ohne Listening
640 if (!pEff1
->IsRunning()) // keine 522 erzeugen
642 //! Changed statt Dirty abfragen !!!
643 if (pEff1
->GetDirty() && !bRelRef1
)
645 if (pEff1
->IsValue())
648 nVal1
= pEff1
->GetValue();
654 pEff1
->GetString( aStrVal1
);
661 ScFormulaCell
* pTemp2
= NULL
;
662 ScFormulaCell
* pEff2
= pFCell2
; //@ 1!=2
665 pTemp2
= new ScFormulaCell( pDoc
, rPos
, pFormula2
); // ohne Listening
670 if (!pEff2
->IsRunning()) // keine 522 erzeugen
672 if (pEff2
->GetDirty() && !bRelRef2
)
674 if (pEff2
->IsValue())
677 nVal2
= pEff2
->GetValue();
683 pEff2
->GetString( aStrVal2
);
690 // wenn IsRunning, bleiben die letzten Werte erhalten
692 if (bDirty
&& !bFirstRun
)
694 // bei bedingten Formaten neu painten
696 DataChanged( NULL
); // alles
702 BOOL
ScConditionEntry::IsValid( double nArg
) const
704 // Interpret muss schon gerufen sein
708 // wenn auf String getestet wird, bei Zahlen immer FALSE, ausser bei "ungleich"
710 return ( eOp
== SC_COND_NOTEQUAL
);
713 if ( eOp
== SC_COND_BETWEEN
|| eOp
== SC_COND_NOTBETWEEN
)
717 double nComp1
= nVal1
; // Kopie, damit vertauscht werden kann
718 double nComp2
= nVal2
;
720 if ( eOp
== SC_COND_BETWEEN
|| eOp
== SC_COND_NOTBETWEEN
)
721 if ( nComp1
> nComp2
)
723 // richtige Reihenfolge fuer Wertebereich
724 double nTemp
= nComp1
; nComp1
= nComp2
; nComp2
= nTemp
;
727 // Alle Grenzfaelle muessen per ::rtl::math::approxEqual getestet werden!
733 break; // immer FALSE;
735 bValid
= ::rtl::math::approxEqual( nArg
, nComp1
);
737 case SC_COND_NOTEQUAL
:
738 bValid
= !::rtl::math::approxEqual( nArg
, nComp1
);
740 case SC_COND_GREATER
:
741 bValid
= ( nArg
> nComp1
) && !::rtl::math::approxEqual( nArg
, nComp1
);
743 case SC_COND_EQGREATER
:
744 bValid
= ( nArg
>= nComp1
) || ::rtl::math::approxEqual( nArg
, nComp1
);
747 bValid
= ( nArg
< nComp1
) && !::rtl::math::approxEqual( nArg
, nComp1
);
750 bValid
= ( nArg
<= nComp1
) || ::rtl::math::approxEqual( nArg
, nComp1
);
752 case SC_COND_BETWEEN
:
753 bValid
= ( nArg
>= nComp1
&& nArg
<= nComp2
) ||
754 ::rtl::math::approxEqual( nArg
, nComp1
) || ::rtl::math::approxEqual( nArg
, nComp2
);
756 case SC_COND_NOTBETWEEN
:
757 bValid
= ( nArg
< nComp1
|| nArg
> nComp2
) &&
758 !::rtl::math::approxEqual( nArg
, nComp1
) && !::rtl::math::approxEqual( nArg
, nComp2
);
761 bValid
= !::rtl::math::approxEqual( nComp1
, 0.0 );
764 DBG_ERROR("unbekannte Operation bei ScConditionEntry");
770 BOOL
ScConditionEntry::IsValidStr( const String
& rArg
) const
772 // Interpret muss schon gerufen sein
774 if ( eOp
== SC_COND_DIRECT
) // Formel ist unabhaengig vom Inhalt
775 return !::rtl::math::approxEqual( nVal1
, 0.0 );
777 // Wenn Bedingung Zahl enthaelt, immer FALSE, ausser bei "ungleich"
780 return ( eOp
== SC_COND_NOTEQUAL
);
781 if ( eOp
== SC_COND_BETWEEN
|| eOp
== SC_COND_NOTBETWEEN
)
785 String
aUpVal1( aStrVal1
); //! als Member? (dann auch in Interpret setzen)
786 String
aUpVal2( aStrVal2
);
788 if ( eOp
== SC_COND_BETWEEN
|| eOp
== SC_COND_NOTBETWEEN
)
789 if ( ScGlobal::pCollator
->compareString( aUpVal1
, aUpVal2
)
792 // richtige Reihenfolge fuer Wertebereich
793 String
aTemp( aUpVal1
); aUpVal1
= aUpVal2
; aUpVal2
= aTemp
;
800 bValid
= (ScGlobal::pCollator
->compareString(
801 rArg
, aUpVal1
) == COMPARE_EQUAL
);
803 case SC_COND_NOTEQUAL
:
804 bValid
= (ScGlobal::pCollator
->compareString(
805 rArg
, aUpVal1
) != COMPARE_EQUAL
);
809 sal_Int32 nCompare
= ScGlobal::pCollator
->compareString(
813 case SC_COND_GREATER
:
814 bValid
= ( nCompare
== COMPARE_GREATER
);
816 case SC_COND_EQGREATER
:
817 bValid
= ( nCompare
== COMPARE_EQUAL
|| nCompare
== COMPARE_GREATER
);
820 bValid
= ( nCompare
== COMPARE_LESS
);
823 bValid
= ( nCompare
== COMPARE_EQUAL
|| nCompare
== COMPARE_LESS
);
825 case SC_COND_BETWEEN
:
826 case SC_COND_NOTBETWEEN
:
827 // Test auf NOTBETWEEN:
828 bValid
= ( nCompare
== COMPARE_LESS
||
829 ScGlobal::pCollator
->compareString( rArg
,
830 aUpVal2
) == COMPARE_GREATER
);
831 if ( eOp
== SC_COND_BETWEEN
)
834 // SC_COND_DIRECT schon oben abgefragt
836 DBG_ERROR("unbekannte Operation bei ScConditionEntry");
845 BOOL
ScConditionEntry::IsCellValid( ScBaseCell
* pCell
, const ScAddress
& rPos
) const
847 ((ScConditionEntry
*)this)->Interpret(rPos
); // Formeln auswerten
855 CellType eType
= pCell
->GetCellType();
859 nArg
= ((ScValueCell
*)pCell
)->GetValue();
861 case CELLTYPE_FORMULA
:
863 ScFormulaCell
* pFCell
= (ScFormulaCell
*)pCell
;
864 bVal
= pFCell
->IsValue();
866 nArg
= pFCell
->GetValue();
868 pFCell
->GetString(aArgStr
);
871 case CELLTYPE_STRING
:
874 if ( eType
== CELLTYPE_STRING
)
875 ((ScStringCell
*)pCell
)->GetString(aArgStr
);
877 ((ScEditCell
*)pCell
)->GetString(aArgStr
);
881 pCell
= NULL
; // Note-Zellen wie leere
888 bVal
= FALSE
; // leere Zellen je nach Bedingung
891 return IsValid( nArg
);
893 return IsValidStr( aArgStr
);
896 String
ScConditionEntry::GetExpression( const ScAddress
& rCursor
, USHORT nIndex
,
898 const FormulaGrammar::Grammar eGrammar
) const
902 if ( FormulaGrammar::isEnglish( eGrammar
) && nNumFmt
== 0 )
903 nNumFmt
= pDoc
->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US
);
909 ScCompiler
aComp(pDoc
, rCursor
, *pFormula1
);
910 aComp
.SetGrammar(eGrammar
);
911 aComp
.CreateStringFromTokenArray( aRet
);
920 pDoc
->GetFormatTable()->GetInputLineString(nVal1
, nNumFmt
, aRet
);
922 else if ( nIndex
==1 )
926 ScCompiler
aComp(pDoc
, rCursor
, *pFormula2
);
927 aComp
.SetGrammar(eGrammar
);
928 aComp
.CreateStringFromTokenArray( aRet
);
937 pDoc
->GetFormatTable()->GetInputLineString(nVal2
, nNumFmt
, aRet
);
941 DBG_ERROR("GetExpression: falscher Index");
947 ScTokenArray
* ScConditionEntry::CreateTokenArry( USHORT nIndex
) const
949 ScTokenArray
* pRet
= NULL
;
955 pRet
= new ScTokenArray( *pFormula1
);
958 pRet
= new ScTokenArray();
960 pRet
->AddString( aStrVal1
.GetBuffer() );
962 pRet
->AddDouble( nVal1
);
965 else if ( nIndex
==1 )
968 pRet
= new ScTokenArray( *pFormula2
);
971 pRet
= new ScTokenArray();
973 pRet
->AddString( aStrVal2
.GetBuffer() );
975 pRet
->AddDouble( nVal2
);
980 DBG_ERROR("GetExpression: falscher Index");
986 void ScConditionEntry::SourceChanged( const ScAddress
& rChanged
)
988 for (USHORT nPass
= 0; nPass
< 2; nPass
++)
990 ScTokenArray
* pFormula
= nPass
? pFormula2
: pFormula1
;
995 while ( ( t
= static_cast<ScToken
*>(pFormula
->GetNextReference()) ) != NULL
)
997 SingleDoubleRefProvider
aProv( *t
);
998 if ( aProv
.Ref1
.IsColRel() || aProv
.Ref1
.IsRowRel() || aProv
.Ref1
.IsTabRel() ||
999 aProv
.Ref2
.IsColRel() || aProv
.Ref2
.IsRowRel() || aProv
.Ref2
.IsTabRel() )
1001 // absolut muss getroffen sein, relativ bestimmt Bereich
1011 if ( aProv
.Ref1
.IsColRel() )
1012 nCol2
= rChanged
.Col() - aProv
.Ref1
.nRelCol
;
1015 bHit
&= ( rChanged
.Col() >= aProv
.Ref1
.nCol
);
1018 if ( aProv
.Ref1
.IsRowRel() )
1019 nRow2
= rChanged
.Row() - aProv
.Ref1
.nRelRow
;
1022 bHit
&= ( rChanged
.Row() >= aProv
.Ref1
.nRow
);
1025 if ( aProv
.Ref1
.IsTabRel() )
1026 nTab2
= rChanged
.Tab() - aProv
.Ref1
.nRelTab
;
1029 bHit
&= ( rChanged
.Tab() >= aProv
.Ref1
.nTab
);
1033 if ( aProv
.Ref2
.IsColRel() )
1034 nCol1
= rChanged
.Col() - aProv
.Ref2
.nRelCol
;
1037 bHit
&= ( rChanged
.Col() <= aProv
.Ref2
.nCol
);
1040 if ( aProv
.Ref2
.IsRowRel() )
1041 nRow1
= rChanged
.Row() - aProv
.Ref2
.nRelRow
;
1044 bHit
&= ( rChanged
.Row() <= aProv
.Ref2
.nRow
);
1047 if ( aProv
.Ref2
.IsTabRel() )
1048 nTab1
= rChanged
.Tab() - aProv
.Ref2
.nRelTab
;
1051 bHit
&= ( rChanged
.Tab() <= aProv
.Ref2
.nTab
);
1059 ScRange
aPaint( nCol1
,nRow1
,nTab1
, nCol2
,nRow2
,nTab2
);
1061 // kein Paint, wenn es nur die Zelle selber ist
1062 if ( aPaint
.aStart
!= rChanged
|| aPaint
.aEnd
!= rChanged
)
1063 DataChanged( &aPaint
);
1071 ScAddress
ScConditionEntry::GetValidSrcPos() const
1073 // return a position that's adjusted to allow textual representation of expressions if possible
1075 SCTAB nMinTab
= aSrcPos
.Tab();
1076 SCTAB nMaxTab
= nMinTab
;
1078 for (USHORT nPass
= 0; nPass
< 2; nPass
++)
1080 ScTokenArray
* pFormula
= nPass
? pFormula2
: pFormula1
;
1085 while ( ( t
= static_cast<ScToken
*>(pFormula
->GetNextReference()) ) != NULL
)
1087 ScSingleRefData
& rRef1
= t
->GetSingleRef();
1088 if ( rRef1
.IsTabRel() && !rRef1
.IsTabDeleted() )
1090 if ( rRef1
.nTab
< nMinTab
)
1091 nMinTab
= rRef1
.nTab
;
1092 if ( rRef1
.nTab
> nMaxTab
)
1093 nMaxTab
= rRef1
.nTab
;
1095 if ( t
->GetType() == svDoubleRef
)
1097 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
1098 if ( rRef2
.IsTabRel() && !rRef2
.IsTabDeleted() )
1100 if ( rRef2
.nTab
< nMinTab
)
1101 nMinTab
= rRef2
.nTab
;
1102 if ( rRef2
.nTab
> nMaxTab
)
1103 nMaxTab
= rRef2
.nTab
;
1110 ScAddress aValidPos
= aSrcPos
;
1111 SCTAB nTabCount
= pDoc
->GetTableCount();
1112 if ( nMaxTab
>= nTabCount
&& nMinTab
> 0 )
1113 aValidPos
.SetTab( aSrcPos
.Tab() - nMinTab
); // so the lowest tab ref will be on 0
1115 if ( aValidPos
.Tab() >= nTabCount
)
1116 aValidPos
.SetTab( nTabCount
- 1 ); // ensure a valid position even if some references will be invalid
1121 void ScConditionEntry::DataChanged( const ScRange
* /* pModified */ ) const
1126 bool ScConditionEntry::MarkUsedExternalReferences() const
1128 bool bAllMarked
= false;
1129 for (USHORT nPass
= 0; !bAllMarked
&& nPass
< 2; nPass
++)
1131 ScTokenArray
* pFormula
= nPass
? pFormula2
: pFormula1
;
1133 bAllMarked
= pDoc
->MarkUsedExternalReferences( *pFormula
);
1138 //------------------------------------------------------------------------
1140 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper
,
1141 const String
& rExpr1
, const String
& rExpr2
,
1142 ScDocument
* pDocument
, const ScAddress
& rPos
,
1143 const String
& rStyle
,
1144 const String
& rExprNmsp1
, const String
& rExprNmsp2
,
1145 FormulaGrammar::Grammar eGrammar1
,
1146 FormulaGrammar::Grammar eGrammar2
) :
1147 ScConditionEntry( eOper
, rExpr1
, rExpr2
, pDocument
, rPos
, rExprNmsp1
, rExprNmsp2
, eGrammar1
, eGrammar2
),
1148 aStyleName( rStyle
),
1153 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper
,
1154 const ScTokenArray
* pArr1
, const ScTokenArray
* pArr2
,
1155 ScDocument
* pDocument
, const ScAddress
& rPos
,
1156 const String
& rStyle
) :
1157 ScConditionEntry( eOper
, pArr1
, pArr2
, pDocument
, rPos
),
1158 aStyleName( rStyle
),
1163 ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry
& r
) :
1164 ScConditionEntry( r
),
1165 aStyleName( r
.aStyleName
),
1170 ScCondFormatEntry::ScCondFormatEntry( ScDocument
* pDocument
, const ScCondFormatEntry
& r
) :
1171 ScConditionEntry( pDocument
, r
),
1172 aStyleName( r
.aStyleName
),
1177 int ScCondFormatEntry::operator== ( const ScCondFormatEntry
& r
) const
1179 return ScConditionEntry::operator==( r
) &&
1180 aStyleName
== r
.aStyleName
;
1182 // Range wird nicht verglichen
1185 ScCondFormatEntry::~ScCondFormatEntry()
1189 void ScCondFormatEntry::DataChanged( const ScRange
* pModified
) const
1192 pParent
->DoRepaint( pModified
);
1195 //------------------------------------------------------------------------
1197 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey
, ScDocument
* pDocument
) :
1206 ScConditionalFormat::ScConditionalFormat(const ScConditionalFormat
& r
) :
1211 nEntryCount( r
.nEntryCount
)
1215 ppEntries
= new ScCondFormatEntry
*[nEntryCount
];
1216 for (USHORT i
=0; i
<nEntryCount
; i
++)
1218 ppEntries
[i
] = new ScCondFormatEntry(*r
.ppEntries
[i
]);
1219 ppEntries
[i
]->SetParent(this);
1224 ScConditionalFormat
* ScConditionalFormat::Clone(ScDocument
* pNewDoc
) const
1226 // echte Kopie der Formeln (fuer Ref-Undo / zwischen Dokumenten)
1231 ScConditionalFormat
* pNew
= new ScConditionalFormat(nKey
, pNewDoc
);
1232 DBG_ASSERT(!pNew
->ppEntries
, "wo kommen die Eintraege her?");
1236 pNew
->ppEntries
= new ScCondFormatEntry
*[nEntryCount
];
1237 for (USHORT i
=0; i
<nEntryCount
; i
++)
1239 pNew
->ppEntries
[i
] = new ScCondFormatEntry( pNewDoc
, *ppEntries
[i
] );
1240 pNew
->ppEntries
[i
]->SetParent(pNew
);
1242 pNew
->nEntryCount
= nEntryCount
;
1248 BOOL
ScConditionalFormat::EqualEntries( const ScConditionalFormat
& r
) const
1250 if ( nEntryCount
!= r
.nEntryCount
)
1253 //! auf gleiche Eintraege in anderer Reihenfolge testen ???
1255 for (USHORT i
=0; i
<nEntryCount
; i
++)
1256 if ( ! (*ppEntries
[i
] == *r
.ppEntries
[i
]) )
1262 void ScConditionalFormat::AddEntry( const ScCondFormatEntry
& rNew
)
1264 ScCondFormatEntry
** ppNew
= new ScCondFormatEntry
*[nEntryCount
+1];
1265 for (USHORT i
=0; i
<nEntryCount
; i
++)
1266 ppNew
[i
] = ppEntries
[i
];
1267 ppNew
[nEntryCount
] = new ScCondFormatEntry(rNew
);
1268 ppNew
[nEntryCount
]->SetParent(this);
1274 ScConditionalFormat::~ScConditionalFormat()
1276 for (USHORT i
=0; i
<nEntryCount
; i
++)
1277 delete ppEntries
[i
];
1283 const ScCondFormatEntry
* ScConditionalFormat::GetEntry( USHORT nPos
) const
1285 if ( nPos
< nEntryCount
)
1286 return ppEntries
[nPos
];
1291 const String
& ScConditionalFormat::GetCellStyle( ScBaseCell
* pCell
, const ScAddress
& rPos
) const
1293 for (USHORT i
=0; i
<nEntryCount
; i
++)
1294 if ( ppEntries
[i
]->IsCellValid( pCell
, rPos
) )
1295 return ppEntries
[i
]->GetStyle();
1297 return EMPTY_STRING
;
1300 void lcl_Extend( ScRange
& rRange
, ScDocument
* pDoc
, BOOL bLines
)
1302 SCTAB nTab
= rRange
.aStart
.Tab();
1303 DBG_ASSERT(rRange
.aEnd
.Tab() == nTab
, "lcl_Extend - mehrere Tabellen?");
1305 SCCOL nStartCol
= rRange
.aStart
.Col();
1306 SCROW nStartRow
= rRange
.aStart
.Row();
1307 SCCOL nEndCol
= rRange
.aEnd
.Col();
1308 SCROW nEndRow
= rRange
.aEnd
.Row();
1310 BOOL bEx
= pDoc
->ExtendMerge( nStartCol
, nStartRow
, nEndCol
, nEndRow
, nTab
);
1314 if (nStartCol
> 0) --nStartCol
;
1315 if (nStartRow
> 0) --nStartRow
;
1316 if (nEndCol
< MAXCOL
) ++nEndCol
;
1317 if (nEndRow
< MAXROW
) ++nEndRow
;
1320 if ( bEx
|| bLines
)
1322 rRange
.aStart
.Set( nStartCol
, nStartRow
, nTab
);
1323 rRange
.aEnd
.Set( nEndCol
, nEndRow
, nTab
);
1327 BOOL
lcl_CutRange( ScRange
& rRange
, const ScRange
& rOther
)
1330 ScRange aCmpRange
= rOther
;
1331 aCmpRange
.Justify();
1333 if ( rRange
.aStart
.Col() <= aCmpRange
.aEnd
.Col() &&
1334 rRange
.aEnd
.Col() >= aCmpRange
.aStart
.Col() &&
1335 rRange
.aStart
.Row() <= aCmpRange
.aEnd
.Row() &&
1336 rRange
.aEnd
.Row() >= aCmpRange
.aStart
.Row() &&
1337 rRange
.aStart
.Tab() <= aCmpRange
.aEnd
.Tab() &&
1338 rRange
.aEnd
.Tab() >= aCmpRange
.aStart
.Tab() )
1340 if ( rRange
.aStart
.Col() < aCmpRange
.aStart
.Col() )
1341 rRange
.aStart
.SetCol( aCmpRange
.aStart
.Col() );
1342 if ( rRange
.aStart
.Row() < aCmpRange
.aStart
.Row() )
1343 rRange
.aStart
.SetRow( aCmpRange
.aStart
.Row() );
1344 if ( rRange
.aStart
.Tab() < aCmpRange
.aStart
.Tab() )
1345 rRange
.aStart
.SetTab( aCmpRange
.aStart
.Tab() );
1346 if ( rRange
.aEnd
.Col() > aCmpRange
.aEnd
.Col() )
1347 rRange
.aEnd
.SetCol( aCmpRange
.aEnd
.Col() );
1348 if ( rRange
.aEnd
.Row() > aCmpRange
.aEnd
.Row() )
1349 rRange
.aEnd
.SetRow( aCmpRange
.aEnd
.Row() );
1350 if ( rRange
.aEnd
.Tab() > aCmpRange
.aEnd
.Tab() )
1351 rRange
.aEnd
.SetTab( aCmpRange
.aEnd
.Tab() );
1356 return FALSE
; // ausserhalb
1359 void ScConditionalFormat::DoRepaint( const ScRange
* pModified
)
1362 SfxObjectShell
* pSh
= pDoc
->GetDocumentShell();
1365 // Rahmen/Schatten enthalten?
1366 // (alle Bedingungen testen)
1367 BOOL bExtend
= FALSE
;
1368 BOOL bRotate
= FALSE
;
1369 BOOL bAttrTested
= FALSE
;
1371 if (!pAreas
) // RangeList ggf. holen
1373 pAreas
= new ScRangeList
;
1374 pDoc
->FindConditionalFormat( nKey
, *pAreas
);
1376 USHORT nCount
= (USHORT
) pAreas
->Count();
1377 for (i
=0; i
<nCount
; i
++)
1379 ScRange aRange
= *pAreas
->GetObject(i
);
1383 if ( !lcl_CutRange( aRange
, *pModified
) )
1390 // #116562# Look at the style's content only if the repaint is necessary
1391 // for any condition, to avoid the time-consuming Find() if there are many
1392 // conditional formats and styles.
1393 for (USHORT nEntry
=0; nEntry
<nEntryCount
; nEntry
++)
1395 String aStyle
= ppEntries
[nEntry
]->GetStyle();
1398 SfxStyleSheetBase
* pStyleSheet
=
1399 pDoc
->GetStyleSheetPool()->Find( aStyle
, SFX_STYLE_FAMILY_PARA
);
1402 const SfxItemSet
& rSet
= pStyleSheet
->GetItemSet();
1403 if (rSet
.GetItemState( ATTR_BORDER
, TRUE
) == SFX_ITEM_SET
||
1404 rSet
.GetItemState( ATTR_SHADOW
, TRUE
) == SFX_ITEM_SET
)
1408 if (rSet
.GetItemState( ATTR_ROTATE_VALUE
, TRUE
) == SFX_ITEM_SET
||
1409 rSet
.GetItemState( ATTR_ROTATE_MODE
, TRUE
) == SFX_ITEM_SET
)
1419 lcl_Extend( aRange
, pDoc
, bExtend
); // zusammengefasste und bExtend
1422 aRange
.aStart
.SetCol(0);
1423 aRange
.aEnd
.SetCol(MAXCOL
); // gedreht: ganze Zeilen
1426 // gedreht -> ganze Zeilen
1427 if ( aRange
.aStart
.Col() != 0 || aRange
.aEnd
.Col() != MAXCOL
)
1429 if ( pDoc
->HasAttrib( 0,aRange
.aStart
.Row(),aRange
.aStart
.Tab(),
1430 MAXCOL
,aRange
.aEnd
.Row(),aRange
.aEnd
.Tab(),
1433 aRange
.aStart
.SetCol(0);
1434 aRange
.aEnd
.SetCol(MAXCOL
);
1438 pSh
->Broadcast( ScPaintHint( aRange
, PAINT_GRID
) );
1444 void ScConditionalFormat::InvalidateArea()
1450 void ScConditionalFormat::CompileAll()
1452 for (USHORT i
=0; i
<nEntryCount
; i
++)
1453 ppEntries
[i
]->CompileAll();
1456 void ScConditionalFormat::CompileXML()
1458 for (USHORT i
=0; i
<nEntryCount
; i
++)
1459 ppEntries
[i
]->CompileXML();
1462 void ScConditionalFormat::UpdateReference( UpdateRefMode eUpdateRefMode
,
1463 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
1465 for (USHORT i
=0; i
<nEntryCount
; i
++)
1466 ppEntries
[i
]->UpdateReference(eUpdateRefMode
, rRange
, nDx
, nDy
, nDz
);
1468 delete pAreas
; // aus dem AttrArray kommt beim Einfuegen/Loeschen kein Aufruf
1472 void ScConditionalFormat::RenameCellStyle(const String
& rOld
, const String
& rNew
)
1474 for (USHORT i
=0; i
<nEntryCount
; i
++)
1475 if ( ppEntries
[i
]->GetStyle() == rOld
)
1476 ppEntries
[i
]->UpdateStyleName( rNew
);
1479 void ScConditionalFormat::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
)
1481 for (USHORT i
=0; i
<nEntryCount
; i
++)
1482 ppEntries
[i
]->UpdateMoveTab( nOldPos
, nNewPos
);
1484 delete pAreas
; // aus dem AttrArray kommt beim Einfuegen/Loeschen kein Aufruf
1488 void ScConditionalFormat::SourceChanged( const ScAddress
& rAddr
)
1490 for (USHORT i
=0; i
<nEntryCount
; i
++)
1491 ppEntries
[i
]->SourceChanged( rAddr
);
1494 bool ScConditionalFormat::MarkUsedExternalReferences() const
1496 bool bAllMarked
= false;
1497 for (USHORT i
=0; !bAllMarked
&& i
<nEntryCount
; i
++)
1498 bAllMarked
= ppEntries
[i
]->MarkUsedExternalReferences();
1502 //------------------------------------------------------------------------
1504 ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList
& rList
) :
1505 ScConditionalFormats_Impl()
1507 // fuer Ref-Undo - echte Kopie mit neuen Tokens!
1509 USHORT nCount
= rList
.Count();
1511 for (USHORT i
=0; i
<nCount
; i
++)
1512 InsertNew( rList
[i
]->Clone() );
1514 //! sortierte Eintraege aus rList schneller einfuegen ???
1517 ScConditionalFormatList::ScConditionalFormatList(ScDocument
* pNewDoc
,
1518 const ScConditionalFormatList
& rList
)
1520 // fuer neues Dokument - echte Kopie mit neuen Tokens!
1522 USHORT nCount
= rList
.Count();
1524 for (USHORT i
=0; i
<nCount
; i
++)
1525 InsertNew( rList
[i
]->Clone(pNewDoc
) );
1527 //! sortierte Eintraege aus rList schneller einfuegen ???
1530 BOOL
ScConditionalFormatList::operator==( const ScConditionalFormatList
& r
) const
1532 // fuer Ref-Undo - interne Variablen werden nicht verglichen
1534 USHORT nCount
= Count();
1535 BOOL bEqual
= ( nCount
== r
.Count() );
1536 for (USHORT i
=0; i
<nCount
&& bEqual
; i
++) // Eintraege sind sortiert
1537 if ( !(*this)[i
]->EqualEntries(*r
[i
]) ) // Eintraege unterschiedlich ?
1543 ScConditionalFormat
* ScConditionalFormatList::GetFormat( sal_uInt32 nKey
)
1547 USHORT nCount
= Count();
1548 for (USHORT i
=0; i
<nCount
; i
++)
1549 if ((*this)[i
]->GetKey() == nKey
)
1552 DBG_ERROR("ScConditionalFormatList: Eintrag nicht gefunden");
1556 void ScConditionalFormatList::CompileAll()
1558 USHORT nCount
= Count();
1559 for (USHORT i
=0; i
<nCount
; i
++)
1560 (*this)[i
]->CompileAll();
1563 void ScConditionalFormatList::CompileXML()
1565 USHORT nCount
= Count();
1566 for (USHORT i
=0; i
<nCount
; i
++)
1567 (*this)[i
]->CompileXML();
1570 void ScConditionalFormatList::UpdateReference( UpdateRefMode eUpdateRefMode
,
1571 const ScRange
& rRange
, SCsCOL nDx
, SCsROW nDy
, SCsTAB nDz
)
1573 USHORT nCount
= Count();
1574 for (USHORT i
=0; i
<nCount
; i
++)
1575 (*this)[i
]->UpdateReference( eUpdateRefMode
, rRange
, nDx
, nDy
, nDz
);
1578 void ScConditionalFormatList::RenameCellStyle( const String
& rOld
, const String
& rNew
)
1580 ULONG nCount
=Count();
1581 for (USHORT i
=0; i
<nCount
; i
++)
1582 (*this)[i
]->RenameCellStyle(rOld
,rNew
);
1585 void ScConditionalFormatList::UpdateMoveTab( SCTAB nOldPos
, SCTAB nNewPos
)
1587 USHORT nCount
= Count();
1588 for (USHORT i
=0; i
<nCount
; i
++)
1589 (*this)[i
]->UpdateMoveTab( nOldPos
, nNewPos
);
1592 void ScConditionalFormatList::SourceChanged( const ScAddress
& rAddr
)
1594 USHORT nCount
= Count();
1595 for (USHORT i
=0; i
<nCount
; i
++)
1596 (*this)[i
]->SourceChanged( rAddr
);
1599 bool ScConditionalFormatList::MarkUsedExternalReferences() const
1601 bool bAllMarked
= false;
1602 USHORT nCount
= Count();
1603 for (USHORT i
=0; !bAllMarked
&& i
<nCount
; i
++)
1604 bAllMarked
= (*this)[i
]->MarkUsedExternalReferences();