fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / grouptokenconverter.cxx
blobde3fbf2d2bd05814eee951c93ac97842e0217f1a
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))
67 // This can end up negative! Was that the original intent, or
68 // is it accidental? Was it not like that originally but the
69 // surrounding conditions changed?
70 nRowLen = nLastRow - nRow + 1;
71 // Anyway, let's assume it doesn't make sense to return a
72 // negative value here. But should we then return 0 or 1? In
73 // the "Column is empty" case below, we return 1, why!? And,
74 // at the callsites there are tests for a zero value returned
75 // from this function (but not for a negative one).
76 if (nRowLen < 0)
77 nRowLen = 0;
79 else if (nLastRow == 0)
80 // Column is empty.
81 nRowLen = 1;
83 return nRowLen;
86 ScGroupTokenConverter::ScGroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
87 mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos)
92 bool ScGroupTokenConverter::convert(ScTokenArray& rCode, std::vector<ScTokenArray*>& rConversionStack)
94 #if 0
95 { // debug to start with:
96 ScCompiler aComp( &mrDoc, mrPos, rCode);
97 aComp.SetGrammar(formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1);
98 OUStringBuffer aAsString;
99 aComp.CreateStringFromTokenArray(aAsString);
101 #endif
103 rCode.Reset();
104 for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
106 // A reference can be either absolute or relative. If it's absolute,
107 // convert it to a static value token. If relative, convert it to a
108 // vector reference token. Note: we only care about relative vs
109 // absolute reference state for row directions.
111 SCROW nLen = mrCell.GetCellGroup()->mnLength;
112 switch (p->GetType())
114 case svSingleRef:
116 ScSingleRefData aRef = *p->GetSingleRef();
117 ScAddress aRefPos = aRef.toAbs(mrPos);
118 if (aRef.IsRowRel())
120 if (isSelfReferenceRelative(aRefPos, aRef.Row()))
121 return false;
123 // Trim data array length to actual data range.
124 SCROW nTrimLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen);
125 // Fetch double array guarantees that the length of the
126 // returned array equals or greater than the requested
127 // length.
129 formula::VectorRefArray aArray;
130 if (nTrimLen)
131 aArray = mrDoc.FetchVectorRefArray(aRefPos, nTrimLen);
133 if (!aArray.isValid())
134 return false;
136 formula::SingleVectorRefToken aTok(aArray, nLen, nTrimLen);
137 mrGroupTokens.AddToken(aTok);
139 else
141 // Absolute row reference.
142 if (isSelfReferenceAbsolute(aRefPos))
143 return false;
145 formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos);
146 if (!pNewToken)
147 return false;
149 mrGroupTokens.AddToken(*pNewToken);
152 break;
153 case svDoubleRef:
155 ScComplexRefData aRef = *p->GetDoubleRef();
156 ScRange aAbs = aRef.toAbs(mrPos);
158 // Check for self reference.
159 if (aRef.Ref1.IsRowRel())
161 if (isSelfReferenceRelative(aAbs.aStart, aRef.Ref1.Row()))
162 return false;
164 else if (isSelfReferenceAbsolute(aAbs.aStart))
165 return false;
167 if (aRef.Ref2.IsRowRel())
169 if (isSelfReferenceRelative(aAbs.aEnd, aRef.Ref2.Row()))
170 return false;
172 else if (isSelfReferenceAbsolute(aAbs.aEnd))
173 return false;
175 // Row reference is relative.
176 bool bAbsFirst = !aRef.Ref1.IsRowRel();
177 bool bAbsLast = !aRef.Ref2.IsRowRel();
178 ScAddress aRefPos = aAbs.aStart;
179 size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1;
180 std::vector<formula::VectorRefArray> aArrays;
181 aArrays.reserve(nCols);
182 SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1;
183 SCROW nArrayLength = nRefRowSize;
184 if (!bAbsLast)
186 // range end position is relative. Extend the array length.
187 SCROW nLastRefRowOffset = aAbs.aEnd.Row() - mrPos.Row();
188 SCROW nLastRefRow = mrPos.Row() + nLen - 1 + nLastRefRowOffset;
189 SCROW nNewLength = nLastRefRow - aAbs.aStart.Row() + 1;
190 if (nNewLength > nArrayLength)
191 nArrayLength = nNewLength;
194 // Trim trailing empty rows.
195 SCROW nRequestedLength = nArrayLength; // keep the original length.
196 nArrayLength = trimLength(aRefPos.Tab(), aAbs.aStart.Col(), aAbs.aEnd.Col(), aRefPos.Row(), nArrayLength);
198 for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i)
200 aRefPos.SetCol(i);
201 formula::VectorRefArray aArray;
202 if (nArrayLength)
203 aArray = mrDoc.FetchVectorRefArray(aRefPos, nArrayLength);
205 if (!aArray.isValid())
206 return false;
208 aArrays.push_back(aArray);
211 formula::DoubleVectorRefToken aTok(aArrays, nRequestedLength, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
212 mrGroupTokens.AddToken(aTok);
214 break;
215 case svIndex:
217 // Named range.
218 ScRangeName* pNames = mrDoc.GetRangeName();
219 if (!pNames)
220 // This should never fail.
221 return false;
223 ScRangeData* pRange = pNames->findByIndex(p->GetIndex());
224 if (!pRange)
225 // No named range exists by that index.
226 return false;
228 ScTokenArray* pNamedTokens = pRange->GetCode();
229 if (!pNamedTokens)
230 // This named range is empty.
231 return false;
233 mrGroupTokens.AddOpCode(ocOpen);
235 if (std::find(rConversionStack.begin(), rConversionStack.end(), pNamedTokens) != rConversionStack.end())
237 SAL_WARN("sc", "loop in recursive ScGroupTokenConverter::convert");
238 return false;
241 rConversionStack.push_back(pNamedTokens);
242 bool bOk = convert(*pNamedTokens, rConversionStack);
243 rConversionStack.pop_back();
244 if (!bOk)
245 return false;
247 mrGroupTokens.AddOpCode(ocClose);
249 break;
250 default:
251 mrGroupTokens.AddToken(*p);
255 return true;
258 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */