1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "reffind.hxx"
22 #include "compiler.hxx"
23 #include "document.hxx"
28 // Include colon; addresses in range reference are handled individually.
29 const sal_Unicode pDelimiters
[] = {
30 '=','(',')','+','-','*','/','^','&',' ','{','}','<','>',':', 0
33 inline bool IsText( sal_Unicode c
)
35 bool bFound
= ScGlobal::UnicodeStrChr( pDelimiters
, c
);
37 // This is one of delimiters, therefore not text.
40 // argument separator is configurable.
41 const sal_Unicode sep
= ScCompiler::GetNativeSymbolChar(ocSep
);
45 inline bool IsText( bool& bQuote
, sal_Unicode c
)
59 * Find first character position that is considered text. A character is
60 * considered a text when it's within the ascii range and when it's not a
63 sal_Int32
FindStartPos(const sal_Unicode
* p
, sal_Int32 nStartPos
, sal_Int32 nEndPos
)
65 while (nStartPos
<= nEndPos
&& !IsText(p
[nStartPos
]))
71 sal_Int32
FindEndPosA1(const sal_Unicode
* p
, sal_Int32 nStartPos
, sal_Int32 nEndPos
)
74 sal_Int32 nNewEnd
= nStartPos
;
75 while (nNewEnd
<= nEndPos
&& IsText(bQuote
, p
[nNewEnd
]))
81 sal_Int32
FindEndPosR1C1(const sal_Unicode
* p
, sal_Int32 nStartPos
, sal_Int32 nEndPos
)
83 sal_Int32 nNewEnd
= nStartPos
;
85 for (; nNewEnd
<= nEndPos
; ++p
, ++nNewEnd
)
89 // Skip until the closing quote.
90 for (; nNewEnd
<= nEndPos
; ++p
, ++nNewEnd
)
93 if (nNewEnd
> nEndPos
)
98 // Skip until the closing braket.
99 for (; nNewEnd
<= nEndPos
; ++p
, ++nNewEnd
)
102 if (nNewEnd
> nEndPos
)
105 else if (!IsText(*p
))
113 * Find last character position that is considred text, from the specified
116 sal_Int32
FindEndPos(const sal_Unicode
* p
, sal_Int32 nStartPos
, sal_Int32 nEndPos
,
117 formula::FormulaGrammar::AddressConvention eConv
)
121 case formula::FormulaGrammar::CONV_XL_R1C1
:
122 return FindEndPosR1C1(p
, nStartPos
, nEndPos
);
123 case formula::FormulaGrammar::CONV_OOO
:
124 case formula::FormulaGrammar::CONV_XL_A1
:
126 return FindEndPosA1(p
, nStartPos
, nEndPos
);
130 void ExpandToTextA1(const sal_Unicode
* p
, sal_Int32 nLen
, sal_Int32
& rStartPos
, sal_Int32
& rEndPos
)
132 while (rStartPos
> 0 && IsText(p
[rStartPos
- 1]) )
136 while (rEndPos
+1 < nLen
&& IsText(p
[rEndPos
+ 1]) )
140 void ExpandToTextR1C1(const sal_Unicode
* p
, sal_Int32 nLen
, sal_Int32
& rStartPos
, sal_Int32
& rEndPos
)
142 // move back the start position to the first text character.
145 for (--rStartPos
; rStartPos
> 0; --rStartPos
)
147 sal_Unicode c
= p
[rStartPos
];
150 // Skip until the opening quote.
151 for (--rStartPos
; rStartPos
> 0; --rStartPos
)
162 // Skip until the opening braket.
163 for (--rStartPos
; rStartPos
> 0; --rStartPos
)
180 // move forward the end position to the last text character.
181 rEndPos
= FindEndPosR1C1(p
, rEndPos
, nLen
-1);
184 void ExpandToText(const sal_Unicode
* p
, sal_Int32 nLen
, sal_Int32
& rStartPos
, sal_Int32
& rEndPos
,
185 formula::FormulaGrammar::AddressConvention eConv
)
189 case formula::FormulaGrammar::CONV_XL_R1C1
:
190 ExpandToTextR1C1(p
, nLen
, rStartPos
, rEndPos
);
192 case formula::FormulaGrammar::CONV_OOO
:
193 case formula::FormulaGrammar::CONV_XL_A1
:
195 ExpandToTextA1(p
, nLen
, rStartPos
, rEndPos
);
201 ScRefFinder::ScRefFinder(
202 const OUString
& rFormula
, const ScAddress
& rPos
,
203 ScDocument
* pDoc
, formula::FormulaGrammar::AddressConvention eConvP
) :
214 ScRefFinder::~ScRefFinder()
218 static sal_uInt16
lcl_NextFlags( sal_uInt16 nOld
)
220 sal_uInt16 nNew
= nOld
& 7; // die drei Abs-Flags
221 nNew
= ( nNew
- 1 ) & 7; // weiterzaehlen
223 if (!(nOld
& SCA_TAB_3D
))
224 nNew
&= ~SCA_TAB_ABSOLUTE
; // not 3D -> never absolute!
226 return ( nOld
& 0xfff8 ) | nNew
;
229 void ScRefFinder::ToggleRel( sal_Int32 nStartPos
, sal_Int32 nEndPos
)
231 sal_Int32 nLen
= maFormula
.getLength();
234 const sal_Unicode
* pSource
= maFormula
.getStr(); // for quick access
236 // expand selection, and instead of selection start- and end-index
238 if ( nEndPos
< nStartPos
)
239 ::std::swap(nEndPos
, nStartPos
);
241 ExpandToText(pSource
, nLen
, nStartPos
, nEndPos
, meConv
);
249 sal_Int32 nLoopStart
= nStartPos
;
250 while ( nLoopStart
<= nEndPos
)
252 // Determine the stard and end positions of a text segment. Note that
253 // the end position returned from FindEndPos may be one position after
254 // the last character position in case of the last segment.
255 sal_Int32 nEStart
= FindStartPos(pSource
, nLoopStart
, nEndPos
);
256 sal_Int32 nEEnd
= FindEndPos(pSource
, nEStart
, nEndPos
, meConv
);
258 aSep
= maFormula
.copy(nLoopStart
, nEStart
-nLoopStart
);
259 if (nEEnd
< maFormula
.getLength())
260 aExpr
= maFormula
.copy(nEStart
, nEEnd
-nEStart
);
262 aExpr
= maFormula
.copy(nEStart
);
264 // Check the validity of the expression, and toggle the relative flag.
265 ScAddress::Details
aDetails(meConv
, maPos
.Row(), maPos
.Col());
266 sal_uInt16 nResult
= aAddr
.Parse(aExpr
, mpDoc
, aDetails
);
267 if ( nResult
& SCA_VALID
)
269 sal_uInt16 nFlags
= lcl_NextFlags( nResult
);
270 aExpr
= aAddr
.Format(nFlags
, mpDoc
, aDetails
);
272 sal_Int32 nAbsStart
= nStartPos
+aResult
.getLength()+aSep
.getLength();
274 if (!mnFound
) // first reference ?
275 mnSelStart
= nAbsStart
;
276 mnSelEnd
= nAbsStart
+ aExpr
.getLength(); // selection, no indices
288 OUString aTotal
= maFormula
.copy(0, nStartPos
);
290 if (nEndPos
< maFormula
.getLength()-1)
291 aTotal
+= maFormula
.copy(nEndPos
+1);
296 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */