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 <formula/token.hxx>
11 : #include <formula/vectortoken.hxx>
12 :
13 : #include "compiler.hxx"
14 : #include "grouptokenconverter.hxx"
15 :
16 : using namespace formula;
17 :
18 0 : bool ScGroupTokenConverter::isSelfReferenceRelative(const ScAddress& rRefPos, SCROW nRelRow)
19 : {
20 0 : if (rRefPos.Col() != mrPos.Col())
21 0 : return false;
22 :
23 0 : SCROW nLen = mrCell.GetCellGroup()->mnLength;
24 0 : SCROW nEndRow = mrPos.Row() + nLen - 1;
25 :
26 0 : if (nRelRow < 0)
27 : {
28 0 : SCROW nTest = nEndRow;
29 0 : nTest += nRelRow;
30 0 : if (nTest >= mrPos.Row())
31 0 : return true;
32 : }
33 0 : else if (nRelRow > 0)
34 : {
35 0 : SCROW nTest = mrPos.Row(); // top row.
36 0 : nTest += nRelRow;
37 0 : if (nTest <= nEndRow)
38 0 : return true;
39 : }
40 :
41 0 : return false;
42 : }
43 :
44 0 : bool ScGroupTokenConverter::isSelfReferenceAbsolute(const ScAddress& rRefPos)
45 : {
46 0 : if (rRefPos.Col() != mrPos.Col())
47 0 : return false;
48 :
49 0 : SCROW nLen = mrCell.GetCellGroup()->mnLength;
50 0 : SCROW nEndRow = mrPos.Row() + nLen - 1;
51 :
52 0 : if (rRefPos.Row() < mrPos.Row())
53 0 : return false;
54 :
55 0 : if (rRefPos.Row() > nEndRow)
56 0 : return false;
57 :
58 0 : return true;
59 : }
60 :
61 0 : SCROW ScGroupTokenConverter::trimLength(SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCROW nRow, SCROW nRowLen)
62 : {
63 0 : SCROW nLastRow = nRow + nRowLen - 1; // current last row.
64 0 : nLastRow = mrDoc.GetLastDataRow(nTab, nCol1, nCol2, nLastRow);
65 0 : if (nLastRow < (nRow + nRowLen - 1))
66 0 : nRowLen = nLastRow - nRow + 1;
67 0 : else if (nLastRow == 0)
68 : // Column is empty.
69 0 : nRowLen = 1;
70 :
71 0 : return nRowLen;
72 : }
73 :
74 0 : ScGroupTokenConverter::ScGroupTokenConverter(ScTokenArray& rGroupTokens, ScDocument& rDoc, ScFormulaCell& rCell, const ScAddress& rPos) :
75 0 : mrGroupTokens(rGroupTokens), mrDoc(rDoc), mrCell(rCell), mrPos(rPos)
76 :
77 : {
78 0 : }
79 :
80 0 : bool ScGroupTokenConverter::convert(ScTokenArray& rCode)
81 : {
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);
88 : }
89 : #endif
90 :
91 0 : rCode.Reset();
92 0 : for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
93 : {
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.
98 :
99 0 : SCROW nLen = mrCell.GetCellGroup()->mnLength;
100 0 : switch (p->GetType())
101 : {
102 : case svSingleRef:
103 : {
104 0 : ScSingleRefData aRef = *p->GetSingleRef();
105 0 : ScAddress aRefPos = aRef.toAbs(mrPos);
106 0 : if (aRef.IsRowRel())
107 : {
108 0 : if (isSelfReferenceRelative(aRefPos, aRef.Row()))
109 0 : return false;
110 :
111 : // Trim data array length to actual data range.
112 0 : SCROW nTrimLen = trimLength(aRefPos.Tab(), aRefPos.Col(), aRefPos.Col(), aRefPos.Row(), nLen);
113 : // Fetch double array guarantees that the length of the
114 : // returned array equals or greater than the requested
115 : // length.
116 :
117 0 : formula::VectorRefArray aArray;
118 0 : if (nTrimLen)
119 0 : aArray = mrDoc.FetchVectorRefArray(aRefPos, nTrimLen);
120 :
121 0 : if (!aArray.isValid())
122 0 : return false;
123 :
124 0 : formula::SingleVectorRefToken aTok(aArray, nLen, nTrimLen);
125 0 : mrGroupTokens.AddToken(aTok);
126 : }
127 : else
128 : {
129 : // Absolute row reference.
130 0 : if (isSelfReferenceAbsolute(aRefPos))
131 0 : return false;
132 :
133 0 : formula::FormulaTokenRef pNewToken = mrDoc.ResolveStaticReference(aRefPos);
134 0 : if (!pNewToken)
135 0 : return false;
136 :
137 0 : mrGroupTokens.AddToken(*pNewToken);
138 : }
139 : }
140 0 : break;
141 : case svDoubleRef:
142 : {
143 0 : ScComplexRefData aRef = *p->GetDoubleRef();
144 0 : ScRange aAbs = aRef.toAbs(mrPos);
145 :
146 : // Check for self reference.
147 0 : if (aRef.Ref1.IsRowRel())
148 : {
149 0 : if (isSelfReferenceRelative(aAbs.aStart, aRef.Ref1.Row()))
150 0 : return false;
151 : }
152 0 : else if (isSelfReferenceAbsolute(aAbs.aStart))
153 0 : return false;
154 :
155 0 : if (aRef.Ref2.IsRowRel())
156 : {
157 0 : if (isSelfReferenceRelative(aAbs.aEnd, aRef.Ref2.Row()))
158 0 : return false;
159 : }
160 0 : else if (isSelfReferenceAbsolute(aAbs.aEnd))
161 0 : return false;
162 :
163 : // Row reference is relative.
164 0 : bool bAbsFirst = !aRef.Ref1.IsRowRel();
165 0 : bool bAbsLast = !aRef.Ref2.IsRowRel();
166 0 : ScAddress aRefPos = aAbs.aStart;
167 0 : size_t nCols = aAbs.aEnd.Col() - aAbs.aStart.Col() + 1;
168 0 : std::vector<formula::VectorRefArray> aArrays;
169 0 : aArrays.reserve(nCols);
170 0 : SCROW nRefRowSize = aAbs.aEnd.Row() - aAbs.aStart.Row() + 1;
171 0 : SCROW nArrayLength = nRefRowSize;
172 0 : if (!bAbsLast)
173 : {
174 : // range end position is relative. Extend the array length.
175 0 : SCROW nLastRefRowOffset = aAbs.aEnd.Row() - mrPos.Row();
176 0 : SCROW nLastRefRow = mrPos.Row() + nLen - 1 + nLastRefRowOffset;
177 0 : SCROW nNewLength = nLastRefRow - aAbs.aStart.Row() + 1;
178 0 : if (nNewLength > nArrayLength)
179 0 : nArrayLength = nNewLength;
180 : }
181 :
182 : // Trim trailing empty rows.
183 0 : SCROW nRequestedLength = nArrayLength; // keep the original length.
184 0 : nArrayLength = trimLength(aRefPos.Tab(), aAbs.aStart.Col(), aAbs.aEnd.Col(), aRefPos.Row(), nArrayLength);
185 :
186 0 : for (SCCOL i = aAbs.aStart.Col(); i <= aAbs.aEnd.Col(); ++i)
187 : {
188 0 : aRefPos.SetCol(i);
189 0 : formula::VectorRefArray aArray;
190 0 : if (nArrayLength)
191 0 : aArray = mrDoc.FetchVectorRefArray(aRefPos, nArrayLength);
192 :
193 0 : if (!aArray.isValid())
194 0 : return false;
195 :
196 0 : aArrays.push_back(aArray);
197 : }
198 :
199 0 : formula::DoubleVectorRefToken aTok(aArrays, nRequestedLength, nArrayLength, nRefRowSize, bAbsFirst, bAbsLast);
200 0 : mrGroupTokens.AddToken(aTok);
201 : }
202 0 : break;
203 : case svIndex:
204 : {
205 : // Named range.
206 0 : ScRangeName* pNames = mrDoc.GetRangeName();
207 0 : if (!pNames)
208 : // This should never fail.
209 0 : return false;
210 :
211 0 : ScRangeData* pRange = pNames->findByIndex(p->GetIndex());
212 0 : if (!pRange)
213 : // No named range exists by that index.
214 0 : return false;
215 :
216 0 : ScTokenArray* pNamedTokens = pRange->GetCode();
217 0 : if (!pNamedTokens)
218 : // This named range is empty.
219 0 : return false;
220 :
221 0 : mrGroupTokens.AddOpCode(ocOpen);
222 :
223 0 : if (!convert(*pNamedTokens))
224 0 : return false;
225 :
226 0 : mrGroupTokens.AddOpCode(ocClose);
227 : }
228 0 : break;
229 : default:
230 0 : mrGroupTokens.AddToken(*p);
231 : }
232 : }
233 :
234 0 : return true;
235 228 : }
236 :
237 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|