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