Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <string.h>
30 : :
31 : : #include "reffind.hxx"
32 : : #include "global.hxx"
33 : : #include "compiler.hxx"
34 : : #include "document.hxx"
35 : :
36 : : // STATIC DATA -----------------------------------------------------------
37 : :
38 : : namespace {
39 : :
40 : : // incl. Doppelpunkt -> Doppelte Referenzen werden einzeln behandelt
41 : : const sal_Unicode pDelimiters[] = {
42 : : '=','(',')','+','-','*','/','^','&',' ','{','}','<','>',':', 0
43 : : };
44 : :
45 : : // =======================================================================
46 : :
47 : 156 : inline bool IsText( sal_Unicode c )
48 : : {
49 : 156 : bool bFound = ScGlobal::UnicodeStrChr( pDelimiters, c );
50 [ + + ]: 156 : if (bFound)
51 : : // This is one of delimiters, therefore not text.
52 : 24 : return false;
53 : :
54 : : // argument separator is configurable.
55 : 132 : const sal_Unicode sep = ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
56 : 156 : return c != sep;
57 : : }
58 : :
59 : 60 : inline bool IsText( bool& bQuote, sal_Unicode c )
60 : : {
61 [ - + ]: 60 : if (c == '\'')
62 : : {
63 : 0 : bQuote = !bQuote;
64 : 0 : return true;
65 : : }
66 [ - + ]: 60 : if (bQuote)
67 : 0 : return true;
68 : :
69 : 60 : return IsText(c);
70 : : }
71 : :
72 : : /**
73 : : * Find first character position that is considered text. A character is
74 : : * considered a text when it's within the ascii range and when it's not a
75 : : * delimiter.
76 : : */
77 : 24 : xub_StrLen FindStartPos(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos)
78 : : {
79 [ + - ][ + + ]: 48 : while (nStartPos <= nEndPos && !IsText(p[nStartPos]))
[ + + ]
80 : 24 : ++nStartPos;
81 : :
82 : 24 : return nStartPos;
83 : : }
84 : :
85 : 12 : xub_StrLen FindEndPosA1(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos)
86 : : {
87 : 12 : bool bQuote = false;
88 : 12 : xub_StrLen nNewEnd = nStartPos;
89 [ + + ][ + - ]: 72 : while (nNewEnd <= nEndPos && IsText(bQuote, p[nNewEnd]))
[ + - ][ + + ]
90 : 60 : ++nNewEnd;
91 : :
92 : 12 : return nNewEnd;
93 : : }
94 : :
95 : 24 : xub_StrLen FindEndPosR1C1(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos)
96 : : {
97 : 24 : xub_StrLen nNewEnd = nStartPos;
98 : 24 : p = &p[nStartPos];
99 [ + + ]: 84 : for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
100 : : {
101 [ - + ]: 60 : if (*p == '\'')
102 : : {
103 : : // Skip until the closing quote.
104 [ # # ]: 0 : for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
105 [ # # ]: 0 : if (*p == '\'')
106 : 0 : break;
107 : : }
108 [ + + ]: 60 : else if (*p == '[')
109 : : {
110 : : // Skip until the closing braket.
111 [ + - ]: 60 : for (; nNewEnd <= nEndPos; ++p, ++nNewEnd)
112 [ + + ]: 48 : if (*p == ']')
113 : 12 : break;
114 : : }
115 [ - + ]: 48 : else if (!IsText(*p))
116 : 0 : break;
117 : : }
118 : :
119 : 24 : return nNewEnd;
120 : : }
121 : :
122 : : /**
123 : : * Find last character position that is considred text, from the specified
124 : : * start position.
125 : : */
126 : 24 : xub_StrLen FindEndPos(const sal_Unicode* p, xub_StrLen nStartPos, xub_StrLen nEndPos,
127 : : formula::FormulaGrammar::AddressConvention eConv)
128 : : {
129 [ + + ]: 24 : switch (eConv)
130 : : {
131 : : case formula::FormulaGrammar::CONV_XL_R1C1:
132 : 12 : return FindEndPosR1C1(p, nStartPos, nEndPos);
133 : : case formula::FormulaGrammar::CONV_OOO:
134 : : case formula::FormulaGrammar::CONV_XL_A1:
135 : : default:
136 : 24 : return FindEndPosA1(p, nStartPos, nEndPos);
137 : : }
138 : : }
139 : :
140 : 12 : void ExpandToTextA1(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos)
141 : : {
142 [ - + ][ # # ]: 12 : while (rStartPos > 0 && IsText(p[rStartPos - 1]) )
[ - + ]
143 : 0 : --rStartPos;
144 [ + - ]: 12 : if (rEndPos)
145 : 12 : --rEndPos;
146 [ - + ][ # # ]: 12 : while (rEndPos+1 < nLen && IsText(p[rEndPos + 1]) )
[ - + ]
147 : 0 : ++rEndPos;
148 : 12 : }
149 : :
150 : 12 : void ExpandToTextR1C1(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos)
151 : : {
152 : : // move back the start position to the first text character.
153 [ - + ]: 12 : if (rStartPos > 0)
154 : : {
155 [ # # ]: 0 : for (--rStartPos; rStartPos > 0; --rStartPos)
156 : : {
157 : 0 : sal_Unicode c = p[rStartPos];
158 [ # # ]: 0 : if (c == '\'')
159 : : {
160 : : // Skip until the opening quote.
161 [ # # ]: 0 : for (--rStartPos; rStartPos > 0; --rStartPos)
162 : : {
163 : 0 : c = p[rStartPos];
164 [ # # ]: 0 : if (c == '\'')
165 : 0 : break;
166 : : }
167 : : }
168 [ # # ]: 0 : else if (c == ']')
169 : : {
170 : : // Skip until the opening braket.
171 [ # # ]: 0 : for (--rStartPos; rStartPos > 0; --rStartPos)
172 : : {
173 [ # # ]: 0 : if (c == '[')
174 : 0 : break;
175 : : }
176 : : }
177 [ # # ]: 0 : else if (!IsText(c))
178 : : {
179 : 0 : ++rStartPos;
180 : 0 : break;
181 : : }
182 : : }
183 : : }
184 : :
185 : : // move forward the end position to the last text character.
186 : 12 : rEndPos = FindEndPosR1C1(p, rEndPos, nLen-1);
187 : 12 : }
188 : :
189 : 24 : void ExpandToText(const sal_Unicode* p, xub_StrLen nLen, xub_StrLen& rStartPos, xub_StrLen& rEndPos,
190 : : formula::FormulaGrammar::AddressConvention eConv)
191 : : {
192 [ + + ]: 24 : switch (eConv)
193 : : {
194 : : case formula::FormulaGrammar::CONV_XL_R1C1:
195 : 12 : ExpandToTextR1C1(p, nLen, rStartPos, rEndPos);
196 : 12 : break;
197 : : case formula::FormulaGrammar::CONV_OOO:
198 : : case formula::FormulaGrammar::CONV_XL_A1:
199 : : default:
200 : 12 : ExpandToTextA1(p, nLen, rStartPos, rEndPos);
201 : : }
202 : 24 : }
203 : :
204 : : }
205 : :
206 : 6 : ScRefFinder::ScRefFinder(
207 : : const String& rFormula, const ScAddress& rPos,
208 : : ScDocument* pDocument, formula::FormulaGrammar::AddressConvention eConvP) :
209 : : aFormula( rFormula ),
210 : : eConv( eConvP ),
211 : : pDoc( pDocument ),
212 : 6 : maPos(rPos)
213 : : {
214 : 6 : nSelStart = nSelEnd = nFound = 0;
215 : 6 : }
216 : :
217 : 6 : ScRefFinder::~ScRefFinder()
218 : : {
219 : 6 : }
220 : :
221 : 24 : sal_uInt16 lcl_NextFlags( sal_uInt16 nOld )
222 : : {
223 : 24 : sal_uInt16 nNew = nOld & 7; // die drei Abs-Flags
224 : 24 : nNew = ( nNew - 1 ) & 7; // weiterzaehlen
225 : :
226 [ + - ]: 24 : if (!(nOld & SCA_TAB_3D))
227 : 24 : nNew &= ~SCA_TAB_ABSOLUTE; // nicht 3D -> nie absolut!
228 : :
229 : 24 : return ( nOld & 0xfff8 ) | nNew;
230 : : }
231 : :
232 : 24 : void ScRefFinder::ToggleRel( xub_StrLen nStartPos, xub_StrLen nEndPos )
233 : : {
234 : 24 : xub_StrLen nLen = aFormula.Len();
235 [ + - ]: 24 : if (!nLen)
236 : 24 : return;
237 : 24 : const sal_Unicode* pSource = aFormula.GetBuffer(); // fuer schnellen Zugriff
238 : :
239 : : // Selektion erweitern, und statt Selektion Start- und Endindex
240 : :
241 [ - + ]: 24 : if ( nEndPos < nStartPos )
242 : 0 : ::std::swap(nEndPos, nStartPos);
243 : :
244 [ + - ]: 24 : ExpandToText(pSource, nLen, nStartPos, nEndPos, eConv);
245 : :
246 [ + - ]: 24 : String aResult;
247 [ + - ]: 24 : String aExpr;
248 [ + - ]: 24 : String aSep;
249 : 24 : ScAddress aAddr;
250 : 24 : nFound = 0;
251 : :
252 : 24 : xub_StrLen nLoopStart = nStartPos;
253 [ + + ]: 48 : while ( nLoopStart <= nEndPos )
254 : : {
255 : : // Determine the stard and end positions of a text segment.
256 [ + - ]: 24 : xub_StrLen nEStart = FindStartPos(pSource, nLoopStart, nEndPos);
257 [ + - ]: 24 : xub_StrLen nEEnd = FindEndPos(pSource, nEStart, nEndPos, eConv);
258 : :
259 [ + - ][ + - ]: 24 : aSep = aFormula.Copy( nLoopStart, nEStart-nLoopStart );
[ + - ]
260 [ + - ][ + - ]: 24 : aExpr = aFormula.Copy( nEStart, nEEnd-nEStart );
[ + - ]
261 : :
262 : : // Check the validity of the expression, and toggle the relative flag.
263 : 24 : ScAddress::Details aDetails(eConv, maPos.Row(), maPos.Col());
264 [ + - ]: 24 : sal_uInt16 nResult = aAddr.Parse(aExpr, pDoc, aDetails);
265 [ + - ]: 24 : if ( nResult & SCA_VALID )
266 : : {
267 : 24 : sal_uInt16 nFlags = lcl_NextFlags( nResult );
268 [ + - ]: 24 : aAddr.Format(aExpr, nFlags, pDoc, aDetails);
269 : :
270 : 24 : xub_StrLen nAbsStart = nStartPos+aResult.Len()+aSep.Len();
271 : :
272 [ + - ]: 24 : if (!nFound) // erste Referenz ?
273 : 24 : nSelStart = nAbsStart;
274 : 24 : nSelEnd = nAbsStart+aExpr.Len(); // Selektion, keine Indizes
275 : 24 : ++nFound;
276 : : }
277 : :
278 : : // zusammenbauen
279 : :
280 [ + - ]: 24 : aResult += aSep;
281 [ + - ]: 24 : aResult += aExpr;
282 : :
283 : 24 : nLoopStart = nEEnd;
284 : : }
285 : :
286 [ + - ]: 24 : String aTotal = aFormula.Copy( 0, nStartPos );
287 [ + - ]: 24 : aTotal += aResult;
288 [ + - ][ + - ]: 24 : aTotal += aFormula.Copy( nEndPos+1 );
[ + - ]
289 : :
290 [ + - ][ + - ]: 24 : aFormula = aTotal;
[ + - ][ + - ]
[ + - ]
291 : : }
292 : :
293 : :
294 : :
295 : :
296 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|