xref: /AOO41X/main/sc/source/core/data/conditio.cxx (revision 6dfe295f00cc28dd3ec66d4599aca1aa6c372dde)
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