merge the formfield patch from ooo-build
[ooovba.git] / sc / source / core / tool / reftokenhelper.cxx
blobf2aba4ebcfae45781dd24d7edfe8d2f13a58623b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: token.hxx,v $
10 * $Revision: 1.15.32.3 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
35 #include "reftokenhelper.hxx"
36 #include "document.hxx"
37 #include "rangeutl.hxx"
38 #include "compiler.hxx"
39 #include "tokenarray.hxx"
41 #include "rtl/ustring.hxx"
42 #include "formula/grammar.hxx"
43 #include "formula/token.hxx"
45 using namespace formula;
47 using ::std::vector;
48 using ::std::auto_ptr;
49 using ::rtl::OUString;
51 void ScRefTokenHelper::compileRangeRepresentation(
52 vector<ScSharedTokenRef>& rRefTokens, const OUString& rRangeStr, ScDocument* pDoc, FormulaGrammar::Grammar eGrammar)
54 const sal_Unicode cSep = GetScCompilerNativeSymbol(ocSep).GetChar(0);
55 const sal_Unicode cQuote = '\'';
57 bool bFailure = false;
58 sal_Int32 nOffset = 0;
59 while (nOffset >= 0 && !bFailure)
61 OUString aToken;
62 ScRangeStringConverter::GetTokenByOffset(aToken, rRangeStr, nOffset, cSep, cQuote);
63 if (nOffset < 0)
64 break;
66 ScCompiler aCompiler(pDoc, ScAddress(0,0,0));
67 aCompiler.SetGrammar(eGrammar);
68 auto_ptr<ScTokenArray> pArray(aCompiler.CompileString(aToken));
70 // There MUST be exactly one reference per range token and nothing
71 // else, and it MUST be a valid reference, not some #REF!
72 USHORT nLen = pArray->GetLen();
73 if (!nLen)
74 continue; // Should a missing range really be allowed?
75 if (nLen != 1)
76 bFailure = true;
77 else
79 pArray->Reset();
80 const FormulaToken* p = pArray->GetNextReference();
81 if (!p)
82 bFailure = true;
83 else
85 const ScToken* pT = static_cast<const ScToken*>(p);
86 switch (pT->GetType())
88 case svSingleRef:
89 if (!pT->GetSingleRef().Valid())
90 bFailure = true;
91 break;
92 case svDoubleRef:
93 if (!pT->GetDoubleRef().Valid())
94 bFailure = true;
95 break;
96 case svExternalSingleRef:
97 if (!pT->GetSingleRef().ValidExternal())
98 bFailure = true;
99 break;
100 case svExternalDoubleRef:
101 if (!pT->GetDoubleRef().ValidExternal())
102 bFailure = true;
103 break;
104 default:
107 if (!bFailure)
108 rRefTokens.push_back(
109 ScSharedTokenRef(static_cast<ScToken*>(p->Clone())));
113 #if 0
114 switch (p->GetType())
116 case svSingleRef:
117 fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: single ref\n");
118 break;
119 case svDoubleRef:
120 fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: double ref\n");
121 break;
122 case svExternalSingleRef:
123 fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: external single ref\n");
124 break;
125 case svExternalDoubleRef:
126 fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: external double ref\n");
127 break;
128 default:
131 #endif
134 if (bFailure)
135 rRefTokens.clear();
138 bool ScRefTokenHelper::getRangeFromToken(ScRange& rRange, const ScSharedTokenRef& pToken, bool bExternal)
140 StackVar eType = pToken->GetType();
141 switch (pToken->GetType())
143 case svSingleRef:
144 case svExternalSingleRef:
146 if ((eType == svExternalSingleRef && !bExternal) ||
147 (eType == svSingleRef && bExternal))
148 return false;
150 const ScSingleRefData& rRefData = pToken->GetSingleRef();
151 rRange.aStart.SetCol(rRefData.nCol);
152 rRange.aStart.SetRow(rRefData.nRow);
153 rRange.aStart.SetTab(rRefData.nTab);
154 rRange.aEnd = rRange.aStart;
155 return true;
157 case svDoubleRef:
158 case svExternalDoubleRef:
160 if ((eType == svExternalDoubleRef && !bExternal) ||
161 (eType == svDoubleRef && bExternal))
162 return false;
164 const ScComplexRefData& rRefData = pToken->GetDoubleRef();
165 rRange.aStart.SetCol(rRefData.Ref1.nCol);
166 rRange.aStart.SetRow(rRefData.Ref1.nRow);
167 rRange.aStart.SetTab(rRefData.Ref1.nTab);
168 rRange.aEnd.SetCol(rRefData.Ref2.nCol);
169 rRange.aEnd.SetRow(rRefData.Ref2.nRow);
170 rRange.aEnd.SetTab(rRefData.Ref2.nTab);
171 return true;
173 default:
174 ; // do nothing
176 return false;
179 void ScRefTokenHelper::getRangeListFromTokens(ScRangeList& rRangeList, const vector<ScSharedTokenRef>& rTokens)
181 vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
182 for (; itr != itrEnd; ++itr)
184 ScRange aRange;
185 getRangeFromToken(aRange, *itr);
186 rRangeList.Append(aRange);
190 void ScRefTokenHelper::getTokenFromRange(ScSharedTokenRef& pToken, const ScRange& rRange)
192 ScComplexRefData aData;
193 aData.InitFlags();
194 aData.Ref1.nCol = rRange.aStart.Col();
195 aData.Ref1.nRow = rRange.aStart.Row();
196 aData.Ref1.nTab = rRange.aStart.Tab();
197 aData.Ref1.SetColRel(false);
198 aData.Ref1.SetRowRel(false);
199 aData.Ref1.SetTabRel(false);
200 aData.Ref1.SetFlag3D(true);
202 aData.Ref2.nCol = rRange.aEnd.Col();
203 aData.Ref2.nRow = rRange.aEnd.Row();
204 aData.Ref2.nTab = rRange.aEnd.Tab();
205 aData.Ref2.SetColRel(false);
206 aData.Ref2.SetRowRel(false);
207 aData.Ref2.SetTabRel(false);
208 // Display sheet name on 2nd reference only when the 1st and 2nd refs are on
209 // different sheets.
210 aData.Ref2.SetFlag3D(aData.Ref1.nTab != aData.Ref2.nTab);
212 pToken.reset(new ScDoubleRefToken(aData));
215 void ScRefTokenHelper::getTokensFromRangeList(vector<ScSharedTokenRef>& pTokens, const ScRangeList& rRanges)
217 vector<ScSharedTokenRef> aTokens;
218 sal_uInt32 nCount = rRanges.Count();
219 aTokens.reserve(nCount);
220 for (sal_uInt32 i = 0; i < nCount; ++i)
222 ScRange* pRange = static_cast<ScRange*>(rRanges.GetObject(i));
223 if (!pRange)
224 // failed.
225 return;
227 ScSharedTokenRef pToken;
228 ScRefTokenHelper::getTokenFromRange(pToken,* pRange);
229 aTokens.push_back(pToken);
231 pTokens.swap(aTokens);
234 bool ScRefTokenHelper::isRef(const ScSharedTokenRef& pToken)
236 switch (pToken->GetType())
238 case svSingleRef:
239 case svDoubleRef:
240 case svExternalSingleRef:
241 case svExternalDoubleRef:
242 return true;
243 default:
246 return false;
249 bool ScRefTokenHelper::isExternalRef(const ScSharedTokenRef& pToken)
251 switch (pToken->GetType())
253 case svExternalSingleRef:
254 case svExternalDoubleRef:
255 return true;
256 default:
259 return false;
262 bool ScRefTokenHelper::intersects(const vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
264 if (!isRef(pToken))
265 return false;
267 bool bExternal = isExternalRef(pToken);
268 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
270 ScRange aRange;
271 getRangeFromToken(aRange, pToken, bExternal);
273 vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
274 for (; itr != itrEnd; ++itr)
276 const ScSharedTokenRef& p = *itr;
277 if (!isRef(p))
278 continue;
280 if (bExternal != isExternalRef(p))
281 continue;
283 ScRange aRange2;
284 getRangeFromToken(aRange2, p, bExternal);
286 if (bExternal && nFileId != p->GetIndex())
287 // different external file
288 continue;
290 if (aRange.Intersects(aRange2))
291 return true;
293 return false;
296 namespace {
298 class JoinRefTokenRanges
300 public:
301 /**
302 * Insert a new reference token into the existing list of reference tokens,
303 * but in that process, try to join as many adjacent ranges as possible.
305 * @param rTokens existing list of reference tokens
306 * @param rToken new token
308 void operator() (vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
310 join(rTokens, pToken);
313 private:
315 /**
316 * Check two 1-dimensional ranges to see if they overlap each other.
318 * @param nMin1 min value of range 1
319 * @param nMax1 max value of range 1
320 * @param nMin2 min value of range 2
321 * @param nMax2 max value of range 2
322 * @param rNewMin min value of new range in case they overlap
323 * @param rNewMax max value of new range in case they overlap
325 template<typename T>
326 static bool overlaps(T nMin1, T nMax1, T nMin2, T nMax2, T& rNewMin, T& rNewMax)
328 bool bDisjoint1 = (nMin1 > nMax2) && (nMin1 - nMax2 > 1);
329 bool bDisjoint2 = (nMin2 > nMax1) && (nMin2 - nMax1 > 1);
330 if (bDisjoint1 || bDisjoint2)
331 // These two ranges cannot be joined. Move on.
332 return false;
334 T nMin = nMin1 < nMin2 ? nMin1 : nMin2;
335 T nMax = nMax1 > nMax2 ? nMax1 : nMax2;
337 rNewMin = nMin;
338 rNewMax = nMax;
340 return true;
343 bool isContained(const ScComplexRefData& aOldData, const ScComplexRefData& aData) const
345 // Check for containment.
346 bool bRowsContained = (aOldData.Ref1.nRow <= aData.Ref1.nRow) && (aData.Ref2.nRow <= aOldData.Ref2.nRow);
347 bool bColsContained = (aOldData.Ref1.nCol <= aData.Ref1.nCol) && (aData.Ref2.nCol <= aOldData.Ref2.nCol);
348 return (bRowsContained && bColsContained);
351 void join(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
353 // Normalize the token to a double reference.
354 ScComplexRefData aData;
355 if (!ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken))
356 return;
358 // Get the information of the new token.
359 bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
360 sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
361 String aTabName = bExternal ? pToken->GetString() : String();
363 bool bJoined = false;
364 vector<ScSharedTokenRef>::iterator itr = rTokens.begin(), itrEnd = rTokens.end();
365 for (; itr != itrEnd; ++itr)
367 ScSharedTokenRef& pOldToken = *itr;
369 if (!ScRefTokenHelper::isRef(pOldToken))
370 // A non-ref token should not have been added here in the first
371 // place!
372 continue;
374 if (bExternal != ScRefTokenHelper::isExternalRef(pOldToken))
375 // External and internal refs don't mix.
376 continue;
378 if (bExternal)
380 if (nFileId != pOldToken->GetIndex())
381 // Different external files.
382 continue;
384 if (aTabName != pOldToken->GetString())
385 // Different table names.
386 continue;
389 ScComplexRefData aOldData;
390 if (!ScRefTokenHelper::getDoubleRefDataFromToken(aOldData, pOldToken))
391 continue;
393 if (aData.Ref1.nTab != aOldData.Ref1.nTab || aData.Ref2.nTab != aOldData.Ref2.nTab)
394 // Sheet ranges differ.
395 continue;
397 if (isContained(aOldData, aData))
398 // This new range is part of an existing range. Skip it.
399 return;
401 bool bSameRows = (aData.Ref1.nRow == aOldData.Ref1.nRow) && (aData.Ref2.nRow == aOldData.Ref2.nRow);
402 bool bSameCols = (aData.Ref1.nCol == aOldData.Ref1.nCol) && (aData.Ref2.nCol == aOldData.Ref2.nCol);
403 ScComplexRefData aNewData = aOldData;
404 bool bJoinRanges = false;
405 if (bSameRows)
407 bJoinRanges = overlaps(
408 aData.Ref1.nCol, aData.Ref2.nCol, aOldData.Ref1.nCol, aOldData.Ref2.nCol,
409 aNewData.Ref1.nCol, aNewData.Ref2.nCol);
411 else if (bSameCols)
413 bJoinRanges = overlaps(
414 aData.Ref1.nRow, aData.Ref2.nRow, aOldData.Ref1.nRow, aOldData.Ref2.nRow,
415 aNewData.Ref1.nRow, aNewData.Ref2.nRow);
418 if (bJoinRanges)
420 if (bExternal)
421 pOldToken.reset(new ScExternalDoubleRefToken(nFileId, aTabName, aNewData));
422 else
423 pOldToken.reset(new ScDoubleRefToken(aNewData));
425 bJoined = true;
426 break;
430 if (bJoined)
432 if (rTokens.size() == 1)
433 // There is only one left. No need to do more joining.
434 return;
436 // Pop the last token from the list, and keep joining recursively.
437 ScSharedTokenRef p = rTokens.back();
438 rTokens.pop_back();
439 join(rTokens, p);
441 else
442 rTokens.push_back(pToken);
448 void ScRefTokenHelper::join(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
450 JoinRefTokenRanges join;
451 join(rTokens, pToken);
454 bool ScRefTokenHelper::getDoubleRefDataFromToken(ScComplexRefData& rData, const ScSharedTokenRef& pToken)
456 switch (pToken->GetType())
458 case svSingleRef:
459 case svExternalSingleRef:
461 const ScSingleRefData& r = pToken->GetSingleRef();
462 rData.Ref1 = r;
463 rData.Ref1.SetFlag3D(true);
464 rData.Ref2 = r;
465 rData.Ref2.SetFlag3D(false); // Don't display sheet name on second reference.
467 break;
468 case svDoubleRef:
469 case svExternalDoubleRef:
470 rData = pToken->GetDoubleRef();
471 break;
472 default:
473 // Not a reference token. Bail out.
474 return false;
476 return true;
479 ScSharedTokenRef ScRefTokenHelper::createRefToken(const ScAddress& rAddr)
481 ScSingleRefData aRefData;
482 aRefData.InitAddress(rAddr);
483 ScSharedTokenRef pRef(new ScSingleRefToken(aRefData));
484 return pRef;
487 ScSharedTokenRef ScRefTokenHelper::createRefToken(const ScRange& rRange)
489 ScComplexRefData aRefData;
490 aRefData.InitRange(rRange);
491 ScSharedTokenRef pRef(new ScDoubleRefToken(aRefData));
492 return pRef;