LCOV - code coverage report
Current view: top level - sc/source/core/tool - formularesult.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 247 292 84.6 %
Date: 2014-11-03 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        1266 : FormulaResultValue::FormulaResultValue( double fValue ) : meType(Value), mfValue(fValue), mnError(0) {}
      17          40 : FormulaResultValue::FormulaResultValue( const svl::SharedString& rStr ) : meType(String), mfValue(0.0), maString(rStr), mnError(0) {}
      18          22 : FormulaResultValue::FormulaResultValue( sal_uInt16 nErr ) : meType(Error), mfValue(0.0), mnError(nErr) {}
      19             : 
      20             : }
      21             : 
      22       17460 : ScFormulaResult::ScFormulaResult() :
      23             :     mpToken(NULL), mnError(0), mbToken(true),
      24             :     mbEmpty(false), mbEmptyDisplayedAsString(false),
      25       17460 :     meMultiline(MULTILINE_UNKNOWN) {}
      26             : 
      27        1990 : ScFormulaResult::ScFormulaResult( const ScFormulaResult & r ) :
      28             :     mnError( r.mnError), mbToken( r.mbToken),
      29             :     mbEmpty( r.mbEmpty),
      30             :     mbEmptyDisplayedAsString( r.mbEmptyDisplayedAsString),
      31        1990 :     meMultiline( r.meMultiline)
      32             : {
      33        1990 :     if (mbToken)
      34             :     {
      35        1228 :         mpToken = r.mpToken;
      36        1228 :         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         148 :                 r.GetMatrixFormulaCellToken();
      44         148 :             if (pMatFormula)
      45             :             {
      46           0 :                 mpToken = new ScMatrixFormulaCellToken( *pMatFormula);
      47           0 :                 mpToken->IncRef();
      48             :             }
      49             :             else
      50         148 :                 IncrementTokenRef( mpToken);
      51             :         }
      52             :     }
      53             :     else
      54         762 :         mfValue = r.mfValue;
      55        1990 : }
      56             : 
      57       14637 : ScFormulaResult::ScFormulaResult( const formula::FormulaToken* p ) :
      58             :     mnError(0), mbToken(false), mbEmpty(false), mbEmptyDisplayedAsString(false),
      59       14637 :     meMultiline(MULTILINE_UNKNOWN)
      60             : {
      61       14637 :     SetToken( p);
      62       14637 : }
      63             : 
      64       34039 : ScFormulaResult::~ScFormulaResult()
      65             : {
      66       34039 :     if (mbToken && mpToken)
      67         886 :         mpToken->DecRef();
      68       34039 : }
      69             : 
      70       71937 : void ScFormulaResult::ResetToDefaults()
      71             : {
      72       71937 :     mnError = 0;
      73       71937 :     mbEmpty = false;
      74       71937 :     mbEmptyDisplayedAsString = false;
      75       71937 :     meMultiline = MULTILINE_UNKNOWN;
      76       71937 : }
      77             : 
      78       23945 : void ScFormulaResult::ResolveToken( const formula::FormulaToken * p )
      79             : {
      80       23945 :     ResetToDefaults();
      81       23945 :     if (!p)
      82             :     {
      83        2588 :         mpToken = p;
      84        2588 :         mbToken = true;
      85             :     }
      86             :     else
      87             :     {
      88       21357 :         switch (p->GetType())
      89             :         {
      90             :             case formula::svError:
      91         516 :                 mnError = p->GetError();
      92         516 :                 p->DecRef();
      93         516 :                 mbToken = false;
      94             :                 // set in case mnError is 0 now, which shouldn't happen but ...
      95         516 :                 mfValue = 0.0;
      96         516 :                 meMultiline = MULTILINE_FALSE;
      97         516 :                 break;
      98             :             case formula::svEmptyCell:
      99        1372 :                 mbEmpty = true;
     100        1372 :                 mbEmptyDisplayedAsString = static_cast<const ScEmptyCellToken*>(p)->IsDisplayedAsString();
     101        1372 :                 p->DecRef();
     102        1372 :                 mbToken = false;
     103        1372 :                 meMultiline = MULTILINE_FALSE;
     104        1372 :                 break;
     105             :             case formula::svDouble:
     106       17959 :                 mfValue = p->GetDouble();
     107       17959 :                 p->DecRef();
     108       17959 :                 mbToken = false;
     109       17959 :                 meMultiline = MULTILINE_FALSE;
     110       17959 :                 break;
     111             :             default:
     112        1510 :                 mpToken = p;
     113        1510 :                 mbToken = true;
     114             :         }
     115             :     }
     116       23945 : }
     117             : 
     118           0 : ScFormulaResult & ScFormulaResult::operator=( const ScFormulaResult & r )
     119             : {
     120           0 :     Assign( r);
     121           0 :     return *this;
     122             : }
     123             : 
     124       13721 : void ScFormulaResult::Assign( const ScFormulaResult & r )
     125             : {
     126       13721 :     if (this == &r)
     127       13721 :         return;
     128       13721 :     if (r.mbEmpty)
     129             :     {
     130        1310 :         if (mbToken && mpToken)
     131           0 :             mpToken->DecRef();
     132        1310 :         mbToken = false;
     133        1310 :         mbEmpty = true;
     134        1310 :         mbEmptyDisplayedAsString = r.mbEmptyDisplayedAsString;
     135        1310 :         meMultiline = r.meMultiline;
     136             :     }
     137       12411 :     else if (r.mbToken)
     138             :     {
     139             :         // Matrix formula cell token must be cloned, see copy-ctor.
     140             :         const ScMatrixFormulaCellToken* pMatFormula =
     141          74 :             r.GetMatrixFormulaCellToken();
     142          74 :         if (pMatFormula)
     143          28 :             SetToken( new ScMatrixFormulaCellToken( *pMatFormula));
     144             :         else
     145          46 :             SetToken( r.mpToken);
     146             :     }
     147             :     else
     148       12337 :         SetDouble( r.mfValue);
     149             :     // If there was an error there will be an error, no matter what Set...()
     150             :     // methods did.
     151       13721 :     mnError = r.mnError;
     152             : }
     153             : 
     154       24063 : void ScFormulaResult::SetToken( const formula::FormulaToken* p )
     155             : {
     156       24063 :     ResetToDefaults();
     157       24063 :     IncrementTokenRef( p);
     158             :     // Handle a result obtained from the interpreter to be assigned to a matrix
     159             :     // formula cell's ScMatrixFormulaCellToken.
     160       24063 :     ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
     161       24063 :     if (pMatFormula)
     162             :     {
     163             :         const ScMatrixCellResultToken* pMatResult =
     164         118 :             (p && p->GetType() == formula::svMatrixCell ?
     165         166 :              dynamic_cast<const ScMatrixCellResultToken*>(p) : NULL);
     166         118 :         if (pMatResult)
     167             :         {
     168             :             const ScMatrixFormulaCellToken* pNewMatFormula =
     169          48 :                 dynamic_cast<const ScMatrixFormulaCellToken*>(pMatResult);
     170          48 :             if (pNewMatFormula)
     171             :             {
     172             :                 SAL_WARN( "sc", "ScFormulaResult::SetToken: pNewMatFormula and pMatFormula, overriding matrix formula dimension; intended?");
     173          48 :                 pMatFormula->SetMatColsRows( pNewMatFormula->GetMatCols(),
     174          96 :                         pNewMatFormula->GetMatRows());
     175             :             }
     176          48 :             pMatFormula->Assign( *pMatResult);
     177          48 :             p->DecRef();
     178             :         }
     179          70 :         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          70 :             pMatFormula->Assign( *p);
     185          70 :             p->DecRef();
     186             :         }
     187             :         else
     188             :         {
     189             :             // NULL result? Well, if you say so ...
     190           0 :             pMatFormula->ResetResult();
     191             :         }
     192             :     }
     193             :     else
     194             :     {
     195       23945 :         if (mbToken && mpToken)
     196        1014 :             mpToken->DecRef();
     197       23945 :         ResolveToken( p);
     198             :     }
     199       24063 : }
     200             : 
     201       22203 : void ScFormulaResult::SetDouble( double f )
     202             : {
     203       22203 :     ResetToDefaults();
     204             :     // Handle a result obtained from the interpreter to be assigned to a matrix
     205             :     // formula cell's ScMatrixFormulaCellToken.
     206       22203 :     ScMatrixFormulaCellToken* pMatFormula = GetMatrixFormulaCellTokenNonConst();
     207       22203 :     if (pMatFormula)
     208          32 :         pMatFormula->SetUpperLeftDouble( f);
     209             :     else
     210             :     {
     211       22171 :         if (mbToken && mpToken)
     212           0 :             mpToken->DecRef();
     213       22171 :         mfValue = f;
     214       22171 :         mbToken = false;
     215       22171 :         meMultiline = MULTILINE_FALSE;
     216             :     }
     217       22203 : }
     218             : 
     219      278941 : formula::StackVar ScFormulaResult::GetType() const
     220             : {
     221             :     // Order is significant.
     222      278941 :     if (mnError)
     223        1788 :         return formula::svError;
     224      277153 :     if (mbEmpty)
     225        8286 :         return formula::svEmptyCell;
     226      268867 :     if (!mbToken)
     227      222490 :         return formula::svDouble;
     228       46377 :     if (mpToken)
     229       13180 :         return mpToken->GetType();
     230       33197 :     return formula::svUnknown;
     231             : }
     232             : 
     233      202332 : formula::StackVar ScFormulaResult::GetCellResultType() const
     234             : {
     235      202332 :     formula::StackVar sv = GetType();
     236      202332 :     if (sv == formula::svMatrixCell)
     237             :         // don't need to test for mpToken here, GetType() already did it
     238        1332 :         sv = static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftType();
     239      202332 :     return sv;
     240             : }
     241             : 
     242        4793 : bool ScFormulaResult::IsEmptyDisplayedAsString() const
     243             : {
     244        4793 :     if (mbEmpty)
     245          36 :         return mbEmptyDisplayedAsString;
     246        4757 :     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          38 :                     mpToken)->GetUpperLeftToken().get());
     252          38 :         if (p)
     253           0 :             return p->IsDisplayedAsString();
     254             :     }
     255        4757 :     return false;
     256             : }
     257             : 
     258             : namespace {
     259             : 
     260       83454 : inline bool isValue( formula::StackVar sv )
     261             : {
     262        9367 :     return sv == formula::svDouble || sv == formula::svError
     263       91545 :         || sv == formula::svEmptyCell || sv == formula::svHybridValueCell;
     264             : }
     265             : 
     266          40 : inline bool isString( formula::StackVar sv )
     267             : {
     268          40 :     switch (sv)
     269             :     {
     270             :         case formula::svString:
     271             :         case formula::svHybridCell:
     272             :         case formula::svHybridValueCell:
     273          40 :             return true;
     274             :         default:
     275           0 :             break;
     276             :     }
     277             : 
     278           0 :     return false;
     279             : }
     280             : 
     281             : }
     282             : 
     283       74792 : bool ScFormulaResult::IsValue() const
     284             : {
     285       74792 :     return isValue(GetCellResultType());
     286             : }
     287             : 
     288        1258 : bool ScFormulaResult::IsValueNoError() const
     289             : {
     290        1258 :     switch (GetCellResultType())
     291             :     {
     292             :         case formula::svDouble:
     293             :         case formula::svEmptyCell:
     294             :         case formula::svHybridValueCell:
     295        1210 :             return true;
     296             :         default:
     297          48 :             return false;
     298             :     }
     299             : }
     300             : 
     301         171 : bool ScFormulaResult::IsMultiline() const
     302             : {
     303         171 :     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         171 :     return meMultiline == MULTILINE_TRUE;
     312             : }
     313             : 
     314        7644 : bool ScFormulaResult::GetErrorOrDouble( sal_uInt16& rErr, double& rVal ) const
     315             : {
     316        7644 :     if (mnError)
     317             :     {
     318         288 :         rErr = mnError;
     319         288 :         return true;
     320             :     }
     321             : 
     322        7356 :     formula::StackVar sv = GetCellResultType();
     323        7356 :     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        7356 :     if (rErr)
     338           0 :         return true;
     339             : 
     340        7356 :     if (!isValue(sv))
     341           0 :         return false;
     342             : 
     343        7356 :     rVal = GetDouble();
     344        7356 :     return true;
     345             : }
     346             : 
     347        1328 : sc::FormulaResultValue ScFormulaResult::GetResult() const
     348             : {
     349        1328 :     if (mnError)
     350          22 :         return sc::FormulaResultValue(mnError);
     351             : 
     352        1306 :     formula::StackVar sv = GetCellResultType();
     353        1306 :     sal_uInt16 nErr = 0;
     354        1306 :     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        1306 :     if (nErr)
     369           0 :         return sc::FormulaResultValue(nErr);
     370             : 
     371        1306 :     if (isValue(sv))
     372        1266 :         return sc::FormulaResultValue(GetDouble());
     373             : 
     374          40 :     if (!mbToken)
     375             :         // String result type needs token.
     376           0 :         return sc::FormulaResultValue();
     377             : 
     378          40 :     if (isString(sv))
     379          40 :         return sc::FormulaResultValue(GetString());
     380             : 
     381             :     // Invalid
     382           0 :     return sc::FormulaResultValue();
     383             : }
     384             : 
     385       88154 : sal_uInt16 ScFormulaResult::GetResultError() const
     386             : {
     387       88154 :     if (mnError)
     388         960 :         return mnError;
     389       87194 :     formula::StackVar sv = GetCellResultType();
     390       87194 :     if (sv == formula::svError)
     391             :     {
     392          32 :         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          32 :                 GetUpperLeftToken()->GetError();
     396           0 :         if (mpToken)
     397           0 :             return mpToken->GetError();
     398             :     }
     399       87162 :     return 0;
     400             : }
     401             : 
     402       20367 : void ScFormulaResult::SetResultError( sal_uInt16 nErr )
     403             : {
     404       20367 :     mnError = nErr;
     405       20367 : }
     406             : 
     407           0 : formula::FormulaConstTokenRef ScFormulaResult::GetToken() const
     408             : {
     409           0 :     if (mbToken)
     410           0 :         return mpToken;
     411           0 :     return NULL;
     412             : }
     413             : 
     414          32 : formula::FormulaConstTokenRef ScFormulaResult::GetCellResultToken() const
     415             : {
     416          32 :     if (GetType() == formula::svMatrixCell)
     417             :         // don't need to test for mpToken here, GetType() already did it
     418          32 :         return static_cast<const ScMatrixCellResultToken*>(mpToken)->GetUpperLeftToken();
     419           0 :     return GetToken();
     420             : }
     421             : 
     422       85776 : double ScFormulaResult::GetDouble() const
     423             : {
     424       85776 :     if (mbToken)
     425             :     {
     426             :         // Should really not be of type formula::svDouble here.
     427        1402 :         if (mpToken)
     428             :         {
     429        1152 :             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         458 :                             static_cast<const ScMatrixCellResultToken*>(mpToken);
     438         458 :                         if (p->GetUpperLeftType() == formula::svDouble)
     439         446 :                             return p->GetUpperLeftToken()->GetDouble();
     440             :                     }
     441          12 :                     break;
     442             :                 default:
     443             :                     ;   // nothing
     444             :             }
     445             :         }
     446         956 :         return 0.0;
     447             :     }
     448       84374 :     if (mbEmpty)
     449        2774 :         return 0.0;
     450       81600 :     return mfValue;
     451             : }
     452             : 
     453        1093 : svl::SharedString ScFormulaResult::GetString() const
     454             : {
     455        1093 :     if (mbToken && mpToken)
     456             :     {
     457        1058 :         switch (mpToken->GetType())
     458             :         {
     459             :             case formula::svString:
     460             :             case formula::svHybridCell:
     461             :             case formula::svHybridValueCell:
     462        1030 :                 return mpToken->GetString();
     463             :             case formula::svMatrixCell:
     464             :                 {
     465             :                     const ScMatrixCellResultToken* p =
     466          28 :                         static_cast<const ScMatrixCellResultToken*>(mpToken);
     467          28 :                     if (p->GetUpperLeftType() == formula::svString)
     468          28 :                         return p->GetUpperLeftToken()->GetString();
     469             :                 }
     470           0 :                 break;
     471             :             default:
     472             :                 ;   // nothing
     473             :         }
     474             :     }
     475          35 :     return svl::SharedString::getEmptyString();
     476             : }
     477             : 
     478       20821 : ScConstMatrixRef ScFormulaResult::GetMatrix() const
     479             : {
     480       20821 :     if (GetType() == formula::svMatrixCell)
     481         638 :         return mpToken->GetMatrix();
     482       20183 :     return NULL;
     483             : }
     484             : 
     485         262 : const OUString& ScFormulaResult::GetHybridFormula() const
     486             : {
     487         262 :     if (GetType() == formula::svHybridCell)
     488             :     {
     489          10 :         const ScHybridCellToken* p = dynamic_cast<const ScHybridCellToken*>(mpToken);
     490          10 :         if (p)
     491          10 :             return p->GetFormula();
     492             :     }
     493         252 :     return EMPTY_OUSTRING;
     494             : }
     495             : 
     496        1432 : void ScFormulaResult::SetHybridDouble( double f )
     497             : {
     498        1432 :     ResetToDefaults();
     499        1432 :     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        1432 :         mfValue = f;
     515        1432 :         mbToken = false;
     516        1432 :         meMultiline = MULTILINE_FALSE;
     517             :     }
     518        1432 : }
     519             : 
     520         234 : void ScFormulaResult::SetHybridString( const svl::SharedString& rStr )
     521             : {
     522             :     // Obtain values before changing anything.
     523         234 :     double f = GetDouble();
     524         234 :     OUString aFormula( GetHybridFormula());
     525         234 :     ResetToDefaults();
     526         234 :     if (mbToken && mpToken)
     527           0 :         mpToken->DecRef();
     528         234 :     mpToken = new ScHybridCellToken( f, rStr, aFormula);
     529         234 :     mpToken->IncRef();
     530         234 :     mbToken = true;
     531         234 : }
     532             : 
     533          10 : void ScFormulaResult::SetHybridFormula( const OUString & rFormula )
     534             : {
     535             :     // Obtain values before changing anything.
     536          10 :     double f = GetDouble();
     537          10 :     svl::SharedString aStr = GetString();
     538          10 :     ResetToDefaults();
     539          10 :     if (mbToken && mpToken)
     540           0 :         mpToken->DecRef();
     541          10 :     mpToken = new ScHybridCellToken( f, aStr, rFormula);
     542          10 :     mpToken->IncRef();
     543          10 :     mbToken = true;
     544          10 : }
     545             : 
     546          50 : void ScFormulaResult::SetMatrix( SCCOL nCols, SCROW nRows, const ScConstMatrixRef& pMat, formula::FormulaToken* pUL )
     547             : {
     548          50 :     ResetToDefaults();
     549          50 :     if (mbToken && mpToken)
     550          50 :         mpToken->DecRef();
     551          50 :     mpToken = new ScMatrixFormulaCellToken(nCols, nRows, pMat, pUL);
     552          50 :     mpToken->IncRef();
     553          50 :     mbToken = true;
     554          50 : }
     555             : 
     556       46644 : const ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellToken() const
     557             : {
     558       46644 :     return (GetType() == formula::svMatrixCell ?
     559       46644 :             dynamic_cast<const ScMatrixFormulaCellToken*>(mpToken) : NULL);
     560             : }
     561             : 
     562       46360 : ScMatrixFormulaCellToken* ScFormulaResult::GetMatrixFormulaCellTokenNonConst()
     563             : {
     564       46360 :     return const_cast<ScMatrixFormulaCellToken*>( GetMatrixFormulaCellToken());
     565         228 : }
     566             : 
     567             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10