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