LCOV - code coverage report
Current view: top level - sc/source/core/tool - formularesult.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 247 292 84.6 %
Date: 2015-06-13 12:38:46 Functions: 37 40 92.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  */
       9             : 
      10             : #include "formularesult.hxx"
      11             : #include "scmatrix.hxx"
      12             : 
      13             : namespace sc {
      14             : 
      15           0 : FormulaResultValue::FormulaResultValue() : meType(Invalid), mfValue(0.0), mnError(0) {}
      16         612 : FormulaResultValue::FormulaResultValue( double fValue ) : meType(Value), mfValue(fValue), mnError(0) {}
      17          20 : FormulaResultValue::FormulaResultValue( const svl::SharedString& rStr ) : meType(String), mfValue(0.0), maString(rStr), mnError(0) {}
      18           6 : FormulaResultValue::FormulaResultValue( sal_uInt16 nErr ) : meType(Error), mfValue(0.0), mnError(nErr) {}
      19             : 
      20             : }
      21             : 
      22        9718 : ScFormulaResult::ScFormulaResult() :
      23             :     mpToken(NULL), mnError(0), mbToken(true),
      24             :     mbEmpty(false), mbEmptyDisplayedAsString(false),
      25        9718 :     meMultiline(MULTILINE_UNKNOWN) {}
      26             : 
      27        1182 : ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
      28             :     mnError( r.mnError), mbToken( r.mbToken),
      29             :     mbEmpty( r.mbEmpty),
      30             :     mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
      31        1182 :     meMultiline( r.meMultiline)
      32             : {
      33        1182 :     if (mbToken)
      34             :     {
      35         657 :         mpToken = r.mpToken;
      36         657 :         if (mpToken)
      37             :         {
      38             :             // Since matrix dimension and
      39             :             // results are assigned to a matrix
      40             :             // cell formula token we have to
      41             :             // clone that instead of sharing it.
      42             :             const ScMatrixFormulaCellToken* pMatFormula =
      43         102 :                 r.GetMatrixFormulaCellToken();
      44         102 :             if (pMatFormula)
      45             :             {
      46           8 :                 mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
      47           8 :                 mpToken->IncRef();
      48             :             }
      49             :             else
      50          94 :                 IncrementTokenRef( mpToken);
      51             :         }
      52             :     }
      53             :     else
      54         525 :         mfValue = r.mfValue;
      55        1182 : }
      56             : 
      57        7476 : ScFormulaResult::ScFormulaResult( const formula::FormulaToken* p ) :
      58             :     mnError(0), mbToken(false), mbEmpty(false), mbEmptyDisplayedAsString(false),
      59        7476 :     meMultiline(MULTILINE_UNKNOWN)
      60             : {
      61        7476 :     SetToken( p);
      62        7476 : }
      63             : 
      64       17719 : ScFormulaResult::~ScFormulaResult()
      65             : {
      66       17719 :     if (mbToken && mpToken)
      67         460 :         mpToken->DecRef();
      68       17719 : }
      69             : 
      70       40273 : void ScFormulaResult::ResetToDefaults()
      71             : {
      72       40273 :     mnError = 0;
      73       40273 :     mbEmpty = false;
      74       40273 :     mbEmptyDisplayedAsString = false;
      75       40273 :     meMultiline = MULTILINE_UNKNOWN;
      76       40273 : }
      77             : 
      78       13622 : void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
      79             : {
      80       13622 :     ResetToDefaults();
      81       13622 :     if (!p)
      82             :     {
      83        1383 :         mpToken = p;
      84        1383 :         mbToken = true;
      85             :     }
      86             :     else
      87             :     {
      88       12239 :         switch (p->GetType())
      89             :         {
      90             :             case formula::svError:
      91         267 :                 mnError = p->GetError();
      92         267 :                 p->DecRef();
      93         267 :                 mbToken = false;
      94             :                 // set in case mnError is 0 now, which shouldn't happen but ...
      95         267 :                 mfValue = 0.0;
      96         267 :                 meMultiline = MULTILINE_FALSE;
      97         267 :                 break;
      98             :             case formula::svEmptyCell:
      99         730 :                 mbEmpty = true;
     100         730 :                 mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
     101         730 :                 p->DecRef();
     102         730 :                 mbToken = false;
     103         730 :                 meMultiline = MULTILINE_FALSE;
     104         730 :                 break;
     105             :             case formula::svDouble:
     106       10357 :                 mfValue = p->GetDouble();
     107       10357 :                 p->DecRef();
     108       10357 :                 mbToken = false;
     109       10357 :                 meMultiline = MULTILINE_FALSE;
     110       10357 :                 break;
     111             :             default:
     112         885 :                 mpToken = p;
     113         885 :                 mbToken = true;
     114             :         }
     115             :     }
     116       13622 : }
     117             : 
     118           0 : ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
     119             : {
     120           0 :     Assign( r);
     121           0 :     return *this;
     122             : }
     123             : 
     124        7092 : void ScFormulaResult::Assign( const ScFormulaResult & r )
     125             : {
     126        7092 :     if (this == &r)
     127        7092 :         return;
     128        7092 :     if (r.mbEmpty)
     129             :     {
     130         691 :         if (mbToken && mpToken)
     131           0 :             mpToken->DecRef();
     132         691 :         mbToken = false;
     133         691 :         mbEmpty = true;
     134         691 :         mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
     135         691 :         meMultiline = r.meMultiline;
     136             :     }
     137        6401 :     else if (r.mbToken)
     138             :     {
     139             :         // Matrix formula cell token must be cloned, see copy-ctor.
     140             :         const ScMatrixFormulaCellToken* pMatFormula =
     141          45 :             r.GetMatrixFormulaCellToken();
     142          45 :         if (pMatFormula)
     143          18 :             SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
     144             :         else
     145          27 :             SetToken( r.mpToken);
     146             :     }
     147             :     else
     148        6356 :         SetDouble( r.mfValue);
     149             :     // If there was an error there will be an error, no matter what Set...()
     150             :     // methods did.
     151        7092 :     mnError = r.mnError;
     152             : }
     153             : 
     154       13726 : void ScFormulaResult::SetToken( const formula::FormulaToken* p )
     155             : {
     156       13726 :     ResetToDefaults();
     157       13726 :     IncrementTokenRef( p);
     158             :     // Handle a result obtained from the interpreter to be assigned to a matrix
     159             :     // formula cell's ScMatrixFormulaCellToken.
     160       13726 :     ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
     161       13726 :     if (pMatFormula)
     162             :     {
     163             :         const ScMatrixCellResultToken* pMatResult =
     164         104 :             (p && p->GetType() == formula::svMatrixCell ?
     165         140 :              dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
     166         104 :         if (pMatResult)
     167             :         {
     168             :             const ScMatrixFormulaCellToken* pNewMatFormula =
     169          36 :                 dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
     170          36 :             if (pNewMatFormula && (pMatFormula->GetMatCols() <= 0 || pMatFormula->GetMatRows() <= 0))
     171             :             {
     172             :                 SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
     173           0 :                 pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
     174           0 :                         pNewMatFormula->GetMatRows());
     175             :             }
     176          36 :             pMatFormula->Assign( *pMatResult);
     177          36 :             p->DecRef();
     178             :         }
     179          68 :         else if (p)
     180             :         {
     181             :             // This may be the result of some constant expression like
     182             :             // {="string"} that doesn't result in a matrix but still would
     183             :             // display the result in all cells of this matrix formula.
     184          68 :             pMatFormula->Assign( *p);
     185          68 :             p->DecRef();
     186             :         }
     187             :         else
     188             :         {
     189             :             // NULL result? Well, if you say so ...
     190           0 :             pMatFormula->ResetResult();
     191             :         }
     192             :     }
     193             :     else
     194             :     {
     195       13622 :         if (mbToken && mpToken)
     196         609 :             mpToken->DecRef();
     197       13622 :         ResolveToken( p);
     198             :     }
     199       13726 : }
     200             : 
     201       11373 : void ScFormulaResult::SetDouble( double f )
     202             : {
     203       11373 :     ResetToDefaults();
     204             :     // Handle a result obtained from the interpreter to be assigned to a matrix
     205             :     // formula cell's ScMatrixFormulaCellToken.
     206       11373 :     ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
     207       11373 :     if (pMatFormula)
     208          16 :         pMatFormula->SetUpperLeftDouble( f);
     209             :     else
     210             :     {
     211       11357 :         if (mbToken && mpToken)
     212           0 :             mpToken->DecRef();
     213       11357 :         mfValue = f;
     214       11357 :         mbToken = false;
     215       11357 :         meMultiline = MULTILINE_FALSE;
     216             :     }
     217       11373 : }
     218             : 
     219      158431 : formula::StackVar ScFormulaResult::GetType() const
     220             : {
     221             :     // Order is significant.
     222      158431 :     if (mnError)
     223         964 :         return formula::svError;
     224      157467 :     if (mbEmpty)
     225        4539 :         return formula::svEmptyCell;
     226      152928 :     if (!mbToken)
     227      126844 :         return formula::svDouble;
     228       26084 :     if (mpToken)
     229        8497 :         return mpToken->GetType();
     230       17587 :     return formula::svUnknown;
     231             : }
     232             : 
     233      115263 : formula::StackVar ScFormulaResult::GetCellResultType() const
     234             : {
     235      115263 :     formula::StackVar sv = GetType();
     236      115263 :     if (sv == formula::svMatrixCell)
     237             :         // don't need to test for mpToken here, GetType() already did it
     238        1015 :         sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
     239      115263 :     return sv;
     240             : }
     241             : 
     242        3045 : bool ScFormulaResult::IsEmptyDisplayedAsString() const
     243             : {
     244        3045 :     if (mbEmpty)
     245          30 :         return mbEmptyDisplayedAsString;
     246        3015 :     if (GetType() == formula::svMatrixCell)
     247             :     {
     248             :         // don't need to test for mpToken here, GetType() already did it
     249             :         const ScEmptyCellToken* p = dynamic_cast<const ScEmptyCellToken*>(
     250             :                 static_cast<const ScMatrixCellResultToken*>(
     251          46 :                     mpToken)->GetUpperLeftToken().get());
     252          46 :         if (p)
     253           0 :             return p->IsDisplayedAsString();
     254             :     }
     255        3015 :     return false;
     256             : }
     257             : 
     258             : namespace {
     259             : 
     260       48860 : inline bool isValue( formula::StackVar sv )
     261             : {
     262        5542 :     return sv == formula::svDouble || sv == formula::svError
     263       53698 :         || sv == formula::svEmptyCell || sv == formula::svHybridValueCell;
     264             : }
     265             : 
     266          20 : inline bool isString( formula::StackVar sv )
     267             : {
     268          20 :     switch (sv)
     269             :     {
     270             :         case formula::svString:
     271             :         case formula::svHybridCell:
     272             :         case formula::svHybridValueCell:
     273          20 :             return true;
     274             :         default:
     275           0 :             break;
     276             :     }
     277             : 
     278           0 :     return false;
     279             : }
     280             : 
     281             : }
     282             : 
     283       43711 : bool ScFormulaResult::IsValue() const
     284             : {
     285       43711 :     return isValue(GetCellResultType());
     286             : }
     287             : 
     288         629 : bool ScFormulaResult::IsValueNoError() const
     289             : {
     290         629 :     switch (GetCellResultType())
     291             :     {
     292             :         case formula::svDouble:
     293             :         case formula::svEmptyCell:
     294             :         case formula::svHybridValueCell:
     295         605 :             return true;
     296             :         default:
     297          24 :             return false;
     298             :     }
     299             : }
     300             : 
     301         154 : bool ScFormulaResult::IsMultiline() const
     302             : {
     303         154 :     if (meMultiline == MULTILINE_UNKNOWN)
     304             :     {
     305          29 :         svl::SharedString aStr = GetString();
     306          29 :         if (!aStr.isEmpty() && aStr.getString().indexOf('\n') != -1)
     307           0 :             const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_TRUE;
     308             :         else
     309          29 :             const_cast<ScFormulaResult*>(this)->meMultiline = MULTILINE_FALSE;
     310             :     }
     311         154 :     return meMultiline == MULTILINE_TRUE;
     312             : }
     313             : 
     314        4665 : bool ScFormulaResult::GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const
     315             : {
     316        4665 :     if (mnError)
     317             :     {
     318         148 :         rErr = mnError;
     319         148 :         return true;
     320             :     }
     321             : 
     322        4517 :     formula::StackVar sv = GetCellResultType();
     323        4517 :     if (sv == formula::svError)
     324             :     {
     325           0 :         if (GetType() == formula::svMatrixCell)
     326             :         {
     327             :             // don't need to test for mpToken here, GetType() already did it
     328             :             rErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
     329           0 :                 GetUpperLeftToken()->GetError();
     330             :         }
     331           0 :         else if (mpToken)
     332             :         {
     333           0 :             rErr = mpToken->GetError();
     334             :         }
     335             :     }
     336             : 
     337        4517 :     if (rErr)
     338           0 :         return true;
     339             : 
     340        4517 :     if (!isValue(sv))
     341           0 :         return false;
     342             : 
     343        4517 :     rVal = GetDouble();
     344        4517 :     return true;
     345             : }
     346             : 
     347         638 : sc::FormulaResultValue ScFormulaResult::GetResult() const
     348             : {
     349         638 :     if (mnError)
     350           6 :         return sc::FormulaResultValue(mnError);
     351             : 
     352         632 :     formula::StackVar sv = GetCellResultType();
     353         632 :     sal_uInt16 nErr = 0;
     354         632 :     if (sv == formula::svError)
     355             :     {
     356           0 :         if (GetType() == formula::svMatrixCell)
     357             :         {
     358             :             // don't need to test for mpToken here, GetType() already did it
     359             :             nErr = static_cast<const ScMatrixCellResultToken*>(mpToken)->
     360           0 :                 GetUpperLeftToken()->GetError();
     361             :         }
     362           0 :         else if (mpToken)
     363             :         {
     364           0 :             nErr = mpToken->GetError();
     365             :         }
     366             :     }
     367             : 
     368         632 :     if (nErr)
     369           0 :         return sc::FormulaResultValue(nErr);
     370             : 
     371         632 :     if (isValue(sv))
     372         612 :         return sc::FormulaResultValue(GetDouble());
     373             : 
     374          20 :     if (!mbToken)
     375             :         // String result type needs token.
     376           0 :         return sc::FormulaResultValue();
     377             : 
     378          20 :     if (isString(sv))
     379          20 :         return sc::FormulaResultValue(GetString());
     380             : 
     381             :     // Invalid
     382           0 :     return sc::FormulaResultValue();
     383             : }
     384             : 
     385       50700 : sal_uInt16 ScFormulaResult::GetResultError() const
     386             : {
     387       50700 :     if (mnError)
     388         501 :         return mnError;
     389       50199 :     formula::StackVar sv = GetCellResultType();
     390       50199 :     if (sv == formula::svError)
     391             :     {
     392          17 :         if (GetType() == formula::svMatrixCell)
     393             :             // don't need to test for mpToken here, GetType() already did it
     394             :             return static_cast<const ScMatrixCellResultToken*>(mpToken)->
     395          17 :                 GetUpperLeftToken()->GetError();
     396           0 :         if (mpToken)
     397           0 :             return mpToken->GetError();
     398             :     }
     399       50182 :     return 0;
     400             : }
     401             : 
     402       11831 : void ScFormulaResult::SetResultError( sal_uInt16 nErr )
     403             : {
     404       11831 :     mnError = nErr;
     405       11831 : }
     406             : 
     407           0 : formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
     408             : {
     409           0 :     if (mbToken)
     410           0 :         return mpToken;
     411           0 :     return NULL;
     412             : }
     413             : 
     414          24 : formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
     415             : {
     416          24 :     if (GetType() == formula::svMatrixCell)
     417             :         // don't need to test for mpToken here, GetType() already did it
     418          24 :         return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
     419           0 :     return GetToken();
     420             : }
     421             : 
     422       47445 : double ScFormulaResult::GetDouble() const
     423             : {
     424       47445 :     if (mbToken)
     425             :     {
     426             :         // Should really not be of type formula::svDouble here.
     427         832 :         if (mpToken)
     428             :         {
     429         676 :             switch (mpToken->GetType())
     430             :             {
     431             :                 case formula::svHybridCell:
     432             :                 case formula::svHybridValueCell:
     433           0 :                     return mpToken->GetDouble();
     434             :                 case formula::svMatrixCell:
     435             :                     {
     436             :                         const ScMatrixCellResultToken* p =
     437         329 :                             static_cast<const ScMatrixCellResultToken*>(mpToken);
     438         329 :                         if (p->GetUpperLeftType() == formula::svDouble)
     439         322 :                             return p->GetUpperLeftToken()->GetDouble();
     440             :                     }
     441           7 :                     break;
     442             :                 default:
     443             :                     ;   // nothing
     444             :             }
     445             :         }
     446         510 :         return 0.0;
     447             :     }
     448       46613 :     if (mbEmpty)
     449        1525 :         return 0.0;
     450       45088 :     return mfValue;
     451             : }
     452             : 
     453         703 : svl::SharedString ScFormulaResult::GetString() const
     454             : {
     455         703 :     if (mbToken && mpToken)
     456             :     {
     457         671 :         switch (mpToken->GetType())
     458             :         {
     459             :             case formula::svString:
     460             :             case formula::svHybridCell:
     461             :             case formula::svHybridValueCell:
     462         649 :                 return mpToken->GetString();
     463             :             case formula::svMatrixCell:
     464             :                 {
     465             :                     const ScMatrixCellResultToken* p =
     466          22 :                         static_cast<const ScMatrixCellResultToken*>(mpToken);
     467          22 :                     if (p->GetUpperLeftType() == formula::svString)
     468          22 :                         return p->GetUpperLeftToken()->GetString();
     469             :                 }
     470           0 :                 break;
     471             :             default:
     472             :                 ;   // nothing
     473             :         }
     474             :     }
     475          32 :     return svl::SharedString::getEmptyString();
     476             : }
     477             : 
     478       12064 : ScConstMatrixRef ScFormulaResult::GetMatrix() const
     479             : {
     480       12064 :     if (GetType() == formula::svMatrixCell)
     481         368 :         return mpToken->GetMatrix();
     482       11696 :     return NULL;
     483             : }
     484             : 
     485         170 : const OUString& ScFormulaResult::GetHybridFormula() const
     486             : {
     487         170 :     if (GetType() == formula::svHybridCell)
     488             :     {
     489           5 :         const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
     490           5 :         if (p)
     491           5 :             return p->GetFormula();
     492             :     }
     493         165 :     return EMPTY_OUSTRING;
     494             : }
     495             : 
     496        1352 : void ScFormulaResult::SetHybridDouble( double f )
     497             : {
     498        1352 :     ResetToDefaults();
     499        1352 :     if (mbToken && mpToken)
     500             :     {
     501           0 :         if(GetType() == formula::svMatrixCell)
     502           0 :             SetDouble(f);
     503             :         else
     504             :         {
     505           0 :             svl::SharedString aString = GetString();
     506           0 :             OUString aFormula( GetHybridFormula());
     507           0 :             mpToken->DecRef();
     508           0 :             mpToken = new ScHybridCellToken( f, aString, aFormula);
     509           0 :             mpToken->IncRef();
     510           0 :         }
     511             :     }
     512             :     else
     513             :     {
     514        1352 :         mfValue = f;
     515        1352 :         mbToken = false;
     516        1352 :         meMultiline = MULTILINE_FALSE;
     517             :     }
     518        1352 : }
     519             : 
     520         156 : void ScFormulaResult::SetHybridString( const svl::SharedString& rStr )
     521             : {
     522             :     // Obtain values before changing anything.
     523         156 :     double f = GetDouble();
     524         156 :     OUString aFormula( GetHybridFormula());
     525         156 :     ResetToDefaults();
     526         156 :     if (mbToken && mpToken)
     527           0 :         mpToken->DecRef();
     528         156 :     mpToken = new ScHybridCellToken( f, rStr, aFormula);
     529         156 :     mpToken->IncRef();
     530         156 :     mbToken = true;
     531         156 : }
     532             : 
     533           5 : void ScFormulaResult::SetHybridFormula( const OUString & rFormula )
     534             : {
     535             :     // Obtain values before changing anything.
     536           5 :     double f = GetDouble();
     537           5 :     svl::SharedString aStr = GetString();
     538           5 :     ResetToDefaults();
     539           5 :     if (mbToken && mpToken)
     540           0 :         mpToken->DecRef();
     541           5 :     mpToken = new ScHybridCellToken( f, aStr, rFormula);
     542           5 :     mpToken->IncRef();
     543           5 :     mbToken = true;
     544           5 : }
     545             : 
     546          39 : void ScFormulaResult::SetMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL )
     547             : {
     548          39 :     ResetToDefaults();
     549          39 :     if (mbToken && mpToken)
     550          39 :         mpToken->DecRef();
     551          39 :     mpToken = new ScMatrixFormulaCellToken(nCols, nRows, pMat, pUL);
     552          39 :     mpToken->IncRef();
     553          39 :     mbToken = true;
     554          39 : }
     555             : 
     556       25339 : const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
     557             : {
     558       25339 :     return (GetType() == formula::svMatrixCell ?
     559       25339 :             dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
     560             : }
     561             : 
     562       25162 : ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
     563             : {
     564       25162 :     return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
     565         156 : }
     566             : 
     567             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11