Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / tool / sharedformula.cxx
blobed35690a63a7921a0da2dc3086b1d1323a1b028c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include "sharedformula.hxx"
11 #include "calcmacros.hxx"
12 #include "tokenarray.hxx"
14 namespace sc {
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.
22 return;
24 if (aPos.second == 0)
25 // Split position coincides with the block border. Nothing to do.
26 return;
28 sc::formula_block::iterator it = sc::formula_block::begin(*aPos.first->data);
29 std::advance(it, aPos.second);
30 ScFormulaCell& rTop = **it;
31 if (!rTop.IsShared())
32 // Not a shared formula.
33 return;
35 if (nRow == rTop.GetSharedTopRow())
36 // Already the top cell of a shared group.
37 return;
39 ScFormulaCellGroupRef xGroup = rTop.GetCellGroup();
41 SCROW nLength2 = xGroup->mpTopCell->aPos.Row() + xGroup->mnLength - nRow;
42 ScFormulaCellGroupRef xGroup2;
43 if (nLength2 > 1)
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;
66 cerr.flush();
67 abort();
69 #endif
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)
81 if (rBounds.empty())
82 return;
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());
89 it = rBounds.begin();
90 SCROW nRow = *it;
91 CellStoreType::position_type aPos = rCells.position(nRow);
92 if (aPos.first == rCells.end())
93 return;
95 splitFormulaCellGroup(aPos);
96 std::vector<SCROW>::iterator itEnd = rBounds.end();
97 for (++it; it != itEnd; ++it)
99 nRow = *it;
100 aPos = rCells.position(aPos.first, nRow);
101 if (aPos.first == rCells.end())
102 return;
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)
112 return;
114 // Formula tokens equal those of the previous formula cell.
115 ScFormulaCellGroupRef xGroup1 = rCell1.GetCellGroup();
116 ScFormulaCellGroupRef xGroup2 = rCell2.GetCellGroup();
117 if (xGroup1)
119 if (xGroup2)
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.
124 return;
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);
135 else
137 // cell 1 is shared but cell 2 is not.
138 rCell2.SetCellGroup(xGroup1);
139 ++xGroup1->mnLength;
142 else
144 if (xGroup2)
146 // cell 1 is not shared, but cell 2 is already shared.
147 rCell1.SetCellGroup(xGroup2);
148 xGroup2->mpTopCell = &rCell1;
149 ++xGroup2->mnLength;
151 else
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.
165 return;
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.
170 return;
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;
175 --aPosPrev.second;
176 joinFormulaCells(aPosPrev, rPrev, rCell);
179 void SharedFormulaUtil::unshareFormulaCell(const CellStoreType::position_type& aPos, ScFormulaCell& rCell)
181 if (!rCell.IsShared())
182 return;
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;
199 cerr.flush();
200 abort();
202 #endif
203 ScFormulaCell& rNext = *sc::formula_block::at(*it->data, aPos.second+1);
204 rNext.SetCellGroup(xNone);
206 else
208 // Move the top cell to the next formula cell down.
209 ScFormulaCell& rNext = *sc::formula_block::at(*it->data, aPos.second+1);
210 --xGroup->mnLength;
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;
225 cerr.flush();
226 abort();
228 #endif
229 ScFormulaCell& rPrev = *sc::formula_block::at(*it->data, aPos.second-1);
230 rPrev.SetCellGroup(xNone);
232 else
234 // Just shortern the shared range length by one.
235 --xGroup->mnLength;
238 else
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;
251 cerr.flush();
252 abort();
254 #endif
255 ScFormulaCell& rPrev = *sc::formula_block::at(*it->data, aPos.second-1);
256 rPrev.SetCellGroup(xNone);
259 SCROW nLength2 = nEndRow - rCell.aPos.Row();
260 if (nLength2 >= 2)
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;
273 cerr.flush();
274 abort();
276 #endif
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);
287 else
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: */