1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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
;
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
)
62 ScRangeStringConverter::GetTokenByOffset(aToken
, rRangeStr
, nOffset
, cSep
, cQuote
);
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();
74 continue; // Should a missing range really be allowed?
80 const FormulaToken
* p
= pArray
->GetNextReference();
85 const ScToken
* pT
= static_cast<const ScToken
*>(p
);
86 switch (pT
->GetType())
89 if (!pT
->GetSingleRef().Valid())
93 if (!pT
->GetDoubleRef().Valid())
96 case svExternalSingleRef
:
97 if (!pT
->GetSingleRef().ValidExternal())
100 case svExternalDoubleRef
:
101 if (!pT
->GetDoubleRef().ValidExternal())
108 rRefTokens
.push_back(
109 ScSharedTokenRef(static_cast<ScToken
*>(p
->Clone())));
114 switch (p
->GetType())
117 fprintf(stdout
, "ScChart2DataProvider::compileRangeRepresentation: single ref\n");
120 fprintf(stdout
, "ScChart2DataProvider::compileRangeRepresentation: double ref\n");
122 case svExternalSingleRef
:
123 fprintf(stdout
, "ScChart2DataProvider::compileRangeRepresentation: external single ref\n");
125 case svExternalDoubleRef
:
126 fprintf(stdout
, "ScChart2DataProvider::compileRangeRepresentation: external double ref\n");
138 bool ScRefTokenHelper::getRangeFromToken(ScRange
& rRange
, const ScSharedTokenRef
& pToken
, bool bExternal
)
140 StackVar eType
= pToken
->GetType();
141 switch (pToken
->GetType())
144 case svExternalSingleRef
:
146 if ((eType
== svExternalSingleRef
&& !bExternal
) ||
147 (eType
== svSingleRef
&& bExternal
))
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
;
158 case svExternalDoubleRef
:
160 if ((eType
== svExternalDoubleRef
&& !bExternal
) ||
161 (eType
== svDoubleRef
&& bExternal
))
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
);
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
)
185 getRangeFromToken(aRange
, *itr
);
186 rRangeList
.Append(aRange
);
190 void ScRefTokenHelper::getTokenFromRange(ScSharedTokenRef
& pToken
, const ScRange
& rRange
)
192 ScComplexRefData aData
;
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
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
));
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())
240 case svExternalSingleRef
:
241 case svExternalDoubleRef
:
249 bool ScRefTokenHelper::isExternalRef(const ScSharedTokenRef
& pToken
)
251 switch (pToken
->GetType())
253 case svExternalSingleRef
:
254 case svExternalDoubleRef
:
262 bool ScRefTokenHelper::intersects(const vector
<ScSharedTokenRef
>& rTokens
, const ScSharedTokenRef
& pToken
)
267 bool bExternal
= isExternalRef(pToken
);
268 sal_uInt16 nFileId
= bExternal
? pToken
->GetIndex() : 0;
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
;
280 if (bExternal
!= isExternalRef(p
))
284 getRangeFromToken(aRange2
, p
, bExternal
);
286 if (bExternal
&& nFileId
!= p
->GetIndex())
287 // different external file
290 if (aRange
.Intersects(aRange2
))
298 class JoinRefTokenRanges
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
);
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
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.
334 T nMin
= nMin1
< nMin2
? nMin1
: nMin2
;
335 T nMax
= nMax1
> nMax2
? nMax1
: nMax2
;
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
))
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
374 if (bExternal
!= ScRefTokenHelper::isExternalRef(pOldToken
))
375 // External and internal refs don't mix.
380 if (nFileId
!= pOldToken
->GetIndex())
381 // Different external files.
384 if (aTabName
!= pOldToken
->GetString())
385 // Different table names.
389 ScComplexRefData aOldData
;
390 if (!ScRefTokenHelper::getDoubleRefDataFromToken(aOldData
, pOldToken
))
393 if (aData
.Ref1
.nTab
!= aOldData
.Ref1
.nTab
|| aData
.Ref2
.nTab
!= aOldData
.Ref2
.nTab
)
394 // Sheet ranges differ.
397 if (isContained(aOldData
, aData
))
398 // This new range is part of an existing range. Skip it.
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;
407 bJoinRanges
= overlaps(
408 aData
.Ref1
.nCol
, aData
.Ref2
.nCol
, aOldData
.Ref1
.nCol
, aOldData
.Ref2
.nCol
,
409 aNewData
.Ref1
.nCol
, aNewData
.Ref2
.nCol
);
413 bJoinRanges
= overlaps(
414 aData
.Ref1
.nRow
, aData
.Ref2
.nRow
, aOldData
.Ref1
.nRow
, aOldData
.Ref2
.nRow
,
415 aNewData
.Ref1
.nRow
, aNewData
.Ref2
.nRow
);
421 pOldToken
.reset(new ScExternalDoubleRefToken(nFileId
, aTabName
, aNewData
));
423 pOldToken
.reset(new ScDoubleRefToken(aNewData
));
432 if (rTokens
.size() == 1)
433 // There is only one left. No need to do more joining.
436 // Pop the last token from the list, and keep joining recursively.
437 ScSharedTokenRef p
= rTokens
.back();
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())
459 case svExternalSingleRef
:
461 const ScSingleRefData
& r
= pToken
->GetSingleRef();
463 rData
.Ref1
.SetFlag3D(true);
465 rData
.Ref2
.SetFlag3D(false); // Don't display sheet name on second reference.
469 case svExternalDoubleRef
:
470 rData
= pToken
->GetDoubleRef();
473 // Not a reference token. Bail out.
479 ScSharedTokenRef
ScRefTokenHelper::createRefToken(const ScAddress
& rAddr
)
481 ScSingleRefData aRefData
;
482 aRefData
.InitAddress(rAddr
);
483 ScSharedTokenRef
pRef(new ScSingleRefToken(aRefData
));
487 ScSharedTokenRef
ScRefTokenHelper::createRefToken(const ScRange
& rRange
)
489 ScComplexRefData aRefData
;
490 aRefData
.InitRange(rRange
);
491 ScSharedTokenRef
pRef(new ScDoubleRefToken(aRefData
));