Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "scitems.hxx"
21 : #include <sfx2/objsh.hxx>
22 : #include <svl/itemset.hxx>
23 : #include <svl/zforlist.hxx>
24 : #include <rtl/math.hxx>
25 : #include <unotools/collatorwrapper.hxx>
26 :
27 : #include <com/sun/star/sheet/ConditionOperator2.hpp>
28 :
29 : #include "conditio.hxx"
30 : #include "formulacell.hxx"
31 : #include "document.hxx"
32 : #include "hints.hxx"
33 : #include "compiler.hxx"
34 : #include "rechead.hxx"
35 : #include "rangelst.hxx"
36 : #include "stlpool.hxx"
37 : #include "rangenam.hxx"
38 : #include "colorscale.hxx"
39 : #include "cellvalue.hxx"
40 : #include "editutil.hxx"
41 : #include "tokenarray.hxx"
42 : #include "refupdatecontext.hxx"
43 : #include <svl/sharedstring.hxx>
44 : #include <svl/sharedstringpool.hxx>
45 : #include <boost/scoped_ptr.hpp>
46 :
47 : using namespace formula;
48 :
49 668 : ScFormatEntry::ScFormatEntry(ScDocument* pDoc):
50 668 : mpDoc(pDoc)
51 : {
52 668 : }
53 :
54 0 : bool ScFormatEntry::operator==( const ScFormatEntry& r ) const
55 : {
56 0 : if(GetType() != r.GetType())
57 0 : return false;
58 :
59 0 : switch(GetType())
60 : {
61 : case condformat::CONDITION:
62 0 : return static_cast<const ScCondFormatEntry&>(*this) == static_cast<const ScCondFormatEntry&>(r);
63 : default:
64 : // TODO: implement also this case
65 : // actually return false for these cases is not that bad
66 : // as soon as databar and color scale are tested we need
67 : // to think about the range
68 0 : return false;
69 : }
70 : }
71 :
72 0 : void ScFormatEntry::startRendering()
73 : {
74 0 : }
75 :
76 0 : void ScFormatEntry::endRendering()
77 : {
78 0 : }
79 :
80 366 : static bool lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, sal_uInt16 nRecursion = 0 )
81 : {
82 366 : if (pFormula)
83 : {
84 66 : pFormula->Reset();
85 : FormulaToken* t;
86 122 : for( t = pFormula->Next(); t; t = pFormula->Next() )
87 : {
88 102 : switch( t->GetType() )
89 : {
90 : case svDoubleRef:
91 : {
92 16 : ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
93 16 : if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
94 14 : return true;
95 : }
96 : // fall through
97 :
98 : case svSingleRef:
99 : {
100 38 : ScSingleRefData& rRef1 = *t->GetSingleRef();
101 38 : if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
102 32 : return true;
103 : }
104 6 : break;
105 :
106 : case svIndex:
107 : {
108 2 : if( t->GetOpCode() == ocName ) // DB areas always absolute
109 2 : if( ScRangeData* pRangeData = pDoc->GetRangeName()->findByIndex( t->GetIndex() ) )
110 2 : if( (nRecursion < 42) && lcl_HasRelRef( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
111 0 : return true;
112 : }
113 2 : break;
114 :
115 : // #i34474# function result dependent on cell position
116 : case svByte:
117 : {
118 24 : switch( t->GetOpCode() )
119 : {
120 : case ocRow: // ROW() returns own row index
121 : case ocColumn: // COLUMN() returns own column index
122 : case ocTable: // SHEET() returns own sheet index
123 : case ocCell: // CELL() may return own cell address
124 0 : return true;
125 : // break;
126 : default:
127 : {
128 : // added to avoid warnings
129 : }
130 : }
131 : }
132 24 : break;
133 :
134 : default:
135 : {
136 : // added to avoid warnings
137 : }
138 : }
139 : }
140 : }
141 320 : return false;
142 : }
143 :
144 6 : ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) :
145 : ScFormatEntry(r.mpDoc),
146 : eOp(r.eOp),
147 : nOptions(r.nOptions),
148 : nVal1(r.nVal1),
149 : nVal2(r.nVal2),
150 : aStrVal1(r.aStrVal1),
151 : aStrVal2(r.aStrVal2),
152 : aStrNmsp1(r.aStrNmsp1),
153 : aStrNmsp2(r.aStrNmsp2),
154 : eTempGrammar1(r.eTempGrammar1),
155 : eTempGrammar2(r.eTempGrammar2),
156 : bIsStr1(r.bIsStr1),
157 : bIsStr2(r.bIsStr2),
158 : pFormula1(NULL),
159 : pFormula2(NULL),
160 : aSrcPos(r.aSrcPos),
161 : aSrcString(r.aSrcString),
162 : pFCell1(NULL),
163 : pFCell2(NULL),
164 : bRelRef1(r.bRelRef1),
165 : bRelRef2(r.bRelRef2),
166 : bFirstRun(true),
167 6 : pCondFormat(r.pCondFormat)
168 : {
169 : // ScTokenArray copy ctor creates a flat copy
170 6 : if (r.pFormula1)
171 2 : pFormula1 = new ScTokenArray( *r.pFormula1 );
172 6 : if (r.pFormula2)
173 0 : pFormula2 = new ScTokenArray( *r.pFormula2 );
174 :
175 : // Formula cells are created at IsValid
176 6 : }
177 :
178 124 : ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntry& r ) :
179 : ScFormatEntry(pDocument),
180 : eOp(r.eOp),
181 : nOptions(r.nOptions),
182 : nVal1(r.nVal1),
183 : nVal2(r.nVal2),
184 : aStrVal1(r.aStrVal1),
185 : aStrVal2(r.aStrVal2),
186 : aStrNmsp1(r.aStrNmsp1),
187 : aStrNmsp2(r.aStrNmsp2),
188 : eTempGrammar1(r.eTempGrammar1),
189 : eTempGrammar2(r.eTempGrammar2),
190 : bIsStr1(r.bIsStr1),
191 : bIsStr2(r.bIsStr2),
192 : pFormula1(NULL),
193 : pFormula2(NULL),
194 : aSrcPos(r.aSrcPos),
195 : aSrcString(r.aSrcString),
196 : pFCell1(NULL),
197 : pFCell2(NULL),
198 : bRelRef1(r.bRelRef1),
199 : bRelRef2(r.bRelRef2),
200 : bFirstRun(true),
201 124 : pCondFormat(r.pCondFormat)
202 : {
203 : // Real copy of the formulas (for Ref Undo)
204 124 : if (r.pFormula1)
205 78 : pFormula1 = r.pFormula1->Clone();
206 124 : if (r.pFormula2)
207 26 : pFormula2 = r.pFormula2->Clone();
208 :
209 : // Formula cells are created at IsValid
210 : // TODO: But not in the Clipboard! So interpret beforehand!
211 124 : }
212 :
213 334 : ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
214 : const OUString& rExpr1, const OUString& rExpr2, ScDocument* pDocument, const ScAddress& rPos,
215 : const OUString& rExprNmsp1, const OUString& rExprNmsp2,
216 : FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2 ) :
217 : ScFormatEntry(pDocument),
218 : eOp(eOper),
219 : nOptions(0),
220 : nVal1(0.0),
221 : nVal2(0.0),
222 : aStrNmsp1(rExprNmsp1),
223 : aStrNmsp2(rExprNmsp2),
224 : eTempGrammar1(eGrammar1),
225 : eTempGrammar2(eGrammar2),
226 : bIsStr1(false),
227 : bIsStr2(false),
228 : pFormula1(NULL),
229 : pFormula2(NULL),
230 : aSrcPos(rPos),
231 : pFCell1(NULL),
232 : pFCell2(NULL),
233 : bRelRef1(false),
234 : bRelRef2(false),
235 : bFirstRun(true),
236 334 : pCondFormat(NULL)
237 : {
238 334 : Compile( rExpr1, rExpr2, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2, false );
239 :
240 : // Formula cells are created at IsValid
241 334 : }
242 :
243 70 : ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
244 : const ScTokenArray* pArr1, const ScTokenArray* pArr2,
245 : ScDocument* pDocument, const ScAddress& rPos ) :
246 : ScFormatEntry(pDocument),
247 : eOp(eOper),
248 : nOptions(0),
249 : nVal1(0.0),
250 : nVal2(0.0),
251 : eTempGrammar1(FormulaGrammar::GRAM_DEFAULT),
252 : eTempGrammar2(FormulaGrammar::GRAM_DEFAULT),
253 : bIsStr1(false),
254 : bIsStr2(false),
255 : pFormula1(NULL),
256 : pFormula2(NULL),
257 : aSrcPos(rPos),
258 : pFCell1(NULL),
259 : pFCell2(NULL),
260 : bRelRef1(false),
261 : bRelRef2(false),
262 : bFirstRun(true),
263 70 : pCondFormat(NULL)
264 : {
265 70 : if ( pArr1 )
266 : {
267 66 : pFormula1 = new ScTokenArray( *pArr1 );
268 66 : if ( pFormula1->GetLen() == 1 )
269 : {
270 : // Single (constant number)?
271 54 : FormulaToken* pToken = pFormula1->First();
272 54 : if ( pToken->GetOpCode() == ocPush )
273 : {
274 52 : if ( pToken->GetType() == svDouble )
275 : {
276 48 : nVal1 = pToken->GetDouble();
277 48 : DELETEZ(pFormula1); // Do not remember as formula
278 : }
279 4 : else if ( pToken->GetType() == svString )
280 : {
281 0 : bIsStr1 = true;
282 0 : aStrVal1 = pToken->GetString().getString();
283 0 : DELETEZ(pFormula1); // Do not remember as formula
284 : }
285 : }
286 : }
287 66 : bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
288 : }
289 70 : if ( pArr2 )
290 : {
291 2 : pFormula2 = new ScTokenArray( *pArr2 );
292 2 : if ( pFormula2->GetLen() == 1 )
293 : {
294 : // Single (constant number)?
295 2 : FormulaToken* pToken = pFormula2->First();
296 2 : if ( pToken->GetOpCode() == ocPush )
297 : {
298 2 : if ( pToken->GetType() == svDouble )
299 : {
300 0 : nVal2 = pToken->GetDouble();
301 0 : DELETEZ(pFormula2); // Do not remember as formula
302 : }
303 2 : else if ( pToken->GetType() == svString )
304 : {
305 0 : bIsStr2 = true;
306 0 : aStrVal2 = pToken->GetString().getString();
307 0 : DELETEZ(pFormula2); // Do not remember as formula
308 : }
309 : }
310 : }
311 2 : bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
312 : }
313 :
314 : // Formula cells are created at IsValid
315 70 : }
316 :
317 1068 : ScConditionEntry::~ScConditionEntry()
318 : {
319 534 : delete pFCell1;
320 534 : delete pFCell2;
321 :
322 534 : delete pFormula1;
323 534 : delete pFormula2;
324 534 : }
325 :
326 452 : void ScConditionEntry::Compile( const OUString& rExpr1, const OUString& rExpr2,
327 : const OUString& rExprNmsp1, const OUString& rExprNmsp2,
328 : FormulaGrammar::Grammar eGrammar1, FormulaGrammar::Grammar eGrammar2, bool bTextToReal )
329 : {
330 452 : if ( !rExpr1.isEmpty() || !rExpr2.isEmpty() )
331 : {
332 344 : ScCompiler aComp( mpDoc, aSrcPos );
333 :
334 344 : if ( !rExpr1.isEmpty() )
335 : {
336 344 : delete pFormula1;
337 344 : aComp.SetGrammar( eGrammar1 );
338 344 : if ( mpDoc->IsImportingXML() && !bTextToReal )
339 : {
340 : // temporary formula string as string tokens
341 : //! merge with lcl_ScDocFunc_CreateTokenArrayXML
342 184 : pFormula1 = new ScTokenArray;
343 184 : pFormula1->AddStringXML( rExpr1 );
344 : // bRelRef1 is set when the formula is compiled again (CompileXML)
345 : }
346 : else
347 : {
348 160 : pFormula1 = aComp.CompileString( rExpr1, rExprNmsp1 );
349 160 : if ( pFormula1->GetLen() == 1 )
350 : {
351 : // Single (constant number)?
352 136 : FormulaToken* pToken = pFormula1->First();
353 136 : if ( pToken->GetOpCode() == ocPush )
354 : {
355 136 : if ( pToken->GetType() == svDouble )
356 : {
357 116 : nVal1 = pToken->GetDouble();
358 116 : DELETEZ(pFormula1); // Do not remember as formula
359 : }
360 20 : else if ( pToken->GetType() == svString )
361 : {
362 0 : bIsStr1 = true;
363 0 : aStrVal1 = pToken->GetString().getString();
364 0 : DELETEZ(pFormula1); // Do not remember as formula
365 : }
366 : }
367 : }
368 160 : bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
369 : }
370 : }
371 :
372 344 : if ( !rExpr2.isEmpty() )
373 : {
374 192 : delete pFormula2;
375 192 : aComp.SetGrammar( eGrammar2 );
376 192 : if ( mpDoc->IsImportingXML() && !bTextToReal )
377 : {
378 : // temporary formula string as string tokens
379 : //! merge with lcl_ScDocFunc_CreateTokenArrayXML
380 56 : pFormula2 = new ScTokenArray;
381 56 : pFormula2->AddStringXML( rExpr2 );
382 : // bRelRef2 is set when the formula is compiled again (CompileXML)
383 : }
384 : else
385 : {
386 136 : pFormula2 = aComp.CompileString( rExpr2, rExprNmsp2 );
387 136 : if ( pFormula2->GetLen() == 1 )
388 : {
389 : // Sigle (constant number)?
390 136 : FormulaToken* pToken = pFormula2->First();
391 136 : if ( pToken->GetOpCode() == ocPush )
392 : {
393 136 : if ( pToken->GetType() == svDouble )
394 : {
395 136 : nVal2 = pToken->GetDouble();
396 136 : DELETEZ(pFormula2); // Do not remember as formula
397 : }
398 0 : else if ( pToken->GetType() == svString )
399 : {
400 0 : bIsStr2 = true;
401 0 : aStrVal2 = pToken->GetString().getString();
402 0 : DELETEZ(pFormula2); // Do not remember as formula
403 : }
404 : }
405 : }
406 136 : bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
407 : }
408 344 : }
409 : }
410 452 : }
411 :
412 : /**
413 : * Create formula cells
414 : */
415 1570 : void ScConditionEntry::MakeCells( const ScAddress& rPos )
416 : {
417 1570 : if ( !mpDoc->IsClipOrUndo() ) // Never calculate in the Clipboard!
418 : {
419 1570 : if ( pFormula1 && !pFCell1 && !bRelRef1 )
420 : {
421 8 : pFCell1 = new ScFormulaCell(mpDoc, rPos, *pFormula1);
422 8 : pFCell1->StartListeningTo( mpDoc );
423 : }
424 :
425 1570 : if ( pFormula2 && !pFCell2 && !bRelRef2 )
426 : {
427 0 : pFCell2 = new ScFormulaCell(mpDoc, rPos, *pFormula2);
428 0 : pFCell2->StartListeningTo( mpDoc );
429 : }
430 : }
431 1570 : }
432 :
433 70 : void ScConditionEntry::SetIgnoreBlank(bool bSet)
434 : {
435 : // The bit SC_COND_NOBLANKS is set if blanks are not ignored
436 : // (only of valid)
437 70 : if (bSet)
438 68 : nOptions &= ~SC_COND_NOBLANKS;
439 : else
440 2 : nOptions |= SC_COND_NOBLANKS;
441 70 : }
442 :
443 : /**
444 : * Delete formula cells, so we re-complile at the next IsValid
445 : */
446 4 : void ScConditionEntry::CompileAll()
447 : {
448 4 : DELETEZ(pFCell1);
449 4 : DELETEZ(pFCell2);
450 4 : }
451 :
452 118 : void ScConditionEntry::CompileXML()
453 : {
454 : // First parse the formula source position if it was stored as text
455 118 : if ( !aSrcString.isEmpty() )
456 : {
457 118 : ScAddress aNew;
458 : /* XML is always in OOo:A1 format, although R1C1 would be more amenable
459 : * to compression */
460 118 : if ( aNew.Parse( aSrcString, mpDoc ) & SCA_VALID )
461 118 : aSrcPos = aNew;
462 : // if the position is invalid, there isn't much we can do at this time
463 118 : aSrcString = OUString();
464 : }
465 :
466 : // Convert the text tokens that were created during XML import into real tokens.
467 : Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar1),
468 : GetExpression(aSrcPos, 1, 0, eTempGrammar2),
469 118 : aStrNmsp1, aStrNmsp2, eTempGrammar1, eTempGrammar2, true );
470 118 : }
471 :
472 212 : void ScConditionEntry::SetSrcString( const OUString& rNew )
473 : {
474 : // aSrcString is only evaluated in CompileXML
475 : SAL_WARN_IF( !mpDoc->IsImportingXML(), "sc", "SetSrcString is only valid for XML import" );
476 :
477 212 : aSrcString = rNew;
478 212 : }
479 :
480 0 : void ScConditionEntry::SetFormula1( const ScTokenArray& rArray )
481 : {
482 0 : DELETEZ( pFormula1 );
483 0 : if( rArray.GetLen() > 0 )
484 : {
485 0 : pFormula1 = new ScTokenArray( rArray );
486 0 : bRelRef1 = lcl_HasRelRef( mpDoc, pFormula1 );
487 : }
488 0 : }
489 :
490 0 : void ScConditionEntry::SetFormula2( const ScTokenArray& rArray )
491 : {
492 0 : DELETEZ( pFormula2 );
493 0 : if( rArray.GetLen() > 0 )
494 : {
495 0 : pFormula2 = new ScTokenArray( rArray );
496 0 : bRelRef2 = lcl_HasRelRef( mpDoc, pFormula2 );
497 : }
498 0 : }
499 :
500 58 : void ScConditionEntry::UpdateReference( sc::RefUpdateContext& rCxt )
501 : {
502 58 : if(pCondFormat)
503 26 : aSrcPos = pCondFormat->GetRange().Combine().aStart;
504 58 : ScAddress aOldSrcPos = aSrcPos;
505 58 : bool bChangedPos = false;
506 58 : if (rCxt.meMode == URM_INSDEL && rCxt.maRange.In(aSrcPos))
507 : {
508 2 : aSrcPos.Move(rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
509 2 : bChangedPos = aSrcPos != aOldSrcPos;
510 : }
511 :
512 58 : if (pFormula1)
513 : {
514 30 : sc::RefUpdateResult aRes;
515 30 : switch (rCxt.meMode)
516 : {
517 : case URM_INSDEL:
518 10 : aRes = pFormula1->AdjustReferenceOnShift(rCxt, aOldSrcPos);
519 10 : break;
520 : case URM_MOVE:
521 0 : aRes = pFormula1->AdjustReferenceOnMove(rCxt, aOldSrcPos, aSrcPos);
522 0 : break;
523 : default:
524 : ;
525 : }
526 :
527 30 : if (aRes.mbReferenceModified || bChangedPos)
528 6 : DELETEZ(pFCell1); // is created again in IsValid
529 : }
530 :
531 58 : if (pFormula2)
532 : {
533 0 : sc::RefUpdateResult aRes;
534 0 : switch (rCxt.meMode)
535 : {
536 : case URM_INSDEL:
537 0 : aRes = pFormula2->AdjustReferenceOnShift(rCxt, aOldSrcPos);
538 0 : break;
539 : case URM_MOVE:
540 0 : aRes = pFormula2->AdjustReferenceOnMove(rCxt, aOldSrcPos, aSrcPos);
541 0 : break;
542 : default:
543 : ;
544 : }
545 :
546 0 : if (aRes.mbReferenceModified || bChangedPos)
547 0 : DELETEZ(pFCell2); // is created again in IsValid
548 : }
549 58 : }
550 :
551 6 : void ScConditionEntry::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
552 : {
553 6 : if (pFormula1)
554 : {
555 2 : pFormula1->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
556 2 : DELETEZ(pFCell1);
557 : }
558 :
559 6 : if (pFormula2)
560 : {
561 0 : pFormula2->AdjustReferenceOnInsertedTab(rCxt, aSrcPos);
562 0 : DELETEZ(pFCell2);
563 : }
564 6 : }
565 :
566 8 : void ScConditionEntry::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
567 : {
568 8 : if (pFormula1)
569 : {
570 4 : pFormula1->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
571 4 : DELETEZ(pFCell1);
572 : }
573 :
574 8 : if (pFormula2)
575 : {
576 0 : pFormula2->AdjustReferenceOnDeletedTab(rCxt, aSrcPos);
577 0 : DELETEZ(pFCell2);
578 : }
579 8 : }
580 :
581 0 : void ScConditionEntry::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
582 : {
583 0 : if (pFormula1)
584 : {
585 0 : pFormula1->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
586 0 : DELETEZ(pFCell1);
587 : }
588 :
589 0 : if (pFormula2)
590 : {
591 0 : pFormula2->AdjustReferenceOnMovedTab(rCxt, aSrcPos);
592 0 : DELETEZ(pFCell2);
593 : }
594 0 : }
595 :
596 : //FIXME: Make this a comparison operator at the TokenArray?
597 190 : static bool lcl_IsEqual( const ScTokenArray* pArr1, const ScTokenArray* pArr2 )
598 : {
599 : // We only compare the non-RPN array
600 190 : if ( pArr1 && pArr2 )
601 : {
602 42 : sal_uInt16 nLen = pArr1->GetLen();
603 42 : if ( pArr2->GetLen() != nLen )
604 0 : return false;
605 :
606 42 : FormulaToken** ppToken1 = pArr1->GetArray();
607 42 : FormulaToken** ppToken2 = pArr2->GetArray();
608 84 : for (sal_uInt16 i=0; i<nLen; i++)
609 : {
610 84 : if ( ppToken1[i] != ppToken2[i] &&
611 42 : !(*ppToken1[i] == *ppToken2[i]) )
612 0 : return false; // Difference
613 : }
614 42 : return true; // All entries are the same
615 : }
616 : else
617 148 : return !pArr1 && !pArr2; // Both 0? -> the same
618 : }
619 :
620 230 : bool ScConditionEntry::operator== ( const ScConditionEntry& r ) const
621 : {
622 436 : bool bEq = (eOp == r.eOp && nOptions == r.nOptions &&
623 420 : lcl_IsEqual( pFormula1, r.pFormula1 ) &&
624 324 : lcl_IsEqual( pFormula2, r.pFormula2 ));
625 230 : if (bEq)
626 : {
627 : // for formulas, the reference positions must be compared, too
628 : // (including aSrcString, for inserting the entries during XML import)
629 94 : if ( ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
630 0 : bEq = false;
631 :
632 : // If not formulas, compare values
633 94 : if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
634 14 : bEq = false;
635 94 : if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
636 14 : bEq = false;
637 : }
638 :
639 230 : return bEq;
640 : }
641 :
642 5238 : void ScConditionEntry::Interpret( const ScAddress& rPos )
643 : {
644 : // Create formula cells
645 : // Note: New Broadcaster (Note cells) may be insterted into the document!
646 5238 : if ( ( pFormula1 && !pFCell1 ) || ( pFormula2 && !pFCell2 ) )
647 1570 : MakeCells( rPos );
648 :
649 : // Evaluate formulas
650 5238 : bool bDirty = false; // 1 and 2 separate?
651 :
652 5238 : boost::scoped_ptr<ScFormulaCell> pTemp1;
653 5238 : ScFormulaCell* pEff1 = pFCell1;
654 5238 : if ( bRelRef1 )
655 : {
656 1562 : pTemp1.reset(pFormula1 ? new ScFormulaCell(mpDoc, rPos, *pFormula1) : new ScFormulaCell(mpDoc, rPos));
657 1562 : pEff1 = pTemp1.get();
658 : }
659 5238 : if ( pEff1 )
660 : {
661 3850 : if (!pEff1->IsRunning()) // Don't create 522
662 : {
663 : //! Query Changed instead of Dirty!
664 3850 : if (pEff1->GetDirty() && !bRelRef1 && mpDoc->GetAutoCalc())
665 8 : bDirty = true;
666 3850 : if (pEff1->IsValue())
667 : {
668 3850 : bIsStr1 = false;
669 3850 : nVal1 = pEff1->GetValue();
670 3850 : aStrVal1 = OUString();
671 : }
672 : else
673 : {
674 0 : bIsStr1 = true;
675 0 : aStrVal1 = pEff1->GetString().getString();
676 0 : nVal1 = 0.0;
677 : }
678 : }
679 : }
680 5238 : pTemp1.reset();
681 :
682 10476 : boost::scoped_ptr<ScFormulaCell> pTemp2;
683 5238 : ScFormulaCell* pEff2 = pFCell2; //@ 1!=2
684 5238 : if ( bRelRef2 )
685 : {
686 180 : pTemp2.reset(pFormula2 ? new ScFormulaCell(mpDoc, rPos, *pFormula2) : new ScFormulaCell(mpDoc, rPos));
687 180 : pEff2 = pTemp2.get();
688 : }
689 5238 : if ( pEff2 )
690 : {
691 180 : if (!pEff2->IsRunning()) // Don't create 522
692 : {
693 180 : if (pEff2->GetDirty() && !bRelRef2 && mpDoc->GetAutoCalc())
694 0 : bDirty = true;
695 180 : if (pEff2->IsValue())
696 : {
697 180 : bIsStr2 = false;
698 180 : nVal2 = pEff2->GetValue();
699 180 : aStrVal2 = OUString();
700 : }
701 : else
702 : {
703 0 : bIsStr2 = true;
704 0 : aStrVal2 = pEff2->GetString().getString();
705 0 : nVal2 = 0.0;
706 : }
707 : }
708 : }
709 5238 : pTemp2.reset();
710 :
711 : // If IsRunning, the last values remain
712 5238 : if (bDirty && !bFirstRun)
713 : {
714 : // Repaint everything for dependent formats
715 0 : DataChanged( NULL );
716 : }
717 :
718 10476 : bFirstRun = false;
719 5238 : }
720 :
721 6582 : static bool lcl_GetCellContent( ScRefCellValue& rCell, bool bIsStr1, double& rArg, OUString& rArgStr,
722 : const ScDocument* pDoc )
723 : {
724 :
725 6582 : if (rCell.isEmpty())
726 3778 : return !bIsStr1;
727 :
728 2804 : bool bVal = true;
729 :
730 2804 : switch (rCell.meType)
731 : {
732 : case CELLTYPE_VALUE:
733 2804 : rArg = rCell.mfValue;
734 2804 : break;
735 : case CELLTYPE_FORMULA:
736 : {
737 0 : bVal = rCell.mpFormula->IsValue();
738 0 : if (bVal)
739 0 : rArg = rCell.mpFormula->GetValue();
740 : else
741 0 : rArgStr = rCell.mpFormula->GetString().getString();
742 : }
743 0 : break;
744 : case CELLTYPE_STRING:
745 : case CELLTYPE_EDIT:
746 0 : bVal = false;
747 0 : if (rCell.meType == CELLTYPE_STRING)
748 0 : rArgStr = rCell.mpString->getString();
749 0 : else if (rCell.mpEditText)
750 0 : rArgStr = ScEditUtil::GetString(*rCell.mpEditText, pDoc);
751 0 : break;
752 : default:
753 : ;
754 : }
755 :
756 2804 : return bVal;
757 : }
758 :
759 1344 : void ScConditionEntry::FillCache() const
760 : {
761 1344 : if(!mpCache)
762 : {
763 64 : const ScRangeList& rRanges = pCondFormat->GetRange();
764 64 : mpCache.reset(new ScConditionEntryCache);
765 64 : size_t nListCount = rRanges.size();
766 128 : for( size_t i = 0; i < nListCount; i++ )
767 : {
768 64 : const ScRange *aRange = rRanges[i];
769 64 : SCROW nRow = aRange->aEnd.Row();
770 64 : SCCOL nCol = aRange->aEnd.Col();
771 64 : SCCOL nColStart = aRange->aStart.Col();
772 64 : SCROW nRowStart = aRange->aStart.Row();
773 64 : SCTAB nTab = aRange->aStart.Tab();
774 :
775 : // temporary fix to workaorund slow duplicate entry
776 : // conditions, prevent to use a whole row
777 64 : if(nRow == MAXROW)
778 : {
779 0 : bool bShrunk = false;
780 : mpDoc->ShrinkToUsedDataArea(bShrunk, nTab, nColStart, nRowStart,
781 0 : nCol, nRow, false);
782 : }
783 :
784 1408 : for( SCROW r = nRowStart; r <= nRow; r++ )
785 2688 : for( SCCOL c = nColStart; c <= nCol; c++ )
786 : {
787 1344 : ScRefCellValue aCell;
788 1344 : aCell.assign(*mpDoc, ScAddress(c, r, nTab));
789 1344 : if (aCell.isEmpty())
790 0 : continue;
791 :
792 1344 : double nVal = 0.0;
793 2688 : OUString aStr;
794 1344 : if (!lcl_GetCellContent(aCell, false, nVal, aStr, mpDoc))
795 : {
796 : std::pair<ScConditionEntryCache::StringCacheType::iterator, bool> aResult =
797 0 : mpCache->maStrings.insert(
798 0 : ScConditionEntryCache::StringCacheType::value_type(aStr, 1));
799 :
800 0 : if(!aResult.second)
801 0 : aResult.first->second++;
802 : }
803 : else
804 : {
805 : std::pair<ScConditionEntryCache::ValueCacheType::iterator, bool> aResult =
806 1344 : mpCache->maValues.insert(
807 2688 : ScConditionEntryCache::ValueCacheType::value_type(nVal, 1));
808 :
809 1344 : if(!aResult.second)
810 208 : aResult.first->second++;
811 :
812 1344 : ++(mpCache->nValueItems);
813 : }
814 1344 : }
815 : }
816 : }
817 1344 : }
818 :
819 0 : bool ScConditionEntry::IsDuplicate( double nArg, const OUString& rStr ) const
820 : {
821 0 : FillCache();
822 :
823 0 : if(rStr.isEmpty())
824 : {
825 0 : ScConditionEntryCache::ValueCacheType::iterator itr = mpCache->maValues.find(nArg);
826 0 : if(itr == mpCache->maValues.end())
827 0 : return false;
828 : else
829 : {
830 0 : if(itr->second > 1)
831 0 : return true;
832 : else
833 0 : return false;
834 : }
835 : }
836 : else
837 : {
838 0 : ScConditionEntryCache::StringCacheType::iterator itr = mpCache->maStrings.find(rStr);
839 0 : if(itr == mpCache->maStrings.end())
840 0 : return false;
841 : else
842 : {
843 0 : if(itr->second > 1)
844 0 : return true;
845 : else
846 0 : return false;
847 : }
848 : }
849 : }
850 :
851 168 : bool ScConditionEntry::IsTopNElement( double nArg ) const
852 : {
853 168 : FillCache();
854 :
855 168 : if(mpCache->nValueItems <= nVal1)
856 0 : return true;
857 :
858 168 : size_t nCells = 0;
859 1056 : for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
860 168 : itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
861 : {
862 888 : if(nCells >= nVal1)
863 296 : return false;
864 760 : if(itr->first <= nArg)
865 40 : return true;
866 720 : nCells += itr->second;
867 : }
868 :
869 0 : return true;
870 : }
871 :
872 168 : bool ScConditionEntry::IsBottomNElement( double nArg ) const
873 : {
874 168 : FillCache();
875 :
876 168 : if(mpCache->nValueItems <= nVal1)
877 0 : return true;
878 :
879 168 : size_t nCells = 0;
880 744 : for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
881 168 : itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
882 : {
883 576 : if(nCells >= nVal1)
884 288 : return false;
885 456 : if(itr->first >= nArg)
886 48 : return true;
887 408 : nCells += itr->second;
888 : }
889 :
890 0 : return true;
891 : }
892 :
893 168 : bool ScConditionEntry::IsTopNPercent( double nArg ) const
894 : {
895 168 : FillCache();
896 :
897 168 : size_t nCells = 0;
898 168 : size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
899 648 : for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr = mpCache->maValues.rbegin(),
900 168 : itrEnd = mpCache->maValues.rend(); itr != itrEnd; ++itr)
901 : {
902 480 : if(nCells >= nLimitCells)
903 320 : return false;
904 328 : if(itr->first <= nArg)
905 16 : return true;
906 312 : nCells += itr->second;
907 : }
908 :
909 0 : return true;
910 : }
911 :
912 168 : bool ScConditionEntry::IsBottomNPercent( double nArg ) const
913 : {
914 168 : FillCache();
915 :
916 168 : size_t nCells = 0;
917 168 : size_t nLimitCells = static_cast<size_t>(mpCache->nValueItems*nVal1/100);
918 624 : for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
919 168 : itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
920 : {
921 456 : if(nCells >= nLimitCells)
922 304 : return false;
923 320 : if(itr->first >= nArg)
924 32 : return true;
925 288 : nCells += itr->second;
926 : }
927 :
928 0 : return true;
929 : }
930 :
931 336 : bool ScConditionEntry::IsBelowAverage( double nArg, bool bEqual ) const
932 : {
933 336 : FillCache();
934 :
935 336 : double nSum = 0;
936 6552 : for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
937 336 : itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
938 : {
939 5880 : nSum += itr->first * itr->second;
940 : }
941 :
942 336 : if(bEqual)
943 168 : return (nArg <= nSum/mpCache->nValueItems);
944 : else
945 168 : return (nArg < nSum/mpCache->nValueItems);
946 : }
947 :
948 336 : bool ScConditionEntry::IsAboveAverage( double nArg, bool bEqual ) const
949 : {
950 336 : FillCache();
951 :
952 336 : double nSum = 0;
953 6552 : for(ScConditionEntryCache::ValueCacheType::const_iterator itr = mpCache->maValues.begin(),
954 336 : itrEnd = mpCache->maValues.end(); itr != itrEnd; ++itr)
955 : {
956 5880 : nSum += itr->first * itr->second;
957 : }
958 :
959 336 : if(bEqual)
960 168 : return (nArg >= nSum/mpCache->nValueItems);
961 : else
962 168 : return (nArg > nSum/mpCache->nValueItems);
963 : }
964 :
965 0 : bool ScConditionEntry::IsError( const ScAddress& rPos ) const
966 : {
967 0 : switch (mpDoc->GetCellType(rPos))
968 : {
969 : case CELLTYPE_VALUE:
970 0 : return false;
971 : case CELLTYPE_FORMULA:
972 : {
973 0 : ScFormulaCell* pFormulaCell = const_cast<ScFormulaCell*>(mpDoc->GetFormulaCell(rPos));
974 0 : if (pFormulaCell && pFormulaCell->GetErrCode())
975 0 : return true;
976 : }
977 : case CELLTYPE_STRING:
978 : case CELLTYPE_EDIT:
979 0 : return false;
980 : default:
981 0 : break;
982 : }
983 0 : return false;
984 : }
985 :
986 5238 : bool ScConditionEntry::IsValid( double nArg, const ScAddress& rPos ) const
987 : {
988 : // Interpret must already have been called
989 5238 : if ( bIsStr1 )
990 : {
991 0 : switch( eOp )
992 : {
993 : case SC_COND_BEGINS_WITH:
994 : case SC_COND_ENDS_WITH:
995 : case SC_COND_CONTAINS_TEXT:
996 : case SC_COND_NOT_CONTAINS_TEXT:
997 0 : break;
998 : case SC_COND_NOTEQUAL:
999 0 : return true;
1000 : default:
1001 0 : return false;
1002 : }
1003 : }
1004 :
1005 5238 : if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1006 196 : if ( bIsStr2 )
1007 0 : return false;
1008 :
1009 5238 : double nComp1 = nVal1; // Copy, so that it can be changed
1010 5238 : double nComp2 = nVal2;
1011 :
1012 5238 : if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1013 196 : if ( nComp1 > nComp2 )
1014 : {
1015 : // Right order for value range
1016 0 : double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp;
1017 : }
1018 :
1019 : // All corner cases need to be tested with ::rtl::math::approxEqual!
1020 5238 : bool bValid = false;
1021 5238 : switch (eOp)
1022 : {
1023 : case SC_COND_NONE:
1024 0 : break; // Always sal_False
1025 : case SC_COND_EQUAL:
1026 2292 : bValid = ::rtl::math::approxEqual( nArg, nComp1 );
1027 2292 : break;
1028 : case SC_COND_NOTEQUAL:
1029 0 : bValid = !::rtl::math::approxEqual( nArg, nComp1 );
1030 0 : break;
1031 : case SC_COND_GREATER:
1032 1358 : bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1033 1358 : break;
1034 : case SC_COND_EQGREATER:
1035 4 : bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1036 4 : break;
1037 : case SC_COND_LESS:
1038 16 : bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
1039 16 : break;
1040 : case SC_COND_EQLESS:
1041 0 : bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
1042 0 : break;
1043 : case SC_COND_BETWEEN:
1044 192 : bValid = ( nArg >= nComp1 && nArg <= nComp2 ) ||
1045 252 : ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 );
1046 188 : break;
1047 : case SC_COND_NOTBETWEEN:
1048 12 : bValid = ( nArg < nComp1 || nArg > nComp2 ) &&
1049 16 : !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 );
1050 8 : break;
1051 : case SC_COND_DUPLICATE:
1052 : case SC_COND_NOTDUPLICATE:
1053 0 : if( pCondFormat )
1054 : {
1055 0 : bValid = IsDuplicate( nArg, OUString() );
1056 0 : if( eOp == SC_COND_NOTDUPLICATE )
1057 0 : bValid = !bValid;
1058 : }
1059 0 : break;
1060 : case SC_COND_DIRECT:
1061 28 : bValid = !::rtl::math::approxEqual( nComp1, 0.0 );
1062 28 : break;
1063 : case SC_COND_TOP10:
1064 168 : bValid = IsTopNElement( nArg );
1065 168 : break;
1066 : case SC_COND_BOTTOM10:
1067 168 : bValid = IsBottomNElement( nArg );
1068 168 : break;
1069 : case SC_COND_TOP_PERCENT:
1070 168 : bValid = IsTopNPercent( nArg );
1071 168 : break;
1072 : case SC_COND_BOTTOM_PERCENT:
1073 168 : bValid = IsBottomNPercent( nArg );
1074 168 : break;
1075 : case SC_COND_ABOVE_AVERAGE:
1076 : case SC_COND_ABOVE_EQUAL_AVERAGE:
1077 336 : bValid = IsAboveAverage( nArg, eOp == SC_COND_ABOVE_EQUAL_AVERAGE );
1078 336 : break;
1079 : case SC_COND_BELOW_AVERAGE:
1080 : case SC_COND_BELOW_EQUAL_AVERAGE:
1081 336 : bValid = IsBelowAverage( nArg, eOp == SC_COND_BELOW_EQUAL_AVERAGE );
1082 336 : break;
1083 : case SC_COND_ERROR:
1084 : case SC_COND_NOERROR:
1085 0 : bValid = IsError( rPos );
1086 0 : if( eOp == SC_COND_NOERROR )
1087 0 : bValid = !bValid;
1088 0 : break;
1089 : case SC_COND_BEGINS_WITH:
1090 0 : if(aStrVal1.isEmpty())
1091 : {
1092 0 : OUString aStr = OUString::number(nVal1);
1093 0 : OUString aStr2 = OUString::number(nArg);
1094 0 : bValid = aStr2.startsWith(aStr);
1095 : }
1096 : else
1097 : {
1098 0 : OUString aStr2 = OUString::number(nArg);
1099 0 : bValid = aStr2.startsWith(aStrVal1);
1100 : }
1101 0 : break;
1102 : case SC_COND_ENDS_WITH:
1103 0 : if(aStrVal1.isEmpty())
1104 : {
1105 0 : OUString aStr = OUString::number(nVal1);
1106 0 : OUString aStr2 = OUString::number(nArg);
1107 0 : bValid = !aStr2.endsWith(aStr);
1108 : }
1109 : else
1110 : {
1111 0 : OUString aStr2 = OUString::number(nArg);
1112 0 : bValid = !aStr2.endsWith(aStrVal1);
1113 : }
1114 0 : break;
1115 : case SC_COND_CONTAINS_TEXT:
1116 : case SC_COND_NOT_CONTAINS_TEXT:
1117 0 : if(aStrVal1.isEmpty())
1118 : {
1119 0 : OUString aStr = OUString::number(nVal1);
1120 0 : OUString aStr2 = OUString::number(nArg);
1121 0 : bValid = aStr2.indexOf(aStr) != -1;
1122 : }
1123 : else
1124 : {
1125 0 : OUString aStr2 = OUString::number(nArg);
1126 0 : bValid = aStr2.indexOf(aStrVal1) != -1;
1127 : }
1128 :
1129 0 : if( eOp == SC_COND_NOT_CONTAINS_TEXT )
1130 0 : bValid = !bValid;
1131 0 : break;
1132 : default:
1133 : SAL_WARN("sc", "unknown operation at ScConditionEntry");
1134 0 : break;
1135 : }
1136 5238 : return bValid;
1137 : }
1138 :
1139 0 : bool ScConditionEntry::IsValidStr( const OUString& rArg, const ScAddress& rPos ) const
1140 : {
1141 0 : bool bValid = false;
1142 : // Interpret must already have been called
1143 0 : if ( eOp == SC_COND_DIRECT ) // Formula is independent from the content
1144 0 : return !::rtl::math::approxEqual( nVal1, 0.0 );
1145 :
1146 0 : if ( eOp == SC_COND_DUPLICATE || eOp == SC_COND_NOTDUPLICATE )
1147 : {
1148 0 : if( pCondFormat && !rArg.isEmpty() )
1149 : {
1150 0 : bValid = IsDuplicate( 0.0, rArg );
1151 0 : if( eOp == SC_COND_NOTDUPLICATE )
1152 0 : bValid = !bValid;
1153 0 : return bValid;
1154 : }
1155 : }
1156 :
1157 : // If number contains condition, always false, except for "not equal".
1158 0 : if ( !bIsStr1 && (eOp != SC_COND_ERROR && eOp != SC_COND_NOERROR) )
1159 0 : return ( eOp == SC_COND_NOTEQUAL );
1160 0 : if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1161 0 : if ( !bIsStr2 )
1162 0 : return false;
1163 :
1164 0 : OUString aUpVal1( aStrVal1 ); //! As a member? (Also set in Interpret)
1165 0 : OUString aUpVal2( aStrVal2 );
1166 :
1167 0 : if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
1168 0 : if (ScGlobal::GetCollator()->compareString( aUpVal1, aUpVal2 ) > 0)
1169 : {
1170 : // Right order for value range
1171 0 : OUString aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
1172 : }
1173 :
1174 0 : switch ( eOp )
1175 : {
1176 : case SC_COND_EQUAL:
1177 : bValid = (ScGlobal::GetCollator()->compareString(
1178 0 : rArg, aUpVal1 ) == 0);
1179 0 : break;
1180 : case SC_COND_NOTEQUAL:
1181 : bValid = (ScGlobal::GetCollator()->compareString(
1182 0 : rArg, aUpVal1 ) != 0);
1183 0 : break;
1184 : case SC_COND_TOP_PERCENT:
1185 : case SC_COND_BOTTOM_PERCENT:
1186 : case SC_COND_TOP10:
1187 : case SC_COND_BOTTOM10:
1188 : case SC_COND_ABOVE_AVERAGE:
1189 : case SC_COND_BELOW_AVERAGE:
1190 0 : return false;
1191 : case SC_COND_ERROR:
1192 : case SC_COND_NOERROR:
1193 0 : bValid = IsError( rPos );
1194 0 : if(eOp == SC_COND_NOERROR)
1195 0 : bValid = !bValid;
1196 0 : break;
1197 : case SC_COND_BEGINS_WITH:
1198 0 : bValid = rArg.startsWith(aUpVal1);
1199 0 : break;
1200 : case SC_COND_ENDS_WITH:
1201 0 : bValid = rArg.endsWith(aUpVal1);
1202 0 : break;
1203 : case SC_COND_CONTAINS_TEXT:
1204 : case SC_COND_NOT_CONTAINS_TEXT:
1205 0 : bValid = rArg.indexOf(aUpVal1) != -1;
1206 0 : if(eOp == SC_COND_NOT_CONTAINS_TEXT)
1207 0 : bValid = !bValid;
1208 0 : break;
1209 : default:
1210 : {
1211 : sal_Int32 nCompare = ScGlobal::GetCollator()->compareString(
1212 0 : rArg, aUpVal1 );
1213 0 : switch ( eOp )
1214 : {
1215 : case SC_COND_GREATER:
1216 0 : bValid = ( nCompare > 0 );
1217 0 : break;
1218 : case SC_COND_EQGREATER:
1219 0 : bValid = ( nCompare >= 0 );
1220 0 : break;
1221 : case SC_COND_LESS:
1222 0 : bValid = ( nCompare < 0 );
1223 0 : break;
1224 : case SC_COND_EQLESS:
1225 0 : bValid = ( nCompare <= 0 );
1226 0 : break;
1227 : case SC_COND_BETWEEN:
1228 : case SC_COND_NOTBETWEEN:
1229 : // Test for NOTBETWEEN:
1230 0 : bValid = ( nCompare < 0 ||
1231 : ScGlobal::GetCollator()->compareString( rArg,
1232 0 : aUpVal2 ) > 0 );
1233 0 : if ( eOp == SC_COND_BETWEEN )
1234 0 : bValid = !bValid;
1235 0 : break;
1236 : // SC_COND_DIRECT already handled above
1237 : default:
1238 : SAL_WARN("sc", "unknown operation in ScConditionEntry");
1239 0 : bValid = false;
1240 0 : break;
1241 : }
1242 : }
1243 : }
1244 0 : return bValid;
1245 : }
1246 :
1247 5238 : bool ScConditionEntry::IsCellValid( ScRefCellValue& rCell, const ScAddress& rPos ) const
1248 : {
1249 5238 : ((ScConditionEntry*)this)->Interpret(rPos); // Evaluate formula
1250 :
1251 5238 : double nArg = 0.0;
1252 5238 : OUString aArgStr;
1253 5238 : bool bVal = lcl_GetCellContent( rCell, bIsStr1, nArg, aArgStr, mpDoc );
1254 5238 : if (bVal)
1255 5238 : return IsValid( nArg, rPos );
1256 : else
1257 0 : return IsValidStr( aArgStr, rPos );
1258 : }
1259 :
1260 550 : OUString ScConditionEntry::GetExpression( const ScAddress& rCursor, sal_uInt16 nIndex,
1261 : sal_uLong nNumFmt,
1262 : const FormulaGrammar::Grammar eGrammar ) const
1263 : {
1264 : assert( nIndex <= 1);
1265 550 : OUString aRet;
1266 :
1267 550 : if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 )
1268 500 : nNumFmt = mpDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US );
1269 :
1270 550 : if ( nIndex==0 )
1271 : {
1272 292 : if ( pFormula1 )
1273 : {
1274 112 : ScCompiler aComp(mpDoc, rCursor, *pFormula1);
1275 112 : aComp.SetGrammar(eGrammar);
1276 224 : OUStringBuffer aBuffer;
1277 112 : aComp.CreateStringFromTokenArray( aBuffer );
1278 224 : aRet = aBuffer.makeStringAndClear();
1279 : }
1280 180 : else if (bIsStr1)
1281 : {
1282 0 : aRet = "\"";
1283 0 : aRet += aStrVal1;
1284 0 : aRet += "\"";
1285 : }
1286 : else
1287 180 : mpDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet);
1288 : }
1289 258 : else if ( nIndex==1 )
1290 : {
1291 258 : if ( pFormula2 )
1292 : {
1293 20 : ScCompiler aComp(mpDoc, rCursor, *pFormula2);
1294 20 : aComp.SetGrammar(eGrammar);
1295 40 : OUStringBuffer aBuffer;
1296 20 : aComp.CreateStringFromTokenArray( aBuffer );
1297 40 : aRet = aBuffer.makeStringAndClear();
1298 : }
1299 238 : else if (bIsStr2)
1300 : {
1301 0 : aRet = "\"";
1302 0 : aRet += aStrVal2;
1303 0 : aRet += "\"";
1304 : }
1305 : else
1306 238 : mpDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet);
1307 : }
1308 :
1309 550 : return aRet;
1310 : }
1311 :
1312 42 : ScTokenArray* ScConditionEntry::CreateTokenArry( sal_uInt16 nIndex ) const
1313 : {
1314 : assert(nIndex <= 1);
1315 42 : ScTokenArray* pRet = NULL;
1316 42 : ScAddress aAddr;
1317 :
1318 42 : if ( nIndex==0 )
1319 : {
1320 42 : if ( pFormula1 )
1321 18 : pRet = new ScTokenArray( *pFormula1 );
1322 : else
1323 : {
1324 24 : pRet = new ScTokenArray();
1325 24 : if (bIsStr1)
1326 : {
1327 0 : svl::SharedStringPool& rSPool = mpDoc->GetSharedStringPool();
1328 0 : pRet->AddString(rSPool.intern(aStrVal1));
1329 : }
1330 : else
1331 24 : pRet->AddDouble( nVal1 );
1332 : }
1333 : }
1334 0 : else if ( nIndex==1 )
1335 : {
1336 0 : if ( pFormula2 )
1337 0 : pRet = new ScTokenArray( *pFormula2 );
1338 : else
1339 : {
1340 0 : pRet = new ScTokenArray();
1341 0 : if (bIsStr2)
1342 : {
1343 0 : svl::SharedStringPool& rSPool = mpDoc->GetSharedStringPool();
1344 0 : pRet->AddString(rSPool.intern(aStrVal2));
1345 : }
1346 : else
1347 0 : pRet->AddDouble( nVal2 );
1348 : }
1349 : }
1350 :
1351 42 : return pRet;
1352 : }
1353 :
1354 188 : void ScConditionEntry::SourceChanged( const ScAddress& rChanged )
1355 : {
1356 564 : for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1357 : {
1358 376 : ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1359 376 : if (pFormula)
1360 : {
1361 282 : pFormula->Reset();
1362 : formula::FormulaToken* t;
1363 846 : while ( ( t = pFormula->GetNextReference() ) != NULL )
1364 : {
1365 282 : SingleDoubleRefProvider aProv( *t );
1366 846 : if ( aProv.Ref1.IsColRel() || aProv.Ref1.IsRowRel() || aProv.Ref1.IsTabRel() ||
1367 282 : aProv.Ref2.IsColRel() || aProv.Ref2.IsRowRel() || aProv.Ref2.IsTabRel() )
1368 : {
1369 : // Absolute must be reached, relative determines range
1370 282 : bool bHit = true;
1371 : SCsCOL nCol1;
1372 : SCsROW nRow1;
1373 : SCsTAB nTab1;
1374 : SCsCOL nCol2;
1375 : SCsROW nRow2;
1376 : SCsTAB nTab2;
1377 :
1378 282 : if ( aProv.Ref1.IsColRel() )
1379 0 : nCol2 = rChanged.Col() - aProv.Ref1.Col();
1380 : else
1381 : {
1382 282 : bHit &= (rChanged.Col() >= aProv.Ref1.Col());
1383 282 : nCol2 = MAXCOL;
1384 : }
1385 282 : if ( aProv.Ref1.IsRowRel() )
1386 0 : nRow2 = rChanged.Row() - aProv.Ref1.Row();
1387 : else
1388 : {
1389 282 : bHit &= ( rChanged.Row() >= aProv.Ref1.Row() );
1390 282 : nRow2 = MAXROW;
1391 : }
1392 282 : if ( aProv.Ref1.IsTabRel() )
1393 282 : nTab2 = rChanged.Tab() - aProv.Ref1.Tab();
1394 : else
1395 : {
1396 0 : bHit &= (rChanged.Tab() >= aProv.Ref1.Tab());
1397 0 : nTab2 = MAXTAB;
1398 : }
1399 :
1400 282 : if ( aProv.Ref2.IsColRel() )
1401 0 : nCol1 = rChanged.Col() - aProv.Ref2.Col();
1402 : else
1403 : {
1404 282 : bHit &= ( rChanged.Col() <= aProv.Ref2.Col() );
1405 282 : nCol1 = 0;
1406 : }
1407 282 : if ( aProv.Ref2.IsRowRel() )
1408 0 : nRow1 = rChanged.Row() - aProv.Ref2.Row();
1409 : else
1410 : {
1411 282 : bHit &= (rChanged.Row() <= aProv.Ref2.Row());
1412 282 : nRow1 = 0;
1413 : }
1414 282 : if ( aProv.Ref2.IsTabRel() )
1415 282 : nTab1 = rChanged.Tab() - aProv.Ref2.Tab();
1416 : else
1417 : {
1418 0 : bHit &= (rChanged.Tab() <= aProv.Ref2.Tab());
1419 0 : nTab1 = 0;
1420 : }
1421 :
1422 282 : if ( bHit )
1423 : {
1424 : // Limit paint!
1425 22 : ScRange aPaint( nCol1,nRow1,nTab1, nCol2,nRow2,nTab2 );
1426 :
1427 : // No paint if it's the cell itself
1428 22 : if ( aPaint.IsValid() && (aPaint.aStart != rChanged || aPaint.aEnd != rChanged ))
1429 22 : DataChanged( &aPaint );
1430 : }
1431 : }
1432 282 : }
1433 : }
1434 : }
1435 188 : }
1436 :
1437 : /**
1438 : * Return a position that's adjusted to allow textual representation
1439 : * of expressions if possible
1440 : */
1441 146 : ScAddress ScConditionEntry::GetValidSrcPos() const
1442 : {
1443 146 : SCTAB nMinTab = aSrcPos.Tab();
1444 146 : SCTAB nMaxTab = nMinTab;
1445 :
1446 438 : for (sal_uInt16 nPass = 0; nPass < 2; nPass++)
1447 : {
1448 292 : ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1449 292 : if (pFormula)
1450 : {
1451 12 : pFormula->Reset();
1452 : formula::FormulaToken* t;
1453 32 : while ( ( t = pFormula->GetNextReference() ) != NULL )
1454 : {
1455 8 : ScSingleRefData& rRef1 = *t->GetSingleRef();
1456 8 : ScAddress aAbs = rRef1.toAbs(aSrcPos);
1457 8 : if (!rRef1.IsTabDeleted())
1458 : {
1459 8 : if (aAbs.Tab() < nMinTab)
1460 0 : nMinTab = aAbs.Tab();
1461 8 : if (aAbs.Tab() > nMaxTab)
1462 0 : nMaxTab = aAbs.Tab();
1463 : }
1464 8 : if ( t->GetType() == svDoubleRef )
1465 : {
1466 4 : ScSingleRefData& rRef2 = t->GetDoubleRef()->Ref2;
1467 4 : aAbs = rRef2.toAbs(aSrcPos);
1468 4 : if (!rRef2.IsTabDeleted())
1469 : {
1470 4 : if (aAbs.Tab() < nMinTab)
1471 0 : nMinTab = aAbs.Tab();
1472 4 : if (aAbs.Tab() > nMaxTab)
1473 0 : nMaxTab = aAbs.Tab();
1474 : }
1475 : }
1476 : }
1477 : }
1478 : }
1479 :
1480 146 : ScAddress aValidPos = aSrcPos;
1481 146 : SCTAB nTabCount = mpDoc->GetTableCount();
1482 146 : if ( nMaxTab >= nTabCount && nMinTab > 0 )
1483 0 : aValidPos.SetTab( aSrcPos.Tab() - nMinTab ); // so the lowest tab ref will be on 0
1484 :
1485 146 : if ( aValidPos.Tab() >= nTabCount )
1486 0 : aValidPos.SetTab( nTabCount - 1 ); // ensure a valid position even if some references will be invalid
1487 :
1488 146 : return aValidPos;
1489 : }
1490 :
1491 0 : void ScConditionEntry::DataChanged( const ScRange* /* pModified */ ) const
1492 : {
1493 : //FIXME: Nothing so far
1494 0 : }
1495 :
1496 0 : bool ScConditionEntry::MarkUsedExternalReferences() const
1497 : {
1498 0 : bool bAllMarked = false;
1499 0 : for (sal_uInt16 nPass = 0; !bAllMarked && nPass < 2; nPass++)
1500 : {
1501 0 : ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
1502 0 : if (pFormula)
1503 0 : bAllMarked = mpDoc->MarkUsedExternalReferences(*pFormula, aSrcPos);
1504 : }
1505 0 : return bAllMarked;
1506 : }
1507 :
1508 0 : ScFormatEntry* ScConditionEntry::Clone(ScDocument* pDoc) const
1509 : {
1510 0 : return new ScConditionEntry(pDoc, *this);
1511 : }
1512 :
1513 108 : ScConditionMode ScConditionEntry::GetModeFromApi(sal_Int32 nOperation)
1514 : {
1515 108 : ScConditionMode eMode = SC_COND_NONE;
1516 108 : switch (nOperation)
1517 : {
1518 : case com::sun::star::sheet::ConditionOperator2::EQUAL:
1519 26 : eMode = SC_COND_EQUAL;
1520 26 : break;
1521 : case com::sun::star::sheet::ConditionOperator2::LESS:
1522 6 : eMode = SC_COND_LESS;
1523 6 : break;
1524 : case com::sun::star::sheet::ConditionOperator2::GREATER:
1525 14 : eMode = SC_COND_GREATER;
1526 14 : break;
1527 : case com::sun::star::sheet::ConditionOperator2::LESS_EQUAL:
1528 0 : eMode = SC_COND_EQLESS;
1529 0 : break;
1530 : case com::sun::star::sheet::ConditionOperator2::GREATER_EQUAL:
1531 12 : eMode = SC_COND_EQGREATER;
1532 12 : break;
1533 : case com::sun::star::sheet::ConditionOperator2::NOT_EQUAL:
1534 0 : eMode = SC_COND_NOTEQUAL;
1535 0 : break;
1536 : case com::sun::star::sheet::ConditionOperator2::BETWEEN:
1537 26 : eMode = SC_COND_BETWEEN;
1538 26 : break;
1539 : case com::sun::star::sheet::ConditionOperator2::NOT_BETWEEN:
1540 12 : eMode = SC_COND_NOTBETWEEN;
1541 12 : break;
1542 : case com::sun::star::sheet::ConditionOperator2::FORMULA:
1543 12 : eMode = SC_COND_DIRECT;
1544 12 : break;
1545 : case com::sun::star::sheet::ConditionOperator2::DUPLICATE:
1546 0 : eMode = SC_COND_DUPLICATE;
1547 0 : break;
1548 : case com::sun::star::sheet::ConditionOperator2::NOT_DUPLICATE:
1549 0 : eMode = SC_COND_NOTDUPLICATE;
1550 0 : break;
1551 : default:
1552 0 : break;
1553 : }
1554 108 : return eMode;
1555 : }
1556 :
1557 196 : void ScConditionEntry::startRendering()
1558 : {
1559 196 : mpCache.reset();
1560 196 : }
1561 :
1562 196 : void ScConditionEntry::endRendering()
1563 : {
1564 196 : mpCache.reset();
1565 196 : }
1566 :
1567 200 : ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
1568 : const OUString& rExpr1, const OUString& rExpr2,
1569 : ScDocument* pDocument, const ScAddress& rPos,
1570 : const OUString& rStyle,
1571 : const OUString& rExprNmsp1, const OUString& rExprNmsp2,
1572 : FormulaGrammar::Grammar eGrammar1,
1573 : FormulaGrammar::Grammar eGrammar2 ) :
1574 : ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, rExprNmsp1, rExprNmsp2, eGrammar1, eGrammar2 ),
1575 200 : aStyleName( rStyle )
1576 : {
1577 200 : }
1578 :
1579 64 : ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
1580 : const ScTokenArray* pArr1, const ScTokenArray* pArr2,
1581 : ScDocument* pDocument, const ScAddress& rPos,
1582 : const OUString& rStyle ) :
1583 : ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos ),
1584 64 : aStyleName( rStyle )
1585 : {
1586 64 : }
1587 :
1588 0 : ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry& r ) :
1589 : ScConditionEntry( r ),
1590 0 : aStyleName( r.aStyleName )
1591 : {
1592 0 : }
1593 :
1594 68 : ScCondFormatEntry::ScCondFormatEntry( ScDocument* pDocument, const ScCondFormatEntry& r ) :
1595 : ScConditionEntry( pDocument, r ),
1596 68 : aStyleName( r.aStyleName )
1597 : {
1598 68 : }
1599 :
1600 0 : bool ScCondFormatEntry::operator== ( const ScCondFormatEntry& r ) const
1601 : {
1602 0 : return ScConditionEntry::operator==( r ) &&
1603 0 : aStyleName == r.aStyleName;
1604 : }
1605 :
1606 664 : ScCondFormatEntry::~ScCondFormatEntry()
1607 : {
1608 664 : }
1609 :
1610 22 : void ScCondFormatEntry::DataChanged( const ScRange* pModified ) const
1611 : {
1612 22 : if ( pCondFormat )
1613 22 : pCondFormat->DoRepaint( pModified );
1614 22 : }
1615 :
1616 68 : ScFormatEntry* ScCondFormatEntry::Clone( ScDocument* pDoc ) const
1617 : {
1618 68 : return new ScCondFormatEntry( pDoc, *this );
1619 : }
1620 :
1621 0 : ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument* pDoc )
1622 : : ScFormatEntry( pDoc )
1623 0 : , meType(condformat::TODAY)
1624 : {
1625 0 : }
1626 :
1627 0 : ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument* pDoc, const ScCondDateFormatEntry& rFormat ):
1628 : ScFormatEntry( pDoc ),
1629 : meType( rFormat.meType ),
1630 0 : maStyleName( rFormat.maStyleName )
1631 : {
1632 0 : }
1633 :
1634 0 : bool ScCondDateFormatEntry::IsValid( const ScAddress& rPos ) const
1635 : {
1636 0 : CellType eCellType = mpDoc->GetCellType(rPos);
1637 :
1638 0 : if (eCellType == CELLTYPE_NONE)
1639 : // empty cell.
1640 0 : return false;
1641 :
1642 0 : if (eCellType != CELLTYPE_VALUE && eCellType != CELLTYPE_FORMULA)
1643 : // non-numerical cell.
1644 0 : return false;
1645 :
1646 0 : if( !mpCache )
1647 0 : mpCache.reset( new Date( Date::SYSTEM ) );
1648 :
1649 0 : const Date& rActDate = *mpCache;
1650 0 : SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
1651 0 : long nCurrentDate = rActDate - *(pFormatter->GetNullDate());
1652 :
1653 0 : double nVal = mpDoc->GetValue(rPos);
1654 0 : long nCellDate = (long) ::rtl::math::approxFloor(nVal);
1655 0 : Date aCellDate = *(pFormatter->GetNullDate());
1656 0 : aCellDate += (long) ::rtl::math::approxFloor(nVal);
1657 :
1658 0 : switch(meType)
1659 : {
1660 : case condformat::TODAY:
1661 0 : if( nCurrentDate == nCellDate )
1662 0 : return true;
1663 0 : break;
1664 : case condformat::TOMORROW:
1665 0 : if( nCurrentDate == nCellDate -1 )
1666 0 : return true;
1667 0 : break;
1668 : case condformat::YESTERDAY:
1669 0 : if( nCurrentDate == nCellDate + 1)
1670 0 : return true;
1671 0 : break;
1672 : case condformat::LAST7DAYS:
1673 0 : if( nCurrentDate >= nCellDate && nCurrentDate - 7 < nCellDate )
1674 0 : return true;
1675 0 : break;
1676 : case condformat::LASTWEEK:
1677 0 : if( rActDate.GetDayOfWeek() != SUNDAY )
1678 : {
1679 0 : Date aBegin(rActDate - 8 - static_cast<long>(rActDate.GetDayOfWeek()));
1680 0 : Date aEnd(rActDate - 2 -static_cast<long>(rActDate.GetDayOfWeek()));
1681 0 : return aCellDate.IsBetween( aBegin, aEnd );
1682 : }
1683 : else
1684 : {
1685 0 : Date aBegin(rActDate - 8);
1686 0 : Date aEnd(rActDate - 1);
1687 0 : return aCellDate.IsBetween( aBegin, aEnd );
1688 : }
1689 : break;
1690 : case condformat::THISWEEK:
1691 0 : if( rActDate.GetDayOfWeek() != SUNDAY )
1692 : {
1693 0 : Date aBegin(rActDate - 1 - static_cast<long>(rActDate.GetDayOfWeek()));
1694 0 : Date aEnd(rActDate + 5 - static_cast<long>(rActDate.GetDayOfWeek()));
1695 0 : return aCellDate.IsBetween( aBegin, aEnd );
1696 : }
1697 : else
1698 : {
1699 0 : Date aEnd( rActDate + 6);
1700 0 : return aCellDate.IsBetween( rActDate, aEnd );
1701 : }
1702 : break;
1703 : case condformat::NEXTWEEK:
1704 0 : if( rActDate.GetDayOfWeek() != SUNDAY )
1705 : {
1706 0 : return aCellDate.IsBetween( rActDate + 6 - static_cast<long>(rActDate.GetDayOfWeek()), rActDate + 12 - static_cast<long>(rActDate.GetDayOfWeek()) );
1707 : }
1708 : else
1709 : {
1710 0 : return aCellDate.IsBetween( rActDate + 7, rActDate + 13 );
1711 : }
1712 : break;
1713 : case condformat::LASTMONTH:
1714 0 : if( rActDate.GetMonth() == 1 )
1715 : {
1716 0 : if( aCellDate.GetMonth() == 12 && rActDate.GetYear() == aCellDate.GetYear() + 1 )
1717 0 : return true;
1718 : }
1719 0 : else if( rActDate.GetYear() == aCellDate.GetYear() )
1720 : {
1721 0 : if( rActDate.GetMonth() == aCellDate.GetMonth() + 1)
1722 0 : return true;
1723 : }
1724 0 : break;
1725 : case condformat::THISMONTH:
1726 0 : if( rActDate.GetYear() == aCellDate.GetYear() )
1727 : {
1728 0 : if( rActDate.GetMonth() == aCellDate.GetMonth() )
1729 0 : return true;
1730 : }
1731 0 : break;
1732 : case condformat::NEXTMONTH:
1733 0 : if( rActDate.GetMonth() == 12 )
1734 : {
1735 0 : if( aCellDate.GetMonth() == 1 && rActDate.GetYear() == aCellDate.GetYear() - 1 )
1736 0 : return true;
1737 : }
1738 0 : else if( rActDate.GetYear() == aCellDate.GetYear() )
1739 : {
1740 0 : if( rActDate.GetMonth() == aCellDate.GetMonth() - 1)
1741 0 : return true;
1742 : }
1743 0 : break;
1744 : case condformat::LASTYEAR:
1745 0 : if( rActDate.GetYear() == aCellDate.GetYear() + 1 )
1746 0 : return true;
1747 0 : break;
1748 : case condformat::THISYEAR:
1749 0 : if( rActDate.GetYear() == aCellDate.GetYear() )
1750 0 : return true;
1751 0 : break;
1752 : case condformat::NEXTYEAR:
1753 0 : if( rActDate.GetYear() == aCellDate.GetYear() - 1 )
1754 0 : return true;
1755 0 : break;
1756 : }
1757 :
1758 0 : return false;
1759 : }
1760 :
1761 0 : void ScCondDateFormatEntry::SetDateType( condformat::ScCondFormatDateType eType )
1762 : {
1763 0 : meType = eType;
1764 0 : }
1765 :
1766 0 : void ScCondDateFormatEntry::SetStyleName( const OUString& rStyleName )
1767 : {
1768 0 : maStyleName = rStyleName;
1769 0 : }
1770 :
1771 0 : ScFormatEntry* ScCondDateFormatEntry::Clone( ScDocument* pDoc ) const
1772 : {
1773 0 : return new ScCondDateFormatEntry( pDoc, *this );
1774 : }
1775 :
1776 0 : bool ScCondDateFormatEntry::operator==( const ScFormatEntry& r ) const
1777 : {
1778 0 : if(r.GetType() != condformat::DATE)
1779 0 : return false;
1780 :
1781 0 : const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(r);
1782 :
1783 0 : if(rEntry.meType != meType)
1784 0 : return false;
1785 :
1786 0 : return rEntry.maStyleName == maStyleName;
1787 : }
1788 :
1789 0 : void ScCondDateFormatEntry::startRendering()
1790 : {
1791 0 : mpCache.reset();
1792 0 : }
1793 :
1794 0 : void ScCondDateFormatEntry::endRendering()
1795 : {
1796 0 : mpCache.reset();
1797 0 : }
1798 :
1799 2686 : ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
1800 : pDoc( pDocument ),
1801 2686 : nKey( nNewKey )
1802 : {
1803 2686 : }
1804 :
1805 2372 : ScConditionalFormat* ScConditionalFormat::Clone(ScDocument* pNewDoc) const
1806 : {
1807 : // Real copy of the formula (for Ref Undo/between documents)
1808 2372 : if (!pNewDoc)
1809 4 : pNewDoc = pDoc;
1810 :
1811 2372 : ScConditionalFormat* pNew = new ScConditionalFormat(nKey, pNewDoc);
1812 :
1813 2440 : for (CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1814 : {
1815 68 : ScFormatEntry* pNewEntry = itr->Clone(pNewDoc);
1816 68 : pNew->maEntries.push_back( pNewEntry );
1817 68 : pNewEntry->SetParent(pNew);
1818 : }
1819 2372 : pNew->AddRange( maRanges );
1820 :
1821 2372 : return pNew;
1822 : }
1823 :
1824 0 : bool ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const
1825 : {
1826 0 : if( size() != r.size())
1827 0 : return false;
1828 :
1829 : //TODO: Test for same entries in reverse order?
1830 0 : for (sal_uInt16 i=0; i<size(); i++)
1831 0 : if ( ! (maEntries == r.maEntries ) )
1832 0 : return false;
1833 :
1834 : // right now don't check for same range
1835 : // we only use this method to merge same conditional formats from
1836 : // old ODF data structure
1837 0 : return true;
1838 : }
1839 :
1840 3832 : void ScConditionalFormat::AddRange( const ScRangeList& rRanges )
1841 : {
1842 3832 : maRanges = rRanges;
1843 3832 : }
1844 :
1845 396 : void ScConditionalFormat::AddEntry( ScFormatEntry* pNew )
1846 : {
1847 396 : maEntries.push_back(pNew);
1848 396 : pNew->SetParent(this);
1849 396 : }
1850 :
1851 0 : bool ScConditionalFormat::IsEmpty() const
1852 : {
1853 0 : return maEntries.empty();
1854 : }
1855 :
1856 24620 : size_t ScConditionalFormat::size() const
1857 : {
1858 24620 : return maEntries.size();
1859 : }
1860 :
1861 2686 : ScConditionalFormat::~ScConditionalFormat()
1862 : {
1863 2686 : }
1864 :
1865 8948 : const ScFormatEntry* ScConditionalFormat::GetEntry( sal_uInt16 nPos ) const
1866 : {
1867 8948 : if ( nPos < size() )
1868 8948 : return &maEntries[nPos];
1869 : else
1870 0 : return NULL;
1871 : }
1872 :
1873 7994 : const OUString& ScConditionalFormat::GetCellStyle( ScRefCellValue& rCell, const ScAddress& rPos ) const
1874 : {
1875 8912 : for (CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1876 : {
1877 1436 : if(itr->GetType() == condformat::CONDITION)
1878 : {
1879 1436 : const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*itr);
1880 1436 : if (rEntry.IsCellValid(rCell, rPos))
1881 1036 : return rEntry.GetStyle();
1882 : }
1883 0 : else if(itr->GetType() == condformat::DATE)
1884 : {
1885 0 : const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*itr);
1886 0 : if (rEntry.IsValid( rPos ))
1887 0 : return rEntry.GetStyleName();
1888 : }
1889 : }
1890 :
1891 7476 : return EMPTY_OUSTRING;
1892 : }
1893 :
1894 30730 : ScCondFormatData ScConditionalFormat::GetData( ScRefCellValue& rCell, const ScAddress& rPos ) const
1895 : {
1896 30730 : ScCondFormatData aData;
1897 34532 : for(CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1898 : {
1899 3802 : if(itr->GetType() == condformat::CONDITION && aData.aStyleName.isEmpty())
1900 : {
1901 3802 : const ScCondFormatEntry& rEntry = static_cast<const ScCondFormatEntry&>(*itr);
1902 3802 : if (rEntry.IsCellValid(rCell, rPos))
1903 160 : aData.aStyleName = rEntry.GetStyle();
1904 : }
1905 0 : else if(itr->GetType() == condformat::COLORSCALE && !aData.pColorScale)
1906 : {
1907 0 : const ScColorScaleFormat& rEntry = static_cast<const ScColorScaleFormat&>(*itr);
1908 0 : aData.pColorScale = rEntry.GetColor(rPos);
1909 : }
1910 0 : else if(itr->GetType() == condformat::DATABAR && !aData.pDataBar)
1911 : {
1912 0 : const ScDataBarFormat& rEntry = static_cast<const ScDataBarFormat&>(*itr);
1913 0 : aData.pDataBar = rEntry.GetDataBarInfo(rPos);
1914 : }
1915 0 : else if(itr->GetType() == condformat::ICONSET && !aData.pIconSet)
1916 : {
1917 0 : const ScIconSetFormat& rEntry = static_cast<const ScIconSetFormat&>(*itr);
1918 0 : aData.pIconSet = rEntry.GetIconSetInfo(rPos);
1919 : }
1920 0 : else if(itr->GetType() == condformat::DATE && aData.aStyleName.isEmpty())
1921 : {
1922 0 : const ScCondDateFormatEntry& rEntry = static_cast<const ScCondDateFormatEntry&>(*itr);
1923 0 : if ( rEntry.IsValid( rPos ) )
1924 0 : aData.aStyleName = rEntry.GetStyleName();
1925 : }
1926 : }
1927 30730 : return aData;
1928 : }
1929 :
1930 22 : void ScConditionalFormat::DoRepaint( const ScRange* pModified )
1931 : {
1932 22 : if(pModified)
1933 : {
1934 22 : if(maRanges.Intersects(*pModified))
1935 22 : pDoc->RepaintRange(*pModified);
1936 : }
1937 : else
1938 : {
1939 : // all conditional format cells
1940 0 : pDoc->RepaintRange( maRanges );
1941 : }
1942 22 : }
1943 :
1944 4 : void ScConditionalFormat::CompileAll()
1945 : {
1946 8 : for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1947 4 : if(itr->GetType() == condformat::CONDITION)
1948 4 : static_cast<ScCondFormatEntry&>(*itr).CompileAll();
1949 4 : }
1950 :
1951 132 : void ScConditionalFormat::CompileXML()
1952 : {
1953 312 : for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1954 180 : if(itr->GetType() == condformat::CONDITION)
1955 114 : static_cast<ScCondFormatEntry&>(*itr).CompileXML();
1956 132 : }
1957 :
1958 1178 : void ScConditionalFormat::UpdateReference( sc::RefUpdateContext& rCxt, bool bCopyAsMove )
1959 : {
1960 1204 : for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
1961 26 : itr->UpdateReference(rCxt);
1962 :
1963 1178 : if (rCxt.meMode == URM_COPY && bCopyAsMove)
1964 1164 : maRanges.UpdateReference(URM_MOVE, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
1965 : else
1966 14 : maRanges.UpdateReference(rCxt.meMode, pDoc, rCxt.maRange, rCxt.mnColDelta, rCxt.mnRowDelta, rCxt.mnTabDelta);
1967 1178 : }
1968 :
1969 2 : void ScConditionalFormat::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
1970 : {
1971 2 : maRanges.InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
1972 2 : }
1973 :
1974 4 : void ScConditionalFormat::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
1975 : {
1976 4 : maRanges.InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
1977 4 : }
1978 :
1979 6 : void ScConditionalFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
1980 : {
1981 12 : for (size_t i = 0, n = maRanges.size(); i < n; ++i)
1982 : {
1983 : // We assume that the start and end sheet indices are equal.
1984 6 : ScRange* pRange = maRanges[i];
1985 6 : SCTAB nTab = pRange->aStart.Tab();
1986 :
1987 6 : if (nTab < rCxt.mnInsertPos)
1988 : // Unaffected.
1989 2 : continue;
1990 :
1991 4 : pRange->aStart.IncTab(rCxt.mnSheets);
1992 4 : pRange->aEnd.IncTab(rCxt.mnSheets);
1993 : }
1994 :
1995 12 : for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
1996 6 : it->UpdateInsertTab(rCxt);
1997 6 : }
1998 :
1999 8 : void ScConditionalFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
2000 : {
2001 16 : for (size_t i = 0, n = maRanges.size(); i < n; ++i)
2002 : {
2003 : // We assume that the start and end sheet indices are equal.
2004 8 : ScRange* pRange = maRanges[i];
2005 8 : SCTAB nTab = pRange->aStart.Tab();
2006 :
2007 8 : if (nTab < rCxt.mnDeletePos)
2008 : // Left of the deleted sheet(s). Unaffected.
2009 2 : continue;
2010 :
2011 6 : if (nTab <= rCxt.mnDeletePos+rCxt.mnSheets-1)
2012 : {
2013 : // On the deleted sheet(s).
2014 4 : pRange->aStart.SetTab(-1);
2015 4 : pRange->aEnd.SetTab(-1);
2016 4 : continue;
2017 : }
2018 :
2019 : // Right of the deleted sheet(s). Adjust the sheet indices.
2020 2 : pRange->aStart.IncTab(-1*rCxt.mnSheets);
2021 2 : pRange->aEnd.IncTab(-1*rCxt.mnSheets);
2022 : }
2023 :
2024 16 : for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
2025 8 : it->UpdateDeleteTab(rCxt);
2026 8 : }
2027 :
2028 0 : void ScConditionalFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
2029 : {
2030 0 : size_t n = maRanges.size();
2031 0 : SCTAB nMinTab = std::min<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
2032 0 : SCTAB nMaxTab = std::max<SCTAB>(rCxt.mnOldPos, rCxt.mnNewPos);
2033 0 : for(size_t i = 0; i < n; ++i)
2034 : {
2035 0 : ScRange* pRange = maRanges[i];
2036 0 : SCTAB nTab = pRange->aStart.Tab();
2037 0 : if(nTab < nMinTab || nTab > nMaxTab)
2038 : {
2039 0 : continue;
2040 : }
2041 :
2042 0 : if (nTab == rCxt.mnOldPos)
2043 : {
2044 0 : pRange->aStart.SetTab(rCxt.mnNewPos);
2045 0 : pRange->aEnd.SetTab(rCxt.mnNewPos);
2046 0 : continue;
2047 : }
2048 :
2049 0 : if (rCxt.mnNewPos < rCxt.mnOldPos)
2050 : {
2051 0 : pRange->aStart.IncTab();
2052 0 : pRange->aEnd.IncTab();
2053 : }
2054 : else
2055 : {
2056 0 : pRange->aStart.IncTab(-1);
2057 0 : pRange->aEnd.IncTab(-1);
2058 : }
2059 : }
2060 :
2061 0 : for (CondFormatContainer::iterator it = maEntries.begin(); it != maEntries.end(); ++it)
2062 0 : it->UpdateMoveTab(rCxt);
2063 0 : }
2064 :
2065 1236 : void ScConditionalFormat::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2066 : {
2067 1236 : SCTAB nTab = maRanges[0]->aStart.Tab();
2068 1236 : maRanges.DeleteArea( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
2069 1236 : }
2070 :
2071 0 : void ScConditionalFormat::RenameCellStyle(const OUString& rOld, const OUString& rNew)
2072 : {
2073 0 : for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2074 0 : if(itr->GetType() == condformat::CONDITION)
2075 : {
2076 0 : ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*itr);
2077 0 : if(rFormat.GetStyle() == rOld)
2078 0 : rFormat.UpdateStyleName( rNew );
2079 : }
2080 0 : }
2081 :
2082 210 : void ScConditionalFormat::SourceChanged( const ScAddress& rAddr )
2083 : {
2084 398 : for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2085 : {
2086 188 : condformat::ScFormatEntryType eEntryType = itr->GetType();
2087 188 : if( eEntryType == condformat::CONDITION)
2088 : {
2089 188 : ScCondFormatEntry& rFormat = static_cast<ScCondFormatEntry&>(*itr);
2090 188 : rFormat.SourceChanged( rAddr );
2091 : }
2092 0 : else if( eEntryType == condformat::COLORSCALE ||
2093 0 : eEntryType == condformat::DATABAR ||
2094 : eEntryType == condformat::ICONSET )
2095 : {
2096 0 : ScColorFormat& rFormat = static_cast<ScColorFormat&>(*itr);
2097 0 : if(rFormat.NeedsRepaint())
2098 : {
2099 : // we need to repaint the whole range anyway
2100 0 : DoRepaint(NULL);
2101 0 : return;
2102 : }
2103 : }
2104 : }
2105 : }
2106 :
2107 0 : bool ScConditionalFormat::MarkUsedExternalReferences() const
2108 : {
2109 0 : bool bAllMarked = false;
2110 0 : for(CondFormatContainer::const_iterator itr = maEntries.begin(); itr != maEntries.end() && !bAllMarked; ++itr)
2111 0 : if(itr->GetType() == condformat::CONDITION)
2112 : {
2113 0 : const ScCondFormatEntry& rFormat = static_cast<const ScCondFormatEntry&>(*itr);
2114 0 : bAllMarked = rFormat.MarkUsedExternalReferences();
2115 : }
2116 :
2117 0 : return bAllMarked;
2118 : }
2119 :
2120 1627 : void ScConditionalFormat::startRendering()
2121 : {
2122 1823 : for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2123 : {
2124 196 : itr->startRendering();
2125 : }
2126 1627 : }
2127 :
2128 1627 : void ScConditionalFormat::endRendering()
2129 : {
2130 1823 : for(CondFormatContainer::iterator itr = maEntries.begin(); itr != maEntries.end(); ++itr)
2131 : {
2132 196 : itr->endRendering();
2133 : }
2134 1627 : }
2135 :
2136 0 : ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList& rList)
2137 : {
2138 0 : for(const_iterator itr = rList.begin(); itr != rList.end(); ++itr)
2139 0 : InsertNew( itr->Clone() );
2140 0 : }
2141 :
2142 1652 : ScConditionalFormatList::ScConditionalFormatList(ScDocument* pDoc, const ScConditionalFormatList& rList)
2143 : {
2144 2856 : for(const_iterator itr = rList.begin(); itr != rList.end(); ++itr)
2145 1204 : InsertNew( itr->Clone(pDoc) );
2146 1652 : }
2147 :
2148 2664 : void ScConditionalFormatList::InsertNew( ScConditionalFormat* pNew )
2149 : {
2150 2664 : maConditionalFormats.insert(pNew);
2151 2664 : }
2152 :
2153 0 : bool ScConditionalFormatList::operator==( const ScConditionalFormatList& r ) const
2154 : {
2155 : // For Ref Undo - internal variables are not compared
2156 0 : sal_uInt16 nCount = size();
2157 0 : bool bEqual = ( nCount == r.size() );
2158 0 : const_iterator locIterator = begin();
2159 0 : for(const_iterator itr = r.begin(); itr != r.end() && bEqual; ++itr, ++locIterator)
2160 0 : if ( !locIterator->EqualEntries(*itr) ) // Entries differ?
2161 0 : bEqual = false;
2162 :
2163 0 : return bEqual;
2164 : }
2165 :
2166 45048 : ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey )
2167 : {
2168 : //FIXME: Binary search
2169 79154 : for( iterator itr = begin(); itr != end(); ++itr)
2170 79154 : if (itr->GetKey() == nKey)
2171 45048 : return &(*itr);
2172 :
2173 : SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2174 0 : return NULL;
2175 : }
2176 :
2177 7994 : const ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey ) const
2178 : {
2179 : //FIXME: Binary search
2180 19326 : for ( const_iterator itr = begin(); itr != end(); ++itr)
2181 19326 : if (itr->GetKey() == nKey)
2182 7994 : return &(*itr);
2183 :
2184 : SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2185 0 : return NULL;
2186 : }
2187 :
2188 62 : void ScConditionalFormatList::CompileAll()
2189 : {
2190 66 : for( iterator itr = begin(); itr != end(); ++itr)
2191 4 : itr->CompileAll();
2192 62 : }
2193 :
2194 578 : void ScConditionalFormatList::CompileXML()
2195 : {
2196 710 : for( iterator itr = begin(); itr != end(); ++itr)
2197 132 : itr->CompileXML();
2198 578 : }
2199 :
2200 494 : void ScConditionalFormatList::UpdateReference( sc::RefUpdateContext& rCxt )
2201 : {
2202 508 : for( iterator itr = begin(); itr != end(); ++itr)
2203 14 : itr->UpdateReference(rCxt);
2204 :
2205 494 : if (rCxt.meMode == URM_INSDEL)
2206 : {
2207 : // need to check which must be deleted
2208 344 : iterator itr = begin();
2209 694 : while(itr != end())
2210 : {
2211 6 : if(itr->GetRange().empty())
2212 0 : maConditionalFormats.erase(itr++);
2213 : else
2214 6 : ++itr;
2215 : }
2216 : }
2217 494 : }
2218 :
2219 98 : void ScConditionalFormatList::InsertRow(SCTAB nTab, SCCOL nColStart, SCCOL nColEnd, SCROW nRowPos, SCSIZE nSize)
2220 : {
2221 100 : for(iterator it = begin(), itEnd = end(); it != itEnd; ++it)
2222 2 : it->InsertRow(nTab, nColStart, nColEnd, nRowPos, nSize);
2223 98 : }
2224 :
2225 72 : void ScConditionalFormatList::InsertCol(SCTAB nTab, SCROW nRowStart, SCROW nRowEnd, SCCOL nColPos, SCSIZE nSize)
2226 : {
2227 76 : for(iterator it = begin(), itEnd = end(); it != itEnd; ++it)
2228 4 : it->InsertCol(nTab, nRowStart, nRowEnd, nColPos, nSize);
2229 72 : }
2230 :
2231 268 : void ScConditionalFormatList::UpdateInsertTab( sc::RefUpdateInsertTabContext& rCxt )
2232 : {
2233 274 : for (iterator it = begin(); it != end(); ++it)
2234 6 : it->UpdateInsertTab(rCxt);
2235 268 : }
2236 :
2237 428 : void ScConditionalFormatList::UpdateDeleteTab( sc::RefUpdateDeleteTabContext& rCxt )
2238 : {
2239 436 : for (iterator it = begin(); it != end(); ++it)
2240 8 : it->UpdateDeleteTab(rCxt);
2241 428 : }
2242 :
2243 78 : void ScConditionalFormatList::UpdateMoveTab( sc::RefUpdateMoveTabContext& rCxt )
2244 : {
2245 78 : for (iterator it = begin(); it != end(); ++it)
2246 0 : it->UpdateMoveTab(rCxt);
2247 78 : }
2248 :
2249 0 : void ScConditionalFormatList::RenameCellStyle( const OUString& rOld, const OUString& rNew )
2250 : {
2251 0 : for( iterator itr = begin(); itr != end(); ++itr)
2252 0 : itr->RenameCellStyle(rOld,rNew);
2253 0 : }
2254 :
2255 2498 : bool ScConditionalFormatList::CheckAllEntries()
2256 : {
2257 2498 : bool bValid = true;
2258 :
2259 : // need to check which must be deleted
2260 2498 : iterator itr = begin();
2261 6364 : while(itr != end())
2262 : {
2263 1368 : if(itr->GetRange().empty())
2264 : {
2265 1156 : bValid = false;
2266 1156 : maConditionalFormats.erase(itr++);
2267 : }
2268 : else
2269 212 : ++itr;
2270 : }
2271 :
2272 2498 : return bValid;
2273 : }
2274 :
2275 2468 : void ScConditionalFormatList::DeleteArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2276 : {
2277 3704 : for( iterator itr = begin(); itr != end(); ++itr)
2278 1236 : itr->DeleteArea( nCol1, nRow1, nCol2, nRow2 );
2279 :
2280 2468 : CheckAllEntries();
2281 2468 : }
2282 :
2283 151286 : void ScConditionalFormatList::SourceChanged( const ScAddress& rAddr )
2284 : {
2285 151496 : for( iterator itr = begin(); itr != end(); ++itr)
2286 210 : itr->SourceChanged( rAddr );
2287 151286 : }
2288 :
2289 239910 : ScConditionalFormatList::iterator ScConditionalFormatList::begin()
2290 : {
2291 239910 : return maConditionalFormats.begin();
2292 : }
2293 :
2294 9794 : ScConditionalFormatList::const_iterator ScConditionalFormatList::begin() const
2295 : {
2296 9794 : return maConditionalFormats.begin();
2297 : }
2298 :
2299 282108 : ScConditionalFormatList::iterator ScConditionalFormatList::end()
2300 : {
2301 282108 : return maConditionalFormats.end();
2302 : }
2303 :
2304 22396 : ScConditionalFormatList::const_iterator ScConditionalFormatList::end() const
2305 : {
2306 22396 : return maConditionalFormats.end();
2307 : }
2308 :
2309 60 : size_t ScConditionalFormatList::size() const
2310 : {
2311 60 : return maConditionalFormats.size();
2312 : }
2313 :
2314 0 : void ScConditionalFormatList::erase( sal_uLong nIndex )
2315 : {
2316 0 : for( iterator itr = begin(); itr != end(); ++itr )
2317 : {
2318 0 : if( itr->GetKey() == nIndex )
2319 : {
2320 0 : maConditionalFormats.erase(itr);
2321 0 : break;
2322 : }
2323 : }
2324 0 : }
2325 :
2326 16360 : void ScConditionalFormatList::startRendering()
2327 : {
2328 17987 : for(iterator itr = begin(); itr != end(); ++itr)
2329 : {
2330 1627 : itr->startRendering();
2331 : }
2332 16360 : }
2333 :
2334 16360 : void ScConditionalFormatList::endRendering()
2335 : {
2336 17987 : for(iterator itr = begin(); itr != end(); ++itr)
2337 : {
2338 1627 : itr->endRendering();
2339 : }
2340 16588 : }
2341 :
2342 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|