xref: /trunk/main/sc/source/core/data/conditio.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 //------------------------------------------------------------------
34 
35 #include "scitems.hxx"
36 #include <sfx2/objsh.hxx>
37 #include <svl/itemset.hxx>
38 #include <svl/zforlist.hxx>
39 #include <rtl/math.hxx>
40 #include <unotools/collatorwrapper.hxx>
41 
42 #include "conditio.hxx"
43 #include "cell.hxx"
44 #include "document.hxx"
45 #include "hints.hxx"
46 #include "compiler.hxx"
47 #include "rechead.hxx"
48 #include "rangelst.hxx"
49 #include "stlpool.hxx"
50 #include "rangenam.hxx"
51 
52 using namespace formula;
53 //------------------------------------------------------------------------
54 
55 SV_IMPL_OP_PTRARR_SORT( ScConditionalFormats_Impl, ScConditionalFormatPtr );
56 
57 //------------------------------------------------------------------------
58 
59 sal_Bool lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, sal_uInt16 nRecursion = 0 )
60 {
61     if (pFormula)
62     {
63         pFormula->Reset();
64         FormulaToken* t;
65         for( t = pFormula->Next(); t; t = pFormula->Next() )
66         {
67             switch( t->GetType() )
68             {
69                 case svDoubleRef:
70                 {
71                     ScSingleRefData& rRef2 = static_cast<ScToken*>(t)->GetDoubleRef().Ref2;
72                     if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
73                         return sal_True;
74                 }
75                 // fall through
76 
77                 case svSingleRef:
78                 {
79                     ScSingleRefData& rRef1 = static_cast<ScToken*>(t)->GetSingleRef();
80                     if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
81                         return sal_True;
82                 }
83                 break;
84 
85                 case svIndex:
86                 {
87                     if( t->GetOpCode() == ocName )      // DB areas always absolute
88                         if( ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( t->GetIndex() ) )
89                             if( (nRecursion < 42) && lcl_HasRelRef( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
90                                 return sal_True;
91                 }
92                 break;
93 
94                 // #i34474# function result dependent on cell position
95                 case svByte:
96                 {
97                     switch( t->GetOpCode() )
98                     {
99                         case ocRow:     // ROW() returns own row index
100                         case ocColumn:  // COLUMN() returns own column index
101                         case ocTable:   // SHEET() returns own sheet index
102                         case ocCell:    // CELL() may return own cell address
103                             return sal_True;
104 //                        break;
105                         default:
106                         {
107                             // added to avoid warnings
108                         }
109                     }
110                 }
111                 break;
112 
113                 default:
114                 {
115                     // added to avoid warnings
116                 }
117             }
118         }
119     }
120     return sal_False;
121 }
122 
123 ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) :
124     eOp(r.eOp),
125     nOptions(r.nOptions),
126     nVal1(r.nVal1),
127     nVal2(r.nVal2),
128     aStrVal1(r.aStrVal1),
129     aStrVal2(r.aStrVal2),
130     aStrNmsp1(r.aStrNmsp1),
131     aStrNmsp2(r.aStrNmsp2),
132     eTempGrammar1(r.eTempGrammar1),
133     eTempGrammar2(r.eTempGrammar2),
134     bIsStr1(r.bIsStr1),
135     bIsStr2(r.bIsStr2),
136     pFormula1(NULL),
137     pFormula2(NULL),
138     aSrcPos(r.aSrcPos),
139     aSrcString(r.aSrcString),
140     pFCell1(NULL),
141     pFCell2(NULL),
142     pDoc(r.pDoc),
143     bRelRef1(r.bRelRef1),
144     bRelRef2(r.bRelRef2),
145     bFirstRun(sal_True)
146 {
147     //  ScTokenArray copy ctor erzeugt flache Kopie
148 
149     if (r.pFormula1)
150         pFormula1 = new ScTokenArray( *r.pFormula1 );
151     if (r.pFormula2)
152         pFormula2 = new ScTokenArray( *r.pFormula2 );
153 
154     //  Formelzellen werden erst bei IsValid angelegt
155 }
156 
157 ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntry& r ) :
158     eOp(r.eOp),
159     nOptions(r.nOptions),
160     nVal1(r.nVal1),
161     nVal2(r.nVal2),
162     aStrVal1(r.aStrVal1),
163     aStrVal2(r.aStrVal2),
164     aStrNmsp1(r.aStrNmsp1),
165     aStrNmsp2(r.aStrNmsp2),
166     eTempGrammar1(r.eTempGrammar1),
167     eTempGrammar2(r.eTempGrammar2),
168     bIsStr1(r.bIsStr1),
169     bIsStr2(r.bIsStr2),
170     pFormula1(NULL),
171     pFormula2(NULL),
172     aSrcPos(r.aSrcPos),
173     aSrcString(r.aSrcString),
174     pFCell1(NULL),
175     pFCell2(NULL),
176     pDoc(pDocument),
177     bRelRef1(r.bRelRef1),
178     bRelRef2(r.bRelRef2),
179     bFirstRun(sal_True)
180 {
181     // echte Kopie der Formeln (fuer Ref-Undo)
182 
183     if (r.pFormula1)
184         pFormula1 = r.pFormula1->Clone();
185     if (r.pFormula2)
186         pFormula2 = r.pFormula2->Clone();
187 
188     //  Formelzellen werden erst bei IsValid angelegt
189     //! im Clipboard nicht - dann vorher interpretieren !!!
190 }
191 
192 ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
193         const String& rExpr1, const String& rExpr2, ScDocument* pDocument, const ScAddress& rPos,
194         const String& rExprNmsp1, const String& rExprNmsp2,
195         FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) :
196     eOp(eOper),
197     nOptions(0),    // spaeter...
198     nVal1(0.0),
199     nVal2(0.0),
200     aStrNmsp1(rExprNmsp1),
201     aStrNmsp2(rExprNmsp2),
202     eTempGrammar1(eGrammar1),
203     eTempGrammar2(eGrammar2),
204     bIsStr1(sal_False),
205     bIsStr2(sal_False),
206     pFormula1(NULL),
207     pFormula2(NULL),
208     aSrcPos(rPos),
209     pFCell1(NULL),
210     pFCell2(NULL),
211     pDoc(pDocument),
212     bRelRef1(sal_False),
213     bRelRef2(sal_False),
214     bFirstRun(sal_True)
215 {
216     Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, sal_False );
217 
218     //  Formelzellen werden erst bei IsValid angelegt
219 }
220 
221 ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
222                                 const ScTokenArray* pArr1, const ScTokenArray* pArr2,
223                                 ScDocument* pDocument, const ScAddress& rPos ) :
224     eOp(eOper),
225     nOptions(0),    // spaeter...
226     nVal1(0.0),
227     nVal2(0.0),
228     eTempGrammar1(FormulaGrammar::GRAM_DEFAULT),
229     eTempGrammar2(FormulaGrammar::GRAM_DEFAULT),
230     bIsStr1(sal_False),
231     bIsStr2(sal_False),
232     pFormula1(NULL),
233     pFormula2(NULL),
234     aSrcPos(rPos),
235     pFCell1(NULL),
236     pFCell2(NULL),
237     pDoc(pDocument),
238     bRelRef1(sal_False),
239     bRelRef2(sal_False),
240     bFirstRun(sal_True)
241 {
242     if ( pArr1 )
243     {
244         pFormula1 = new ScTokenArray( *pArr1 );
245         if ( pFormula1->GetLen() == 1 )
246         {
247             // einzelne (konstante Zahl) ?
248             FormulaToken* pToken = pFormula1->First();
249             if ( pToken->GetOpCode() == ocPush )
250             {
251                 if ( pToken->GetType() == svDouble )
252                 {
253                     nVal1 = pToken->GetDouble();
254                     DELETEZ(pFormula1);             // nicht als Formel merken
255                 }
256                 else if ( pToken->GetType() == svString )
257                 {
258                     bIsStr1 = sal_True;
259                     aStrVal1 = pToken->GetString();
260                     DELETEZ(pFormula1);             // nicht als Formel merken
261                 }
262             }
263         }
264         bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
265     }
266     if ( pArr2 )
267     {
268         pFormula2 = new ScTokenArray( *pArr2 );
269         if ( pFormula2->GetLen() == 1 )
270         {
271             // einzelne (konstante Zahl) ?
272             FormulaToken* pToken = pFormula2->First();
273             if ( pToken->GetOpCode() == ocPush )
274             {
275                 if ( pToken->GetType() == svDouble )
276                 {
277                     nVal2 = pToken->GetDouble();
278                     DELETEZ(pFormula2);             // nicht als Formel merken
279                 }
280                 else if ( pToken->GetType() == svString )
281                 {
282                     bIsStr2 = sal_True;
283                     aStrVal2 = pToken->GetString();
284                     DELETEZ(pFormula2);             // nicht als Formel merken
285                 }
286             }
287         }
288         bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 );
289     }
290 
291     //  formula cells are created at IsValid
292 }
293 
294 ScConditionEntry::~ScConditionEntry()
295 {
296     delete pFCell1;
297     delete pFCell2;
298 
299     delete pFormula1;
300     delete pFormula2;
301 }
302 
303 void ScConditionEntry::Compile( const String& rExpr1, const String& rExpr2,
304         const String& rExprNmsp1, const String& rExprNmsp2,
305         FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2, sal_Bool bTextToReal )
306 {
307     if ( rExpr1.Len() || rExpr2.Len() )
308     {
309         ScCompiler aComp( pDoc, aSrcPos );
310 
311         if ( rExpr1.Len() )
312         {
313             aComp.SetGrammar( eGrammar1 );
314             if ( pDoc->IsImportingXML() && !bTextToReal )
315             {
316                 //  temporary formula string as string tokens
317                 //! merge with lcl_ScDocFunc_CreateTokenArrayXML
318                 pFormula1 = new ScTokenArray;
319                 pFormula1->AddString( rExpr1 );
320                 // bRelRef1 is set when the formula is compiled again (CompileXML)
321             }
322             else
323             {
324                 pFormula1 = aComp.CompileString( rExpr1, rExprNmsp1 );
325                 if ( pFormula1->GetLen() == 1 )
326                 {
327                     // einzelne (konstante Zahl) ?
328                     FormulaToken* pToken = pFormula1->First();
329                     if ( pToken->GetOpCode() == ocPush )
330                     {
331                         if ( pToken->GetType() == svDouble )
332                         {
333                             nVal1 = pToken->GetDouble();
334                             DELETEZ(pFormula1);             // nicht als Formel merken
335                         }
336                         else if ( pToken->GetType() == svString )
337                         {
338                             bIsStr1 = sal_True;
339                             aStrVal1 = pToken->GetString();
340                             DELETEZ(pFormula1);             // nicht als Formel merken
341                         }
342                     }
343                 }
344                 bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
345             }
346         }
347 
348         if ( rExpr2.Len() )
349         {
350             aComp.SetGrammar( eGrammar2 );
351             if ( pDoc->IsImportingXML() && !bTextToReal )
352             {
353                 //  temporary formula string as string tokens
354                 //! merge with lcl_ScDocFunc_CreateTokenArrayXML
355                 pFormula2 = new ScTokenArray;
356                 pFormula2->AddString( rExpr2 );
357                 // bRelRef2 is set when the formula is compiled again (CompileXML)
358             }
359             else
360             {
361                 pFormula2 = aComp.CompileString( rExpr2, rExprNmsp2 );
362                 if ( pFormula2->GetLen() == 1 )
363                 {
364                     // einzelne (konstante Zahl) ?
365                     FormulaToken* pToken = pFormula2->First();
366                     if ( pToken->GetOpCode() == ocPush )
367                     {
368                         if ( pToken->GetType() == svDouble )
369                         {
370                             nVal2 = pToken->GetDouble();
371                             DELETEZ(pFormula2);             // nicht als Formel merken
372                         }
373                         else if ( pToken->GetType() == svString )
374                         {
375                             bIsStr2 = sal_True;
376                             aStrVal2 = pToken->GetString();
377                             DELETEZ(pFormula2);             // nicht als Formel merken
378                         }
379                     }
380                 }
381                 bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 );
382             }
383         }
384     }
385 }
386 
387 void ScConditionEntry::MakeCells( const ScAddress& rPos )           // Formelzellen anlegen
388 {
389     if ( !pDoc->IsClipOrUndo() )            // nie im Clipboard rechnen!
390     {
391         if ( pFormula1 && !pFCell1 && !bRelRef1 )
392         {
393             pFCell1 = new ScFormulaCell( pDoc, rPos, pFormula1 );
394             pFCell1->StartListeningTo( pDoc );
395         }
396 
397         if ( pFormula2 && !pFCell2 && !bRelRef2 )
398         {
399             pFCell2 = new ScFormulaCell( pDoc, rPos, pFormula2 );
400             pFCell2->StartListeningTo( pDoc );
401         }
402     }
403 }
404 
405 void ScConditionEntry::SetIgnoreBlank(sal_Bool bSet)
406 {
407     //  Das Bit SC_COND_NOBLANKS wird gesetzt, wenn Blanks nicht ignoriert werden
408     //  (nur bei Gueltigkeit)
409 
410     if (bSet)
411         nOptions &= ~SC_COND_NOBLANKS;
412     else
413         nOptions |= SC_COND_NOBLANKS;
414 }
415 
416 void ScConditionEntry::CompileAll()
417 {
418     //  Formelzellen loeschen, dann wird beim naechsten IsValid neu kompiliert
419 
420     DELETEZ(pFCell1);
421     DELETEZ(pFCell2);
422 }
423 
424 void ScConditionEntry::CompileXML()
425 {
426     //  #b4974740# First parse the formula source position if it was stored as text
427 
428     if ( aSrcString.Len() )
429     {
430         ScAddress aNew;
431         /* XML is always in OOo:A1 format, although R1C1 would be more amenable
432          * to compression */
433         if ( aNew.Parse( aSrcString, pDoc ) & SCA_VALID )
434             aSrcPos = aNew;
435         // if the position is invalid, there isn't much we can do at this time
436         aSrcString.Erase();
437     }
438 
439     //  Convert the text tokens that were created during XML import into real tokens.
440 
441     Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar1),
442              GetExpression(aSrcPos, 1, 0, eTempGrammar2),
443              aStrNmsp1, aStrNmsp2, eTempGrammar1, eTempGrammar2, sal_True );
444 }
445 
446 void ScConditionEntry::SetSrcString( const String& rNew )
447 {
448     // aSrcString is only evaluated in CompileXML
449     DBG_ASSERT( pDoc->IsImportingXML(), "SetSrcString is only valid for XML import" );
450 
451     aSrcString = rNew;
452 }
453 
454 void ScConditionEntry::SetFormula1( const ScTokenArray& rArray )
455 {
456     DELETEZ( pFormula1 );
457     if( rArray.GetLen() > 0 )
458     {
459         pFormula1 = new ScTokenArray( rArray );
460         bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
461     }
462 }
463 
464 void ScConditionEntry::SetFormula2( const ScTokenArray& rArray )
465 {
466     DELETEZ( pFormula2 );
467     if( rArray.GetLen() > 0 )
468     {
469         pFormula2 = new ScTokenArray( rArray );
470         bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 );
471     }
472 }
473 
474 void lcl_CondUpdateInsertTab( ScTokenArray& rCode, SCTAB nInsTab, SCTAB nPosTab, sal_Bool& rChanged )
475 {
476     //  Insert table: only update absolute table references.
477     //  (Similar to ScCompiler::UpdateInsertTab with bIsName=sal_True, result is the same as for named ranges)
478     //  For deleting, ScCompiler::UpdateDeleteTab is used because of the handling of invalid references.
479 
480     rCode.Reset();
481     ScToken* p = static_cast<ScToken*>(rCode.GetNextReference());
482     while( p )
483     {
484         ScSingleRefData& rRef1 = p->GetSingleRef();
485         if ( !rRef1.IsTabRel() && nInsTab <= rRef1.nTab )
486         {
487             rRef1.nTab += 1;
488             rRef1.nRelTab = rRef1.nTab - nPosTab;
489             rChanged = sal_True;
490         }
491         if( p->GetType() == svDoubleRef )
492         {
493             ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
494             if ( !rRef2.IsTabRel() && nInsTab <= rRef2.nTab )
495             {
496                 rRef2.nTab += 1;
497                 rRef2.nRelTab = rRef2.nTab - nPosTab;
498                 rChanged = sal_True;
499             }
500         }
501         p = static_cast<ScToken*>(rCode.GetNextReference());
502     }
503 }
504 
505 void ScConditionEntry::UpdateReference( UpdateRefMode eUpdateRefMode,
506                                 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
507 {
508     sal_Bool bInsertTab = ( eUpdateRefMode == URM_INSDEL && nDz == 1 );
509     sal_Bool bDeleteTab = ( eUpdateRefMode == URM_INSDEL && nDz == -1 );
510 
511     sal_Bool bChanged1 = sal_False;
512     sal_Bool bChanged2 = sal_False;
513 
514     if (pFormula1)
515     {
516         if ( bInsertTab )
517             lcl_CondUpdateInsertTab( *pFormula1, rRange.aStart.Tab(), aSrcPos.Tab(), bChanged1 );
518         else
519         {
520             ScCompiler aComp( pDoc, aSrcPos, *pFormula1 );
521             aComp.SetGrammar(pDoc->GetGrammar());
522             if ( bDeleteTab )
523                 aComp.UpdateDeleteTab( rRange.aStart.Tab(), sal_False, sal_True, bChanged1 );
524             else
525                 aComp.UpdateNameReference( eUpdateRefMode, rRange, nDx, nDy, nDz, bChanged1 );
526         }
527 
528         if (bChanged1)
529             DELETEZ(pFCell1);       // is created again in IsValid
530     }
531     if (pFormula2)
532     {
533         if ( bInsertTab )
534             lcl_CondUpdateInsertTab( *pFormula2, rRange.aStart.Tab(), aSrcPos.Tab(), bChanged2 );
535         else
536         {
537             ScCompiler aComp( pDoc, aSrcPos, *pFormula2);
538             aComp.SetGrammar(pDoc->GetGrammar());
539             if ( bDeleteTab )
540                 aComp.UpdateDeleteTab( rRange.aStart.Tab(), sal_False, sal_True, bChanged2 );
541             else
542                 aComp.UpdateNameReference( eUpdateRefMode, rRange, nDx, nDy, nDz, bChanged2 );
543         }
544 
545         if (bChanged2)
546             DELETEZ(pFCell2);       // is created again in IsValid
547     }
548 }
549 
550 void ScConditionEntry::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
551 {
552     if (pFormula1)
553     {
554         ScCompiler aComp( pDoc, aSrcPos, *pFormula1);
555         aComp.SetGrammar(pDoc->GetGrammar());
556         aComp.UpdateMoveTab(nOldPos, nNewPos, sal_True );
557         DELETEZ(pFCell1);
558     }
559     if (pFormula2)
560     {
561         ScCompiler aComp( pDoc, aSrcPos, *pFormula2);
562         aComp.SetGrammar(pDoc->GetGrammar());
563         aComp.UpdateMoveTab(nOldPos, nNewPos, sal_True );
564         DELETEZ(pFCell2);
565     }
566 }
567 
568 //! als Vergleichsoperator ans TokenArray ???
569 
570 sal_Bool lcl_IsEqual( const ScTokenArray* pArr1, const ScTokenArray* pArr2 )
571 {
572     //  verglichen wird nur das nicht-UPN Array
573 
574     if ( pArr1 && pArr2 )
575     {
576         sal_uInt16 nLen = pArr1->GetLen();
577         if ( pArr2->GetLen() != nLen )
578             return sal_False;
579 
580         FormulaToken** ppToken1 = pArr1->GetArray();
581         FormulaToken** ppToken2 = pArr2->GetArray();
582         for (sal_uInt16 i=0; i<nLen; i++)
583         {
584             if ( ppToken1[i] != ppToken2[i] &&
585                  !(*ppToken1[i] == *ppToken2[i]) )
586                 return sal_False;                       // Unterschied
587         }
588         return sal_True;                    // alle Eintraege gleich
589     }
590     else
591         return !pArr1 && !pArr2;        // beide 0 -> gleich
592 }
593 
594 int ScConditionEntry::operator== ( const ScConditionEntry& r ) const
595 {
596     sal_Bool bEq = (eOp == r.eOp && nOptions == r.nOptions &&
597                 lcl_IsEqual( pFormula1, r.pFormula1 ) &&
598                 lcl_IsEqual( pFormula2, r.pFormula2 ));
599     if (bEq)
600     {
601         // for formulas, the reference positions must be compared, too
602         // (including aSrcString, for inserting the entries during XML import)
603         if ( ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
604             bEq = sal_False;
605 
606         //  wenn keine Formeln, Werte vergleichen
607         if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
608             bEq = sal_False;
609         if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
610             bEq = sal_False;
611     }
612 
613     return bEq;
614 }
615 
616 void ScConditionEntry::Interpret( const ScAddress& rPos )
617 {
618     //  Formelzellen anlegen
619     //  dabei koennen neue Broadcaster (Note-Zellen) ins Dokument eingefuegt werden !!!!
620 
621     if ( ( pFormula1 && !pFCell1 ) || ( pFormula2 && !pFCell2 ) )
622         MakeCells( rPos );
623 
624     //  Formeln auswerten
625 
626     sal_Bool bDirty = sal_False;        //! 1 und 2 getrennt ???
627 
628     ScFormulaCell* pTemp1 = NULL;
629     ScFormulaCell* pEff1 = pFCell1;
630     if ( bRelRef1 )
631     {
632         pTemp1 = new ScFormulaCell( pDoc, rPos, pFormula1 );    // ohne Listening
633         pEff1 = pTemp1;
634     }
635     if ( pEff1 )
636     {
637         if (!pEff1->IsRunning())        // keine 522 erzeugen
638         {
639             //! Changed statt Dirty abfragen !!!
640             if (pEff1->GetDirty() && !bRelRef1)
641                 bDirty = sal_True;
642             if (pEff1->IsValue())
643             {
644                 bIsStr1 = sal_False;
645                 nVal1 = pEff1->GetValue();
646                 aStrVal1.Erase();
647             }
648             else
649             {
650                 bIsStr1 = sal_True;
651                 pEff1->GetString( aStrVal1 );
652                 nVal1 = 0.0;
653             }
654         }
655     }
656     delete pTemp1;
657 
658     ScFormulaCell* pTemp2 = NULL;
659     ScFormulaCell* pEff2 = pFCell2; //@ 1!=2
660     if ( bRelRef2 )
661     {
662         pTemp2 = new ScFormulaCell( pDoc, rPos, pFormula2 );    // ohne Listening
663         pEff2 = pTemp2;
664     }
665     if ( pEff2 )
666     {
667         if (!pEff2->IsRunning())        // keine 522 erzeugen
668         {
669             if (pEff2->GetDirty() && !bRelRef2)
670                 bDirty = sal_True;
671             if (pEff2->IsValue())
672             {
673                 bIsStr2 = sal_False;
674                 nVal2 = pEff2->GetValue();
675                 aStrVal2.Erase();
676             }
677             else
678             {
679                 bIsStr2 = sal_True;
680                 pEff2->GetString( aStrVal2 );
681                 nVal2 = 0.0;
682             }
683         }
684     }
685     delete pTemp2;
686 
687     //  wenn IsRunning, bleiben die letzten Werte erhalten
688 
689     if (bDirty && !bFirstRun)
690     {
691         //  bei bedingten Formaten neu painten
692 
693         DataChanged( NULL );    // alles
694     }
695 
696     bFirstRun = sal_False;
697 }
698 
699 sal_Bool ScConditionEntry::IsValid( double nArg ) const
700 {
701     //  Interpret muss schon gerufen sein
702 
703     if ( bIsStr1 )
704     {
705         // wenn auf String getestet wird, bei Zahlen immer sal_False, ausser bei "ungleich"
706 
707         return ( eOp == SC_COND_NOTEQUAL );
708     }
709 
710     if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
711         if ( bIsStr2 )
712             return sal_False;
713 
714     double nComp1 = nVal1;      // Kopie, damit vertauscht werden kann
715     double nComp2 = nVal2;
716 
717     if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
718         if ( nComp1 > nComp2 )
719         {
720             //  richtige Reihenfolge fuer Wertebereich
721             double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp;
722         }
723 
724     //  Alle Grenzfaelle muessen per ::rtl::math::approxEqual getestet werden!
725 
726     sal_Bool bValid = sal_False;
727     switch (eOp)
728     {
729         case SC_COND_NONE:
730             break;                  // immer sal_False;
731         case SC_COND_EQUAL:
732             bValid = ::rtl::math::approxEqual( nArg, nComp1 );
733             break;
734         case SC_COND_NOTEQUAL:
735             bValid = !::rtl::math::approxEqual( nArg, nComp1 );
736             break;
737         case SC_COND_GREATER:
738             bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
739             break;
740         case SC_COND_EQGREATER:
741             bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
742             break;
743         case SC_COND_LESS:
744             bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
745             break;
746         case SC_COND_EQLESS:
747             bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
748             break;
749         case SC_COND_BETWEEN:
750             bValid = ( nArg >= nComp1 && nArg <= nComp2 ) ||
751                      ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 );
752             break;
753         case SC_COND_NOTBETWEEN:
754             bValid = ( nArg < nComp1 || nArg > nComp2 ) &&
755                      !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 );
756             break;
757         case SC_COND_DIRECT:
758             bValid = !::rtl::math::approxEqual( nComp1, 0.0 );
759             break;
760         default:
761             DBG_ERROR("unbekannte Operation bei ScConditionEntry");
762             break;
763     }
764     return bValid;
765 }
766 
767 sal_Bool ScConditionEntry::IsValidStr( const String& rArg ) const
768 {
769     //  Interpret muss schon gerufen sein
770 
771     if ( eOp == SC_COND_DIRECT )                // Formel ist unabhaengig vom Inhalt
772         return !::rtl::math::approxEqual( nVal1, 0.0 );
773 
774     //  Wenn Bedingung Zahl enthaelt, immer sal_False, ausser bei "ungleich"
775 
776     if ( !bIsStr1 )
777         return ( eOp == SC_COND_NOTEQUAL );
778     if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
779         if ( !bIsStr2 )
780             return sal_False;
781 
782     String aUpVal1( aStrVal1 );     //! als Member? (dann auch in Interpret setzen)
783     String aUpVal2( aStrVal2 );
784 
785     if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
786         if ( ScGlobal::GetCollator()->compareString( aUpVal1, aUpVal2 )
787                 == COMPARE_GREATER )
788         {
789             //  richtige Reihenfolge fuer Wertebereich
790             String aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
791         }
792 
793     sal_Bool bValid;
794     switch ( eOp )
795     {
796         case SC_COND_EQUAL:
797             bValid = (ScGlobal::GetCollator()->compareString(
798                 rArg, aUpVal1 ) == COMPARE_EQUAL);
799         break;
800         case SC_COND_NOTEQUAL:
801             bValid = (ScGlobal::GetCollator()->compareString(
802                 rArg, aUpVal1 ) != COMPARE_EQUAL);
803         break;
804         default:
805         {
806             sal_Int32 nCompare = ScGlobal::GetCollator()->compareString(
807                 rArg, aUpVal1 );
808             switch ( eOp )
809             {
810                 case SC_COND_GREATER:
811                     bValid = ( nCompare == COMPARE_GREATER );
812                     break;
813                 case SC_COND_EQGREATER:
814                     bValid = ( nCompare == COMPARE_EQUAL || nCompare == COMPARE_GREATER );
815                     break;
816                 case SC_COND_LESS:
817                     bValid = ( nCompare == COMPARE_LESS );
818                     break;
819                 case SC_COND_EQLESS:
820                     bValid = ( nCompare == COMPARE_EQUAL || nCompare == COMPARE_LESS );
821                     break;
822                 case SC_COND_BETWEEN:
823                 case SC_COND_NOTBETWEEN:
824                     //  Test auf NOTBETWEEN:
825                     bValid = ( nCompare == COMPARE_LESS ||
826                         ScGlobal::GetCollator()->compareString( rArg,
827                         aUpVal2 ) == COMPARE_GREATER );
828                     if ( eOp == SC_COND_BETWEEN )
829                         bValid = !bValid;
830                     break;
831                 //  SC_COND_DIRECT schon oben abgefragt
832                 default:
833                     DBG_ERROR("unbekannte Operation bei ScConditionEntry");
834                     bValid = sal_False;
835                     break;
836             }
837         }
838     }
839     return bValid;
840 }
841 
842 sal_Bool ScConditionEntry::IsCellValid( ScBaseCell* pCell, const ScAddress& rPos ) const
843 {
844     ((ScConditionEntry*)this)->Interpret(rPos);         // Formeln auswerten
845 
846     double nArg = 0.0;
847     String aArgStr;
848     sal_Bool bVal = sal_True;
849 
850     if ( pCell )
851     {
852         CellType eType = pCell->GetCellType();
853         switch (eType)
854         {
855             case CELLTYPE_VALUE:
856                 nArg = ((ScValueCell*)pCell)->GetValue();
857                 break;
858             case CELLTYPE_FORMULA:
859                 {
860                     ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
861                     bVal = pFCell->IsValue();
862                     if (bVal)
863                         nArg = pFCell->GetValue();
864                     else
865                         pFCell->GetString(aArgStr);
866                 }
867                 break;
868             case CELLTYPE_STRING:
869             case CELLTYPE_EDIT:
870                 bVal = sal_False;
871                 if ( eType == CELLTYPE_STRING )
872                     ((ScStringCell*)pCell)->GetString(aArgStr);
873                 else
874                     ((ScEditCell*)pCell)->GetString(aArgStr);
875                 break;
876 
877             default:
878                 pCell = NULL;           // Note-Zellen wie leere
879                 break;
880         }
881     }
882 
883     if (!pCell)
884         if (bIsStr1)
885             bVal = sal_False;               // leere Zellen je nach Bedingung
886 
887     if (bVal)
888         return IsValid( nArg );
889     else
890         return IsValidStr( aArgStr );
891 }
892 
893 String ScConditionEntry::GetExpression( const ScAddress& rCursor, sal_uInt16 nIndex,
894                                         sal_uLong nNumFmt,
895                                         const FormulaGrammar::Grammar eGrammar ) const
896 {
897     String aRet;
898 
899     if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 )
900         nNumFmt = pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US );
901 
902     if ( nIndex==0 )
903     {
904         if ( pFormula1 )
905         {
906             ScCompiler aComp(pDoc, rCursor, *pFormula1);
907             aComp.SetGrammar(eGrammar);
908             aComp.CreateStringFromTokenArray( aRet );
909         }
910         else if (bIsStr1)
911         {
912             aRet = '"';
913             aRet += aStrVal1;
914             aRet += '"';
915         }
916         else
917             pDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet);
918     }
919     else if ( nIndex==1 )
920     {
921         if ( pFormula2 )
922         {
923             ScCompiler aComp(pDoc, rCursor, *pFormula2);
924             aComp.SetGrammar(eGrammar);
925             aComp.CreateStringFromTokenArray( aRet );
926         }
927         else if (bIsStr2)
928         {
929             aRet = '"';
930             aRet += aStrVal2;
931             aRet += '"';
932         }
933         else
934             pDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet);
935     }
936     else
937     {
938         DBG_ERROR("GetExpression: falscher Index");
939     }
940 
941     return aRet;
942 }
943 
944 ScTokenArray* ScConditionEntry::CreateTokenArry( sal_uInt16 nIndex ) const
945 {
946     ScTokenArray* pRet = NULL;
947     ScAddress aAddr;
948 
949     if ( nIndex==0 )
950     {
951         if ( pFormula1 )
952             pRet = new ScTokenArray( *pFormula1 );
953         else
954         {
955             pRet = new ScTokenArray();
956             if (bIsStr1)
957                 pRet->AddString( aStrVal1.GetBuffer() );
958             else
959                 pRet->AddDouble( nVal1 );
960         }
961     }
962     else if ( nIndex==1 )
963     {
964         if ( pFormula2 )
965             pRet = new ScTokenArray( *pFormula2 );
966         else
967         {
968             pRet = new ScTokenArray();
969             if (bIsStr2)
970                 pRet->AddString( aStrVal2.GetBuffer() );
971             else
972                 pRet->AddDouble( nVal2 );
973         }
974     }
975     else
976     {
977         DBG_ERROR("GetExpression: falscher Index");
978     }
979 
980     return pRet;
981 }
982 
983 void ScConditionEntry::SourceChanged( const ScAddress& rChanged )
984 {
985     for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
986     {
987         ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
988         if (pFormula)
989         {
990             pFormula->Reset();
991             ScToken* t;
992             while ( ( t = static_cast<ScToken*>(pFormula->GetNextReference()) ) != NULL )
993             {
994                 SingleDoubleRefProvider aProv( *t );
995                 if ( aProv.Ref1.IsColRel() || aProv.Ref1.IsRowRel() || aProv.Ref1.IsTabRel() ||
996                      aProv.Ref2.IsColRel() || aProv.Ref2.IsRowRel() || aProv.Ref2.IsTabRel() )
997                 {
998                     //  absolut muss getroffen sein, relativ bestimmt Bereich
999 
1000                     sal_Bool bHit = sal_True;
1001                     SCsCOL nCol1;
1002                     SCsROW nRow1;
1003                     SCsTAB nTab1;
1004                     SCsCOL nCol2;
1005                     SCsROW nRow2;
1006                     SCsTAB nTab2;
1007 
1008                     if ( aProv.Ref1.IsColRel() )
1009                         nCol2 = rChanged.Col() - aProv.Ref1.nRelCol;
1010                     else
1011                     {
1012                         bHit &= ( rChanged.Col() >= aProv.Ref1.nCol );
1013                         nCol2 = MAXCOL;
1014                     }
1015                     if ( aProv.Ref1.IsRowRel() )
1016                         nRow2 = rChanged.Row() - aProv.Ref1.nRelRow;
1017                     else
1018                     {
1019                         bHit &= ( rChanged.Row() >= aProv.Ref1.nRow );
1020                         nRow2 = MAXROW;
1021                     }
1022                     if ( aProv.Ref1.IsTabRel() )
1023                         nTab2 = rChanged.Tab() - aProv.Ref1.nRelTab;
1024                     else
1025                     {
1026                         bHit &= ( rChanged.Tab() >= aProv.Ref1.nTab );
1027                         nTab2 = MAXTAB;
1028                     }
1029 
1030                     if ( aProv.Ref2.IsColRel() )
1031                         nCol1 = rChanged.Col() - aProv.Ref2.nRelCol;
1032                     else
1033                     {
1034                         bHit &= ( rChanged.Col() <= aProv.Ref2.nCol );
1035                         nCol1 = 0;
1036                     }
1037                     if ( aProv.Ref2.IsRowRel() )
1038                         nRow1 = rChanged.Row() - aProv.Ref2.nRelRow;
1039                     else
1040                     {
1041                         bHit &= ( rChanged.Row() <= aProv.Ref2.nRow );
1042                         nRow1 = 0;
1043                     }
1044                     if ( aProv.Ref2.IsTabRel() )
1045                         nTab1 = rChanged.Tab() - aProv.Ref2.nRelTab;
1046                     else
1047                     {
1048                         bHit &= ( rChanged.Tab() <= aProv.Ref2.nTab );
1049                         nTab1 = 0;
1050                     }
1051 
1052                     if ( bHit )
1053                     {
1054                         //! begrenzen
1055 
1056                         ScRange aPaint( nCol1,nRow1,nTab1, nCol2,nRow2,nTab2 );
1057 
1058                         //  kein Paint, wenn es nur die Zelle selber ist
1059                         if ( aPaint.aStart != rChanged || aPaint.aEnd != rChanged )
1060                             DataChanged( &aPaint );
1061                     }
1062                 }
1063             }
1064         }
1065     }
1066 }
1067 
1068 ScAddress ScConditionEntry::GetValidSrcPos() const
1069 {
1070     // return a position that's adjusted to allow textual representation of expressions if possible
1071 
1072     SCTAB nMinTab = aSrcPos.Tab();
1073     SCTAB nMaxTab = nMinTab;
1074 
1075     for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1076     {
1077         ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1078         if (pFormula)
1079         {
1080             pFormula->Reset();
1081             ScToken* t;
1082             while ( ( t = static_cast<ScToken*>(pFormula->GetNextReference()) ) != NULL )
1083             {
1084                 ScSingleRefData& rRef1 = t->GetSingleRef();
1085                 if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
1086                 {
1087                     if ( rRef1.nTab < nMinTab )
1088                         nMinTab = rRef1.nTab;
1089                     if ( rRef1.nTab > nMaxTab )
1090                         nMaxTab = rRef1.nTab;
1091                 }
1092                 if ( t->GetType() == svDoubleRef )
1093                 {
1094                     ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
1095                     if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
1096                     {
1097                         if ( rRef2.nTab < nMinTab )
1098                             nMinTab = rRef2.nTab;
1099                         if ( rRef2.nTab > nMaxTab )
1100                             nMaxTab = rRef2.nTab;
1101                     }
1102                 }
1103             }
1104         }
1105     }
1106 
1107     ScAddress aValidPos = aSrcPos;
1108     SCTAB nTabCount = pDoc->GetTableCount();
1109     if ( nMaxTab >= nTabCount && nMinTab > 0 )
1110         aValidPos.SetTab( aSrcPos.Tab() - nMinTab );    // so the lowest tab ref will be on 0
1111 
1112     if ( aValidPos.Tab() >= nTabCount )
1113         aValidPos.SetTab( nTabCount - 1 );  // ensure a valid position even if some references will be invalid
1114 
1115     return aValidPos;
1116 }
1117 
1118 void ScConditionEntry::DataChanged( const ScRange* /* pModified */ ) const
1119 {
1120     // nix
1121 }
1122 
1123 bool ScConditionEntry::MarkUsedExternalReferences() const
1124 {
1125     bool bAllMarked = false;
1126     for (sal_uInt16 nPass = 0; !bAllMarked && nPass < 2; nPass++)
1127     {
1128         ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1129         if (pFormula)
1130             bAllMarked = pDoc->MarkUsedExternalReferences( *pFormula);
1131     }
1132     return bAllMarked;
1133 }
1134 
1135 //------------------------------------------------------------------------
1136 
1137 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
1138                                         const String& rExpr1, const String& rExpr2,
1139                                         ScDocument* pDocument, const ScAddress& rPos,
1140                                         const String& rStyle,
1141                                         const String& rExprNmsp1, const String& rExprNmsp2,
1142                                         FormulaGrammar::Grammar eGrammar1,
1143                                         FormulaGrammar::Grammar eGrammar2 ) :
1144     ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ),
1145     aStyleName( rStyle ),
1146     pParent( NULL )
1147 {
1148 }
1149 
1150 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
1151                                         const ScTokenArray* pArr1, const ScTokenArray* pArr2,
1152                                         ScDocument* pDocument, const ScAddress& rPos,
1153                                         const String& rStyle ) :
1154     ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos ),
1155     aStyleName( rStyle ),
1156     pParent( NULL )
1157 {
1158 }
1159 
1160 ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry& r ) :
1161     ScConditionEntry( r ),
1162     aStyleName( r.aStyleName ),
1163     pParent( NULL )
1164 {
1165 }
1166 
1167 ScCondFormatEntry::ScCondFormatEntry( ScDocument* pDocument, const ScCondFormatEntry& r ) :
1168     ScConditionEntry( pDocument, r ),
1169     aStyleName( r.aStyleName ),
1170     pParent( NULL )
1171 {
1172 }
1173 
1174 int ScCondFormatEntry::operator== ( const ScCondFormatEntry& r ) const
1175 {
1176     return ScConditionEntry::operator==( r ) &&
1177             aStyleName == r.aStyleName;
1178 
1179     //  Range wird nicht verglichen
1180 }
1181 
1182 ScCondFormatEntry::~ScCondFormatEntry()
1183 {
1184 }
1185 
1186 void ScCondFormatEntry::DataChanged( const ScRange* pModified ) const
1187 {
1188     if ( pParent )
1189         pParent->DoRepaint( pModified );
1190 }
1191 
1192 //------------------------------------------------------------------------
1193 
1194 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
1195     pDoc( pDocument ),
1196     pAreas( NULL ),
1197     nKey( nNewKey ),
1198     ppEntries( NULL ),
1199     nEntryCount( 0 )
1200 {
1201 }
1202 
1203 ScConditionalFormat::ScConditionalFormat(const ScConditionalFormat& r) :
1204     pDoc( r.pDoc ),
1205     pAreas( NULL ),
1206     nKey( r.nKey ),
1207     ppEntries( NULL ),
1208     nEntryCount( r.nEntryCount )
1209 {
1210     if (nEntryCount)
1211     {
1212         ppEntries = new ScCondFormatEntry*[nEntryCount];
1213         for (sal_uInt16 i=0; i<nEntryCount; i++)
1214         {
1215             ppEntries[i] = new ScCondFormatEntry(*r.ppEntries[i]);
1216             ppEntries[i]->SetParent(this);
1217         }
1218     }
1219 }
1220 
1221 ScConditionalFormat* ScConditionalFormat::Clone(ScDocument* pNewDoc) const
1222 {
1223     // echte Kopie der Formeln (fuer Ref-Undo / zwischen Dokumenten)
1224 
1225     if (!pNewDoc)
1226         pNewDoc = pDoc;
1227 
1228     ScConditionalFormat* pNew = new ScConditionalFormat(nKey, pNewDoc);
1229     DBG_ASSERT(!pNew->ppEntries, "wo kommen die Eintraege her?");
1230 
1231     if (nEntryCount)
1232     {
1233         pNew->ppEntries = new ScCondFormatEntry*[nEntryCount];
1234         for (sal_uInt16 i=0; i<nEntryCount; i++)
1235         {
1236             pNew->ppEntries[i] = new ScCondFormatEntry( pNewDoc, *ppEntries[i] );
1237             pNew->ppEntries[i]->SetParent(pNew);
1238         }
1239         pNew->nEntryCount = nEntryCount;
1240     }
1241 
1242     return pNew;
1243 }
1244 
1245 sal_Bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const
1246 {
1247     if ( nEntryCount != r.nEntryCount )
1248         return sal_False;
1249 
1250     //! auf gleiche Eintraege in anderer Reihenfolge testen ???
1251 
1252     for (sal_uInt16 i=0; i<nEntryCount; i++)
1253         if ( ! (*ppEntries[i] == *r.ppEntries[i]) )
1254             return sal_False;
1255 
1256     return sal_True;
1257 }
1258 
1259 void ScConditionalFormat::AddEntry( const ScCondFormatEntry& rNew )
1260 {
1261     ScCondFormatEntry** ppNew = new ScCondFormatEntry*[nEntryCount+1];
1262     for (sal_uInt16 i=0; i<nEntryCount; i++)
1263         ppNew[i] = ppEntries[i];
1264     ppNew[nEntryCount] = new ScCondFormatEntry(rNew);
1265     ppNew[nEntryCount]->SetParent(this);
1266     ++nEntryCount;
1267     delete[] ppEntries;
1268     ppEntries = ppNew;
1269 }
1270 
1271 ScConditionalFormat::~ScConditionalFormat()
1272 {
1273     for (sal_uInt16 i=0; i<nEntryCount; i++)
1274         delete ppEntries[i];
1275     delete[] ppEntries;
1276 
1277     delete pAreas;
1278 }
1279 
1280 const ScCondFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const
1281 {
1282     if ( nPos < nEntryCount )
1283         return ppEntries[nPos];
1284     else
1285         return NULL;
1286 }
1287 
1288 const String& ScConditionalFormat::GetCellStyle( ScBaseCell* pCell, const ScAddress& rPos ) const
1289 {
1290     for (sal_uInt16 i=0; i<nEntryCount; i++)
1291         if ( ppEntries[i]->IsCellValid( pCell, rPos ) )
1292             return ppEntries[i]->GetStyle();
1293 
1294     return EMPTY_STRING;
1295 }
1296 
1297 void lcl_Extend( ScRange& rRange, ScDocument* pDoc, sal_Bool bLines )
1298 {
1299     SCTAB nTab = rRange.aStart.Tab();
1300     DBG_ASSERT(rRange.aEnd.Tab() == nTab, "lcl_Extend - mehrere Tabellen?");
1301 
1302     SCCOL nStartCol = rRange.aStart.Col();
1303     SCROW nStartRow = rRange.aStart.Row();
1304     SCCOL nEndCol = rRange.aEnd.Col();
1305     SCROW nEndRow = rRange.aEnd.Row();
1306 
1307     sal_Bool bEx = pDoc->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab );
1308 
1309     if (bLines)
1310     {
1311         if (nStartCol > 0)    --nStartCol;
1312         if (nStartRow > 0)    --nStartRow;
1313         if (nEndCol < MAXCOL) ++nEndCol;
1314         if (nEndRow < MAXROW) ++nEndRow;
1315     }
1316 
1317     if ( bEx || bLines )
1318     {
1319         rRange.aStart.Set( nStartCol, nStartRow, nTab );
1320         rRange.aEnd.Set( nEndCol, nEndRow, nTab );
1321     }
1322 }
1323 
1324 sal_Bool lcl_CutRange( ScRange& rRange, const ScRange& rOther )
1325 {
1326     rRange.Justify();
1327     ScRange aCmpRange = rOther;
1328     aCmpRange.Justify();
1329 
1330     if ( rRange.aStart.Col() <= aCmpRange.aEnd.Col() &&
1331          rRange.aEnd.Col() >= aCmpRange.aStart.Col() &&
1332          rRange.aStart.Row() <= aCmpRange.aEnd.Row() &&
1333          rRange.aEnd.Row() >= aCmpRange.aStart.Row() &&
1334          rRange.aStart.Tab() <= aCmpRange.aEnd.Tab() &&
1335          rRange.aEnd.Tab() >= aCmpRange.aStart.Tab() )
1336     {
1337         if ( rRange.aStart.Col() < aCmpRange.aStart.Col() )
1338             rRange.aStart.SetCol( aCmpRange.aStart.Col() );
1339         if ( rRange.aStart.Row() < aCmpRange.aStart.Row() )
1340             rRange.aStart.SetRow( aCmpRange.aStart.Row() );
1341         if ( rRange.aStart.Tab() < aCmpRange.aStart.Tab() )
1342             rRange.aStart.SetTab( aCmpRange.aStart.Tab() );
1343         if ( rRange.aEnd.Col() > aCmpRange.aEnd.Col() )
1344             rRange.aEnd.SetCol( aCmpRange.aEnd.Col() );
1345         if ( rRange.aEnd.Row() > aCmpRange.aEnd.Row() )
1346             rRange.aEnd.SetRow( aCmpRange.aEnd.Row() );
1347         if ( rRange.aEnd.Tab() > aCmpRange.aEnd.Tab() )
1348             rRange.aEnd.SetTab( aCmpRange.aEnd.Tab() );
1349 
1350         return sal_True;
1351     }
1352 
1353     return sal_False;       // ausserhalb
1354 }
1355 
1356 void ScConditionalFormat::DoRepaint( const ScRange* pModified )
1357 {
1358     sal_uInt16 i;
1359     SfxObjectShell* pSh = pDoc->GetDocumentShell();
1360     if (pSh)
1361     {
1362         //  Rahmen/Schatten enthalten?
1363         //  (alle Bedingungen testen)
1364         sal_Bool bExtend = sal_False;
1365         sal_Bool bRotate = sal_False;
1366         sal_Bool bAttrTested = sal_False;
1367 
1368         if (!pAreas)        //  RangeList ggf. holen
1369         {
1370             pAreas = new ScRangeList;
1371             pDoc->FindConditionalFormat( nKey, *pAreas );
1372         }
1373         sal_uInt16 nCount = (sal_uInt16) pAreas->Count();
1374         for (i=0; i<nCount; i++)
1375         {
1376             ScRange aRange = *pAreas->GetObject(i);
1377             sal_Bool bDo = sal_True;
1378             if ( pModified )
1379             {
1380                 if ( !lcl_CutRange( aRange, *pModified ) )
1381                     bDo = sal_False;
1382             }
1383             if (bDo)
1384             {
1385                 if ( !bAttrTested )
1386                 {
1387                     // #116562# Look at the style's content only if the repaint is necessary
1388                     // for any condition, to avoid the time-consuming Find() if there are many
1389                     // conditional formats and styles.
1390                     for (sal_uInt16 nEntry=0; nEntry<nEntryCount; nEntry++)
1391                     {
1392                         String aStyle = ppEntries[nEntry]->GetStyle();
1393                         if (aStyle.Len())
1394                         {
1395                             SfxStyleSheetBase* pStyleSheet =
1396                                 pDoc->GetStyleSheetPool()->Find( aStyle, SFX_STYLE_FAMILY_PARA );
1397                             if ( pStyleSheet )
1398                             {
1399                                 const SfxItemSet& rSet = pStyleSheet->GetItemSet();
1400                                 if (rSet.GetItemState( ATTR_BORDER, sal_True ) == SFX_ITEM_SET ||
1401                                     rSet.GetItemState( ATTR_SHADOW, sal_True ) == SFX_ITEM_SET)
1402                                 {
1403                                     bExtend = sal_True;
1404                                 }
1405                                 if (rSet.GetItemState( ATTR_ROTATE_VALUE, sal_True ) == SFX_ITEM_SET ||
1406                                     rSet.GetItemState( ATTR_ROTATE_MODE, sal_True ) == SFX_ITEM_SET)
1407                                 {
1408                                     bRotate = sal_True;
1409                                 }
1410                             }
1411                         }
1412                     }
1413                     bAttrTested = sal_True;
1414                 }
1415 
1416                 lcl_Extend( aRange, pDoc, bExtend );        // zusammengefasste und bExtend
1417                 if ( bRotate )
1418                 {
1419                     aRange.aStart.SetCol(0);
1420                     aRange.aEnd.SetCol(MAXCOL);     // gedreht: ganze Zeilen
1421                 }
1422 
1423                 // gedreht -> ganze Zeilen
1424                 if ( aRange.aStart.Col() != 0 || aRange.aEnd.Col() != MAXCOL )
1425                 {
1426                     if ( pDoc->HasAttrib( 0,aRange.aStart.Row(),aRange.aStart.Tab(),
1427                                             MAXCOL,aRange.aEnd.Row(),aRange.aEnd.Tab(),
1428                                             HASATTR_ROTATE ) )
1429                     {
1430                         aRange.aStart.SetCol(0);
1431                         aRange.aEnd.SetCol(MAXCOL);
1432                     }
1433                 }
1434 
1435                 pDoc->RepaintRange( aRange );
1436             }
1437         }
1438     }
1439 }
1440 
1441 void ScConditionalFormat::InvalidateArea()
1442 {
1443     delete pAreas;
1444     pAreas = NULL;
1445 }
1446 
1447 void ScConditionalFormat::CompileAll()
1448 {
1449     for (sal_uInt16 i=0; i<nEntryCount; i++)
1450         ppEntries[i]->CompileAll();
1451 }
1452 
1453 void ScConditionalFormat::CompileXML()
1454 {
1455     for (sal_uInt16 i=0; i<nEntryCount; i++)
1456         ppEntries[i]->CompileXML();
1457 }
1458 
1459 void ScConditionalFormat::UpdateReference( UpdateRefMode eUpdateRefMode,
1460                                 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
1461 {
1462     for (sal_uInt16 i=0; i<nEntryCount; i++)
1463         ppEntries[i]->UpdateReference(eUpdateRefMode, rRange, nDx, nDy, nDz);
1464 
1465     delete pAreas;      // aus dem AttrArray kommt beim Einfuegen/Loeschen kein Aufruf
1466     pAreas = NULL;
1467 }
1468 
1469 void ScConditionalFormat::RenameCellStyle(const String& rOld, const String& rNew)
1470 {
1471     for (sal_uInt16 i=0; i<nEntryCount; i++)
1472         if ( ppEntries[i]->GetStyle() == rOld )
1473             ppEntries[i]->UpdateStyleName( rNew );
1474 }
1475 
1476 void ScConditionalFormat::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
1477 {
1478     for (sal_uInt16 i=0; i<nEntryCount; i++)
1479         ppEntries[i]->UpdateMoveTab( nOldPos, nNewPos );
1480 
1481     delete pAreas;      // aus dem AttrArray kommt beim Einfuegen/Loeschen kein Aufruf
1482     pAreas = NULL;
1483 }
1484 
1485 void ScConditionalFormat::SourceChanged( const ScAddress& rAddr )
1486 {
1487     for (sal_uInt16 i=0; i<nEntryCount; i++)
1488         ppEntries[i]->SourceChanged( rAddr );
1489 }
1490 
1491 bool ScConditionalFormat::MarkUsedExternalReferences() const
1492 {
1493     bool bAllMarked = false;
1494     for (sal_uInt16 i=0; !bAllMarked && i<nEntryCount; i++)
1495         bAllMarked = ppEntries[i]->MarkUsedExternalReferences();
1496     return bAllMarked;
1497 }
1498 
1499 //------------------------------------------------------------------------
1500 
1501 ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList& rList) :
1502     ScConditionalFormats_Impl()
1503 {
1504     //  fuer Ref-Undo - echte Kopie mit neuen Tokens!
1505 
1506     sal_uInt16 nCount = rList.Count();
1507 
1508     for (sal_uInt16 i=0; i<nCount; i++)
1509         InsertNew( rList[i]->Clone() );
1510 
1511     //!     sortierte Eintraege aus rList schneller einfuegen ???
1512 }
1513 
1514 ScConditionalFormatList::ScConditionalFormatList(ScDocument* pNewDoc,
1515                                                 const ScConditionalFormatList& rList)
1516 {
1517     //  fuer neues Dokument - echte Kopie mit neuen Tokens!
1518 
1519     sal_uInt16 nCount = rList.Count();
1520 
1521     for (sal_uInt16 i=0; i<nCount; i++)
1522         InsertNew( rList[i]->Clone(pNewDoc) );
1523 
1524     //!     sortierte Eintraege aus rList schneller einfuegen ???
1525 }
1526 
1527 sal_Bool ScConditionalFormatList::operator==( const ScConditionalFormatList& r ) const
1528 {
1529     // fuer Ref-Undo - interne Variablen werden nicht verglichen
1530 
1531     sal_uInt16 nCount = Count();
1532     sal_Bool bEqual = ( nCount == r.Count() );
1533     for (sal_uInt16 i=0; i<nCount && bEqual; i++)           // Eintraege sind sortiert
1534         if ( !(*this)[i]->EqualEntries(*r[i]) )         // Eintraege unterschiedlich ?
1535             bEqual = sal_False;
1536 
1537     return bEqual;
1538 }
1539 
1540 ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey )
1541 {
1542     //! binaer suchen
1543 
1544     sal_uInt16 nCount = Count();
1545     for (sal_uInt16 i=0; i<nCount; i++)
1546         if ((*this)[i]->GetKey() == nKey)
1547             return (*this)[i];
1548 
1549     DBG_ERROR("ScConditionalFormatList: Eintrag nicht gefunden");
1550     return NULL;
1551 }
1552 
1553 void ScConditionalFormatList::CompileAll()
1554 {
1555     sal_uInt16 nCount = Count();
1556     for (sal_uInt16 i=0; i<nCount; i++)
1557         (*this)[i]->CompileAll();
1558 }
1559 
1560 void ScConditionalFormatList::CompileXML()
1561 {
1562     sal_uInt16 nCount = Count();
1563     for (sal_uInt16 i=0; i<nCount; i++)
1564         (*this)[i]->CompileXML();
1565 }
1566 
1567 void ScConditionalFormatList::UpdateReference( UpdateRefMode eUpdateRefMode,
1568                                 const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
1569 {
1570     sal_uInt16 nCount = Count();
1571     for (sal_uInt16 i=0; i<nCount; i++)
1572         (*this)[i]->UpdateReference( eUpdateRefMode, rRange, nDx, nDy, nDz );
1573 }
1574 
1575 void ScConditionalFormatList::RenameCellStyle( const String& rOld, const String& rNew )
1576 {
1577     sal_uLong nCount=Count();
1578     for (sal_uInt16 i=0; i<nCount; i++)
1579         (*this)[i]->RenameCellStyle(rOld,rNew);
1580 }
1581 
1582 void ScConditionalFormatList::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
1583 {
1584     sal_uInt16 nCount = Count();
1585     for (sal_uInt16 i=0; i<nCount; i++)
1586         (*this)[i]->UpdateMoveTab( nOldPos, nNewPos );
1587 }
1588 
1589 void ScConditionalFormatList::SourceChanged( const ScAddress& rAddr )
1590 {
1591     sal_uInt16 nCount = Count();
1592     for (sal_uInt16 i=0; i<nCount; i++)
1593         (*this)[i]->SourceChanged( rAddr );
1594 }
1595 
1596 bool ScConditionalFormatList::MarkUsedExternalReferences() const
1597 {
1598     bool bAllMarked = false;
1599     sal_uInt16 nCount = Count();
1600     for (sal_uInt16 i=0; !bAllMarked && i<nCount; i++)
1601         bAllMarked = (*this)[i]->MarkUsedExternalReferences();
1602     return bAllMarked;
1603 }
1604