Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / data / grouptokenconverter.cxx
blobb295fee100dedf400e392d9864d697b51e1b2496
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 <formula/token.hxx>
11 #include <formula/vectortoken.hxx>
13 #include "compiler.hxx"
14 #include "grouptokenconverter.hxx"
16 using namespace formula;
18 bool ScGroupTokenConverter::isSelfReferenceRelative(const ScAddress& rRefPos, SCROW nRelRow)
20 if (rRefPos.Col() != mrPos.Col())
21 return false;
23 SCROW nLen = mrCell.GetCellGroup()->mnLength;
24 SCROW nEndRow = mrPos.Row() + nLen - 1;
26 if (nRelRow < 0)
28 SCROW nTest = nEndRow;
29 nTest += nRelRow;
30 if (nTest >= mrPos.Row())
31 return true;
33 else if (nRelRow > 0)
35 SCROW nTest = mrPos.Row(); // top row.
36 nTest += nRelRow;
37 if (nTest <= nEndRow)
38 return true;
41 return false;
44 bool ScGroupTokenConverter::isSelfReferenceAbsolute(const ScAddress& rRefPos)
46 if (rRefPos.Col() != mrPos.Col())
47 return false;
49 SCROW nLen = mrCell.GetCellGroup()->mnLength;
50 SCROW nEndRow = mrPos.Row() + nLen - 1;
52 if (rRefPos.Row() < mrPos.Row())
53 return false;
55 if (rRefPos.Row() > nEndRow)
56 return false;
58 return true;
61 SCROW ScGroupTokenConverter::trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen)
63 SCROW nLastRow = nRow + nRowLen - 1; // current last row.
64 nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2, nLastRow);
65 if (nLastRow < (nRow + nRowLen - 1))
66 nRowLen = nLastRow - nRow + 1;
67 else if (nLastRow == 0)
68 // Column is empty.
69 nRowLen = 1;
71 return nRowLen;
74 ScGroupTokenConverter::ScGroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
75 mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos)
80 bool ScGroupTokenConverter::convert(ScTokenArray& rCode)
82 #if 0
83 { // debug to start with:
84 ScCompiler aComp( &mrDoc, mrPos, rCode);
85 aComp.SetGrammar(formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1);
86 OUStringBuffer aAsString;
87 aComp.CreateStringFromTokenArray(aAsString);
89 #endif
91 rCode.Reset();
92 for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
94 // A reference can be either absolute or relative. If it's absolute,
95 // convert it to a static value token. If relative, convert it to a
96 // vector reference token. Note: we only care about relative vs
97 // absolute reference state for row directions.
99 const ScToken* pToken = static_cast<const ScToken*>(p);
100 SCROW nLen = mrCell.GetCellGroup()->mnLength;
101 switch (pToken->GetType())
103 case svSingleRef:
105 ScSingleRefData aRef = pToken->GetSingleRef();
106 ScAddress aRefPos = aRef.toAbs(mrPos);
107 if (aRef.IsRowRel())
109 if (isSelfReferenceRelative(aRefPos, aRef.Row()))
110 return false;
112 // Trim data array length to actual data range.
113 nLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen);
115 // Fetch double array guarantees that the length of the
116 // returned array equals or greater than the requested
117 // length.
119 formula::VectorRefArray aArray;
120 if (nLen)
121 aArray = mrDoc.FetchVectorRefArray(aRefPos, nLen);
123 formula::SingleVectorRefToken aTok(aArray, nLen);
124 mrGroupTokens.AddToken(aTok);
126 else
128 // Absolute row reference.
129 if (isSelfReferenceAbsolute(aRefPos))
130 return false;
132 formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos);
133 if (!pNewToken)
134 return false;
136 mrGroupTokens.AddToken(*pNewToken);
139 break;
140 case svDoubleRef:
142 ScComplexRefData aRef = pToken->GetDoubleRef();
143 ScRange aAbs = aRef.toAbs(mrPos);
145 // Check for self reference.
146 if (aRef.Ref1.IsRowRel())
148 if (isSelfReferenceRelative(aAbs.aStart, aRef.Ref1.Row()))
149 return false;
151 else if (isSelfReferenceAbsolute(aAbs.aStart))
152 return false;
154 if (aRef.Ref2.IsRowRel())
156 if (isSelfReferenceRelative(aAbs.aEnd, aRef.Ref2.Row()))
157 return false;
159 else if (isSelfReferenceAbsolute(aAbs.aEnd))
160 return false;
162 // Row reference is relative.
163 bool bAbsFirst = !aRef.Ref1.IsRowRel();
164 bool bAbsLast = !aRef.Ref2.IsRowRel();
165 ScAddress aRefPos = aAbs.aStart;
166 size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1;
167 std::vector<formula::VectorRefArray> aArrays;
168 aArrays.reserve(nCols);
169 SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1;
170 SCROW nArrayLength = nRefRowSize;
171 if (!bAbsLast)
173 // range end position is relative. Extend the array length.
174 SCROW nLastRefRowOffset = aAbs.aEnd.Row() - mrPos.Row();
175 SCROW nLastRefRow = mrPos.Row() + nLen - 1 + nLastRefRowOffset;
176 SCROW nNewLength = nLastRefRow - aAbs.aStart.Row() + 1;
177 if (nNewLength > nArrayLength)
178 nArrayLength = nNewLength;
181 // Trim trailing empty rows.
182 nArrayLength = trimLength(aRefPos.Tab(), aAbs.aStart.Col(), aAbs.aEnd.Col(), aRefPos.Row(), nArrayLength);
184 for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i)
186 aRefPos.SetCol(i);
187 formula::VectorRefArray aArray;
188 if (nArrayLength)
189 aArray = mrDoc.FetchVectorRefArray(aRefPos, nArrayLength);
191 aArrays.push_back(aArray);
194 formula::DoubleVectorRefToken aTok(aArrays, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
195 mrGroupTokens.AddToken(aTok);
197 break;
198 case svIndex:
200 // Named range.
201 ScRangeName* pNames = mrDoc.GetRangeName();
202 if (!pNames)
203 // This should never fail.
204 return false;
206 ScRangeData* pRange = pNames->findByIndex(p->GetIndex());
207 if (!pRange)
208 // No named range exists by that index.
209 return false;
211 ScTokenArray* pNamedTokens = pRange->GetCode();
212 if (!pNamedTokens)
213 // This named range is empty.
214 return false;
216 mrGroupTokens.AddOpCode(ocOpen);
218 if (!convert(*pNamedTokens))
219 return false;
221 mrGroupTokens.AddOpCode(ocClose);
223 break;
224 default:
225 mrGroupTokens.AddToken(*pToken);
229 ScCompiler aComp(&mrDoc, mrPos, mrGroupTokens);
230 aComp.SetGrammar(mrDoc.GetGrammar());
231 aComp.CompileTokenArray(); // Regenerate RPN tokens.
233 return true;
236 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */