xref: /aoo41x/main/sc/source/core/data/conditio.cxx (revision cdf0e10c)
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