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