1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include "sharedformula.hxx"
11 #include "calcmacros.hxx"
12 #include "tokenarray.hxx"
16 void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type
& aPos
)
18 SCROW nRow
= aPos
.first
->position
+ aPos
.second
;
20 if (aPos
.first
->type
!= sc::element_type_formula
)
21 // Not a formula cell block.
25 // Split position coincides with the block border. Nothing to do.
28 sc::formula_block::iterator it
= sc::formula_block::begin(*aPos
.first
->data
);
29 std::advance(it
, aPos
.second
);
30 ScFormulaCell
& rTop
= **it
;
32 // Not a shared formula.
35 if (nRow
== rTop
.GetSharedTopRow())
36 // Already the top cell of a shared group.
39 ScFormulaCellGroupRef xGroup
= rTop
.GetCellGroup();
41 SCROW nLength2
= xGroup
->mpTopCell
->aPos
.Row() + xGroup
->mnLength
- nRow
;
42 ScFormulaCellGroupRef xGroup2
;
45 xGroup2
.reset(new ScFormulaCellGroup
);
46 xGroup2
->mbInvariant
= xGroup
->mbInvariant
;
47 xGroup2
->mpTopCell
= &rTop
;
48 xGroup2
->mnLength
= nLength2
;
49 xGroup2
->mpCode
= xGroup
->mpCode
->Clone();
52 xGroup
->mnLength
= nRow
- xGroup
->mpTopCell
->aPos
.Row();
53 if (xGroup
->mnLength
== 1)
55 // The top group consists of only one cell. Ungroup this.
56 ScFormulaCellGroupRef xNone
;
57 ScFormulaCell
& rPrev
= *sc::formula_block::at(*aPos
.first
->data
, aPos
.second
-1);
58 rPrev
.SetCellGroup(xNone
);
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
)
65 cerr
<< "ScColumn::SplitFormulaCellGroup: Shared formula region goes beyond the formula block. Not good." << endl
;
70 sc::formula_block::iterator itEnd
= it
;
71 std::advance(itEnd
, nLength2
);
72 for (; it
!= itEnd
; ++it
)
74 ScFormulaCell
& rCell
= **it
;
75 rCell
.SetCellGroup(xGroup2
);
79 void SharedFormulaUtil::splitFormulaCellGroups(CellStoreType
& rCells
, std::vector
<SCROW
>& rBounds
)
84 // Sort and remove duplicates.
85 std::sort(rBounds
.begin(), rBounds
.end());
86 std::vector
<SCROW
>::iterator it
= std::unique(rBounds
.begin(), rBounds
.end());
87 rBounds
.erase(it
, rBounds
.end());
91 CellStoreType::position_type aPos
= rCells
.position(nRow
);
92 if (aPos
.first
== rCells
.end())
95 splitFormulaCellGroup(aPos
);
96 std::vector
<SCROW
>::iterator itEnd
= rBounds
.end();
97 for (++it
; it
!= itEnd
; ++it
)
100 aPos
= rCells
.position(aPos
.first
, nRow
);
101 if (aPos
.first
== rCells
.end())
104 splitFormulaCellGroup(aPos
);
108 void SharedFormulaUtil::joinFormulaCells(const CellStoreType::position_type
& rPos
, ScFormulaCell
& rCell1
, ScFormulaCell
& rCell2
)
110 ScFormulaCell::CompareState eState
= rCell1
.CompareByTokenArray(rCell2
);
111 if (eState
== ScFormulaCell::NotEqual
)
114 // Formula tokens equal those of the previous formula cell.
115 ScFormulaCellGroupRef xGroup1
= rCell1
.GetCellGroup();
116 ScFormulaCellGroupRef xGroup2
= rCell2
.GetCellGroup();
121 // Both cell 1 and cell 2 are shared. Merge them together.
122 if (xGroup1
.get() == xGroup2
.get())
123 // They belong to the same group.
126 // Set the group object from cell 1 to all cells in group 2.
127 xGroup1
->mnLength
+= xGroup2
->mnLength
;
128 size_t nOffset
= rPos
.second
+ 1; // position of cell 2
129 for (size_t i
= 0, n
= xGroup2
->mnLength
; i
< n
; ++i
)
131 ScFormulaCell
& rCell
= *sc::formula_block::at(*rPos
.first
->data
, nOffset
+i
);
132 rCell
.SetCellGroup(xGroup1
);
137 // cell 1 is shared but cell 2 is not.
138 rCell2
.SetCellGroup(xGroup1
);
146 // cell 1 is not shared, but cell 2 is already shared.
147 rCell1
.SetCellGroup(xGroup2
);
148 xGroup2
->mpTopCell
= &rCell1
;
153 // neither cells are shared.
154 assert(rCell1
.aPos
.Row() == (SCROW
)(rPos
.first
->position
+ rPos
.second
));
155 xGroup1
= rCell1
.CreateCellGroup(2, eState
== ScFormulaCell::EqualInvariant
);
156 rCell2
.SetCellGroup(xGroup1
);
161 void SharedFormulaUtil::joinFormulaCellAbove(const CellStoreType::position_type
& aPos
)
163 if (aPos
.first
->type
!= sc::element_type_formula
)
164 // This is not a formula cell.
167 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.
172 ScFormulaCell
& rPrev
= *sc::formula_block::at(*aPos
.first
->data
, aPos
.second
-1);
173 ScFormulaCell
& rCell
= *sc::formula_block::at(*aPos
.first
->data
, aPos
.second
);
174 sc::CellStoreType::position_type aPosPrev
= aPos
;
176 joinFormulaCells(aPosPrev
, rPrev
, rCell
);
179 void SharedFormulaUtil::unshareFormulaCell(const CellStoreType::position_type
& aPos
, ScFormulaCell
& rCell
)
181 if (!rCell
.IsShared())
184 ScFormulaCellGroupRef xNone
;
185 sc::CellStoreType::iterator it
= aPos
.first
;
187 // This formula cell is shared. Adjust the shared group.
188 if (rCell
.aPos
.Row() == rCell
.GetSharedTopRow())
190 // Top of the shared range.
191 ScFormulaCellGroupRef xGroup
= rCell
.GetCellGroup();
192 if (xGroup
->mnLength
== 2)
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
)
198 cerr
<< "ScColumn::UnshareFormulaCell: There is no next formula cell but there should be!" << endl
;
203 ScFormulaCell
& rNext
= *sc::formula_block::at(*it
->data
, aPos
.second
+1);
204 rNext
.SetCellGroup(xNone
);
208 // Move the top cell to the next formula cell down.
209 ScFormulaCell
& rNext
= *sc::formula_block::at(*it
->data
, aPos
.second
+1);
211 xGroup
->mpTopCell
= &rNext
;
214 else if (rCell
.aPos
.Row() == rCell
.GetSharedTopRow() + rCell
.GetSharedLength() - 1)
216 // Bottom of the shared range.
217 ScFormulaCellGroupRef xGroup
= rCell
.GetCellGroup();
218 if (xGroup
->mnLength
== 2)
220 // Mark the top cell non-shared.
221 #if DEBUG_COLUMN_STORAGE
222 if (aPos
.second
== 0)
224 cerr
<< "ScColumn::UnshareFormulaCell: There is no previous formula cell but there should be!" << endl
;
229 ScFormulaCell
& rPrev
= *sc::formula_block::at(*it
->data
, aPos
.second
-1);
230 rPrev
.SetCellGroup(xNone
);
234 // Just shortern the shared range length by one.
240 // In the middle of the shared range. Split it into two groups.
241 ScFormulaCellGroupRef xGroup
= rCell
.GetCellGroup();
242 SCROW nEndRow
= xGroup
->mpTopCell
->aPos
.Row() + xGroup
->mnLength
- 1;
243 xGroup
->mnLength
= rCell
.aPos
.Row() - xGroup
->mpTopCell
->aPos
.Row(); // Shorten the top group.
244 if (xGroup
->mnLength
== 1)
246 // Make the top cell non-shared.
247 #if DEBUG_COLUMN_STORAGE
248 if (aPos
.second
== 0)
250 cerr
<< "ScColumn::UnshareFormulaCell: There is no previous formula cell but there should be!" << endl
;
255 ScFormulaCell
& rPrev
= *sc::formula_block::at(*it
->data
, aPos
.second
-1);
256 rPrev
.SetCellGroup(xNone
);
259 SCROW nLength2
= nEndRow
- rCell
.aPos
.Row();
262 ScFormulaCellGroupRef xGroup2
;
263 xGroup2
.reset(new ScFormulaCellGroup
);
264 ScFormulaCell
& rNext
= *sc::formula_block::at(*it
->data
, aPos
.second
+1);
265 xGroup2
->mpTopCell
= &rNext
;
266 xGroup2
->mnLength
= nLength2
;
267 xGroup2
->mbInvariant
= xGroup
->mbInvariant
;
268 xGroup2
->mpCode
= xGroup
->mpCode
->Clone();
269 #if DEBUG_COLUMN_STORAGE
270 if (xGroup2
->mpTopCell
->aPos
.Row() + xGroup2
->mnLength
> it
->position
+ it
->size
)
272 cerr
<< "ScColumn::UnshareFormulaCell: Shared formula region goes beyond the formula block. Not good." << endl
;
277 sc::formula_block::iterator itCell
= sc::formula_block::begin(*it
->data
);
278 std::advance(itCell
, aPos
.second
+1);
279 sc::formula_block::iterator itCellEnd
= itCell
;
280 std::advance(itCellEnd
, xGroup2
->mnLength
);
281 for (; itCell
!= itCellEnd
; ++itCell
)
283 ScFormulaCell
& rCell2
= **itCell
;
284 rCell2
.SetCellGroup(xGroup2
);
289 // Make the next cell non-shared.
290 sc::formula_block::iterator itCell
= sc::formula_block::begin(*it
->data
);
291 std::advance(itCell
, aPos
.second
+1);
292 ScFormulaCell
& rCell2
= **itCell
;
293 rCell2
.SetCellGroup(xNone
);
297 rCell
.SetCellGroup(xNone
);
302 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */