update dev300-m57
[ooovba.git] / sc / source / core / data / conditio.cxx
blobcbfea174e5ba44eb1e545fd80303b14260342fef
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"
46 #include "cell.hxx"
47 #include "document.hxx"
48 #include "hints.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 )
64 if (pFormula)
66 pFormula->Reset();
67 FormulaToken* t;
68 for( t = pFormula->Next(); t; t = pFormula->Next() )
70 switch( t->GetType() )
72 case svDoubleRef:
74 ScSingleRefData& rRef2 = static_cast<ScToken*>(t)->GetDoubleRef().Ref2;
75 if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
76 return TRUE;
78 // fall through
80 case svSingleRef:
82 ScSingleRefData& rRef1 = static_cast<ScToken*>(t)->GetSingleRef();
83 if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
84 return TRUE;
86 break;
88 case svIndex:
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 ) )
93 return TRUE;
95 break;
97 // #i34474# function result dependent on cell position
98 case svByte:
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
106 return TRUE;
107 // break;
108 default:
110 // added to avoid warnings
114 break;
116 default:
118 // added to avoid warnings
123 return FALSE;
126 ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) :
127 eOp(r.eOp),
128 nOptions(r.nOptions),
129 nVal1(r.nVal1),
130 nVal2(r.nVal2),
131 aStrVal1(r.aStrVal1),
132 aStrVal2(r.aStrVal2),
133 aStrNmsp1(r.aStrNmsp1),
134 aStrNmsp2(r.aStrNmsp2),
135 eTempGrammar1(r.eTempGrammar1),
136 eTempGrammar2(r.eTempGrammar2),
137 bIsStr1(r.bIsStr1),
138 bIsStr2(r.bIsStr2),
139 pFormula1(NULL),
140 pFormula2(NULL),
141 aSrcPos(r.aSrcPos),
142 aSrcString(r.aSrcString),
143 pFCell1(NULL),
144 pFCell2(NULL),
145 pDoc(r.pDoc),
146 bRelRef1(r.bRelRef1),
147 bRelRef2(r.bRelRef2),
148 bFirstRun(TRUE)
150 // ScTokenArray copy ctor erzeugt flache Kopie
152 if (r.pFormula1)
153 pFormula1 = new ScTokenArray( *r.pFormula1 );
154 if (r.pFormula2)
155 pFormula2 = new ScTokenArray( *r.pFormula2 );
157 // Formelzellen werden erst bei IsValid angelegt
160 ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntry& r ) :
161 eOp(r.eOp),
162 nOptions(r.nOptions),
163 nVal1(r.nVal1),
164 nVal2(r.nVal2),
165 aStrVal1(r.aStrVal1),
166 aStrVal2(r.aStrVal2),
167 aStrNmsp1(r.aStrNmsp1),
168 aStrNmsp2(r.aStrNmsp2),
169 eTempGrammar1(r.eTempGrammar1),
170 eTempGrammar2(r.eTempGrammar2),
171 bIsStr1(r.bIsStr1),
172 bIsStr2(r.bIsStr2),
173 pFormula1(NULL),
174 pFormula2(NULL),
175 aSrcPos(r.aSrcPos),
176 aSrcString(r.aSrcString),
177 pFCell1(NULL),
178 pFCell2(NULL),
179 pDoc(pDocument),
180 bRelRef1(r.bRelRef1),
181 bRelRef2(r.bRelRef2),
182 bFirstRun(TRUE)
184 // echte Kopie der Formeln (fuer Ref-Undo)
186 if (r.pFormula1)
187 pFormula1 = r.pFormula1->Clone();
188 if (r.pFormula2)
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 ) :
199 eOp(eOper),
200 nOptions(0), // spaeter...
201 nVal1(0.0),
202 nVal2(0.0),
203 aStrNmsp1(rExprNmsp1),
204 aStrNmsp2(rExprNmsp2),
205 eTempGrammar1(eGrammar1),
206 eTempGrammar2(eGrammar2),
207 bIsStr1(FALSE),
208 bIsStr2(FALSE),
209 pFormula1(NULL),
210 pFormula2(NULL),
211 aSrcPos(rPos),
212 pFCell1(NULL),
213 pFCell2(NULL),
214 pDoc(pDocument),
215 bRelRef1(FALSE),
216 bRelRef2(FALSE),
217 bFirstRun(TRUE)
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 ) :
227 eOp(eOper),
228 nOptions(0), // spaeter...
229 nVal1(0.0),
230 nVal2(0.0),
231 eTempGrammar1(FormulaGrammar::GRAM_DEFAULT),
232 eTempGrammar2(FormulaGrammar::GRAM_DEFAULT),
233 bIsStr1(FALSE),
234 bIsStr2(FALSE),
235 pFormula1(NULL),
236 pFormula2(NULL),
237 aSrcPos(rPos),
238 pFCell1(NULL),
239 pFCell2(NULL),
240 pDoc(pDocument),
241 bRelRef1(FALSE),
242 bRelRef2(FALSE),
243 bFirstRun(TRUE)
245 if ( pArr1 )
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 )
261 bIsStr1 = TRUE;
262 aStrVal1 = pToken->GetString();
263 DELETEZ(pFormula1); // nicht als Formel merken
267 bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
269 if ( pArr2 )
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 )
285 bIsStr2 = TRUE;
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()
299 delete pFCell1;
300 delete pFCell2;
302 delete pFormula1;
303 delete pFormula2;
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 );
314 if ( rExpr1.Len() )
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)
325 else
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 )
341 bIsStr1 = TRUE;
342 aStrVal1 = pToken->GetString();
343 DELETEZ(pFormula1); // nicht als Formel merken
347 bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
351 if ( rExpr2.Len() )
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)
362 else
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 )
378 bIsStr2 = TRUE;
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)
413 if (bSet)
414 nOptions &= ~SC_COND_NOBLANKS;
415 else
416 nOptions |= SC_COND_NOBLANKS;
419 void ScConditionEntry::CompileAll()
421 // Formelzellen loeschen, dann wird beim naechsten IsValid neu kompiliert
423 DELETEZ(pFCell1);
424 DELETEZ(pFCell2);
427 void ScConditionEntry::CompileXML()
429 // #b4974740# First parse the formula source position if it was stored as text
431 if ( aSrcString.Len() )
433 ScAddress aNew;
434 /* XML is always in OOo:A1 format, although R1C1 would be more amenable
435 * to compression */
436 if ( aNew.Parse( aSrcString, pDoc ) & SCA_VALID )
437 aSrcPos = aNew;
438 // if the position is invalid, there isn't much we can do at this time
439 aSrcString.Erase();
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" );
454 aSrcString = rNew;
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.
483 rCode.Reset();
484 ScToken* p = static_cast<ScToken*>(rCode.GetNextReference());
485 while( p )
487 ScSingleRefData& rRef1 = p->GetSingleRef();
488 if ( !rRef1.IsTabRel() && nInsTab <= rRef1.nTab )
490 rRef1.nTab += 1;
491 rRef1.nRelTab = rRef1.nTab - nPosTab;
492 rChanged = TRUE;
494 if( p->GetType() == svDoubleRef )
496 ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
497 if ( !rRef2.IsTabRel() && nInsTab <= rRef2.nTab )
499 rRef2.nTab += 1;
500 rRef2.nRelTab = rRef2.nTab - nPosTab;
501 rChanged = TRUE;
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;
517 if (pFormula1)
519 if ( bInsertTab )
520 lcl_CondUpdateInsertTab( *pFormula1, rRange.aStart.Tab(), aSrcPos.Tab(), bChanged1 );
521 else
523 ScCompiler aComp( pDoc, aSrcPos, *pFormula1 );
524 aComp.SetGrammar(pDoc->GetGrammar());
525 if ( bDeleteTab )
526 aComp.UpdateDeleteTab( rRange.aStart.Tab(), FALSE, TRUE, bChanged1 );
527 else
528 aComp.UpdateNameReference( eUpdateRefMode, rRange, nDx, nDy, nDz, bChanged1 );
531 if (bChanged1)
532 DELETEZ(pFCell1); // is created again in IsValid
534 if (pFormula2)
536 if ( bInsertTab )
537 lcl_CondUpdateInsertTab( *pFormula2, rRange.aStart.Tab(), aSrcPos.Tab(), bChanged2 );
538 else
540 ScCompiler aComp( pDoc, aSrcPos, *pFormula2);
541 aComp.SetGrammar(pDoc->GetGrammar());
542 if ( bDeleteTab )
543 aComp.UpdateDeleteTab( rRange.aStart.Tab(), FALSE, TRUE, bChanged2 );
544 else
545 aComp.UpdateNameReference( eUpdateRefMode, rRange, nDx, nDy, nDz, bChanged2 );
548 if (bChanged2)
549 DELETEZ(pFCell2); // is created again in IsValid
553 void ScConditionEntry::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
555 if (pFormula1)
557 ScCompiler aComp( pDoc, aSrcPos, *pFormula1);
558 aComp.SetGrammar(pDoc->GetGrammar());
559 aComp.UpdateMoveTab(nOldPos, nNewPos, TRUE );
560 DELETEZ(pFCell1);
562 if (pFormula2)
564 ScCompiler aComp( pDoc, aSrcPos, *pFormula2);
565 aComp.SetGrammar(pDoc->GetGrammar());
566 aComp.UpdateMoveTab(nOldPos, nNewPos, TRUE );
567 DELETEZ(pFCell2);
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 )
581 return FALSE;
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
593 else
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 ));
602 if (bEq)
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 ) )
607 bEq = FALSE;
609 // wenn keine Formeln, Werte vergleichen
610 if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
611 bEq = FALSE;
612 if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
613 bEq = FALSE;
616 return bEq;
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 ) )
625 MakeCells( rPos );
627 // Formeln auswerten
629 BOOL bDirty = FALSE; //! 1 und 2 getrennt ???
631 ScFormulaCell* pTemp1 = NULL;
632 ScFormulaCell* pEff1 = pFCell1;
633 if ( bRelRef1 )
635 pTemp1 = new ScFormulaCell( pDoc, rPos, pFormula1 ); // ohne Listening
636 pEff1 = pTemp1;
638 if ( pEff1 )
640 if (!pEff1->IsRunning()) // keine 522 erzeugen
642 //! Changed statt Dirty abfragen !!!
643 if (pEff1->GetDirty() && !bRelRef1)
644 bDirty = TRUE;
645 if (pEff1->IsValue())
647 bIsStr1 = FALSE;
648 nVal1 = pEff1->GetValue();
649 aStrVal1.Erase();
651 else
653 bIsStr1 = TRUE;
654 pEff1->GetString( aStrVal1 );
655 nVal1 = 0.0;
659 delete pTemp1;
661 ScFormulaCell* pTemp2 = NULL;
662 ScFormulaCell* pEff2 = pFCell2; //@ 1!=2
663 if ( bRelRef2 )
665 pTemp2 = new ScFormulaCell( pDoc, rPos, pFormula2 ); // ohne Listening
666 pEff2 = pTemp2;
668 if ( pEff2 )
670 if (!pEff2->IsRunning()) // keine 522 erzeugen
672 if (pEff2->GetDirty() && !bRelRef2)
673 bDirty = TRUE;
674 if (pEff2->IsValue())
676 bIsStr2 = FALSE;
677 nVal2 = pEff2->GetValue();
678 aStrVal2.Erase();
680 else
682 bIsStr2 = TRUE;
683 pEff2->GetString( aStrVal2 );
684 nVal2 = 0.0;
688 delete pTemp2;
690 // wenn IsRunning, bleiben die letzten Werte erhalten
692 if (bDirty && !bFirstRun)
694 // bei bedingten Formaten neu painten
696 DataChanged( NULL ); // alles
699 bFirstRun = FALSE;
702 BOOL ScConditionEntry::IsValid( double nArg ) const
704 // Interpret muss schon gerufen sein
706 if ( bIsStr1 )
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 )
714 if ( bIsStr2 )
715 return FALSE;
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!
729 BOOL bValid = FALSE;
730 switch (eOp)
732 case SC_COND_NONE:
733 break; // immer FALSE;
734 case SC_COND_EQUAL:
735 bValid = ::rtl::math::approxEqual( nArg, nComp1 );
736 break;
737 case SC_COND_NOTEQUAL:
738 bValid = !::rtl::math::approxEqual( nArg, nComp1 );
739 break;
740 case SC_COND_GREATER:
741 bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
742 break;
743 case SC_COND_EQGREATER:
744 bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
745 break;
746 case SC_COND_LESS:
747 bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
748 break;
749 case SC_COND_EQLESS:
750 bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
751 break;
752 case SC_COND_BETWEEN:
753 bValid = ( nArg >= nComp1 && nArg <= nComp2 ) ||
754 ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 );
755 break;
756 case SC_COND_NOTBETWEEN:
757 bValid = ( nArg < nComp1 || nArg > nComp2 ) &&
758 !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 );
759 break;
760 case SC_COND_DIRECT:
761 bValid = !::rtl::math::approxEqual( nComp1, 0.0 );
762 break;
763 default:
764 DBG_ERROR("unbekannte Operation bei ScConditionEntry");
765 break;
767 return bValid;
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"
779 if ( !bIsStr1 )
780 return ( eOp == SC_COND_NOTEQUAL );
781 if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
782 if ( !bIsStr2 )
783 return FALSE;
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 )
790 == COMPARE_GREATER )
792 // richtige Reihenfolge fuer Wertebereich
793 String aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
796 BOOL bValid;
797 switch ( eOp )
799 case SC_COND_EQUAL:
800 bValid = (ScGlobal::pCollator->compareString(
801 rArg, aUpVal1 ) == COMPARE_EQUAL);
802 break;
803 case SC_COND_NOTEQUAL:
804 bValid = (ScGlobal::pCollator->compareString(
805 rArg, aUpVal1 ) != COMPARE_EQUAL);
806 break;
807 default:
809 sal_Int32 nCompare = ScGlobal::pCollator->compareString(
810 rArg, aUpVal1 );
811 switch ( eOp )
813 case SC_COND_GREATER:
814 bValid = ( nCompare == COMPARE_GREATER );
815 break;
816 case SC_COND_EQGREATER:
817 bValid = ( nCompare == COMPARE_EQUAL || nCompare == COMPARE_GREATER );
818 break;
819 case SC_COND_LESS:
820 bValid = ( nCompare == COMPARE_LESS );
821 break;
822 case SC_COND_EQLESS:
823 bValid = ( nCompare == COMPARE_EQUAL || nCompare == COMPARE_LESS );
824 break;
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 )
832 bValid = !bValid;
833 break;
834 // SC_COND_DIRECT schon oben abgefragt
835 default:
836 DBG_ERROR("unbekannte Operation bei ScConditionEntry");
837 bValid = FALSE;
838 break;
842 return bValid;
845 BOOL ScConditionEntry::IsCellValid( ScBaseCell* pCell, const ScAddress& rPos ) const
847 ((ScConditionEntry*)this)->Interpret(rPos); // Formeln auswerten
849 double nArg = 0.0;
850 String aArgStr;
851 BOOL bVal = TRUE;
853 if ( pCell )
855 CellType eType = pCell->GetCellType();
856 switch (eType)
858 case CELLTYPE_VALUE:
859 nArg = ((ScValueCell*)pCell)->GetValue();
860 break;
861 case CELLTYPE_FORMULA:
863 ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
864 bVal = pFCell->IsValue();
865 if (bVal)
866 nArg = pFCell->GetValue();
867 else
868 pFCell->GetString(aArgStr);
870 break;
871 case CELLTYPE_STRING:
872 case CELLTYPE_EDIT:
873 bVal = FALSE;
874 if ( eType == CELLTYPE_STRING )
875 ((ScStringCell*)pCell)->GetString(aArgStr);
876 else
877 ((ScEditCell*)pCell)->GetString(aArgStr);
878 break;
880 default:
881 pCell = NULL; // Note-Zellen wie leere
882 break;
886 if (!pCell)
887 if (bIsStr1)
888 bVal = FALSE; // leere Zellen je nach Bedingung
890 if (bVal)
891 return IsValid( nArg );
892 else
893 return IsValidStr( aArgStr );
896 String ScConditionEntry::GetExpression( const ScAddress& rCursor, USHORT nIndex,
897 ULONG nNumFmt,
898 const FormulaGrammar::Grammar eGrammar ) const
900 String aRet;
902 if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 )
903 nNumFmt = pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US );
905 if ( nIndex==0 )
907 if ( pFormula1 )
909 ScCompiler aComp(pDoc, rCursor, *pFormula1);
910 aComp.SetGrammar(eGrammar);
911 aComp.CreateStringFromTokenArray( aRet );
913 else if (bIsStr1)
915 aRet = '"';
916 aRet += aStrVal1;
917 aRet += '"';
919 else
920 pDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet);
922 else if ( nIndex==1 )
924 if ( pFormula2 )
926 ScCompiler aComp(pDoc, rCursor, *pFormula2);
927 aComp.SetGrammar(eGrammar);
928 aComp.CreateStringFromTokenArray( aRet );
930 else if (bIsStr2)
932 aRet = '"';
933 aRet += aStrVal2;
934 aRet += '"';
936 else
937 pDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet);
939 else
941 DBG_ERROR("GetExpression: falscher Index");
944 return aRet;
947 ScTokenArray* ScConditionEntry::CreateTokenArry( USHORT nIndex ) const
949 ScTokenArray* pRet = NULL;
950 ScAddress aAddr;
952 if ( nIndex==0 )
954 if ( pFormula1 )
955 pRet = new ScTokenArray( *pFormula1 );
956 else
958 pRet = new ScTokenArray();
959 if (bIsStr1)
960 pRet->AddString( aStrVal1.GetBuffer() );
961 else
962 pRet->AddDouble( nVal1 );
965 else if ( nIndex==1 )
967 if ( pFormula2 )
968 pRet = new ScTokenArray( *pFormula2 );
969 else
971 pRet = new ScTokenArray();
972 if (bIsStr2)
973 pRet->AddString( aStrVal2.GetBuffer() );
974 else
975 pRet->AddDouble( nVal2 );
978 else
980 DBG_ERROR("GetExpression: falscher Index");
983 return pRet;
986 void ScConditionEntry::SourceChanged( const ScAddress& rChanged )
988 for (USHORT nPass = 0; nPass < 2; nPass++)
990 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
991 if (pFormula)
993 pFormula->Reset();
994 ScToken* t;
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
1003 BOOL bHit = TRUE;
1004 SCsCOL nCol1;
1005 SCsROW nRow1;
1006 SCsTAB nTab1;
1007 SCsCOL nCol2;
1008 SCsROW nRow2;
1009 SCsTAB nTab2;
1011 if ( aProv.Ref1.IsColRel() )
1012 nCol2 = rChanged.Col() - aProv.Ref1.nRelCol;
1013 else
1015 bHit &= ( rChanged.Col() >= aProv.Ref1.nCol );
1016 nCol2 = MAXCOL;
1018 if ( aProv.Ref1.IsRowRel() )
1019 nRow2 = rChanged.Row() - aProv.Ref1.nRelRow;
1020 else
1022 bHit &= ( rChanged.Row() >= aProv.Ref1.nRow );
1023 nRow2 = MAXROW;
1025 if ( aProv.Ref1.IsTabRel() )
1026 nTab2 = rChanged.Tab() - aProv.Ref1.nRelTab;
1027 else
1029 bHit &= ( rChanged.Tab() >= aProv.Ref1.nTab );
1030 nTab2 = MAXTAB;
1033 if ( aProv.Ref2.IsColRel() )
1034 nCol1 = rChanged.Col() - aProv.Ref2.nRelCol;
1035 else
1037 bHit &= ( rChanged.Col() <= aProv.Ref2.nCol );
1038 nCol1 = 0;
1040 if ( aProv.Ref2.IsRowRel() )
1041 nRow1 = rChanged.Row() - aProv.Ref2.nRelRow;
1042 else
1044 bHit &= ( rChanged.Row() <= aProv.Ref2.nRow );
1045 nRow1 = 0;
1047 if ( aProv.Ref2.IsTabRel() )
1048 nTab1 = rChanged.Tab() - aProv.Ref2.nRelTab;
1049 else
1051 bHit &= ( rChanged.Tab() <= aProv.Ref2.nTab );
1052 nTab1 = 0;
1055 if ( bHit )
1057 //! begrenzen
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;
1081 if (pFormula)
1083 pFormula->Reset();
1084 ScToken* t;
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
1118 return aValidPos;
1121 void ScConditionEntry::DataChanged( const ScRange* /* pModified */ ) const
1123 // nix
1126 bool ScConditionEntry::MarkUsedExternalReferences() const
1128 bool bAllMarked = false;
1129 for (USHORT nPass = 0; !bAllMarked && nPass < 2; nPass++)
1131 ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1132 if (pFormula)
1133 bAllMarked = pDoc->MarkUsedExternalReferences( *pFormula);
1135 return bAllMarked;
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 ),
1149 pParent( NULL )
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 ),
1159 pParent( NULL )
1163 ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry& r ) :
1164 ScConditionEntry( r ),
1165 aStyleName( r.aStyleName ),
1166 pParent( NULL )
1170 ScCondFormatEntry::ScCondFormatEntry( ScDocument* pDocument, const ScCondFormatEntry& r ) :
1171 ScConditionEntry( pDocument, r ),
1172 aStyleName( r.aStyleName ),
1173 pParent( NULL )
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
1191 if ( pParent )
1192 pParent->DoRepaint( pModified );
1195 //------------------------------------------------------------------------
1197 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
1198 pDoc( pDocument ),
1199 pAreas( NULL ),
1200 nKey( nNewKey ),
1201 ppEntries( NULL ),
1202 nEntryCount( 0 )
1206 ScConditionalFormat::ScConditionalFormat(const ScConditionalFormat& r) :
1207 pDoc( r.pDoc ),
1208 pAreas( NULL ),
1209 nKey( r.nKey ),
1210 ppEntries( NULL ),
1211 nEntryCount( r.nEntryCount )
1213 if (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)
1228 if (!pNewDoc)
1229 pNewDoc = pDoc;
1231 ScConditionalFormat* pNew = new ScConditionalFormat(nKey, pNewDoc);
1232 DBG_ASSERT(!pNew->ppEntries, "wo kommen die Eintraege her?");
1234 if (nEntryCount)
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;
1245 return pNew;
1248 BOOL ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const
1250 if ( nEntryCount != r.nEntryCount )
1251 return FALSE;
1253 //! auf gleiche Eintraege in anderer Reihenfolge testen ???
1255 for (USHORT i=0; i<nEntryCount; i++)
1256 if ( ! (*ppEntries[i] == *r.ppEntries[i]) )
1257 return FALSE;
1259 return TRUE;
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);
1269 ++nEntryCount;
1270 delete[] ppEntries;
1271 ppEntries = ppNew;
1274 ScConditionalFormat::~ScConditionalFormat()
1276 for (USHORT i=0; i<nEntryCount; i++)
1277 delete ppEntries[i];
1278 delete[] ppEntries;
1280 delete pAreas;
1283 const ScCondFormatEntry* ScConditionalFormat::GetEntry( USHORT nPos ) const
1285 if ( nPos < nEntryCount )
1286 return ppEntries[nPos];
1287 else
1288 return NULL;
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 );
1312 if (bLines)
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 )
1329 rRange.Justify();
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() );
1353 return TRUE;
1356 return FALSE; // ausserhalb
1359 void ScConditionalFormat::DoRepaint( const ScRange* pModified )
1361 USHORT i;
1362 SfxObjectShell* pSh = pDoc->GetDocumentShell();
1363 if (pSh)
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);
1380 BOOL bDo = TRUE;
1381 if ( pModified )
1383 if ( !lcl_CutRange( aRange, *pModified ) )
1384 bDo = FALSE;
1386 if (bDo)
1388 if ( !bAttrTested )
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();
1396 if (aStyle.Len())
1398 SfxStyleSheetBase* pStyleSheet =
1399 pDoc->GetStyleSheetPool()->Find( aStyle, SFX_STYLE_FAMILY_PARA );
1400 if ( pStyleSheet )
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)
1406 bExtend = TRUE;
1408 if (rSet.GetItemState( ATTR_ROTATE_VALUE, TRUE ) == SFX_ITEM_SET ||
1409 rSet.GetItemState( ATTR_ROTATE_MODE, TRUE ) == SFX_ITEM_SET)
1411 bRotate = TRUE;
1416 bAttrTested = TRUE;
1419 lcl_Extend( aRange, pDoc, bExtend ); // zusammengefasste und bExtend
1420 if ( bRotate )
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(),
1431 HASATTR_ROTATE ) )
1433 aRange.aStart.SetCol(0);
1434 aRange.aEnd.SetCol(MAXCOL);
1438 pSh->Broadcast( ScPaintHint( aRange, PAINT_GRID ) );
1444 void ScConditionalFormat::InvalidateArea()
1446 delete pAreas;
1447 pAreas = NULL;
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
1469 pAreas = NULL;
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
1485 pAreas = NULL;
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();
1499 return bAllMarked;
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 ?
1538 bEqual = FALSE;
1540 return bEqual;
1543 ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey )
1545 //! binaer suchen
1547 USHORT nCount = Count();
1548 for (USHORT i=0; i<nCount; i++)
1549 if ((*this)[i]->GetKey() == nKey)
1550 return (*this)[i];
1552 DBG_ERROR("ScConditionalFormatList: Eintrag nicht gefunden");
1553 return NULL;
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();
1605 return bAllMarked;