1b3f79822SAndrew Rist /**************************************************************
2cdf0e10cSrcweir *
3b3f79822SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one
4b3f79822SAndrew Rist * or more contributor license agreements. See the NOTICE file
5b3f79822SAndrew Rist * distributed with this work for additional information
6b3f79822SAndrew Rist * regarding copyright ownership. The ASF licenses this file
7b3f79822SAndrew Rist * to you under the Apache License, Version 2.0 (the
8b3f79822SAndrew Rist * "License"); you may not use this file except in compliance
9b3f79822SAndrew Rist * with the License. You may obtain a copy of the License at
10cdf0e10cSrcweir *
11b3f79822SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir *
13b3f79822SAndrew Rist * Unless required by applicable law or agreed to in writing,
14b3f79822SAndrew Rist * software distributed under the License is distributed on an
15b3f79822SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16b3f79822SAndrew Rist * KIND, either express or implied. See the License for the
17b3f79822SAndrew Rist * specific language governing permissions and limitations
18b3f79822SAndrew Rist * under the License.
19cdf0e10cSrcweir *
20b3f79822SAndrew Rist *************************************************************/
21b3f79822SAndrew Rist
22b3f79822SAndrew Rist
23cdf0e10cSrcweir
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sc.hxx"
26cdf0e10cSrcweir
27cdf0e10cSrcweir
28cdf0e10cSrcweir #include "reftokenhelper.hxx"
29cdf0e10cSrcweir #include "document.hxx"
30cdf0e10cSrcweir #include "rangeutl.hxx"
31cdf0e10cSrcweir #include "compiler.hxx"
32cdf0e10cSrcweir #include "tokenarray.hxx"
33cdf0e10cSrcweir
34cdf0e10cSrcweir #include "rtl/ustring.hxx"
35cdf0e10cSrcweir #include "formula/grammar.hxx"
36cdf0e10cSrcweir #include "formula/token.hxx"
37cdf0e10cSrcweir
38cdf0e10cSrcweir using namespace formula;
39cdf0e10cSrcweir
40cdf0e10cSrcweir using ::std::vector;
41cdf0e10cSrcweir using ::std::auto_ptr;
42cdf0e10cSrcweir using ::rtl::OUString;
43cdf0e10cSrcweir
compileRangeRepresentation(vector<ScSharedTokenRef> & rRefTokens,const OUString & rRangeStr,ScDocument * pDoc,FormulaGrammar::Grammar eGrammar)44cdf0e10cSrcweir void ScRefTokenHelper::compileRangeRepresentation(
45cdf0e10cSrcweir vector<ScSharedTokenRef>& rRefTokens, const OUString& rRangeStr, ScDocument* pDoc, FormulaGrammar::Grammar eGrammar)
46cdf0e10cSrcweir {
47cdf0e10cSrcweir const sal_Unicode cSep = GetScCompilerNativeSymbol(ocSep).GetChar(0);
48cdf0e10cSrcweir const sal_Unicode cQuote = '\'';
49cdf0e10cSrcweir
50cdf0e10cSrcweir // #i107275# ignore parentheses
51cdf0e10cSrcweir OUString aRangeStr = rRangeStr;
52cdf0e10cSrcweir while( (aRangeStr.getLength() >= 2) && (aRangeStr[ 0 ] == '(') && (aRangeStr[ aRangeStr.getLength() - 1 ] == ')') )
53cdf0e10cSrcweir aRangeStr = aRangeStr.copy( 1, aRangeStr.getLength() - 2 );
54cdf0e10cSrcweir
55cdf0e10cSrcweir bool bFailure = false;
56cdf0e10cSrcweir sal_Int32 nOffset = 0;
57cdf0e10cSrcweir while (nOffset >= 0 && !bFailure)
58cdf0e10cSrcweir {
59cdf0e10cSrcweir OUString aToken;
60cdf0e10cSrcweir ScRangeStringConverter::GetTokenByOffset(aToken, aRangeStr, nOffset, cSep, cQuote);
61cdf0e10cSrcweir if (nOffset < 0)
62cdf0e10cSrcweir break;
63cdf0e10cSrcweir
64cdf0e10cSrcweir ScCompiler aCompiler(pDoc, ScAddress(0,0,0));
65cdf0e10cSrcweir aCompiler.SetGrammar(eGrammar);
66cdf0e10cSrcweir auto_ptr<ScTokenArray> pArray(aCompiler.CompileString(aToken));
67cdf0e10cSrcweir
68cdf0e10cSrcweir // There MUST be exactly one reference per range token and nothing
69cdf0e10cSrcweir // else, and it MUST be a valid reference, not some #REF!
70cdf0e10cSrcweir sal_uInt16 nLen = pArray->GetLen();
71cdf0e10cSrcweir if (!nLen)
72cdf0e10cSrcweir continue; // Should a missing range really be allowed?
73cdf0e10cSrcweir if (nLen != 1)
74cdf0e10cSrcweir bFailure = true;
75cdf0e10cSrcweir else
76cdf0e10cSrcweir {
77cdf0e10cSrcweir pArray->Reset();
78cdf0e10cSrcweir const FormulaToken* p = pArray->GetNextReference();
79cdf0e10cSrcweir if (!p)
80cdf0e10cSrcweir bFailure = true;
81cdf0e10cSrcweir else
82cdf0e10cSrcweir {
83cdf0e10cSrcweir const ScToken* pT = static_cast<const ScToken*>(p);
84cdf0e10cSrcweir switch (pT->GetType())
85cdf0e10cSrcweir {
86cdf0e10cSrcweir case svSingleRef:
87cdf0e10cSrcweir if (!pT->GetSingleRef().Valid())
88cdf0e10cSrcweir bFailure = true;
89cdf0e10cSrcweir break;
90cdf0e10cSrcweir case svDoubleRef:
91cdf0e10cSrcweir if (!pT->GetDoubleRef().Valid())
92cdf0e10cSrcweir bFailure = true;
93cdf0e10cSrcweir break;
94cdf0e10cSrcweir case svExternalSingleRef:
95cdf0e10cSrcweir if (!pT->GetSingleRef().ValidExternal())
96cdf0e10cSrcweir bFailure = true;
97cdf0e10cSrcweir break;
98cdf0e10cSrcweir case svExternalDoubleRef:
99cdf0e10cSrcweir if (!pT->GetDoubleRef().ValidExternal())
100cdf0e10cSrcweir bFailure = true;
101cdf0e10cSrcweir break;
102cdf0e10cSrcweir default:
103cdf0e10cSrcweir ;
104cdf0e10cSrcweir }
105cdf0e10cSrcweir if (!bFailure)
106cdf0e10cSrcweir rRefTokens.push_back(
107cdf0e10cSrcweir ScSharedTokenRef(static_cast<ScToken*>(p->Clone())));
108cdf0e10cSrcweir }
109cdf0e10cSrcweir }
110cdf0e10cSrcweir
111cdf0e10cSrcweir #if 0
112cdf0e10cSrcweir switch (p->GetType())
113cdf0e10cSrcweir {
114cdf0e10cSrcweir case svSingleRef:
115cdf0e10cSrcweir fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: single ref\n");
116cdf0e10cSrcweir break;
117cdf0e10cSrcweir case svDoubleRef:
118cdf0e10cSrcweir fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: double ref\n");
119cdf0e10cSrcweir break;
120cdf0e10cSrcweir case svExternalSingleRef:
121cdf0e10cSrcweir fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: external single ref\n");
122cdf0e10cSrcweir break;
123cdf0e10cSrcweir case svExternalDoubleRef:
124cdf0e10cSrcweir fprintf(stdout, "ScChart2DataProvider::compileRangeRepresentation: external double ref\n");
125cdf0e10cSrcweir break;
126cdf0e10cSrcweir default:
127cdf0e10cSrcweir ;
128cdf0e10cSrcweir }
129cdf0e10cSrcweir #endif
130cdf0e10cSrcweir
131cdf0e10cSrcweir }
132cdf0e10cSrcweir if (bFailure)
133cdf0e10cSrcweir rRefTokens.clear();
134cdf0e10cSrcweir }
135cdf0e10cSrcweir
getRangeFromToken(ScRange & rRange,const ScSharedTokenRef & pToken,bool bExternal)136cdf0e10cSrcweir bool ScRefTokenHelper::getRangeFromToken(ScRange& rRange, const ScSharedTokenRef& pToken, bool bExternal)
137cdf0e10cSrcweir {
138cdf0e10cSrcweir StackVar eType = pToken->GetType();
139cdf0e10cSrcweir switch (pToken->GetType())
140cdf0e10cSrcweir {
141cdf0e10cSrcweir case svSingleRef:
142cdf0e10cSrcweir case svExternalSingleRef:
143cdf0e10cSrcweir {
144cdf0e10cSrcweir if ((eType == svExternalSingleRef && !bExternal) ||
145cdf0e10cSrcweir (eType == svSingleRef && bExternal))
146cdf0e10cSrcweir return false;
147cdf0e10cSrcweir
148cdf0e10cSrcweir const ScSingleRefData& rRefData = pToken->GetSingleRef();
149*38e63b1dSArmin Le Grand
150*38e63b1dSArmin Le Grand if(!rRefData.Valid())
151*38e63b1dSArmin Le Grand {
152*38e63b1dSArmin Le Grand OSL_ENSURE(false, "RefData out of range, correct before usage (!)");
153*38e63b1dSArmin Le Grand }
154*38e63b1dSArmin Le Grand
155cdf0e10cSrcweir rRange.aStart.SetCol(rRefData.nCol);
156cdf0e10cSrcweir rRange.aStart.SetRow(rRefData.nRow);
157cdf0e10cSrcweir rRange.aStart.SetTab(rRefData.nTab);
158cdf0e10cSrcweir rRange.aEnd = rRange.aStart;
159cdf0e10cSrcweir return true;
160cdf0e10cSrcweir }
161cdf0e10cSrcweir case svDoubleRef:
162cdf0e10cSrcweir case svExternalDoubleRef:
163cdf0e10cSrcweir {
164cdf0e10cSrcweir if ((eType == svExternalDoubleRef && !bExternal) ||
165cdf0e10cSrcweir (eType == svDoubleRef && bExternal))
166cdf0e10cSrcweir return false;
167cdf0e10cSrcweir
168cdf0e10cSrcweir const ScComplexRefData& rRefData = pToken->GetDoubleRef();
169*38e63b1dSArmin Le Grand
170*38e63b1dSArmin Le Grand if(!rRefData.Valid())
171*38e63b1dSArmin Le Grand {
172*38e63b1dSArmin Le Grand OSL_ENSURE(false, "RefData out of range, correct before usage (!)");
173*38e63b1dSArmin Le Grand }
174*38e63b1dSArmin Le Grand
175cdf0e10cSrcweir rRange.aStart.SetCol(rRefData.Ref1.nCol);
176cdf0e10cSrcweir rRange.aStart.SetRow(rRefData.Ref1.nRow);
177cdf0e10cSrcweir rRange.aStart.SetTab(rRefData.Ref1.nTab);
178cdf0e10cSrcweir rRange.aEnd.SetCol(rRefData.Ref2.nCol);
179cdf0e10cSrcweir rRange.aEnd.SetRow(rRefData.Ref2.nRow);
180cdf0e10cSrcweir rRange.aEnd.SetTab(rRefData.Ref2.nTab);
181cdf0e10cSrcweir return true;
182cdf0e10cSrcweir }
183cdf0e10cSrcweir default:
184cdf0e10cSrcweir ; // do nothing
185cdf0e10cSrcweir }
186cdf0e10cSrcweir return false;
187cdf0e10cSrcweir }
188cdf0e10cSrcweir
getRangeListFromTokens(ScRangeList & rRangeList,const vector<ScSharedTokenRef> & rTokens)189cdf0e10cSrcweir void ScRefTokenHelper::getRangeListFromTokens(ScRangeList& rRangeList, const vector<ScSharedTokenRef>& rTokens)
190cdf0e10cSrcweir {
191cdf0e10cSrcweir vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
192cdf0e10cSrcweir for (; itr != itrEnd; ++itr)
193cdf0e10cSrcweir {
194cdf0e10cSrcweir ScRange aRange;
195cdf0e10cSrcweir getRangeFromToken(aRange, *itr);
196cdf0e10cSrcweir rRangeList.Append(aRange);
197cdf0e10cSrcweir }
198cdf0e10cSrcweir }
199cdf0e10cSrcweir
getTokenFromRange(ScSharedTokenRef & pToken,const ScRange & rRange)200cdf0e10cSrcweir void ScRefTokenHelper::getTokenFromRange(ScSharedTokenRef& pToken, const ScRange& rRange)
201cdf0e10cSrcweir {
202cdf0e10cSrcweir ScComplexRefData aData;
203cdf0e10cSrcweir aData.InitFlags();
204cdf0e10cSrcweir aData.Ref1.nCol = rRange.aStart.Col();
205cdf0e10cSrcweir aData.Ref1.nRow = rRange.aStart.Row();
206cdf0e10cSrcweir aData.Ref1.nTab = rRange.aStart.Tab();
207cdf0e10cSrcweir aData.Ref1.SetColRel(false);
208cdf0e10cSrcweir aData.Ref1.SetRowRel(false);
209cdf0e10cSrcweir aData.Ref1.SetTabRel(false);
210cdf0e10cSrcweir aData.Ref1.SetFlag3D(true);
211cdf0e10cSrcweir
212cdf0e10cSrcweir aData.Ref2.nCol = rRange.aEnd.Col();
213cdf0e10cSrcweir aData.Ref2.nRow = rRange.aEnd.Row();
214cdf0e10cSrcweir aData.Ref2.nTab = rRange.aEnd.Tab();
215cdf0e10cSrcweir aData.Ref2.SetColRel(false);
216cdf0e10cSrcweir aData.Ref2.SetRowRel(false);
217cdf0e10cSrcweir aData.Ref2.SetTabRel(false);
218cdf0e10cSrcweir // Display sheet name on 2nd reference only when the 1st and 2nd refs are on
219cdf0e10cSrcweir // different sheets.
220cdf0e10cSrcweir aData.Ref2.SetFlag3D(aData.Ref1.nTab != aData.Ref2.nTab);
221cdf0e10cSrcweir
222cdf0e10cSrcweir pToken.reset(new ScDoubleRefToken(aData));
223cdf0e10cSrcweir }
224cdf0e10cSrcweir
getTokensFromRangeList(vector<ScSharedTokenRef> & pTokens,const ScRangeList & rRanges)225cdf0e10cSrcweir void ScRefTokenHelper::getTokensFromRangeList(vector<ScSharedTokenRef>& pTokens, const ScRangeList& rRanges)
226cdf0e10cSrcweir {
227cdf0e10cSrcweir vector<ScSharedTokenRef> aTokens;
228cdf0e10cSrcweir sal_uInt32 nCount = rRanges.Count();
229cdf0e10cSrcweir aTokens.reserve(nCount);
230cdf0e10cSrcweir for (sal_uInt32 i = 0; i < nCount; ++i)
231cdf0e10cSrcweir {
232cdf0e10cSrcweir ScRange* pRange = static_cast<ScRange*>(rRanges.GetObject(i));
233cdf0e10cSrcweir if (!pRange)
234cdf0e10cSrcweir // failed.
235cdf0e10cSrcweir return;
236cdf0e10cSrcweir
237cdf0e10cSrcweir ScSharedTokenRef pToken;
238cdf0e10cSrcweir ScRefTokenHelper::getTokenFromRange(pToken,* pRange);
239cdf0e10cSrcweir aTokens.push_back(pToken);
240cdf0e10cSrcweir }
241cdf0e10cSrcweir pTokens.swap(aTokens);
242cdf0e10cSrcweir }
243cdf0e10cSrcweir
isRef(const ScSharedTokenRef & pToken)244cdf0e10cSrcweir bool ScRefTokenHelper::isRef(const ScSharedTokenRef& pToken)
245cdf0e10cSrcweir {
246cdf0e10cSrcweir switch (pToken->GetType())
247cdf0e10cSrcweir {
248cdf0e10cSrcweir case svSingleRef:
249cdf0e10cSrcweir case svDoubleRef:
250cdf0e10cSrcweir case svExternalSingleRef:
251cdf0e10cSrcweir case svExternalDoubleRef:
252cdf0e10cSrcweir return true;
253cdf0e10cSrcweir default:
254cdf0e10cSrcweir ;
255cdf0e10cSrcweir }
256cdf0e10cSrcweir return false;
257cdf0e10cSrcweir }
258cdf0e10cSrcweir
isExternalRef(const ScSharedTokenRef & pToken)259cdf0e10cSrcweir bool ScRefTokenHelper::isExternalRef(const ScSharedTokenRef& pToken)
260cdf0e10cSrcweir {
261cdf0e10cSrcweir switch (pToken->GetType())
262cdf0e10cSrcweir {
263cdf0e10cSrcweir case svExternalSingleRef:
264cdf0e10cSrcweir case svExternalDoubleRef:
265cdf0e10cSrcweir return true;
266cdf0e10cSrcweir default:
267cdf0e10cSrcweir ;
268cdf0e10cSrcweir }
269cdf0e10cSrcweir return false;
270cdf0e10cSrcweir }
271cdf0e10cSrcweir
intersects(const vector<ScSharedTokenRef> & rTokens,const ScSharedTokenRef & pToken)272cdf0e10cSrcweir bool ScRefTokenHelper::intersects(const vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
273cdf0e10cSrcweir {
274cdf0e10cSrcweir if (!isRef(pToken))
275cdf0e10cSrcweir return false;
276cdf0e10cSrcweir
277cdf0e10cSrcweir bool bExternal = isExternalRef(pToken);
278cdf0e10cSrcweir sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
279cdf0e10cSrcweir
280cdf0e10cSrcweir ScRange aRange;
281cdf0e10cSrcweir getRangeFromToken(aRange, pToken, bExternal);
282cdf0e10cSrcweir
283cdf0e10cSrcweir vector<ScSharedTokenRef>::const_iterator itr = rTokens.begin(), itrEnd = rTokens.end();
284cdf0e10cSrcweir for (; itr != itrEnd; ++itr)
285cdf0e10cSrcweir {
286cdf0e10cSrcweir const ScSharedTokenRef& p = *itr;
287cdf0e10cSrcweir if (!isRef(p))
288cdf0e10cSrcweir continue;
289cdf0e10cSrcweir
290cdf0e10cSrcweir if (bExternal != isExternalRef(p))
291cdf0e10cSrcweir continue;
292cdf0e10cSrcweir
293cdf0e10cSrcweir ScRange aRange2;
294cdf0e10cSrcweir getRangeFromToken(aRange2, p, bExternal);
295cdf0e10cSrcweir
296cdf0e10cSrcweir if (bExternal && nFileId != p->GetIndex())
297cdf0e10cSrcweir // different external file
298cdf0e10cSrcweir continue;
299cdf0e10cSrcweir
300cdf0e10cSrcweir if (aRange.Intersects(aRange2))
301cdf0e10cSrcweir return true;
302cdf0e10cSrcweir }
303cdf0e10cSrcweir return false;
304cdf0e10cSrcweir }
305cdf0e10cSrcweir
306cdf0e10cSrcweir namespace {
307cdf0e10cSrcweir
308cdf0e10cSrcweir class JoinRefTokenRanges
309cdf0e10cSrcweir {
310cdf0e10cSrcweir public:
311cdf0e10cSrcweir /**
312cdf0e10cSrcweir * Insert a new reference token into the existing list of reference tokens,
313cdf0e10cSrcweir * but in that process, try to join as many adjacent ranges as possible.
314cdf0e10cSrcweir *
315cdf0e10cSrcweir * @param rTokens existing list of reference tokens
316cdf0e10cSrcweir * @param rToken new token
317cdf0e10cSrcweir */
operator ()(vector<ScSharedTokenRef> & rTokens,const ScSharedTokenRef & pToken)318cdf0e10cSrcweir void operator() (vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
319cdf0e10cSrcweir {
320cdf0e10cSrcweir join(rTokens, pToken);
321cdf0e10cSrcweir }
322cdf0e10cSrcweir
323cdf0e10cSrcweir private:
324cdf0e10cSrcweir
325cdf0e10cSrcweir /**
326cdf0e10cSrcweir * Check two 1-dimensional ranges to see if they overlap each other.
327cdf0e10cSrcweir *
328cdf0e10cSrcweir * @param nMin1 min value of range 1
329cdf0e10cSrcweir * @param nMax1 max value of range 1
330cdf0e10cSrcweir * @param nMin2 min value of range 2
331cdf0e10cSrcweir * @param nMax2 max value of range 2
332cdf0e10cSrcweir * @param rNewMin min value of new range in case they overlap
333cdf0e10cSrcweir * @param rNewMax max value of new range in case they overlap
334cdf0e10cSrcweir */
335cdf0e10cSrcweir template<typename T>
overlaps(T nMin1,T nMax1,T nMin2,T nMax2,T & rNewMin,T & rNewMax)336cdf0e10cSrcweir static bool overlaps(T nMin1, T nMax1, T nMin2, T nMax2, T& rNewMin, T& rNewMax)
337cdf0e10cSrcweir {
338cdf0e10cSrcweir bool bDisjoint1 = (nMin1 > nMax2) && (nMin1 - nMax2 > 1);
339cdf0e10cSrcweir bool bDisjoint2 = (nMin2 > nMax1) && (nMin2 - nMax1 > 1);
340cdf0e10cSrcweir if (bDisjoint1 || bDisjoint2)
341cdf0e10cSrcweir // These two ranges cannot be joined. Move on.
342cdf0e10cSrcweir return false;
343cdf0e10cSrcweir
344cdf0e10cSrcweir T nMin = nMin1 < nMin2 ? nMin1 : nMin2;
345cdf0e10cSrcweir T nMax = nMax1 > nMax2 ? nMax1 : nMax2;
346cdf0e10cSrcweir
347cdf0e10cSrcweir rNewMin = nMin;
348cdf0e10cSrcweir rNewMax = nMax;
349cdf0e10cSrcweir
350cdf0e10cSrcweir return true;
351cdf0e10cSrcweir }
352cdf0e10cSrcweir
isContained(const ScComplexRefData & aOldData,const ScComplexRefData & aData) const353cdf0e10cSrcweir bool isContained(const ScComplexRefData& aOldData, const ScComplexRefData& aData) const
354cdf0e10cSrcweir {
355cdf0e10cSrcweir // Check for containment.
356cdf0e10cSrcweir bool bRowsContained = (aOldData.Ref1.nRow <= aData.Ref1.nRow) && (aData.Ref2.nRow <= aOldData.Ref2.nRow);
357cdf0e10cSrcweir bool bColsContained = (aOldData.Ref1.nCol <= aData.Ref1.nCol) && (aData.Ref2.nCol <= aOldData.Ref2.nCol);
358cdf0e10cSrcweir return (bRowsContained && bColsContained);
359cdf0e10cSrcweir }
360cdf0e10cSrcweir
join(vector<ScSharedTokenRef> & rTokens,const ScSharedTokenRef & pToken)361cdf0e10cSrcweir void join(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
362cdf0e10cSrcweir {
363cdf0e10cSrcweir // Normalize the token to a double reference.
364cdf0e10cSrcweir ScComplexRefData aData;
365cdf0e10cSrcweir if (!ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken))
366cdf0e10cSrcweir return;
367cdf0e10cSrcweir
368cdf0e10cSrcweir // Get the information of the new token.
369cdf0e10cSrcweir bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
370cdf0e10cSrcweir sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
371cdf0e10cSrcweir String aTabName = bExternal ? pToken->GetString() : String();
372cdf0e10cSrcweir
373cdf0e10cSrcweir bool bJoined = false;
374cdf0e10cSrcweir vector<ScSharedTokenRef>::iterator itr = rTokens.begin(), itrEnd = rTokens.end();
375cdf0e10cSrcweir for (; itr != itrEnd; ++itr)
376cdf0e10cSrcweir {
377cdf0e10cSrcweir ScSharedTokenRef& pOldToken = *itr;
378cdf0e10cSrcweir
379cdf0e10cSrcweir if (!ScRefTokenHelper::isRef(pOldToken))
380cdf0e10cSrcweir // A non-ref token should not have been added here in the first
381cdf0e10cSrcweir // place!
382cdf0e10cSrcweir continue;
383cdf0e10cSrcweir
384cdf0e10cSrcweir if (bExternal != ScRefTokenHelper::isExternalRef(pOldToken))
385cdf0e10cSrcweir // External and internal refs don't mix.
386cdf0e10cSrcweir continue;
387cdf0e10cSrcweir
388cdf0e10cSrcweir if (bExternal)
389cdf0e10cSrcweir {
390cdf0e10cSrcweir if (nFileId != pOldToken->GetIndex())
391cdf0e10cSrcweir // Different external files.
392cdf0e10cSrcweir continue;
393cdf0e10cSrcweir
394cdf0e10cSrcweir if (aTabName != pOldToken->GetString())
395cdf0e10cSrcweir // Different table names.
396cdf0e10cSrcweir continue;
397cdf0e10cSrcweir }
398cdf0e10cSrcweir
399cdf0e10cSrcweir ScComplexRefData aOldData;
400cdf0e10cSrcweir if (!ScRefTokenHelper::getDoubleRefDataFromToken(aOldData, pOldToken))
401cdf0e10cSrcweir continue;
402cdf0e10cSrcweir
403cdf0e10cSrcweir if (aData.Ref1.nTab != aOldData.Ref1.nTab || aData.Ref2.nTab != aOldData.Ref2.nTab)
404cdf0e10cSrcweir // Sheet ranges differ.
405cdf0e10cSrcweir continue;
406cdf0e10cSrcweir
407cdf0e10cSrcweir if (isContained(aOldData, aData))
408cdf0e10cSrcweir // This new range is part of an existing range. Skip it.
409cdf0e10cSrcweir return;
410cdf0e10cSrcweir
411cdf0e10cSrcweir bool bSameRows = (aData.Ref1.nRow == aOldData.Ref1.nRow) && (aData.Ref2.nRow == aOldData.Ref2.nRow);
412cdf0e10cSrcweir bool bSameCols = (aData.Ref1.nCol == aOldData.Ref1.nCol) && (aData.Ref2.nCol == aOldData.Ref2.nCol);
413cdf0e10cSrcweir ScComplexRefData aNewData = aOldData;
414cdf0e10cSrcweir bool bJoinRanges = false;
415cdf0e10cSrcweir if (bSameRows)
416cdf0e10cSrcweir {
417cdf0e10cSrcweir bJoinRanges = overlaps(
418cdf0e10cSrcweir aData.Ref1.nCol, aData.Ref2.nCol, aOldData.Ref1.nCol, aOldData.Ref2.nCol,
419cdf0e10cSrcweir aNewData.Ref1.nCol, aNewData.Ref2.nCol);
420cdf0e10cSrcweir }
421cdf0e10cSrcweir else if (bSameCols)
422cdf0e10cSrcweir {
423cdf0e10cSrcweir bJoinRanges = overlaps(
424cdf0e10cSrcweir aData.Ref1.nRow, aData.Ref2.nRow, aOldData.Ref1.nRow, aOldData.Ref2.nRow,
425cdf0e10cSrcweir aNewData.Ref1.nRow, aNewData.Ref2.nRow);
426cdf0e10cSrcweir }
427cdf0e10cSrcweir
428cdf0e10cSrcweir if (bJoinRanges)
429cdf0e10cSrcweir {
430cdf0e10cSrcweir if (bExternal)
431cdf0e10cSrcweir pOldToken.reset(new ScExternalDoubleRefToken(nFileId, aTabName, aNewData));
432cdf0e10cSrcweir else
433cdf0e10cSrcweir pOldToken.reset(new ScDoubleRefToken(aNewData));
434cdf0e10cSrcweir
435cdf0e10cSrcweir bJoined = true;
436cdf0e10cSrcweir break;
437cdf0e10cSrcweir }
438cdf0e10cSrcweir }
439cdf0e10cSrcweir
440cdf0e10cSrcweir if (bJoined)
441cdf0e10cSrcweir {
442cdf0e10cSrcweir if (rTokens.size() == 1)
443cdf0e10cSrcweir // There is only one left. No need to do more joining.
444cdf0e10cSrcweir return;
445cdf0e10cSrcweir
446cdf0e10cSrcweir // Pop the last token from the list, and keep joining recursively.
447cdf0e10cSrcweir ScSharedTokenRef p = rTokens.back();
448cdf0e10cSrcweir rTokens.pop_back();
449cdf0e10cSrcweir join(rTokens, p);
450cdf0e10cSrcweir }
451cdf0e10cSrcweir else
452cdf0e10cSrcweir rTokens.push_back(pToken);
453cdf0e10cSrcweir }
454cdf0e10cSrcweir };
455cdf0e10cSrcweir
456cdf0e10cSrcweir }
457cdf0e10cSrcweir
join(vector<ScSharedTokenRef> & rTokens,const ScSharedTokenRef & pToken)458cdf0e10cSrcweir void ScRefTokenHelper::join(vector<ScSharedTokenRef>& rTokens, const ScSharedTokenRef& pToken)
459cdf0e10cSrcweir {
460cdf0e10cSrcweir JoinRefTokenRanges join;
461cdf0e10cSrcweir join(rTokens, pToken);
462cdf0e10cSrcweir }
463cdf0e10cSrcweir
getDoubleRefDataFromToken(ScComplexRefData & rData,const ScSharedTokenRef & pToken)464cdf0e10cSrcweir bool ScRefTokenHelper::getDoubleRefDataFromToken(ScComplexRefData& rData, const ScSharedTokenRef& pToken)
465cdf0e10cSrcweir {
466cdf0e10cSrcweir switch (pToken->GetType())
467cdf0e10cSrcweir {
468cdf0e10cSrcweir case svSingleRef:
469cdf0e10cSrcweir case svExternalSingleRef:
470cdf0e10cSrcweir {
471cdf0e10cSrcweir const ScSingleRefData& r = pToken->GetSingleRef();
472cdf0e10cSrcweir rData.Ref1 = r;
473cdf0e10cSrcweir rData.Ref1.SetFlag3D(true);
474cdf0e10cSrcweir rData.Ref2 = r;
475cdf0e10cSrcweir rData.Ref2.SetFlag3D(false); // Don't display sheet name on second reference.
476cdf0e10cSrcweir }
477cdf0e10cSrcweir break;
478cdf0e10cSrcweir case svDoubleRef:
479cdf0e10cSrcweir case svExternalDoubleRef:
480cdf0e10cSrcweir rData = pToken->GetDoubleRef();
481cdf0e10cSrcweir break;
482cdf0e10cSrcweir default:
483cdf0e10cSrcweir // Not a reference token. Bail out.
484cdf0e10cSrcweir return false;
485cdf0e10cSrcweir }
486cdf0e10cSrcweir return true;
487cdf0e10cSrcweir }
488