LCOV - code coverage report
Current view: top level - sc/source/core/data - grouptokenconverter.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 32 125 25.6 %
Date: 2015-06-13 12:38:46 Functions: 6 7 85.7 %
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 <formula/token.hxx>
      11             : #include <formula/vectortoken.hxx>
      12             : 
      13             : #include "compiler.hxx"
      14             : #include "grouptokenconverter.hxx"
      15             : 
      16             : using namespace formula;
      17             : 
      18           2 : bool ScGroupTokenConverter::isSelfReferenceRelative(const ScAddress& rRefPos, SCROW nRelRow)
      19             : {
      20           2 :     if (rRefPos.Col() != mrPos.Col())
      21           2 :         return false;
      22             : 
      23           0 :     SCROW nLen = mrCell.GetCellGroup()->mnLength;
      24           0 :     SCROW nEndRow = mrPos.Row() + nLen - 1;
      25             : 
      26           0 :     if (nRelRow < 0)
      27             :     {
      28           0 :         SCROW nTest = nEndRow;
      29           0 :         nTest += nRelRow;
      30           0 :         if (nTest >= mrPos.Row())
      31           0 :             return true;
      32             :     }
      33           0 :     else if (nRelRow > 0)
      34             :     {
      35           0 :         SCROW nTest = mrPos.Row(); // top row.
      36           0 :         nTest += nRelRow;
      37           0 :         if (nTest <= nEndRow)
      38           0 :             return true;
      39             :     }
      40             : 
      41           0 :     return false;
      42             : }
      43             : 
      44           0 : bool ScGroupTokenConverter::isSelfReferenceAbsolute(const ScAddress& rRefPos)
      45             : {
      46           0 :     if (rRefPos.Col() != mrPos.Col())
      47           0 :         return false;
      48             : 
      49           0 :     SCROW nLen = mrCell.GetCellGroup()->mnLength;
      50           0 :     SCROW nEndRow = mrPos.Row() + nLen - 1;
      51             : 
      52           0 :     if (rRefPos.Row() < mrPos.Row())
      53           0 :         return false;
      54             : 
      55           0 :     if (rRefPos.Row() > nEndRow)
      56           0 :         return false;
      57             : 
      58           0 :     return true;
      59             : }
      60             : 
      61           2 : SCROW ScGroupTokenConverter::trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen)
      62             : {
      63           2 :     SCROW nLastRow = nRow + nRowLen - 1; // current last row.
      64           2 :     nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2, nLastRow);
      65           2 :     if (nLastRow < (nRow + nRowLen - 1))
      66             :     {
      67             :         // This can end up negative! Was that the original intent, or
      68             :         // is it accidental? Was it not like that originally but the
      69             :         // surrounding conditions changed?
      70           0 :         nRowLen = nLastRow - nRow + 1;
      71             :         // Anyway, let's assume it doesn't make sense to return a
      72             :         // negative value here. But should we then return 0 or 1? In
      73             :         // the "Column is empty" case below, we return 1, why!? And,
      74             :         // at the callsites there are tests for a zero value returned
      75             :         // from this function (but not for a negative one).
      76           0 :         if (nRowLen < 0)
      77           0 :             nRowLen = 0;
      78             :     }
      79           2 :     else if (nLastRow == 0)
      80             :         // Column is empty.
      81           0 :         nRowLen = 1;
      82             : 
      83           2 :     return nRowLen;
      84             : }
      85             : 
      86           1 : ScGroupTokenConverter::ScGroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
      87           1 :         mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos)
      88             : 
      89             : {
      90           1 : }
      91             : 
      92           1 : bool ScGroupTokenConverter::convert(ScTokenArray& rCode, std::vector<ScTokenArray*>& rConversionStack)
      93             : {
      94             : #if 0
      95             :     { // debug to start with:
      96             :         ScCompiler aComp( &mrDoc, mrPos, rCode);
      97             :         aComp.SetGrammar(formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1);
      98             :         OUStringBuffer aAsString;
      99             :         aComp.CreateStringFromTokenArray(aAsString);
     100             :     }
     101             : #endif
     102             : 
     103           1 :     rCode.Reset();
     104           4 :     for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
     105             :     {
     106             :         // A reference can be either absolute or relative.  If it's absolute,
     107             :         // convert it to a static value token.  If relative, convert it to a
     108             :         // vector reference token.  Note: we only care about relative vs
     109             :         // absolute reference state for row directions.
     110             : 
     111           3 :         SCROW nLen = mrCell.GetCellGroup()->mnLength;
     112           3 :         switch (p->GetType())
     113             :         {
     114             :             case svSingleRef:
     115             :             {
     116           2 :                 ScSingleRefData aRef = *p->GetSingleRef();
     117           2 :                 ScAddress aRefPos = aRef.toAbs(mrPos);
     118           2 :                 if (aRef.IsRowRel())
     119             :                 {
     120           2 :                     if (isSelfReferenceRelative(aRefPos, aRef.Row()))
     121           0 :                         return false;
     122             : 
     123             :                     // Trim data array length to actual data range.
     124           2 :                     SCROW nTrimLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen);
     125             :                     // Fetch double array guarantees that the length of the
     126             :                     // returned array equals or greater than the requested
     127             :                     // length.
     128             : 
     129           2 :                     formula::VectorRefArray aArray;
     130           2 :                     if (nTrimLen)
     131           2 :                         aArray = mrDoc.FetchVectorRefArray(aRefPos, nTrimLen);
     132             : 
     133           2 :                     if (!aArray.isValid())
     134           0 :                         return false;
     135             : 
     136           2 :                     formula::SingleVectorRefToken aTok(aArray, nLen, nTrimLen);
     137           2 :                     mrGroupTokens.AddToken(aTok);
     138             :                 }
     139             :                 else
     140             :                 {
     141             :                     // Absolute row reference.
     142           0 :                     if (isSelfReferenceAbsolute(aRefPos))
     143           0 :                         return false;
     144             : 
     145           0 :                     formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos);
     146           0 :                     if (!pNewToken)
     147           0 :                         return false;
     148             : 
     149           0 :                     mrGroupTokens.AddToken(*pNewToken);
     150             :                 }
     151             :             }
     152           2 :             break;
     153             :             case svDoubleRef:
     154             :             {
     155           0 :                 ScComplexRefData aRef = *p->GetDoubleRef();
     156           0 :                 ScRange aAbs = aRef.toAbs(mrPos);
     157             : 
     158             :                 // Check for self reference.
     159           0 :                 if (aRef.Ref1.IsRowRel())
     160             :                 {
     161           0 :                     if (isSelfReferenceRelative(aAbs.aStart, aRef.Ref1.Row()))
     162           0 :                         return false;
     163             :                 }
     164           0 :                 else if (isSelfReferenceAbsolute(aAbs.aStart))
     165           0 :                     return false;
     166             : 
     167           0 :                 if (aRef.Ref2.IsRowRel())
     168             :                 {
     169           0 :                     if (isSelfReferenceRelative(aAbs.aEnd, aRef.Ref2.Row()))
     170           0 :                         return false;
     171             :                 }
     172           0 :                 else if (isSelfReferenceAbsolute(aAbs.aEnd))
     173           0 :                     return false;
     174             : 
     175             :                 // Row reference is relative.
     176           0 :                 bool bAbsFirst = !aRef.Ref1.IsRowRel();
     177           0 :                 bool bAbsLast = !aRef.Ref2.IsRowRel();
     178           0 :                 ScAddress aRefPos = aAbs.aStart;
     179           0 :                 size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1;
     180           0 :                 std::vector<formula::VectorRefArray> aArrays;
     181           0 :                 aArrays.reserve(nCols);
     182           0 :                 SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1;
     183           0 :                 SCROW nArrayLength = nRefRowSize;
     184           0 :                 if (!bAbsLast)
     185             :                 {
     186             :                     // range end position is relative. Extend the array length.
     187           0 :                     SCROW nLastRefRowOffset = aAbs.aEnd.Row() - mrPos.Row();
     188           0 :                     SCROW nLastRefRow = mrPos.Row() + nLen - 1 + nLastRefRowOffset;
     189           0 :                     SCROW nNewLength = nLastRefRow - aAbs.aStart.Row() + 1;
     190           0 :                     if (nNewLength > nArrayLength)
     191           0 :                         nArrayLength = nNewLength;
     192             :                 }
     193             : 
     194             :                 // Trim trailing empty rows.
     195           0 :                 SCROW nRequestedLength = nArrayLength; // keep the original length.
     196           0 :                 nArrayLength = trimLength(aRefPos.Tab(), aAbs.aStart.Col(), aAbs.aEnd.Col(), aRefPos.Row(), nArrayLength);
     197             : 
     198           0 :                 for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i)
     199             :                 {
     200           0 :                     aRefPos.SetCol(i);
     201           0 :                     formula::VectorRefArray aArray;
     202           0 :                     if (nArrayLength)
     203           0 :                         aArray = mrDoc.FetchVectorRefArray(aRefPos, nArrayLength);
     204             : 
     205           0 :                     if (!aArray.isValid())
     206           0 :                         return false;
     207             : 
     208           0 :                     aArrays.push_back(aArray);
     209             :                 }
     210             : 
     211           0 :                 formula::DoubleVectorRefToken aTok(aArrays, nRequestedLength, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
     212           0 :                 mrGroupTokens.AddToken(aTok);
     213             :             }
     214           0 :             break;
     215             :             case svIndex:
     216             :             {
     217             :                 // Named range.
     218           0 :                 ScRangeName* pNames = mrDoc.GetRangeName();
     219           0 :                 if (!pNames)
     220             :                     // This should never fail.
     221           0 :                     return false;
     222             : 
     223           0 :                 ScRangeData* pRange = pNames->findByIndex(p->GetIndex());
     224           0 :                 if (!pRange)
     225             :                     // No named range exists by that index.
     226           0 :                     return false;
     227             : 
     228           0 :                 ScTokenArray* pNamedTokens = pRange->GetCode();
     229           0 :                 if (!pNamedTokens)
     230             :                     // This named range is empty.
     231           0 :                     return false;
     232             : 
     233           0 :                 mrGroupTokens.AddOpCode(ocOpen);
     234             : 
     235           0 :                 if (std::find(rConversionStack.begin(), rConversionStack.end(), pNamedTokens) != rConversionStack.end())
     236             :                 {
     237             :                     SAL_WARN("sc", "loop in recursive ScGroupTokenConverter::convert");
     238           0 :                     return false;
     239             :                 }
     240             : 
     241           0 :                 rConversionStack.push_back(pNamedTokens);
     242           0 :                 bool bOk = convert(*pNamedTokens, rConversionStack);
     243           0 :                 rConversionStack.pop_back();
     244           0 :                 if (!bOk)
     245           0 :                     return false;
     246             : 
     247           0 :                 mrGroupTokens.AddOpCode(ocClose);
     248             :             }
     249           0 :             break;
     250             :             default:
     251           1 :                 mrGroupTokens.AddToken(*p);
     252             :         }
     253             :     }
     254             : 
     255           1 :     return true;
     256         156 : }
     257             : 
     258             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11