KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > text > java > JavaDoubleClickSelector


1 /*******************************************************************************
2  * Copyright (c) 2000, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.ui.text.java;
12
13
14 import org.eclipse.jface.text.BadLocationException;
15 import org.eclipse.jface.text.IDocument;
16 import org.eclipse.jface.text.IRegion;
17 import org.eclipse.jface.text.ITextDoubleClickStrategy;
18 import org.eclipse.jface.text.ITextViewer;
19 import org.eclipse.jface.text.Region;
20
21 import org.eclipse.jdt.core.JavaCore;
22
23 import org.eclipse.jdt.internal.ui.text.ISourceVersionDependent;
24 import org.eclipse.jdt.internal.ui.text.JavaPairMatcher;
25
26 /**
27  * Double click strategy aware of Java identifier syntax rules.
28  */

29 public class JavaDoubleClickSelector implements ITextDoubleClickStrategy, ISourceVersionDependent {
30
31     /**
32      * Detects java words depending on the source level. In 1.4 mode, detects
33      * <code>[[:ID:]]*</code>. In 1.5 mode, it also detects
34      * <code>@\s*[[:IDS:]][[:ID:]]*</code>.
35      *
36      * Character class definitions:
37      * <dl>
38      * <dt>[[:IDS:]]</dt><dd>a java identifier start character</dd>
39      * <dt>[[:ID:]]</dt><dd>a java identifier part character</dd>
40      * <dt>\s</dt><dd>a white space character</dd>
41      * <dt>@</dt><dd>the at symbol</dd>
42      * </dl>
43      *
44      * @since 3.1
45      */

46     private static final class AtJavaIdentifierDetector implements ISourceVersionDependent {
47
48         private boolean fSelectAnnotations;
49
50         private static final int UNKNOWN= -1;
51
52         /* states */
53         private static final int WS= 0;
54         private static final int ID= 1;
55         private static final int IDS= 2;
56         private static final int AT= 3;
57
58         /* directions */
59         private static final int FORWARD= 0;
60         private static final int BACKWARD= 1;
61
62         /** The current state. */
63         private int fState;
64         /**
65          * The state at the anchor (if already detected by going the other way),
66          * or <code>UNKNOWN</code>.
67          */

68         private int fAnchorState;
69         /** The current direction. */
70         private int fDirection;
71         /** The start of the detected word. */
72         private int fStart;
73         /** The end of the word. */
74         private int fEnd;
75
76         /**
77          * Initializes the detector at offset <code>anchor</code>.
78          *
79          * @param anchor the offset of the double click
80          */

81         private void setAnchor(int anchor) {
82             fState= UNKNOWN;
83             fAnchorState= UNKNOWN;
84             fDirection= UNKNOWN;
85             fStart= anchor;
86             fEnd= anchor - 1;
87         }
88
89         private boolean isAt(char c) {
90             return fSelectAnnotations && c == '@';
91         }
92
93         private boolean isIdentifierStart(char c) {
94             return Character.isJavaIdentifierStart(c);
95         }
96
97         private boolean isIdentifierPart(char c) {
98             return Character.isJavaIdentifierPart(c);
99         }
100
101         private boolean isWhitespace(char c) {
102             return fSelectAnnotations && Character.isWhitespace(c);
103         }
104
105         /*
106          * @see org.eclipse.jdt.internal.ui.text.ISourceVersionDependent#setSourceVersion(java.lang.String)
107          */

108         public void setSourceVersion(String JavaDoc version) {
109             if (JavaCore.VERSION_1_5.compareTo(version) <= 0)
110                 fSelectAnnotations= true;
111             else
112                 fSelectAnnotations= false;
113         }
114
115         /**
116          * Try to add a character to the word going backward. Only call after
117          * forward calls!
118          *
119          * @param c the character to add
120          * @param offset the offset of the character
121          * @return <code>true</code> if further characters may be added to the
122          * word
123          */

124         private boolean backward(char c, int offset) {
125             checkDirection(BACKWARD);
126             switch (fState) {
127                 case AT:
128                     return false;
129                 case IDS:
130                     if (isAt(c)) {
131                         fStart= offset;
132                         fState= AT;
133                         return false;
134                     }
135                     if (isWhitespace(c)) {
136                         fState= WS;
137                         return true;
138                     }
139                     // fall through ID
140
case ID:
141                     if (isIdentifierStart(c)) {
142                         fStart= offset;
143                         fState= IDS;
144                         return true;
145                     }
146                     if (isIdentifierPart(c)) {
147                         fStart= offset;
148                         fState= ID;
149                         return true;
150                     }
151                     return false;
152                 case WS:
153                     if (isWhitespace(c)) {
154                         return true;
155                     }
156                     if (isAt(c)) {
157                         fStart= offset;
158                         fState= AT;
159                         return false;
160                     }
161                     return false;
162                 default:
163                     return false;
164             }
165         }
166
167         /**
168          * Try to add a character to the word going forward.
169          *
170          * @param c the character to add
171          * @param offset the offset of the character
172          * @return <code>true</code> if further characters may be added to the
173          * word
174          */

175         private boolean forward(char c, int offset) {
176             checkDirection(FORWARD);
177             switch (fState) {
178                 case WS:
179                 case AT:
180                     if (isWhitespace(c)) {
181                         fState= WS;
182                         return true;
183                     }
184                     if (isIdentifierStart(c)) {
185                         fEnd= offset;
186                         fState= IDS;
187                         return true;
188                     }
189                     return false;
190                 case IDS:
191                 case ID:
192                     if (isIdentifierStart(c)) {
193                         fEnd= offset;
194                         fState= IDS;
195                         return true;
196                     }
197                     if (isIdentifierPart(c)) {
198                         fEnd= offset;
199                         fState= ID;
200                         return true;
201                     }
202                     return false;
203                 case UNKNOWN:
204                     if (isIdentifierStart(c)) {
205                         fEnd= offset;
206                         fState= IDS;
207                         fAnchorState= fState;
208                         return true;
209                     }
210                     if (isIdentifierPart(c)) {
211                         fEnd= offset;
212                         fState= ID;
213                         fAnchorState= fState;
214                         return true;
215                     }
216                     if (isWhitespace(c)) {
217                         fState= WS;
218                         fAnchorState= fState;
219                         return true;
220                     }
221                     if (isAt(c)) {
222                         fStart= offset;
223                         fState= AT;
224                         fAnchorState= fState;
225                         return true;
226                     }
227                     return false;
228                 default:
229                     return false;
230             }
231         }
232
233         /**
234          * If the direction changes, set state to be the previous anchor state.
235          *
236          * @param direction the new direction
237          */

238         private void checkDirection(int direction) {
239             if (fDirection == direction)
240                 return;
241
242             if (direction == FORWARD) {
243                 if (fStart <= fEnd)
244                     fState= fAnchorState;
245                 else
246                     fState= UNKNOWN;
247             } else if (direction == BACKWARD) {
248                 if (fEnd >= fStart)
249                     fState= fAnchorState;
250                 else
251                     fState= UNKNOWN;
252             }
253
254             fDirection= direction;
255         }
256
257         /**
258          * Returns the region containing <code>anchor</code> that is a java
259          * word.
260          *
261          * @param document the document from which to read characters
262          * @param anchor the offset around which to select a word
263          * @return the region describing a java word around <code>anchor</code>
264          */

265         public IRegion getWordSelection(IDocument document, int anchor) {
266
267             try {
268
269                 final int min= 0;
270                 final int max= document.getLength();
271                 setAnchor(anchor);
272
273                 char c;
274
275                 int offset= anchor;
276                 while (offset < max) {
277                     c= document.getChar(offset);
278                     if (!forward(c, offset))
279                         break;
280                     ++offset;
281                 }
282
283                 offset= anchor; // use to not select the previous word when right behind it
284
// offset= anchor - 1; // use to select the previous word when right behind it
285
while (offset >= min) {
286                     c= document.getChar(offset);
287                     if (!backward(c, offset))
288                         break;
289                     --offset;
290                 }
291
292                 return new Region(fStart, fEnd - fStart + 1);
293
294             } catch (BadLocationException x) {
295                 return new Region(anchor, 0);
296             }
297         }
298
299     }
300
301     protected static final char[] BRACKETS= {'{', '}', '(', ')', '[', ']', '<', '>' };
302     protected JavaPairMatcher fPairMatcher= new JavaPairMatcher(BRACKETS);
303     protected final AtJavaIdentifierDetector fWordDetector= new AtJavaIdentifierDetector();
304
305
306     public JavaDoubleClickSelector() {
307         super();
308     }
309
310     /**
311      * @see ITextDoubleClickStrategy#doubleClicked
312      */

313     public void doubleClicked(ITextViewer textViewer) {
314
315         int offset= textViewer.getSelectedRange().x;
316
317         if (offset < 0)
318             return;
319
320         IDocument document= textViewer.getDocument();
321
322         IRegion region= fPairMatcher.match(document, offset);
323         if (region != null && region.getLength() >= 2) {
324             textViewer.setSelectedRange(region.getOffset() + 1, region.getLength() - 2);
325         } else {
326             region= selectWord(document, offset);
327             textViewer.setSelectedRange(region.getOffset(), region.getLength());
328         }
329     }
330
331     protected IRegion selectWord(IDocument document, int anchor) {
332         return fWordDetector.getWordSelection(document, anchor);
333     }
334
335     /*
336      * @see org.eclipse.jdt.internal.ui.text.ISourceVersionDependent#setSourceVersion(java.lang.String)
337      */

338     public void setSourceVersion(String JavaDoc version) {
339         fPairMatcher.setSourceVersion(version);
340         fWordDetector.setSourceVersion(version);
341     }
342 }
343
Popular Tags