LCOV - code coverage report
Current view: top level - sc/source/core/tool - sharedformula.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 149 152 98.0 %
Date: 2014-11-03 Functions: 8 8 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             : 
      10             : #include "sharedformula.hxx"
      11             : #include "calcmacros.hxx"
      12             : #include "tokenarray.hxx"
      13             : 
      14             : namespace sc {
      15             : 
      16      111392 : void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type& aPos)
      17             : {
      18      111392 :     SCROW nRow = aPos.first->position + aPos.second;
      19             : 
      20      111392 :     if (aPos.first->type != sc::element_type_formula)
      21             :         // Not a formula cell block.
      22      222410 :         return;
      23             : 
      24         284 :     if (aPos.second == 0)
      25             :         // Split position coincides with the block border. Nothing to do.
      26         158 :         return;
      27             : 
      28         126 :     sc::formula_block::iterator it = sc::formula_block::begin(*aPos.first->data);
      29         126 :     std::advance(it, aPos.second);
      30         126 :     ScFormulaCell& rTop = **it;
      31         126 :     if (!rTop.IsShared())
      32             :         // Not a shared formula.
      33          26 :         return;
      34             : 
      35         100 :     if (nRow == rTop.GetSharedTopRow())
      36             :         // Already the top cell of a shared group.
      37          10 :         return;
      38             : 
      39          90 :     ScFormulaCellGroupRef xGroup = rTop.GetCellGroup();
      40             : 
      41          90 :     SCROW nLength2 = xGroup->mpTopCell->aPos.Row() + xGroup->mnLength - nRow;
      42         180 :     ScFormulaCellGroupRef xGroup2;
      43          90 :     if (nLength2 > 1)
      44             :     {
      45          72 :         xGroup2.reset(new ScFormulaCellGroup);
      46          72 :         xGroup2->mbInvariant = xGroup->mbInvariant;
      47          72 :         xGroup2->mpTopCell = &rTop;
      48          72 :         xGroup2->mnLength = nLength2;
      49          72 :         xGroup2->mpCode = xGroup->mpCode->Clone();
      50             :     }
      51             : 
      52          90 :     xGroup->mnLength = nRow - xGroup->mpTopCell->aPos.Row();
      53          90 :     if (xGroup->mnLength == 1)
      54             :     {
      55             :         // The top group consists of only one cell. Ungroup this.
      56          66 :         ScFormulaCellGroupRef xNone;
      57          66 :         ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
      58          66 :         rPrev.SetCellGroup(xNone);
      59             :     }
      60             : 
      61             :     // Apply the lower group object to the lower cells.
      62             : #if DEBUG_COLUMN_STORAGE
      63             :     if (xGroup2->mpTopCell->aPos.Row() + xGroup2->mnLength > aPos.first->position + aPos.first->size)
      64             :     {
      65             :         cerr << "ScColumn::SplitFormulaCellGroup: Shared formula region goes beyond the formula block. Not good." << endl;
      66             :         cerr.flush();
      67             :         abort();
      68             :     }
      69             : #endif
      70          90 :     sc::formula_block::iterator itEnd = it;
      71          90 :     std::advance(itEnd, nLength2);
      72         384 :     for (; it != itEnd; ++it)
      73             :     {
      74         294 :         ScFormulaCell& rCell = **it;
      75         294 :         rCell.SetCellGroup(xGroup2);
      76          90 :     }
      77             : }
      78             : 
      79        3178 : void SharedFormulaUtil::splitFormulaCellGroups(CellStoreType& rCells, std::vector<SCROW>& rBounds)
      80             : {
      81        3178 :     if (rBounds.empty())
      82         732 :         return;
      83             : 
      84             :     // Sort and remove duplicates.
      85        2812 :     std::sort(rBounds.begin(), rBounds.end());
      86        2812 :     std::vector<SCROW>::iterator it = std::unique(rBounds.begin(), rBounds.end());
      87        2812 :     rBounds.erase(it, rBounds.end());
      88             : 
      89        2812 :     it = rBounds.begin();
      90        2812 :     SCROW nRow = *it;
      91        2812 :     CellStoreType::position_type aPos = rCells.position(nRow);
      92        2812 :     if (aPos.first == rCells.end())
      93           0 :         return;
      94             : 
      95        2812 :     splitFormulaCellGroup(aPos);
      96        2812 :     std::vector<SCROW>::iterator itEnd = rBounds.end();
      97        5364 :     for (++it; it != itEnd; ++it)
      98             :     {
      99        2552 :         nRow = *it;
     100        2552 :         aPos = rCells.position(aPos.first, nRow);
     101        2552 :         if (aPos.first == rCells.end())
     102           0 :             return;
     103             : 
     104        2552 :         splitFormulaCellGroup(aPos);
     105             :     }
     106             : }
     107             : 
     108        1982 : void SharedFormulaUtil::joinFormulaCells(const CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2)
     109             : {
     110        1982 :     ScFormulaCell::CompareState eState = rCell1.CompareByTokenArray(rCell2);
     111        1982 :     if (eState == ScFormulaCell::NotEqual)
     112        1388 :         return;
     113             : 
     114             :     // Formula tokens equal those of the previous formula cell.
     115        1292 :     ScFormulaCellGroupRef xGroup1 = rCell1.GetCellGroup();
     116        2576 :     ScFormulaCellGroupRef xGroup2 = rCell2.GetCellGroup();
     117        1292 :     if (xGroup1)
     118             :     {
     119        1026 :         if (xGroup2)
     120             :         {
     121             :             // Both cell 1 and cell 2 are shared. Merge them together.
     122          44 :             if (xGroup1.get() == xGroup2.get())
     123             :                 // They belong to the same group.
     124           8 :                 return;
     125             : 
     126             :             // Set the group object from cell 1 to all cells in group 2.
     127          36 :             xGroup1->mnLength += xGroup2->mnLength;
     128          36 :             size_t nOffset = rPos.second + 1; // position of cell 2
     129         174 :             for (size_t i = 0, n = xGroup2->mnLength; i < n; ++i)
     130             :             {
     131         138 :                 ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, nOffset+i);
     132         138 :                 rCell.SetCellGroup(xGroup1);
     133             :             }
     134             :         }
     135             :         else
     136             :         {
     137             :             // cell 1 is shared but cell 2 is not.
     138         982 :             rCell2.SetCellGroup(xGroup1);
     139         982 :             ++xGroup1->mnLength;
     140             :         }
     141             :     }
     142             :     else
     143             :     {
     144         266 :         if (xGroup2)
     145             :         {
     146             :             // cell 1 is not shared, but cell 2 is already shared.
     147           8 :             rCell1.SetCellGroup(xGroup2);
     148           8 :             xGroup2->mpTopCell = &rCell1;
     149           8 :             ++xGroup2->mnLength;
     150             :         }
     151             :         else
     152             :         {
     153             :             // neither cells are shared.
     154             :             assert(rCell1.aPos.Row() == (SCROW)(rPos.first->position + rPos.second));
     155         258 :             xGroup1 = rCell1.CreateCellGroup(2, eState == ScFormulaCell::EqualInvariant);
     156         258 :             rCell2.SetCellGroup(xGroup1);
     157             :         }
     158        1284 :     }
     159             : }
     160             : 
     161       88576 : void SharedFormulaUtil::joinFormulaCellAbove(const CellStoreType::position_type& aPos)
     162             : {
     163       88576 :     if (aPos.first->type != sc::element_type_formula)
     164             :         // This is not a formula cell.
     165      176960 :         return;
     166             : 
     167         178 :     if (aPos.second == 0)
     168             :         // This cell is already the top cell in a formula block; the previous
     169             :         // cell is not a formula cell.
     170         164 :         return;
     171             : 
     172          14 :     ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
     173          14 :     ScFormulaCell& rCell = *sc::formula_block::at(*aPos.first->data, aPos.second);
     174          14 :     sc::CellStoreType::position_type aPosPrev = aPos;
     175          14 :     --aPosPrev.second;
     176          14 :     joinFormulaCells(aPosPrev, rPrev, rCell);
     177             : }
     178             : 
     179         640 : void SharedFormulaUtil::unshareFormulaCell(const CellStoreType::position_type& aPos, ScFormulaCell& rCell)
     180             : {
     181         640 :     if (!rCell.IsShared())
     182        1088 :         return;
     183             : 
     184         192 :     ScFormulaCellGroupRef xNone;
     185         192 :     sc::CellStoreType::iterator it = aPos.first;
     186             : 
     187             :     // This formula cell is shared. Adjust the shared group.
     188         192 :     if (rCell.aPos.Row() == rCell.GetSharedTopRow())
     189             :     {
     190             :         // Top of the shared range.
     191          98 :         ScFormulaCellGroupRef xGroup = rCell.GetCellGroup();
     192          98 :         if (xGroup->mnLength == 2)
     193             :         {
     194             :             // Group consists only only two cells. Mark the second one non-shared.
     195             : #if DEBUG_COLUMN_STORAGE
     196             :             if (aPos.second+1 >= aPos.first->size)
     197             :             {
     198             :                 cerr << "ScColumn::UnshareFormulaCell: There is no next formula cell but there should be!" << endl;
     199             :                 cerr.flush();
     200             :                 abort();
     201             :             }
     202             : #endif
     203          26 :             ScFormulaCell& rNext = *sc::formula_block::at(*it->data, aPos.second+1);
     204          26 :             rNext.SetCellGroup(xNone);
     205             :         }
     206             :         else
     207             :         {
     208             :             // Move the top cell to the next formula cell down.
     209          72 :             ScFormulaCell& rNext = *sc::formula_block::at(*it->data, aPos.second+1);
     210          72 :             --xGroup->mnLength;
     211          72 :             xGroup->mpTopCell = &rNext;
     212          98 :         }
     213             :     }
     214          94 :     else if (rCell.aPos.Row() == rCell.GetSharedTopRow() + rCell.GetSharedLength() - 1)
     215             :     {
     216             :         // Bottom of the shared range.
     217          46 :         ScFormulaCellGroupRef xGroup = rCell.GetCellGroup();
     218          46 :         if (xGroup->mnLength == 2)
     219             :         {
     220             :             // Mark the top cell non-shared.
     221             : #if DEBUG_COLUMN_STORAGE
     222             :             if (aPos.second == 0)
     223             :             {
     224             :                 cerr << "ScColumn::UnshareFormulaCell: There is no previous formula cell but there should be!" << endl;
     225             :                 cerr.flush();
     226             :                 abort();
     227             :             }
     228             : #endif
     229          16 :             ScFormulaCell& rPrev = *sc::formula_block::at(*it->data, aPos.second-1);
     230          16 :             rPrev.SetCellGroup(xNone);
     231             :         }
     232             :         else
     233             :         {
     234             :             // Just shortern the shared range length by one.
     235          30 :             --xGroup->mnLength;
     236          46 :         }
     237             :     }
     238             :     else
     239             :     {
     240             :         // In the middle of the shared range. Split it into two groups.
     241          48 :         ScFormulaCellGroupRef xGroup = rCell.GetCellGroup();
     242          48 :         SCROW nEndRow = xGroup->mpTopCell->aPos.Row() + xGroup->mnLength - 1;
     243          48 :         xGroup->mnLength = rCell.aPos.Row() - xGroup->mpTopCell->aPos.Row(); // Shorten the top group.
     244          48 :         if (xGroup->mnLength == 1)
     245             :         {
     246             :             // Make the top cell non-shared.
     247             : #if DEBUG_COLUMN_STORAGE
     248             :             if (aPos.second == 0)
     249             :             {
     250             :                 cerr << "ScColumn::UnshareFormulaCell: There is no previous formula cell but there should be!" << endl;
     251             :                 cerr.flush();
     252             :                 abort();
     253             :             }
     254             : #endif
     255          10 :             ScFormulaCell& rPrev = *sc::formula_block::at(*it->data, aPos.second-1);
     256          10 :             rPrev.SetCellGroup(xNone);
     257             :         }
     258             : 
     259          48 :         SCROW nLength2 = nEndRow - rCell.aPos.Row();
     260          48 :         if (nLength2 >= 2)
     261             :         {
     262          38 :             ScFormulaCellGroupRef xGroup2;
     263          38 :             xGroup2.reset(new ScFormulaCellGroup);
     264          38 :             ScFormulaCell& rNext = *sc::formula_block::at(*it->data, aPos.second+1);
     265          38 :             xGroup2->mpTopCell = &rNext;
     266          38 :             xGroup2->mnLength = nLength2;
     267          38 :             xGroup2->mbInvariant = xGroup->mbInvariant;
     268          38 :             xGroup2->mpCode = xGroup->mpCode->Clone();
     269             : #if DEBUG_COLUMN_STORAGE
     270             :             if (xGroup2->mpTopCell->aPos.Row() + xGroup2->mnLength > it->position + it->size)
     271             :             {
     272             :                 cerr << "ScColumn::UnshareFormulaCell: Shared formula region goes beyond the formula block. Not good." << endl;
     273             :                 cerr.flush();
     274             :                 abort();
     275             :             }
     276             : #endif
     277          38 :             sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
     278          38 :             std::advance(itCell, aPos.second+1);
     279          38 :             sc::formula_block::iterator itCellEnd = itCell;
     280          38 :             std::advance(itCellEnd, xGroup2->mnLength);
     281         230 :             for (; itCell != itCellEnd; ++itCell)
     282             :             {
     283         192 :                 ScFormulaCell& rCell2 = **itCell;
     284         192 :                 rCell2.SetCellGroup(xGroup2);
     285          38 :             }
     286             :         }
     287             :         else
     288             :         {
     289             :             // Make the next cell non-shared.
     290          10 :             sc::formula_block::iterator itCell = sc::formula_block::begin(*it->data);
     291          10 :             std::advance(itCell, aPos.second+1);
     292          10 :             ScFormulaCell& rCell2 = **itCell;
     293          10 :             rCell2.SetCellGroup(xNone);
     294          48 :         }
     295             :     }
     296             : 
     297         192 :     rCell.SetCellGroup(xNone);
     298             : }
     299             : 
     300          10 : void SharedFormulaUtil::unshareFormulaCells(CellStoreType& rCells, std::vector<SCROW>& rRows)
     301             : {
     302          10 :     if (rRows.empty())
     303          10 :         return;
     304             : 
     305             :     // Sort and remove duplicates.
     306          10 :     std::sort(rRows.begin(), rRows.end());
     307          10 :     rRows.erase(std::unique(rRows.begin(), rRows.end()), rRows.end());
     308             : 
     309             :     // Add next cell positions to the list (to ensure that each position becomes a single cell).
     310          10 :     std::vector<SCROW> aRows2;
     311          10 :     std::vector<SCROW>::const_iterator it = rRows.begin(), itEnd = rRows.end();
     312          62 :     for (; it != itEnd; ++it)
     313             :     {
     314          52 :         if (*it > MAXROW)
     315           0 :             break;
     316             : 
     317          52 :         aRows2.push_back(*it);
     318             : 
     319          52 :         if (*it < MAXROW)
     320          52 :             aRows2.push_back(*it+1);
     321             :     }
     322             : 
     323             :     // Remove duplicates again (the vector should still be sorted).
     324          10 :     aRows2.erase(std::unique(aRows2.begin(), aRows2.end()), aRows2.end());
     325             : 
     326          10 :     splitFormulaCellGroups(rCells, aRows2);
     327             : }
     328             : 
     329         228 : }
     330             : 
     331             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10