LCOV - code coverage report
Current view: top level - sc/source/core/tool - reffind.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 118 150 78.7 %
Date: 2014-11-03 Functions: 15 15 100.0 %
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             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include "reffind.hxx"
      21             : #include "global.hxx"
      22             : #include "compiler.hxx"
      23             : #include "document.hxx"
      24             : 
      25             : // STATIC DATA
      26             : namespace {
      27             : 
      28             : // Include colon; addresses in range reference are handled individually.
      29             : const sal_Unicode pDelimiters[] = {
      30             :     '=','(',')','+','-','*','/','^','&',' ','{','}','<','>',':', 0
      31             : };
      32             : 
      33         248 : inline bool IsText( sal_Unicode c )
      34             : {
      35         248 :     bool bFound = ScGlobal::UnicodeStrChr( pDelimiters, c );
      36         248 :     if (bFound)
      37             :         // This is one of delimiters, therefore not text.
      38          40 :         return false;
      39             : 
      40             :     // argument separator is configurable.
      41         208 :     const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
      42         208 :     return c != sep;
      43             : }
      44             : 
      45          80 : inline bool IsText( bool& bQuote, sal_Unicode c )
      46             : {
      47          80 :     if (c == '\'')
      48             :     {
      49           0 :         bQuote = !bQuote;
      50           0 :         return true;
      51             :     }
      52          80 :     if (bQuote)
      53           0 :         return true;
      54             : 
      55          80 :     return IsText(c);
      56             : }
      57             : 
      58             : /**
      59             :  * Find first character position that is considered text.  A character is
      60             :  * considered a text when it's within the ascii range and when it's not a
      61             :  * delimiter.
      62             :  */
      63          32 : sal_Int32 FindStartPos(const sal_Unicode* p, sal_Int32 nStartPos, sal_Int32 nEndPos)
      64             : {
      65          88 :     while (nStartPos <= nEndPos && !IsText(p[nStartPos]))
      66          24 :         ++nStartPos;
      67             : 
      68          32 :     return nStartPos;
      69             : }
      70             : 
      71          16 : sal_Int32 FindEndPosA1(const sal_Unicode* p, sal_Int32 nStartPos, sal_Int32 nEndPos)
      72             : {
      73          16 :     bool bQuote = false;
      74          16 :     sal_Int32 nNewEnd = nStartPos;
      75          96 :     while (nNewEnd <= nEndPos && IsText(bQuote, p[nNewEnd]))
      76          64 :         ++nNewEnd;
      77             : 
      78          16 :     return nNewEnd;
      79             : }
      80             : 
      81          32 : sal_Int32 FindEndPosR1C1(const sal_Unicode* p, sal_Int32 nStartPos, sal_Int32 nEndPos)
      82             : {
      83          32 :     sal_Int32 nNewEnd = nStartPos;
      84          32 :     p = &p[nStartPos];
      85         112 :     for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
      86             :     {
      87          80 :         if (*p == '\'')
      88             :         {
      89             :             // Skip until the closing quote.
      90           0 :             for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
      91           0 :                 if (*p == '\'')
      92           0 :                     break;
      93           0 :             if (nNewEnd > nEndPos)
      94           0 :                 break;
      95             :         }
      96          80 :         else if (*p == '[')
      97             :         {
      98             :             // Skip until the closing braket.
      99          64 :             for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
     100          64 :                 if (*p == ']')
     101          16 :                     break;
     102          16 :             if (nNewEnd > nEndPos)
     103           0 :                 break;
     104             :         }
     105          64 :         else if (!IsText(*p))
     106           0 :             break;
     107             :     }
     108             : 
     109          32 :     return nNewEnd;
     110             : }
     111             : 
     112             : /**
     113             :  * Find last character position that is considred text, from the specified
     114             :  * start position.
     115             :  */
     116          32 : sal_Int32 FindEndPos(const sal_Unicode* p, sal_Int32 nStartPos, sal_Int32 nEndPos,
     117             :                      formula::FormulaGrammar::AddressConvention eConv)
     118             : {
     119          32 :     switch (eConv)
     120             :     {
     121             :         case formula::FormulaGrammar::CONV_XL_R1C1:
     122          16 :             return FindEndPosR1C1(p, nStartPos, nEndPos);
     123             :         case formula::FormulaGrammar::CONV_OOO:
     124             :         case formula::FormulaGrammar::CONV_XL_A1:
     125             :         default:
     126          16 :             return FindEndPosA1(p, nStartPos, nEndPos);
     127             :     }
     128             : }
     129             : 
     130          16 : void ExpandToTextA1(const sal_Unicode* p, sal_Int32 nLen, sal_Int32& rStartPos, sal_Int32& rEndPos)
     131             : {
     132          16 :     bool bQuote = false;  // skip quoted text
     133          40 :     while (rStartPos > 0 && IsText(bQuote, p[rStartPos - 1]) )
     134           8 :         --rStartPos;
     135          16 :     if (rEndPos)
     136          16 :         --rEndPos;
     137          48 :     while (rEndPos+1 < nLen && IsText(p[rEndPos + 1]) )
     138          16 :         ++rEndPos;
     139          16 : }
     140             : 
     141          16 : void ExpandToTextR1C1(const sal_Unicode* p, sal_Int32 nLen, sal_Int32& rStartPos, sal_Int32& rEndPos)
     142             : {
     143             :     // move back the start position to the first text character.
     144          16 :     if (rStartPos > 0)
     145             :     {
     146          40 :         for (--rStartPos; rStartPos > 0; --rStartPos)
     147             :         {
     148          32 :             sal_Unicode c = p[rStartPos];
     149          32 :             if (c == '\'')
     150             :             {
     151             :                 // Skip until the opening quote.
     152           0 :                 for (--rStartPos; rStartPos > 0; --rStartPos)
     153             :                 {
     154           0 :                     c = p[rStartPos];
     155           0 :                     if (c == '\'')
     156           0 :                         break;
     157             :                 }
     158           0 :                 if (rStartPos == 0)
     159           0 :                     break;
     160             :             }
     161          32 :             else if (c == ']')
     162             :             {
     163             :                 // Skip until the opening braket.
     164          24 :                 for (--rStartPos; rStartPos > 0; --rStartPos)
     165             :                 {
     166          24 :                     c = p[rStartPos];
     167          24 :                     if (c == '[')
     168           8 :                         break;
     169             :                 }
     170           8 :                 if (rStartPos == 0)
     171           0 :                     break;
     172             :             }
     173          24 :             else if (!IsText(c))
     174             :             {
     175           0 :                 ++rStartPos;
     176           0 :                 break;
     177             :             }
     178             :         }
     179             :     }
     180             : 
     181             :     // move forward the end position to the last text character.
     182          16 :     rEndPos = FindEndPosR1C1(p, rEndPos, nLen-1);
     183          16 : }
     184             : 
     185          32 : void ExpandToText(const sal_Unicode* p, sal_Int32 nLen, sal_Int32& rStartPos, sal_Int32& rEndPos,
     186             :                   formula::FormulaGrammar::AddressConvention eConv)
     187             : {
     188          32 :     switch (eConv)
     189             :     {
     190             :         case formula::FormulaGrammar::CONV_XL_R1C1:
     191          16 :             ExpandToTextR1C1(p, nLen, rStartPos, rEndPos);
     192          16 :         break;
     193             :         case formula::FormulaGrammar::CONV_OOO:
     194             :         case formula::FormulaGrammar::CONV_XL_A1:
     195             :         default:
     196          16 :             ExpandToTextA1(p, nLen, rStartPos, rEndPos);
     197             :     }
     198          32 : }
     199             : 
     200             : }
     201             : 
     202           8 : ScRefFinder::ScRefFinder(
     203             :     const OUString& rFormula, const ScAddress& rPos,
     204             :     ScDocument* pDoc, formula::FormulaGrammar::AddressConvention eConvP) :
     205             :     maFormula(rFormula),
     206             :     meConv(eConvP),
     207             :     mpDoc(pDoc),
     208             :     maPos(rPos),
     209             :     mnFound(0),
     210             :     mnSelStart(0),
     211           8 :     mnSelEnd(0)
     212             : {
     213           8 : }
     214             : 
     215           8 : ScRefFinder::~ScRefFinder()
     216             : {
     217           8 : }
     218             : 
     219          32 : static sal_uInt16 lcl_NextFlags( sal_uInt16 nOld )
     220             : {
     221          32 :     sal_uInt16 nNew = nOld & 7;                 // die drei Abs-Flags
     222          32 :     nNew = ( nNew - 1 ) & 7;                // weiterzaehlen
     223             : 
     224          32 :     if (!(nOld & SCA_TAB_3D))
     225          32 :         nNew &= ~SCA_TAB_ABSOLUTE;          // not 3D -> never absolute!
     226             : 
     227          32 :     return ( nOld & 0xfff8 ) | nNew;
     228             : }
     229             : 
     230          32 : void ScRefFinder::ToggleRel( sal_Int32 nStartPos, sal_Int32 nEndPos )
     231             : {
     232          32 :     sal_Int32 nLen = maFormula.getLength();
     233          32 :     if (nLen <= 0)
     234          32 :         return;
     235          32 :     const sal_Unicode* pSource = maFormula.getStr();      // for quick access
     236             : 
     237             :     // expand selection, and instead of selection start- and end-index
     238             : 
     239          32 :     if ( nEndPos < nStartPos )
     240           0 :         ::std::swap(nEndPos, nStartPos);
     241             : 
     242          32 :     ExpandToText(pSource, nLen, nStartPos, nEndPos, meConv);
     243             : 
     244          32 :     OUString aResult;
     245          64 :     OUString aExpr;
     246          64 :     OUString aSep;
     247          32 :     ScAddress aAddr;
     248          32 :     mnFound = 0;
     249             : 
     250          32 :     sal_Int32 nLoopStart = nStartPos;
     251          96 :     while ( nLoopStart <= nEndPos )
     252             :     {
     253             :         // Determine the start and end positions of a text segment.  Note that
     254             :         // the end position returned from FindEndPos may be one position after
     255             :         // the last character position in case of the last segment.
     256          32 :         sal_Int32 nEStart = FindStartPos(pSource, nLoopStart, nEndPos);
     257          32 :         sal_Int32 nEEnd  = FindEndPos(pSource, nEStart, nEndPos, meConv);
     258             : 
     259          32 :         aSep  = maFormula.copy(nLoopStart, nEStart-nLoopStart);
     260          32 :         if (nEEnd < maFormula.getLength())
     261           8 :             aExpr = maFormula.copy(nEStart, nEEnd-nEStart);
     262             :         else
     263          24 :             aExpr = maFormula.copy(nEStart);
     264             : 
     265             :         // Check the validity of the expression, and toggle the relative flag.
     266          32 :         ScAddress::Details aDetails(meConv, maPos.Row(), maPos.Col());
     267          32 :         ScAddress::ExternalInfo aExtInfo;
     268          32 :         sal_uInt16 nResult = aAddr.Parse(aExpr, mpDoc, aDetails, &aExtInfo);
     269          32 :         if ( nResult & SCA_VALID )
     270             :         {
     271          32 :             sal_uInt16 nFlags = lcl_NextFlags( nResult );
     272          32 :             if( aExtInfo.mbExternal )
     273             :             {    // retain external doc name and tab name before toggle relative flag
     274             :                 sal_Int32 nSep;
     275           0 :                 switch(meConv)
     276             :                 {
     277             :                   case formula::FormulaGrammar::CONV_XL_A1 :
     278             :                   case formula::FormulaGrammar::CONV_XL_OOX :
     279             :                   case formula::FormulaGrammar::CONV_XL_R1C1 :
     280           0 :                          nSep = aExpr.lastIndexOf('!');
     281           0 :                          break;
     282             :                   case formula::FormulaGrammar::CONV_OOO :
     283             :                   default:
     284           0 :                          nSep = aExpr.lastIndexOf('.');
     285           0 :                          break;
     286             :                 }
     287           0 :                 if (nSep < 0)
     288             :                 {
     289             :                     assert(!"Invalid syntax according to address convention.");
     290             :                 }
     291             :                 else
     292             :                 {
     293           0 :                     OUString aRef = aExpr.copy(nSep+1);
     294           0 :                     OUString aExtDocNameTabName = aExpr.copy(0, nSep+1);
     295           0 :                     nResult = aAddr.Parse(aRef, mpDoc, aDetails);
     296           0 :                     aAddr.SetTab(0); // force to first tab to avoid error on checking
     297           0 :                     nFlags = lcl_NextFlags( nResult );
     298           0 :                     aExpr = aExtDocNameTabName + aAddr.Format(nFlags, mpDoc, aDetails);
     299             :                 }
     300             :             }
     301             :             else
     302             :             {
     303          32 :                 aExpr = aAddr.Format(nFlags, mpDoc, aDetails);
     304             :             }
     305             : 
     306          32 :             sal_Int32 nAbsStart = nStartPos+aResult.getLength()+aSep.getLength();
     307             : 
     308          32 :             if (!mnFound)                            // first reference ?
     309          32 :                 mnSelStart = nAbsStart;
     310          32 :             mnSelEnd = nAbsStart + aExpr.getLength();        // selection, no indices
     311          32 :             ++mnFound;
     312             :         }
     313             : 
     314             :         // assemble
     315             : 
     316          32 :         aResult += aSep;
     317          32 :         aResult += aExpr;
     318             : 
     319          32 :         nLoopStart = nEEnd;
     320          32 :     }
     321             : 
     322          32 :     OUString aTotal = maFormula.copy(0, nStartPos);
     323          32 :     aTotal += aResult;
     324          32 :     if (nEndPos < maFormula.getLength()-1)
     325           8 :         aTotal += maFormula.copy(nEndPos+1);
     326             : 
     327          64 :     maFormula = aTotal;
     328         228 : }
     329             : 
     330             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10