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