1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scitems.hxx"
21 #include <sfx2/objsh.hxx>
22 #include <svl/itemset.hxx>
23 #include <svl/zforlist.hxx>
24 #include <rtl/math.hxx>
25 #include <unotools/collatorwrapper.hxx>
27 #include <com/sun/star/sheet/ConditionOperator2.hpp>
29 #include "conditio.hxx"
30 #include "formulacell.hxx"
31 #include "document.hxx"
33 #include "compiler.hxx"
34 #include "rechead.hxx"
35 #include "rangelst.hxx"
36 #include "stlpool.hxx"
37 #include "rangenam.hxx"
38 #include "colorscale.hxx"
39 #include "cellvalue.hxx"
40 #include "editutil.hxx"
41 #include "tokenarray.hxx"
42 #include "refupdatecontext.hxx"
43 #include "svl/sharedstring.hxx"
45 using namespace formula
;
46 //------------------------------------------------------------------------
48 ScFormatEntry::ScFormatEntry(ScDocument
* pDoc
):
53 bool ScFormatEntry::operator==( const ScFormatEntry
& r
) const
55 if(GetType() != r
.GetType())
60 case condformat::CONDITION
:
61 return static_cast<const ScCondFormatEntry
&>(*this) == static_cast<const ScCondFormatEntry
&>(r
);
63 // TODO: implement also this case
64 // actually return false for these cases is not that bad
65 // as soon as databar and color scale are tested we need
66 // to think about the range
71 void ScFormatEntry::startRendering()
75 void ScFormatEntry::endRendering()
79 static bool lcl_HasRelRef( ScDocument
* pDoc
, ScTokenArray
* pFormula
, sal_uInt16 nRecursion
= 0 )
85 for( t
= pFormula
->Next(); t
; t
= pFormula
->Next() )
87 switch( t
->GetType() )
91 ScSingleRefData
& rRef2
= static_cast<ScToken
*>(t
)->GetDoubleRef().Ref2
;
92 if ( rRef2
.IsColRel() || rRef2
.IsRowRel() || rRef2
.IsTabRel() )
99 ScSingleRefData
& rRef1
= static_cast<ScToken
*>(t
)->GetSingleRef();
100 if ( rRef1
.IsColRel() || rRef1
.IsRowRel() || rRef1
.IsTabRel() )
107 if( t
->GetOpCode() == ocName
) // DB areas always absolute
108 if( ScRangeData
* pRangeData
= pDoc
->GetRangeName()->findByIndex( t
->GetIndex() ) )
109 if( (nRecursion
< 42) && lcl_HasRelRef( pDoc
, pRangeData
->GetCode(), nRecursion
+ 1 ) )
114 // #i34474# function result dependent on cell position
117 switch( t
->GetOpCode() )
119 case ocRow
: // ROW() returns own row index
120 case ocColumn
: // COLUMN() returns own column index
121 case ocTable
: // SHEET() returns own sheet index
122 case ocCell
: // CELL() may return own cell address
127 // added to avoid warnings
135 // added to avoid warnings
143 ScConditionEntry::ScConditionEntry( const ScConditionEntry
& r
) :
144 ScFormatEntry(r
.mpDoc
),
146 nOptions(r
.nOptions
),
149 aStrVal1(r
.aStrVal1
),
150 aStrVal2(r
.aStrVal2
),
151 aStrNmsp1(r
.aStrNmsp1
),
152 aStrNmsp2(r
.aStrNmsp2
),
153 eTempGrammar1(r
.eTempGrammar1
),
154 eTempGrammar2(r
.eTempGrammar2
),
160 aSrcString(r
.aSrcString
),
163 bRelRef1(r
.bRelRef1
),
164 bRelRef2(r
.bRelRef2
),
166 pCondFormat(r
.pCondFormat
)
168 // ScTokenArray copy ctor erzeugt flache Kopie
171 pFormula1
= new ScTokenArray( *r
.pFormula1
);
173 pFormula2
= new ScTokenArray( *r
.pFormula2
);
175 // Formelzellen werden erst bei IsValid angelegt
178 ScConditionEntry::ScConditionEntry( ScDocument
* pDocument
, const ScConditionEntry
& r
) :
179 ScFormatEntry(pDocument
),
181 nOptions(r
.nOptions
),
184 aStrVal1(r
.aStrVal1
),
185 aStrVal2(r
.aStrVal2
),
186 aStrNmsp1(r
.aStrNmsp1
),
187 aStrNmsp2(r
.aStrNmsp2
),
188 eTempGrammar1(r
.eTempGrammar1
),
189 eTempGrammar2(r
.eTempGrammar2
),
195 aSrcString(r
.aSrcString
),
198 bRelRef1(r
.bRelRef1
),
199 bRelRef2(r
.bRelRef2
),
201 pCondFormat(r
.pCondFormat
)
203 // echte Kopie der Formeln (fuer Ref-Undo)
206 pFormula1
= r
.pFormula1
->Clone();
208 pFormula2
= r
.pFormula2
->Clone();
210 // Formelzellen werden erst bei IsValid angelegt
211 //! im Clipboard nicht - dann vorher interpretieren !!!
214 ScConditionEntry::ScConditionEntry( ScConditionMode eOper
,
215 const OUString
& rExpr1
, const OUString
& rExpr2
, ScDocument
* pDocument
, const ScAddress
& rPos
,
216 const OUString
& rExprNmsp1
, const OUString
& rExprNmsp2
,
217 FormulaGrammar::Grammar eGrammar1
, FormulaGrammar::Grammar eGrammar2
) :
218 ScFormatEntry(pDocument
),
223 aStrNmsp1(rExprNmsp1
),
224 aStrNmsp2(rExprNmsp2
),
225 eTempGrammar1(eGrammar1
),
226 eTempGrammar2(eGrammar2
),
239 Compile( rExpr1
, rExpr2
, rExprNmsp1
, rExprNmsp2
, eGrammar1
, eGrammar2
, false );
241 // Formelzellen werden erst bei IsValid angelegt
244 ScConditionEntry::ScConditionEntry( ScConditionMode eOper
,
245 const ScTokenArray
* pArr1
, const ScTokenArray
* pArr2
,
246 ScDocument
* pDocument
, const ScAddress
& rPos
) :
247 ScFormatEntry(pDocument
),
252 eTempGrammar1(FormulaGrammar::GRAM_DEFAULT
),
253 eTempGrammar2(FormulaGrammar::GRAM_DEFAULT
),
268 pFormula1
= new ScTokenArray( *pArr1
);
269 if ( pFormula1
->GetLen() == 1 )
271 // einzelne (konstante Zahl) ?
272 FormulaToken
* pToken
= pFormula1
->First();
273 if ( pToken
->GetOpCode() == ocPush
)
275 if ( pToken
->GetType() == svDouble
)
277 nVal1
= pToken
->GetDouble();
278 DELETEZ(pFormula1
); // nicht als Formel merken
280 else if ( pToken
->GetType() == svString
)
283 aStrVal1
= pToken
->GetString().getString();
284 DELETEZ(pFormula1
); // nicht als Formel merken
288 bRelRef1
= lcl_HasRelRef( mpDoc
, pFormula1
);
292 pFormula2
= new ScTokenArray( *pArr2
);
293 if ( pFormula2
->GetLen() == 1 )
295 // einzelne (konstante Zahl) ?
296 FormulaToken
* pToken
= pFormula2
->First();
297 if ( pToken
->GetOpCode() == ocPush
)
299 if ( pToken
->GetType() == svDouble
)
301 nVal2
= pToken
->GetDouble();
302 DELETEZ(pFormula2
); // nicht als Formel merken
304 else if ( pToken
->GetType() == svString
)
307 aStrVal2
= pToken
->GetString().getString();
308 DELETEZ(pFormula2
); // nicht als Formel merken
312 bRelRef2
= lcl_HasRelRef( mpDoc
, pFormula2
);
315 // formula cells are created at IsValid
318 ScConditionEntry::~ScConditionEntry()
327 void ScConditionEntry::Compile( const OUString
& rExpr1
, const OUString
& rExpr2
,
328 const OUString
& rExprNmsp1
, const OUString
& rExprNmsp2
,
329 FormulaGrammar::Grammar eGrammar1
, FormulaGrammar::Grammar eGrammar2
, bool bTextToReal
)
331 if ( !rExpr1
.isEmpty() || !rExpr2
.isEmpty() )
333 ScCompiler
aComp( mpDoc
, aSrcPos
);
335 if ( !rExpr1
.isEmpty() )
337 aComp
.SetGrammar( eGrammar1
);
338 if ( mpDoc
->IsImportingXML() && !bTextToReal
)
340 // temporary formula string as string tokens
341 //! merge with lcl_ScDocFunc_CreateTokenArrayXML
342 pFormula1
= new ScTokenArray
;
343 pFormula1
->AddStringXML( rExpr1
);
344 // bRelRef1 is set when the formula is compiled again (CompileXML)
348 pFormula1
= aComp
.CompileString( rExpr1
, rExprNmsp1
);
349 if ( pFormula1
->GetLen() == 1 )
351 // einzelne (konstante Zahl) ?
352 FormulaToken
* pToken
= pFormula1
->First();
353 if ( pToken
->GetOpCode() == ocPush
)
355 if ( pToken
->GetType() == svDouble
)
357 nVal1
= pToken
->GetDouble();
358 DELETEZ(pFormula1
); // nicht als Formel merken
360 else if ( pToken
->GetType() == svString
)
363 aStrVal1
= pToken
->GetString().getString();
364 DELETEZ(pFormula1
); // nicht als Formel merken
368 bRelRef1
= lcl_HasRelRef( mpDoc
, pFormula1
);
372 if ( !rExpr2
.isEmpty() )
374 aComp
.SetGrammar( eGrammar2
);
375 if ( mpDoc
->IsImportingXML() && !bTextToReal
)
377 // temporary formula string as string tokens
378 //! merge with lcl_ScDocFunc_CreateTokenArrayXML
379 pFormula2
= new ScTokenArray
;
380 pFormula2
->AddStringXML( rExpr2
);
381 // bRelRef2 is set when the formula is compiled again (CompileXML)
385 pFormula2
= aComp
.CompileString( rExpr2
, rExprNmsp2
);
386 if ( pFormula2
->GetLen() == 1 )
388 // einzelne (konstante Zahl) ?
389 FormulaToken
* pToken
= pFormula2
->First();
390 if ( pToken
->GetOpCode() == ocPush
)
392 if ( pToken
->GetType() == svDouble
)
394 nVal2
= pToken
->GetDouble();
395 DELETEZ(pFormula2
); // nicht als Formel merken
397 else if ( pToken
->GetType() == svString
)
400 aStrVal2
= pToken
->GetString().getString();
401 DELETEZ(pFormula2
); // nicht als Formel merken
405 bRelRef2
= lcl_HasRelRef( mpDoc
, pFormula2
);
411 void ScConditionEntry::MakeCells( const ScAddress
& rPos
) // Formelzellen anlegen
413 if ( !mpDoc
->IsClipOrUndo() ) // nie im Clipboard rechnen!
415 if ( pFormula1
&& !pFCell1
&& !bRelRef1
)
417 pFCell1
= new ScFormulaCell(mpDoc
, rPos
, *pFormula1
);
418 pFCell1
->StartListeningTo( mpDoc
);
421 if ( pFormula2
&& !pFCell2
&& !bRelRef2
)
423 pFCell2
= new ScFormulaCell(mpDoc
, rPos
, *pFormula2
);
424 pFCell2
->StartListeningTo( mpDoc
);
429 void ScConditionEntry::SetIgnoreBlank(bool bSet
)
431 // Das Bit SC_COND_NOBLANKS wird gesetzt, wenn Blanks nicht ignoriert werden
432 // (nur bei Gueltigkeit)
435 nOptions
&= ~SC_COND_NOBLANKS
;
437 nOptions
|= SC_COND_NOBLANKS
;
440 void ScConditionEntry::CompileAll()
442 // Formelzellen loeschen, dann wird beim naechsten IsValid neu kompiliert
448 void ScConditionEntry::CompileXML()
450 // First parse the formula source position if it was stored as text
452 if ( !aSrcString
.isEmpty() )
455 /* XML is always in OOo:A1 format, although R1C1 would be more amenable
457 if ( aNew
.Parse( aSrcString
, mpDoc
) & SCA_VALID
)
459 // if the position is invalid, there isn't much we can do at this time
460 aSrcString
= OUString();
463 // Convert the text tokens that were created during XML import into real tokens.
465 Compile( GetExpression(aSrcPos
, 0, 0, eTempGrammar1
),
466 GetExpression(aSrcPos
, 1, 0, eTempGrammar2
),
467 aStrNmsp1
, aStrNmsp2
, eTempGrammar1
, eTempGrammar2
, true );
470 void ScConditionEntry::SetSrcString( const OUString
& rNew
)
472 // aSrcString is only evaluated in CompileXML
473 SAL_WARN_IF( !mpDoc
->IsImportingXML(), "sc", "SetSrcString is only valid for XML import" );
478 void ScConditionEntry::SetFormula1( const ScTokenArray
& rArray
)
480 DELETEZ( pFormula1
);
481 if( rArray
.GetLen() > 0 )
483 pFormula1
= new ScTokenArray( rArray
);
484 bRelRef1
= lcl_HasRelRef( mpDoc
, pFormula1
);
488 void ScConditionEntry::SetFormula2( const ScTokenArray
& rArray
)
490 DELETEZ( pFormula2
);
491 if( rArray
.GetLen() > 0 )
493 pFormula2
= new ScTokenArray( rArray
);
494 bRelRef2
= lcl_HasRelRef( mpDoc
, pFormula2
);
498 void ScConditionEntry::UpdateReference( sc::RefUpdateContext
& rCxt
)
501 aSrcPos
= pCondFormat
->GetRange().Combine().aStart
;
502 ScAddress aOldSrcPos
= aSrcPos
;
503 bool bChangedPos
= false;
504 if (rCxt
.meMode
== URM_INSDEL
&& rCxt
.maRange
.In(aSrcPos
))
506 aSrcPos
.Move(rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
);
507 bChangedPos
= aSrcPos
!= aOldSrcPos
;
512 sc::RefUpdateResult aRes
= pFormula1
->AdjustReferenceInName(rCxt
, aOldSrcPos
);
513 if (aRes
.mbReferenceModified
|| bChangedPos
)
514 DELETEZ(pFCell1
); // is created again in IsValid
518 sc::RefUpdateResult aRes
= pFormula2
->AdjustReferenceInName(rCxt
, aOldSrcPos
);
519 if (aRes
.mbReferenceModified
|| bChangedPos
)
520 DELETEZ(pFCell2
); // is created again in IsValid
524 void ScConditionEntry::UpdateInsertTab( sc::RefUpdateInsertTabContext
& rCxt
)
528 pFormula1
->AdjustReferenceOnInsertedTab(rCxt
, aSrcPos
);
534 pFormula2
->AdjustReferenceOnInsertedTab(rCxt
, aSrcPos
);
539 void ScConditionEntry::UpdateDeleteTab( sc::RefUpdateDeleteTabContext
& rCxt
)
543 pFormula1
->AdjustReferenceOnDeletedTab(rCxt
, aSrcPos
);
549 pFormula2
->AdjustReferenceOnDeletedTab(rCxt
, aSrcPos
);
554 void ScConditionEntry::UpdateMoveTab( sc::RefUpdateMoveTabContext
& rCxt
)
558 pFormula1
->AdjustReferenceOnMovedTab(rCxt
, aSrcPos
);
564 pFormula2
->AdjustReferenceOnMovedTab(rCxt
, aSrcPos
);
569 //! als Vergleichsoperator ans TokenArray ???
571 static bool lcl_IsEqual( const ScTokenArray
* pArr1
, const ScTokenArray
* pArr2
)
573 // verglichen wird nur das nicht-RPN Array
575 if ( pArr1
&& pArr2
)
577 sal_uInt16 nLen
= pArr1
->GetLen();
578 if ( pArr2
->GetLen() != nLen
)
581 FormulaToken
** ppToken1
= pArr1
->GetArray();
582 FormulaToken
** ppToken2
= pArr2
->GetArray();
583 for (sal_uInt16 i
=0; i
<nLen
; i
++)
585 if ( ppToken1
[i
] != ppToken2
[i
] &&
586 !(*ppToken1
[i
] == *ppToken2
[i
]) )
587 return false; // Unterschied
589 return true; // alle Eintraege gleich
592 return !pArr1
&& !pArr2
; // beide 0 -> gleich
595 int ScConditionEntry::operator== ( const ScConditionEntry
& r
) const
597 bool bEq
= (eOp
== r
.eOp
&& nOptions
== r
.nOptions
&&
598 lcl_IsEqual( pFormula1
, r
.pFormula1
) &&
599 lcl_IsEqual( pFormula2
, r
.pFormula2
));
602 // for formulas, the reference positions must be compared, too
603 // (including aSrcString, for inserting the entries during XML import)
604 if ( ( pFormula1
|| pFormula2
) && ( aSrcPos
!= r
.aSrcPos
|| aSrcString
!= r
.aSrcString
) )
607 // wenn keine Formeln, Werte vergleichen
608 if ( !pFormula1
&& ( nVal1
!= r
.nVal1
|| aStrVal1
!= r
.aStrVal1
|| bIsStr1
!= r
.bIsStr1
) )
610 if ( !pFormula2
&& ( nVal2
!= r
.nVal2
|| aStrVal2
!= r
.aStrVal2
|| bIsStr2
!= r
.bIsStr2
) )
617 void ScConditionEntry::Interpret( const ScAddress
& rPos
)
619 // Formelzellen anlegen
620 // dabei koennen neue Broadcaster (Note-Zellen) ins Dokument eingefuegt werden !!!!
622 if ( ( pFormula1
&& !pFCell1
) || ( pFormula2
&& !pFCell2
) )
627 bool bDirty
= false; //! 1 und 2 getrennt ???
629 ScFormulaCell
* pTemp1
= NULL
;
630 ScFormulaCell
* pEff1
= pFCell1
;
633 pTemp1
= pFormula1
? new ScFormulaCell(mpDoc
, rPos
, *pFormula1
) : new ScFormulaCell(mpDoc
, rPos
);
638 if (!pEff1
->IsRunning()) // keine 522 erzeugen
640 //! Changed statt Dirty abfragen !!!
641 if (pEff1
->GetDirty() && !bRelRef1
&& mpDoc
->GetAutoCalc())
643 if (pEff1
->IsValue())
646 nVal1
= pEff1
->GetValue();
647 aStrVal1
= OUString();
652 aStrVal1
= pEff1
->GetString().getString();
659 ScFormulaCell
* pTemp2
= NULL
;
660 ScFormulaCell
* pEff2
= pFCell2
; //@ 1!=2
663 pTemp2
= pFormula2
? new ScFormulaCell(mpDoc
, rPos
, *pFormula2
) : new ScFormulaCell(mpDoc
, rPos
);
668 if (!pEff2
->IsRunning()) // keine 522 erzeugen
670 if (pEff2
->GetDirty() && !bRelRef2
&& mpDoc
->GetAutoCalc())
672 if (pEff2
->IsValue())
675 nVal2
= pEff2
->GetValue();
676 aStrVal2
= OUString();
681 aStrVal2
= pEff2
->GetString().getString();
688 // wenn IsRunning, bleiben die letzten Werte erhalten
690 if (bDirty
&& !bFirstRun
)
692 // bei bedingten Formaten neu painten
694 DataChanged( NULL
); // alles
700 static bool lcl_GetCellContent( ScRefCellValue
& rCell
, bool bIsStr1
, double& rArg
, OUString
& rArgStr
,
701 const ScDocument
* pDoc
)
709 switch (rCell
.meType
)
712 rArg
= rCell
.mfValue
;
714 case CELLTYPE_FORMULA
:
716 bVal
= rCell
.mpFormula
->IsValue();
718 rArg
= rCell
.mpFormula
->GetValue();
720 rArgStr
= rCell
.mpFormula
->GetString().getString();
723 case CELLTYPE_STRING
:
726 if (rCell
.meType
== CELLTYPE_STRING
)
727 rArgStr
= rCell
.mpString
->getString();
728 else if (rCell
.mpEditText
)
729 rArgStr
= ScEditUtil::GetString(*rCell
.mpEditText
, pDoc
);
738 void ScConditionEntry::FillCache() const
742 const ScRangeList
& rRanges
= pCondFormat
->GetRange();
743 mpCache
.reset(new ScConditionEntryCache
);
744 size_t nListCount
= rRanges
.size();
745 for( size_t i
= 0; i
< nListCount
; i
++ )
747 const ScRange
*aRange
= rRanges
[i
];
748 SCROW nRow
= aRange
->aEnd
.Row();
749 SCCOL nCol
= aRange
->aEnd
.Col();
750 SCCOL nColStart
= aRange
->aStart
.Col();
751 SCROW nRowStart
= aRange
->aStart
.Row();
752 SCTAB nTab
= aRange
->aStart
.Tab();
754 // temporary fix to workaorund slow duplicate entry
755 // conditions, prevent to use a whole row
758 bool bShrunk
= false;
759 mpDoc
->ShrinkToUsedDataArea(bShrunk
, nTab
, nColStart
, nRowStart
,
763 for( SCROW r
= nRowStart
; r
<= nRow
; r
++ )
764 for( SCCOL c
= nColStart
; c
<= nCol
; c
++ )
766 ScRefCellValue aCell
;
767 aCell
.assign(*mpDoc
, ScAddress(c
, r
, nTab
));
773 if (!lcl_GetCellContent(aCell
, false, nVal
, aStr
, mpDoc
))
775 std::pair
<ScConditionEntryCache::StringCacheType::iterator
, bool> aResult
=
776 mpCache
->maStrings
.insert(
777 ScConditionEntryCache::StringCacheType::value_type(aStr
, 1));
780 aResult
.first
->second
++;
784 std::pair
<ScConditionEntryCache::ValueCacheType::iterator
, bool> aResult
=
785 mpCache
->maValues
.insert(
786 ScConditionEntryCache::ValueCacheType::value_type(nVal
, 1));
789 aResult
.first
->second
++;
791 ++(mpCache
->nValueItems
);
798 bool ScConditionEntry::IsDuplicate( double nArg
, const OUString
& rStr
) const
804 ScConditionEntryCache::ValueCacheType::iterator itr
= mpCache
->maValues
.find(nArg
);
805 if(itr
== mpCache
->maValues
.end())
817 ScConditionEntryCache::StringCacheType::iterator itr
= mpCache
->maStrings
.find(rStr
);
818 if(itr
== mpCache
->maStrings
.end())
830 bool ScConditionEntry::IsTopNElement( double nArg
) const
834 if(mpCache
->nValueItems
<= nVal1
)
838 for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr
= mpCache
->maValues
.rbegin(),
839 itrEnd
= mpCache
->maValues
.rend(); itr
!= itrEnd
; ++itr
)
843 if(itr
->first
<= nArg
)
845 nCells
+= itr
->second
;
851 bool ScConditionEntry::IsBottomNElement( double nArg
) const
855 if(mpCache
->nValueItems
<= nVal1
)
859 for(ScConditionEntryCache::ValueCacheType::const_iterator itr
= mpCache
->maValues
.begin(),
860 itrEnd
= mpCache
->maValues
.end(); itr
!= itrEnd
; ++itr
)
864 if(itr
->first
>= nArg
)
866 nCells
+= itr
->second
;
872 bool ScConditionEntry::IsTopNPercent( double nArg
) const
877 size_t nLimitCells
= static_cast<size_t>(mpCache
->nValueItems
*nVal1
/100);
878 for(ScConditionEntryCache::ValueCacheType::const_reverse_iterator itr
= mpCache
->maValues
.rbegin(),
879 itrEnd
= mpCache
->maValues
.rend(); itr
!= itrEnd
; ++itr
)
881 if(nCells
>= nLimitCells
)
883 if(itr
->first
<= nArg
)
885 nCells
+= itr
->second
;
891 bool ScConditionEntry::IsBottomNPercent( double nArg
) const
896 size_t nLimitCells
= static_cast<size_t>(mpCache
->nValueItems
*nVal1
/100);
897 for(ScConditionEntryCache::ValueCacheType::const_iterator itr
= mpCache
->maValues
.begin(),
898 itrEnd
= mpCache
->maValues
.end(); itr
!= itrEnd
; ++itr
)
900 if(nCells
>= nLimitCells
)
902 if(itr
->first
>= nArg
)
904 nCells
+= itr
->second
;
910 bool ScConditionEntry::IsBelowAverage( double nArg
, bool bEqual
) const
915 for(ScConditionEntryCache::ValueCacheType::const_iterator itr
= mpCache
->maValues
.begin(),
916 itrEnd
= mpCache
->maValues
.end(); itr
!= itrEnd
; ++itr
)
918 nSum
+= itr
->first
* itr
->second
;
922 return (nArg
<= nSum
/mpCache
->nValueItems
);
924 return (nArg
< nSum
/mpCache
->nValueItems
);
927 bool ScConditionEntry::IsAboveAverage( double nArg
, bool bEqual
) const
932 for(ScConditionEntryCache::ValueCacheType::const_iterator itr
= mpCache
->maValues
.begin(),
933 itrEnd
= mpCache
->maValues
.end(); itr
!= itrEnd
; ++itr
)
935 nSum
+= itr
->first
* itr
->second
;
939 return (nArg
>= nSum
/mpCache
->nValueItems
);
941 return (nArg
> nSum
/mpCache
->nValueItems
);
944 bool ScConditionEntry::IsError( const ScAddress
& rPos
) const
946 switch (mpDoc
->GetCellType(rPos
))
950 case CELLTYPE_FORMULA
:
952 ScFormulaCell
* pFormulaCell
= const_cast<ScFormulaCell
*>(mpDoc
->GetFormulaCell(rPos
));
953 if(pFormulaCell
->GetErrCode())
956 case CELLTYPE_STRING
:
965 bool ScConditionEntry::IsValid( double nArg
, const ScAddress
& rPos
) const
967 // Interpret muss schon gerufen sein
973 case SC_COND_BEGINS_WITH
:
974 case SC_COND_ENDS_WITH
:
975 case SC_COND_CONTAINS_TEXT
:
976 case SC_COND_NOT_CONTAINS_TEXT
:
978 case SC_COND_NOTEQUAL
:
985 if ( eOp
== SC_COND_BETWEEN
|| eOp
== SC_COND_NOTBETWEEN
)
989 double nComp1
= nVal1
; // Kopie, damit vertauscht werden kann
990 double nComp2
= nVal2
;
992 if ( eOp
== SC_COND_BETWEEN
|| eOp
== SC_COND_NOTBETWEEN
)
993 if ( nComp1
> nComp2
)
995 // richtige Reihenfolge fuer Wertebereich
996 double nTemp
= nComp1
; nComp1
= nComp2
; nComp2
= nTemp
;
999 // Alle Grenzfaelle muessen per ::rtl::math::approxEqual getestet werden!
1001 bool bValid
= false;
1005 break; // immer sal_False;
1007 bValid
= ::rtl::math::approxEqual( nArg
, nComp1
);
1009 case SC_COND_NOTEQUAL
:
1010 bValid
= !::rtl::math::approxEqual( nArg
, nComp1
);
1012 case SC_COND_GREATER
:
1013 bValid
= ( nArg
> nComp1
) && !::rtl::math::approxEqual( nArg
, nComp1
);
1015 case SC_COND_EQGREATER
:
1016 bValid
= ( nArg
>= nComp1
) || ::rtl::math::approxEqual( nArg
, nComp1
);
1019 bValid
= ( nArg
< nComp1
) && !::rtl::math::approxEqual( nArg
, nComp1
);
1021 case SC_COND_EQLESS
:
1022 bValid
= ( nArg
<= nComp1
) || ::rtl::math::approxEqual( nArg
, nComp1
);
1024 case SC_COND_BETWEEN
:
1025 bValid
= ( nArg
>= nComp1
&& nArg
<= nComp2
) ||
1026 ::rtl::math::approxEqual( nArg
, nComp1
) || ::rtl::math::approxEqual( nArg
, nComp2
);
1028 case SC_COND_NOTBETWEEN
:
1029 bValid
= ( nArg
< nComp1
|| nArg
> nComp2
) &&
1030 !::rtl::math::approxEqual( nArg
, nComp1
) && !::rtl::math::approxEqual( nArg
, nComp2
);
1032 case SC_COND_DUPLICATE
:
1033 case SC_COND_NOTDUPLICATE
:
1036 bValid
= IsDuplicate( nArg
, OUString() );
1037 if( eOp
== SC_COND_NOTDUPLICATE
)
1041 case SC_COND_DIRECT
:
1042 bValid
= !::rtl::math::approxEqual( nComp1
, 0.0 );
1045 bValid
= IsTopNElement( nArg
);
1047 case SC_COND_BOTTOM10
:
1048 bValid
= IsBottomNElement( nArg
);
1050 case SC_COND_TOP_PERCENT
:
1051 bValid
= IsTopNPercent( nArg
);
1053 case SC_COND_BOTTOM_PERCENT
:
1054 bValid
= IsBottomNPercent( nArg
);
1056 case SC_COND_ABOVE_AVERAGE
:
1057 case SC_COND_ABOVE_EQUAL_AVERAGE
:
1058 bValid
= IsAboveAverage( nArg
, eOp
== SC_COND_ABOVE_EQUAL_AVERAGE
);
1060 case SC_COND_BELOW_AVERAGE
:
1061 case SC_COND_BELOW_EQUAL_AVERAGE
:
1062 bValid
= IsBelowAverage( nArg
, eOp
== SC_COND_BELOW_EQUAL_AVERAGE
);
1065 case SC_COND_NOERROR
:
1066 bValid
= IsError( rPos
);
1067 if( eOp
== SC_COND_NOERROR
)
1070 case SC_COND_BEGINS_WITH
:
1071 if(aStrVal1
.isEmpty())
1073 OUString aStr
= OUString::number(nVal1
);
1074 OUString aStr2
= OUString::number(nArg
);
1075 bValid
= aStr2
.startsWith(aStr
);
1079 OUString aStr2
= OUString::number(nArg
);
1080 bValid
= aStr2
.startsWith(aStrVal1
);
1083 case SC_COND_ENDS_WITH
:
1084 if(aStrVal1
.isEmpty())
1086 OUString aStr
= OUString::number(nVal1
);
1087 OUString aStr2
= OUString::number(nArg
);
1088 bValid
= aStr2
.endsWith(aStr
) == 0;
1092 OUString aStr2
= OUString::number(nArg
);
1093 bValid
= aStr2
.endsWith(aStrVal1
) == 0;
1096 case SC_COND_CONTAINS_TEXT
:
1097 case SC_COND_NOT_CONTAINS_TEXT
:
1098 if(aStrVal1
.isEmpty())
1100 OUString aStr
= OUString::number(nVal1
);
1101 OUString aStr2
= OUString::number(nArg
);
1102 bValid
= aStr2
.indexOf(aStr
) != -1;
1106 OUString aStr2
= OUString::number(nArg
);
1107 bValid
= aStr2
.indexOf(aStrVal1
) != -1;
1110 if( eOp
== SC_COND_NOT_CONTAINS_TEXT
)
1114 SAL_WARN("sc", "unknown operation at ScConditionEntry");
1120 bool ScConditionEntry::IsValidStr( const OUString
& rArg
, const ScAddress
& rPos
) const
1122 bool bValid
= false;
1123 // Interpret muss schon gerufen sein
1125 if ( eOp
== SC_COND_DIRECT
) // Formel ist unabhaengig vom Inhalt
1126 return !::rtl::math::approxEqual( nVal1
, 0.0 );
1128 if ( eOp
== SC_COND_DUPLICATE
|| eOp
== SC_COND_NOTDUPLICATE
)
1130 if( pCondFormat
&& !rArg
.isEmpty() )
1132 bValid
= IsDuplicate( 0.0, rArg
);
1133 if( eOp
== SC_COND_NOTDUPLICATE
)
1139 // If number contains condition, always false, except for "not equal".
1141 if ( !bIsStr1
&& (eOp
!= SC_COND_ERROR
&& eOp
!= SC_COND_NOERROR
) )
1142 return ( eOp
== SC_COND_NOTEQUAL
);
1143 if ( eOp
== SC_COND_BETWEEN
|| eOp
== SC_COND_NOTBETWEEN
)
1147 OUString
aUpVal1( aStrVal1
); //! als Member? (dann auch in Interpret setzen)
1148 OUString
aUpVal2( aStrVal2
);
1150 if ( eOp
== SC_COND_BETWEEN
|| eOp
== SC_COND_NOTBETWEEN
)
1151 if (ScGlobal::GetCollator()->compareString( aUpVal1
, aUpVal2
) > 0)
1153 // richtige Reihenfolge fuer Wertebereich
1154 OUString
aTemp( aUpVal1
); aUpVal1
= aUpVal2
; aUpVal2
= aTemp
;
1160 bValid
= (ScGlobal::GetCollator()->compareString(
1161 rArg
, aUpVal1
) == 0);
1163 case SC_COND_NOTEQUAL
:
1164 bValid
= (ScGlobal::GetCollator()->compareString(
1165 rArg
, aUpVal1
) != 0);
1167 case SC_COND_TOP_PERCENT
:
1168 case SC_COND_BOTTOM_PERCENT
:
1170 case SC_COND_BOTTOM10
:
1171 case SC_COND_ABOVE_AVERAGE
:
1172 case SC_COND_BELOW_AVERAGE
:
1175 case SC_COND_NOERROR
:
1176 bValid
= IsError( rPos
);
1177 if(eOp
== SC_COND_NOERROR
)
1180 case SC_COND_BEGINS_WITH
:
1181 bValid
= rArg
.startsWith(aUpVal1
);
1183 case SC_COND_ENDS_WITH
:
1184 bValid
= rArg
.endsWith(aUpVal1
);
1186 case SC_COND_CONTAINS_TEXT
:
1187 case SC_COND_NOT_CONTAINS_TEXT
:
1188 bValid
= rArg
.indexOf(aUpVal1
) != -1;
1189 if(eOp
== SC_COND_NOT_CONTAINS_TEXT
)
1194 sal_Int32 nCompare
= ScGlobal::GetCollator()->compareString(
1198 case SC_COND_GREATER
:
1199 bValid
= ( nCompare
> 0 );
1201 case SC_COND_EQGREATER
:
1202 bValid
= ( nCompare
>= 0 );
1205 bValid
= ( nCompare
< 0 );
1207 case SC_COND_EQLESS
:
1208 bValid
= ( nCompare
<= 0 );
1210 case SC_COND_BETWEEN
:
1211 case SC_COND_NOTBETWEEN
:
1212 // Test auf NOTBETWEEN:
1213 bValid
= ( nCompare
< 0 ||
1214 ScGlobal::GetCollator()->compareString( rArg
,
1216 if ( eOp
== SC_COND_BETWEEN
)
1219 // SC_COND_DIRECT schon oben abgefragt
1221 SAL_WARN("sc", "unbekannte Operation bei ScConditionEntry");
1230 bool ScConditionEntry::IsCellValid( ScRefCellValue
& rCell
, const ScAddress
& rPos
) const
1232 ((ScConditionEntry
*)this)->Interpret(rPos
); // Formeln auswerten
1236 bool bVal
= lcl_GetCellContent( rCell
, bIsStr1
, nArg
, aArgStr
, mpDoc
);
1238 return IsValid( nArg
, rPos
);
1240 return IsValidStr( aArgStr
, rPos
);
1243 OUString
ScConditionEntry::GetExpression( const ScAddress
& rCursor
, sal_uInt16 nIndex
,
1245 const FormulaGrammar::Grammar eGrammar
) const
1247 assert( nIndex
<= 1);
1250 if ( FormulaGrammar::isEnglish( eGrammar
) && nNumFmt
== 0 )
1251 nNumFmt
= mpDoc
->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US
);
1257 ScCompiler
aComp(mpDoc
, rCursor
, *pFormula1
);
1258 aComp
.SetGrammar(eGrammar
);
1259 OUStringBuffer aBuffer
;
1260 aComp
.CreateStringFromTokenArray( aBuffer
);
1261 aRet
= aBuffer
.makeStringAndClear();
1270 mpDoc
->GetFormatTable()->GetInputLineString(nVal1
, nNumFmt
, aRet
);
1272 else if ( nIndex
==1 )
1276 ScCompiler
aComp(mpDoc
, rCursor
, *pFormula2
);
1277 aComp
.SetGrammar(eGrammar
);
1278 OUStringBuffer aBuffer
;
1279 aComp
.CreateStringFromTokenArray( aBuffer
);
1280 aRet
= aBuffer
.makeStringAndClear();
1289 mpDoc
->GetFormatTable()->GetInputLineString(nVal2
, nNumFmt
, aRet
);
1295 ScTokenArray
* ScConditionEntry::CreateTokenArry( sal_uInt16 nIndex
) const
1297 assert(nIndex
<= 1);
1298 ScTokenArray
* pRet
= NULL
;
1304 pRet
= new ScTokenArray( *pFormula1
);
1307 pRet
= new ScTokenArray();
1309 pRet
->AddString( aStrVal1
);
1311 pRet
->AddDouble( nVal1
);
1314 else if ( nIndex
==1 )
1317 pRet
= new ScTokenArray( *pFormula2
);
1320 pRet
= new ScTokenArray();
1322 pRet
->AddString( aStrVal2
);
1324 pRet
->AddDouble( nVal2
);
1331 void ScConditionEntry::SourceChanged( const ScAddress
& rChanged
)
1333 for (sal_uInt16 nPass
= 0; nPass
< 2; nPass
++)
1335 ScTokenArray
* pFormula
= nPass
? pFormula2
: pFormula1
;
1340 while ( ( t
= static_cast<ScToken
*>(pFormula
->GetNextReference()) ) != NULL
)
1342 SingleDoubleRefProvider
aProv( *t
);
1343 if ( aProv
.Ref1
.IsColRel() || aProv
.Ref1
.IsRowRel() || aProv
.Ref1
.IsTabRel() ||
1344 aProv
.Ref2
.IsColRel() || aProv
.Ref2
.IsRowRel() || aProv
.Ref2
.IsTabRel() )
1346 // absolut muss getroffen sein, relativ bestimmt Bereich
1356 if ( aProv
.Ref1
.IsColRel() )
1357 nCol2
= rChanged
.Col() - aProv
.Ref1
.Col();
1360 bHit
&= (rChanged
.Col() >= aProv
.Ref1
.Col());
1363 if ( aProv
.Ref1
.IsRowRel() )
1364 nRow2
= rChanged
.Row() - aProv
.Ref1
.Row();
1367 bHit
&= ( rChanged
.Row() >= aProv
.Ref1
.Row() );
1370 if ( aProv
.Ref1
.IsTabRel() )
1371 nTab2
= rChanged
.Tab() - aProv
.Ref1
.Tab();
1374 bHit
&= (rChanged
.Tab() >= aProv
.Ref1
.Tab());
1378 if ( aProv
.Ref2
.IsColRel() )
1379 nCol1
= rChanged
.Col() - aProv
.Ref2
.Col();
1382 bHit
&= ( rChanged
.Col() <= aProv
.Ref2
.Col() );
1385 if ( aProv
.Ref2
.IsRowRel() )
1386 nRow1
= rChanged
.Row() - aProv
.Ref2
.Row();
1389 bHit
&= (rChanged
.Row() <= aProv
.Ref2
.Row());
1392 if ( aProv
.Ref2
.IsTabRel() )
1393 nTab1
= rChanged
.Tab() - aProv
.Ref2
.Tab();
1396 bHit
&= (rChanged
.Tab() <= aProv
.Ref2
.Tab());
1404 ScRange
aPaint( nCol1
,nRow1
,nTab1
, nCol2
,nRow2
,nTab2
);
1406 // kein Paint, wenn es nur die Zelle selber ist
1407 if ( aPaint
.IsValid() && (aPaint
.aStart
!= rChanged
|| aPaint
.aEnd
!= rChanged
))
1408 DataChanged( &aPaint
);
1416 ScAddress
ScConditionEntry::GetValidSrcPos() const
1418 // return a position that's adjusted to allow textual representation of expressions if possible
1420 SCTAB nMinTab
= aSrcPos
.Tab();
1421 SCTAB nMaxTab
= nMinTab
;
1423 for (sal_uInt16 nPass
= 0; nPass
< 2; nPass
++)
1425 ScTokenArray
* pFormula
= nPass
? pFormula2
: pFormula1
;
1430 while ( ( t
= static_cast<ScToken
*>(pFormula
->GetNextReference()) ) != NULL
)
1432 ScSingleRefData
& rRef1
= t
->GetSingleRef();
1433 ScAddress aAbs
= rRef1
.toAbs(aSrcPos
);
1434 if (!rRef1
.IsTabDeleted())
1436 if (aAbs
.Tab() < nMinTab
)
1437 nMinTab
= aAbs
.Tab();
1438 if (aAbs
.Tab() > nMaxTab
)
1439 nMaxTab
= aAbs
.Tab();
1441 if ( t
->GetType() == svDoubleRef
)
1443 ScSingleRefData
& rRef2
= t
->GetDoubleRef().Ref2
;
1444 aAbs
= rRef2
.toAbs(aSrcPos
);
1445 if (!rRef2
.IsTabDeleted())
1447 if (aAbs
.Tab() < nMinTab
)
1448 nMinTab
= aAbs
.Tab();
1449 if (aAbs
.Tab() > nMaxTab
)
1450 nMaxTab
= aAbs
.Tab();
1457 ScAddress aValidPos
= aSrcPos
;
1458 SCTAB nTabCount
= mpDoc
->GetTableCount();
1459 if ( nMaxTab
>= nTabCount
&& nMinTab
> 0 )
1460 aValidPos
.SetTab( aSrcPos
.Tab() - nMinTab
); // so the lowest tab ref will be on 0
1462 if ( aValidPos
.Tab() >= nTabCount
)
1463 aValidPos
.SetTab( nTabCount
- 1 ); // ensure a valid position even if some references will be invalid
1468 void ScConditionEntry::DataChanged( const ScRange
* /* pModified */ ) const
1473 bool ScConditionEntry::MarkUsedExternalReferences() const
1475 bool bAllMarked
= false;
1476 for (sal_uInt16 nPass
= 0; !bAllMarked
&& nPass
< 2; nPass
++)
1478 ScTokenArray
* pFormula
= nPass
? pFormula2
: pFormula1
;
1480 bAllMarked
= mpDoc
->MarkUsedExternalReferences(*pFormula
, aSrcPos
);
1485 ScFormatEntry
* ScConditionEntry::Clone(ScDocument
* pDoc
) const
1487 return new ScConditionEntry(pDoc
, *this);
1490 ScConditionMode
ScConditionEntry::GetModeFromApi(sal_Int32 nOperation
)
1492 ScConditionMode eMode
= SC_COND_NONE
;
1495 case com::sun::star::sheet::ConditionOperator2::EQUAL
:
1496 eMode
= SC_COND_EQUAL
;
1498 case com::sun::star::sheet::ConditionOperator2::LESS
:
1499 eMode
= SC_COND_LESS
;
1501 case com::sun::star::sheet::ConditionOperator2::GREATER
:
1502 eMode
= SC_COND_GREATER
;
1504 case com::sun::star::sheet::ConditionOperator2::LESS_EQUAL
:
1505 eMode
= SC_COND_EQLESS
;
1507 case com::sun::star::sheet::ConditionOperator2::GREATER_EQUAL
:
1508 eMode
= SC_COND_EQGREATER
;
1510 case com::sun::star::sheet::ConditionOperator2::NOT_EQUAL
:
1511 eMode
= SC_COND_NOTEQUAL
;
1513 case com::sun::star::sheet::ConditionOperator2::BETWEEN
:
1514 eMode
= SC_COND_BETWEEN
;
1516 case com::sun::star::sheet::ConditionOperator2::NOT_BETWEEN
:
1517 eMode
= SC_COND_NOTBETWEEN
;
1519 case com::sun::star::sheet::ConditionOperator2::FORMULA
:
1520 eMode
= SC_COND_DIRECT
;
1522 case com::sun::star::sheet::ConditionOperator2::DUPLICATE
:
1523 eMode
= SC_COND_DUPLICATE
;
1525 case com::sun::star::sheet::ConditionOperator2::NOT_DUPLICATE
:
1526 eMode
= SC_COND_NOTDUPLICATE
;
1534 void ScConditionEntry::startRendering()
1539 void ScConditionEntry::endRendering()
1544 //------------------------------------------------------------------------
1546 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper
,
1547 const OUString
& rExpr1
, const OUString
& rExpr2
,
1548 ScDocument
* pDocument
, const ScAddress
& rPos
,
1549 const OUString
& rStyle
,
1550 const OUString
& rExprNmsp1
, const OUString
& rExprNmsp2
,
1551 FormulaGrammar::Grammar eGrammar1
,
1552 FormulaGrammar::Grammar eGrammar2
) :
1553 ScConditionEntry( eOper
, rExpr1
, rExpr2
, pDocument
, rPos
, rExprNmsp1
, rExprNmsp2
, eGrammar1
, eGrammar2
),
1554 aStyleName( rStyle
)
1558 ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper
,
1559 const ScTokenArray
* pArr1
, const ScTokenArray
* pArr2
,
1560 ScDocument
* pDocument
, const ScAddress
& rPos
,
1561 const OUString
& rStyle
) :
1562 ScConditionEntry( eOper
, pArr1
, pArr2
, pDocument
, rPos
),
1563 aStyleName( rStyle
)
1567 ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry
& r
) :
1568 ScConditionEntry( r
),
1569 aStyleName( r
.aStyleName
)
1573 ScCondFormatEntry::ScCondFormatEntry( ScDocument
* pDocument
, const ScCondFormatEntry
& r
) :
1574 ScConditionEntry( pDocument
, r
),
1575 aStyleName( r
.aStyleName
)
1579 int ScCondFormatEntry::operator== ( const ScCondFormatEntry
& r
) const
1581 return ScConditionEntry::operator==( r
) &&
1582 aStyleName
== r
.aStyleName
;
1585 ScCondFormatEntry::~ScCondFormatEntry()
1589 void ScCondFormatEntry::DataChanged( const ScRange
* pModified
) const
1592 pCondFormat
->DoRepaint( pModified
);
1595 ScFormatEntry
* ScCondFormatEntry::Clone( ScDocument
* pDoc
) const
1597 return new ScCondFormatEntry( pDoc
, *this );
1600 //------------------------------------------------------------------------
1602 ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument
* pDoc
):
1603 ScFormatEntry( pDoc
)
1607 ScCondDateFormatEntry::ScCondDateFormatEntry( ScDocument
* pDoc
, const ScCondDateFormatEntry
& rFormat
):
1608 ScFormatEntry( pDoc
),
1609 meType( rFormat
.meType
),
1610 maStyleName( rFormat
.maStyleName
)
1614 bool ScCondDateFormatEntry::IsValid( const ScAddress
& rPos
) const
1616 CellType eCellType
= mpDoc
->GetCellType(rPos
);
1618 if (eCellType
== CELLTYPE_NONE
)
1622 if (eCellType
!= CELLTYPE_VALUE
&& eCellType
!= CELLTYPE_FORMULA
)
1623 // non-numerical cell.
1627 mpCache
.reset( new Date( Date::SYSTEM
) );
1629 const Date
& rActDate
= *mpCache
;
1630 SvNumberFormatter
* pFormatter
= mpDoc
->GetFormatTable();
1631 long nCurrentDate
= rActDate
- *(pFormatter
->GetNullDate());
1633 double nVal
= mpDoc
->GetValue(rPos
);
1634 long nCellDate
= (long) ::rtl::math::approxFloor(nVal
);
1635 Date aCellDate
= *(pFormatter
->GetNullDate());
1636 aCellDate
+= (long) ::rtl::math::approxFloor(nVal
);
1640 case condformat::TODAY
:
1641 if( nCurrentDate
== nCellDate
)
1644 case condformat::TOMORROW
:
1645 if( nCurrentDate
== nCellDate
-1 )
1648 case condformat::YESTERDAY
:
1649 if( nCurrentDate
== nCellDate
+ 1)
1652 case condformat::LAST7DAYS
:
1653 if( nCurrentDate
>= nCellDate
&& nCurrentDate
- 7 < nCellDate
)
1656 case condformat::LASTWEEK
:
1657 if( rActDate
.GetDayOfWeek() != SUNDAY
)
1659 Date
aBegin(rActDate
- 8 - static_cast<long>(rActDate
.GetDayOfWeek()));
1660 Date
aEnd(rActDate
- 2 -static_cast<long>(rActDate
.GetDayOfWeek()));
1661 return aCellDate
.IsBetween( aBegin
, aEnd
);
1665 Date
aBegin(rActDate
- 8);
1666 Date
aEnd(rActDate
- 1);
1667 return aCellDate
.IsBetween( aBegin
, aEnd
);
1670 case condformat::THISWEEK
:
1671 if( rActDate
.GetDayOfWeek() != SUNDAY
)
1673 Date
aBegin(rActDate
- 1 - static_cast<long>(rActDate
.GetDayOfWeek()));
1674 Date
aEnd(rActDate
+ 5 - static_cast<long>(rActDate
.GetDayOfWeek()));
1675 return aCellDate
.IsBetween( aBegin
, aEnd
);
1679 Date
aEnd( rActDate
+ 6);
1680 return aCellDate
.IsBetween( rActDate
, aEnd
);
1683 case condformat::NEXTWEEK
:
1684 if( rActDate
.GetDayOfWeek() != SUNDAY
)
1686 return aCellDate
.IsBetween( rActDate
+ 6 - static_cast<long>(rActDate
.GetDayOfWeek()), rActDate
+ 12 - static_cast<long>(rActDate
.GetDayOfWeek()) );
1690 return aCellDate
.IsBetween( rActDate
+ 7, rActDate
+ 13 );
1693 case condformat::LASTMONTH
:
1694 if( rActDate
.GetMonth() == 1 )
1696 if( aCellDate
.GetMonth() == 12 && rActDate
.GetYear() == aCellDate
.GetYear() + 1 )
1699 else if( rActDate
.GetYear() == aCellDate
.GetYear() )
1701 if( rActDate
.GetMonth() == aCellDate
.GetMonth() + 1)
1705 case condformat::THISMONTH
:
1706 if( rActDate
.GetYear() == aCellDate
.GetYear() )
1708 if( rActDate
.GetMonth() == aCellDate
.GetMonth() )
1712 case condformat::NEXTMONTH
:
1713 if( rActDate
.GetMonth() == 12 )
1715 if( aCellDate
.GetMonth() == 1 && rActDate
.GetYear() == aCellDate
.GetYear() - 1 )
1718 else if( rActDate
.GetYear() == aCellDate
.GetYear() )
1720 if( rActDate
.GetMonth() == aCellDate
.GetMonth() - 1)
1724 case condformat::LASTYEAR
:
1725 if( rActDate
.GetYear() == aCellDate
.GetYear() + 1 )
1728 case condformat::THISYEAR
:
1729 if( rActDate
.GetYear() == aCellDate
.GetYear() )
1732 case condformat::NEXTYEAR
:
1733 if( rActDate
.GetYear() == aCellDate
.GetYear() - 1 )
1741 void ScCondDateFormatEntry::SetDateType( condformat::ScCondFormatDateType eType
)
1746 condformat::ScCondFormatDateType
ScCondDateFormatEntry::GetDateType() const
1751 const OUString
& ScCondDateFormatEntry::GetStyleName() const
1756 void ScCondDateFormatEntry::SetStyleName( const OUString
& rStyleName
)
1758 maStyleName
= rStyleName
;
1761 ScFormatEntry
* ScCondDateFormatEntry::Clone( ScDocument
* pDoc
) const
1763 return new ScCondDateFormatEntry( pDoc
, *this );
1766 bool ScCondDateFormatEntry::operator==( const ScFormatEntry
& r
) const
1768 if(r
.GetType() != condformat::DATE
)
1771 const ScCondDateFormatEntry
& rEntry
= static_cast<const ScCondDateFormatEntry
&>(r
);
1773 if(rEntry
.meType
!= meType
)
1776 return rEntry
.maStyleName
== maStyleName
;
1779 void ScCondDateFormatEntry::startRendering()
1784 void ScCondDateFormatEntry::endRendering()
1789 //------------------------------------------------------------------------
1791 ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey
, ScDocument
* pDocument
) :
1797 ScConditionalFormat
* ScConditionalFormat::Clone(ScDocument
* pNewDoc
) const
1799 // echte Kopie der Formeln (fuer Ref-Undo / zwischen Dokumenten)
1804 ScConditionalFormat
* pNew
= new ScConditionalFormat(nKey
, pNewDoc
);
1806 for (CondFormatContainer::const_iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
1808 ScFormatEntry
* pNewEntry
= itr
->Clone(pNewDoc
);
1809 pNew
->maEntries
.push_back( pNewEntry
);
1810 pNewEntry
->SetParent(pNew
);
1812 pNew
->AddRange( maRanges
);
1817 bool ScConditionalFormat::EqualEntries( const ScConditionalFormat
& r
) const
1819 if( size() != r
.size())
1822 //! auf gleiche Eintraege in anderer Reihenfolge testen ???
1824 for (sal_uInt16 i
=0; i
<size(); i
++)
1825 if ( ! (maEntries
== r
.maEntries
) )
1828 // right now don't check for same range
1829 // we only use this method to merge same conditional formats from
1830 // old ODF data structure
1834 void ScConditionalFormat::AddRange( const ScRangeList
& rRanges
)
1839 void ScConditionalFormat::AddEntry( ScFormatEntry
* pNew
)
1841 maEntries
.push_back(pNew
);
1842 pNew
->SetParent(this);
1845 bool ScConditionalFormat::IsEmpty() const
1847 return maEntries
.empty();
1850 size_t ScConditionalFormat::size() const
1852 return maEntries
.size();
1855 ScConditionalFormat::~ScConditionalFormat()
1859 const ScFormatEntry
* ScConditionalFormat::GetEntry( sal_uInt16 nPos
) const
1861 if ( nPos
< size() )
1862 return &maEntries
[nPos
];
1867 const OUString
& ScConditionalFormat::GetCellStyle( ScRefCellValue
& rCell
, const ScAddress
& rPos
) const
1869 for (CondFormatContainer::const_iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
1871 if(itr
->GetType() == condformat::CONDITION
)
1873 const ScCondFormatEntry
& rEntry
= static_cast<const ScCondFormatEntry
&>(*itr
);
1874 if (rEntry
.IsCellValid(rCell
, rPos
))
1875 return rEntry
.GetStyle();
1877 else if(itr
->GetType() == condformat::DATE
)
1879 const ScCondDateFormatEntry
& rEntry
= static_cast<const ScCondDateFormatEntry
&>(*itr
);
1880 if (rEntry
.IsValid( rPos
))
1881 return rEntry
.GetStyleName();
1885 return EMPTY_OUSTRING
;
1888 ScCondFormatData
ScConditionalFormat::GetData( ScRefCellValue
& rCell
, const ScAddress
& rPos
) const
1890 ScCondFormatData aData
;
1891 for(CondFormatContainer::const_iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
1893 if(itr
->GetType() == condformat::CONDITION
&& aData
.aStyleName
.isEmpty())
1895 const ScCondFormatEntry
& rEntry
= static_cast<const ScCondFormatEntry
&>(*itr
);
1896 if (rEntry
.IsCellValid(rCell
, rPos
))
1897 aData
.aStyleName
= rEntry
.GetStyle();
1899 else if(itr
->GetType() == condformat::COLORSCALE
&& !aData
.pColorScale
)
1901 const ScColorScaleFormat
& rEntry
= static_cast<const ScColorScaleFormat
&>(*itr
);
1902 aData
.pColorScale
= rEntry
.GetColor(rPos
);
1904 else if(itr
->GetType() == condformat::DATABAR
&& !aData
.pDataBar
)
1906 const ScDataBarFormat
& rEntry
= static_cast<const ScDataBarFormat
&>(*itr
);
1907 aData
.pDataBar
= rEntry
.GetDataBarInfo(rPos
);
1909 else if(itr
->GetType() == condformat::ICONSET
&& !aData
.pIconSet
)
1911 const ScIconSetFormat
& rEntry
= static_cast<const ScIconSetFormat
&>(*itr
);
1912 aData
.pIconSet
= rEntry
.GetIconSetInfo(rPos
);
1914 else if(itr
->GetType() == condformat::DATE
&& aData
.aStyleName
.isEmpty())
1916 const ScCondDateFormatEntry
& rEntry
= static_cast<const ScCondDateFormatEntry
&>(*itr
);
1917 if ( rEntry
.IsValid( rPos
) )
1918 aData
.aStyleName
= rEntry
.GetStyleName();
1924 void ScConditionalFormat::DoRepaint( const ScRange
* pModified
)
1928 if(maRanges
.Intersects(*pModified
))
1929 pDoc
->RepaintRange(*pModified
);
1933 // all conditional format cells
1934 pDoc
->RepaintRange( maRanges
);
1938 void ScConditionalFormat::CompileAll()
1940 for(CondFormatContainer::iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
1941 if(itr
->GetType() == condformat::CONDITION
)
1942 static_cast<ScCondFormatEntry
&>(*itr
).CompileAll();
1945 void ScConditionalFormat::CompileXML()
1947 for(CondFormatContainer::iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
1948 if(itr
->GetType() == condformat::CONDITION
)
1949 static_cast<ScCondFormatEntry
&>(*itr
).CompileXML();
1952 void ScConditionalFormat::UpdateReference( sc::RefUpdateContext
& rCxt
, bool bCopyAsMove
)
1954 for(CondFormatContainer::iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
1955 itr
->UpdateReference(rCxt
);
1957 if (rCxt
.meMode
== URM_COPY
&& bCopyAsMove
)
1958 maRanges
.UpdateReference(URM_MOVE
, pDoc
, rCxt
.maRange
, rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
);
1960 maRanges
.UpdateReference(rCxt
.meMode
, pDoc
, rCxt
.maRange
, rCxt
.mnColDelta
, rCxt
.mnRowDelta
, rCxt
.mnTabDelta
);
1963 void ScConditionalFormat::InsertRow(SCTAB nTab
, SCCOL nColStart
, SCCOL nColEnd
, SCROW nRowPos
, SCSIZE nSize
)
1965 maRanges
.InsertRow(nTab
, nColStart
, nColEnd
, nRowPos
, nSize
);
1968 void ScConditionalFormat::InsertCol(SCTAB nTab
, SCROW nRowStart
, SCROW nRowEnd
, SCCOL nColPos
, SCSIZE nSize
)
1970 maRanges
.InsertCol(nTab
, nRowStart
, nRowEnd
, nColPos
, nSize
);
1973 void ScConditionalFormat::UpdateInsertTab( sc::RefUpdateInsertTabContext
& rCxt
)
1975 for (CondFormatContainer::iterator it
= maEntries
.begin(); it
!= maEntries
.end(); ++it
)
1976 it
->UpdateInsertTab(rCxt
);
1979 void ScConditionalFormat::UpdateDeleteTab( sc::RefUpdateDeleteTabContext
& rCxt
)
1981 for (CondFormatContainer::iterator it
= maEntries
.begin(); it
!= maEntries
.end(); ++it
)
1982 it
->UpdateDeleteTab(rCxt
);
1985 void ScConditionalFormat::UpdateMoveTab( sc::RefUpdateMoveTabContext
& rCxt
)
1987 size_t n
= maRanges
.size();
1988 SCTAB nMinTab
= std::min
<SCTAB
>(rCxt
.mnOldPos
, rCxt
.mnNewPos
);
1989 SCTAB nMaxTab
= std::max
<SCTAB
>(rCxt
.mnOldPos
, rCxt
.mnNewPos
);
1990 for(size_t i
= 0; i
< n
; ++i
)
1992 ScRange
* pRange
= maRanges
[i
];
1993 SCTAB nTab
= pRange
->aStart
.Tab();
1994 if(nTab
< nMinTab
|| nTab
> nMaxTab
)
1999 if (nTab
== rCxt
.mnOldPos
)
2001 pRange
->aStart
.SetTab(rCxt
.mnNewPos
);
2002 pRange
->aEnd
.SetTab(rCxt
.mnNewPos
);
2006 if (rCxt
.mnNewPos
< rCxt
.mnOldPos
)
2008 pRange
->aStart
.IncTab();
2009 pRange
->aEnd
.IncTab();
2013 pRange
->aStart
.IncTab(-1);
2014 pRange
->aEnd
.IncTab(-1);
2018 for (CondFormatContainer::iterator it
= maEntries
.begin(); it
!= maEntries
.end(); ++it
)
2019 it
->UpdateMoveTab(rCxt
);
2022 void ScConditionalFormat::DeleteArea( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
2024 SCTAB nTab
= maRanges
[0]->aStart
.Tab();
2025 maRanges
.DeleteArea( nCol1
, nRow1
, nTab
, nCol2
, nRow2
, nTab
);
2028 void ScConditionalFormat::RenameCellStyle(const OUString
& rOld
, const OUString
& rNew
)
2030 for(CondFormatContainer::iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
2031 if(itr
->GetType() == condformat::CONDITION
)
2033 ScCondFormatEntry
& rFormat
= static_cast<ScCondFormatEntry
&>(*itr
);
2034 if(rFormat
.GetStyle() == rOld
)
2035 rFormat
.UpdateStyleName( rNew
);
2039 void ScConditionalFormat::SourceChanged( const ScAddress
& rAddr
)
2041 for(CondFormatContainer::iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
2043 condformat::ScFormatEntryType eEntryType
= itr
->GetType();
2044 if( eEntryType
== condformat::CONDITION
)
2046 ScCondFormatEntry
& rFormat
= static_cast<ScCondFormatEntry
&>(*itr
);
2047 rFormat
.SourceChanged( rAddr
);
2049 else if( eEntryType
== condformat::COLORSCALE
||
2050 eEntryType
== condformat::DATABAR
||
2051 eEntryType
== condformat::ICONSET
)
2053 ScColorFormat
& rFormat
= static_cast<ScColorFormat
&>(*itr
);
2054 if(rFormat
.NeedsRepaint())
2056 // we need to repaint the whole range anyway
2064 bool ScConditionalFormat::MarkUsedExternalReferences() const
2066 bool bAllMarked
= false;
2067 for(CondFormatContainer::const_iterator itr
= maEntries
.begin(); itr
!= maEntries
.end() && !bAllMarked
; ++itr
)
2068 if(itr
->GetType() == condformat::CONDITION
)
2070 const ScCondFormatEntry
& rFormat
= static_cast<const ScCondFormatEntry
&>(*itr
);
2071 bAllMarked
= rFormat
.MarkUsedExternalReferences();
2077 void ScConditionalFormat::startRendering()
2079 for(CondFormatContainer::iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
2081 itr
->startRendering();
2085 void ScConditionalFormat::endRendering()
2087 for(CondFormatContainer::iterator itr
= maEntries
.begin(); itr
!= maEntries
.end(); ++itr
)
2089 itr
->endRendering();
2093 //------------------------------------------------------------------------
2095 ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList
& rList
)
2097 for(const_iterator itr
= rList
.begin(); itr
!= rList
.end(); ++itr
)
2098 InsertNew( itr
->Clone() );
2101 ScConditionalFormatList::ScConditionalFormatList(ScDocument
* pDoc
, const ScConditionalFormatList
& rList
)
2103 for(const_iterator itr
= rList
.begin(); itr
!= rList
.end(); ++itr
)
2104 InsertNew( itr
->Clone(pDoc
) );
2107 void ScConditionalFormatList::InsertNew( ScConditionalFormat
* pNew
)
2109 maConditionalFormats
.insert(pNew
);
2112 bool ScConditionalFormatList::operator==( const ScConditionalFormatList
& r
) const
2114 // fuer Ref-Undo - interne Variablen werden nicht verglichen
2116 sal_uInt16 nCount
= size();
2117 bool bEqual
= ( nCount
== r
.size() );
2118 const_iterator locIterator
= begin();
2119 for(const_iterator itr
= r
.begin(); itr
!= r
.end() && bEqual
; ++itr
, ++locIterator
)
2120 if ( !locIterator
->EqualEntries(*itr
) ) // Eintraege unterschiedlich ?
2126 ScConditionalFormat
* ScConditionalFormatList::GetFormat( sal_uInt32 nKey
)
2130 for( iterator itr
= begin(); itr
!= end(); ++itr
)
2131 if (itr
->GetKey() == nKey
)
2134 SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2138 const ScConditionalFormat
* ScConditionalFormatList::GetFormat( sal_uInt32 nKey
) const
2142 for ( const_iterator itr
= begin(); itr
!= end(); ++itr
)
2143 if (itr
->GetKey() == nKey
)
2146 SAL_WARN("sc", "ScConditionalFormatList: Entry not found");
2150 void ScConditionalFormatList::CompileAll()
2152 for( iterator itr
= begin(); itr
!= end(); ++itr
)
2156 void ScConditionalFormatList::CompileXML()
2158 for( iterator itr
= begin(); itr
!= end(); ++itr
)
2162 void ScConditionalFormatList::UpdateReference( sc::RefUpdateContext
& rCxt
)
2164 for( iterator itr
= begin(); itr
!= end(); ++itr
)
2165 itr
->UpdateReference(rCxt
);
2167 if (rCxt
.meMode
== URM_INSDEL
)
2169 // need to check which must be deleted
2170 iterator itr
= begin();
2173 if(itr
->GetRange().empty())
2174 maConditionalFormats
.erase(itr
++);
2181 void ScConditionalFormatList::InsertRow(SCTAB nTab
, SCCOL nColStart
, SCCOL nColEnd
, SCROW nRowPos
, SCSIZE nSize
)
2183 for(iterator it
= begin(), itEnd
= end(); it
!= itEnd
; ++it
)
2184 it
->InsertRow(nTab
, nColStart
, nColEnd
, nRowPos
, nSize
);
2187 void ScConditionalFormatList::InsertCol(SCTAB nTab
, SCROW nRowStart
, SCROW nRowEnd
, SCCOL nColPos
, SCSIZE nSize
)
2189 for(iterator it
= begin(), itEnd
= end(); it
!= itEnd
; ++it
)
2190 it
->InsertCol(nTab
, nRowStart
, nRowEnd
, nColPos
, nSize
);
2193 void ScConditionalFormatList::UpdateInsertTab( sc::RefUpdateInsertTabContext
& rCxt
)
2195 for (iterator it
= begin(); it
!= end(); ++it
)
2196 it
->UpdateInsertTab(rCxt
);
2199 void ScConditionalFormatList::UpdateDeleteTab( sc::RefUpdateDeleteTabContext
& rCxt
)
2201 for (iterator it
= begin(); it
!= end(); ++it
)
2202 it
->UpdateDeleteTab(rCxt
);
2205 void ScConditionalFormatList::UpdateMoveTab( sc::RefUpdateMoveTabContext
& rCxt
)
2207 for (iterator it
= begin(); it
!= end(); ++it
)
2208 it
->UpdateMoveTab(rCxt
);
2211 void ScConditionalFormatList::RenameCellStyle( const OUString
& rOld
, const OUString
& rNew
)
2213 for( iterator itr
= begin(); itr
!= end(); ++itr
)
2214 itr
->RenameCellStyle(rOld
,rNew
);
2217 bool ScConditionalFormatList::CheckAllEntries()
2221 // need to check which must be deleted
2222 iterator itr
= begin();
2225 if(itr
->GetRange().empty())
2228 maConditionalFormats
.erase(itr
++);
2237 void ScConditionalFormatList::DeleteArea( SCCOL nCol1
, SCROW nRow1
, SCCOL nCol2
, SCROW nRow2
)
2239 for( iterator itr
= begin(); itr
!= end(); ++itr
)
2240 itr
->DeleteArea( nCol1
, nRow1
, nCol2
, nRow2
);
2245 void ScConditionalFormatList::SourceChanged( const ScAddress
& rAddr
)
2247 for( iterator itr
= begin(); itr
!= end(); ++itr
)
2248 itr
->SourceChanged( rAddr
);
2251 ScConditionalFormatList::iterator
ScConditionalFormatList::begin()
2253 return maConditionalFormats
.begin();
2256 ScConditionalFormatList::const_iterator
ScConditionalFormatList::begin() const
2258 return maConditionalFormats
.begin();
2261 ScConditionalFormatList::iterator
ScConditionalFormatList::end()
2263 return maConditionalFormats
.end();
2266 ScConditionalFormatList::const_iterator
ScConditionalFormatList::end() const
2268 return maConditionalFormats
.end();
2271 size_t ScConditionalFormatList::size() const
2273 return maConditionalFormats
.size();
2276 void ScConditionalFormatList::erase( sal_uLong nIndex
)
2278 for( iterator itr
= begin(); itr
!= end(); ++itr
)
2280 if( itr
->GetKey() == nIndex
)
2282 maConditionalFormats
.erase(itr
);
2288 void ScConditionalFormatList::startRendering()
2290 for(iterator itr
= begin(); itr
!= end(); ++itr
)
2292 itr
->startRendering();
2296 void ScConditionalFormatList::endRendering()
2298 for(iterator itr
= begin(); itr
!= end(); ++itr
)
2300 itr
->endRendering();
2304 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */