001: /*******************************************************************************
002: * Copyright (c) 2000, 2005 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.examples.javaeditor.java;
011:
012: import org.eclipse.jface.text.BadLocationException;
013: import org.eclipse.jface.text.IDocument;
014: import org.eclipse.jface.text.ITextDoubleClickStrategy;
015: import org.eclipse.jface.text.ITextViewer;
016:
017: /**
018: * Double click strategy aware of Java identifier syntax rules.
019: */
020: public class JavaDoubleClickSelector implements
021: ITextDoubleClickStrategy {
022:
023: protected ITextViewer fText;
024: protected int fPos;
025: protected int fStartPos;
026: protected int fEndPos;
027:
028: protected static char[] fgBrackets = { '{', '}', '(', ')', '[',
029: ']', '"', '"' };
030:
031: /*
032: * Create a JavaDoubleClickSelector.
033: */
034: public JavaDoubleClickSelector() {
035: super ();
036: }
037:
038: /* (non-Javadoc)
039: * Method declared on ITextDoubleClickStrategy
040: */
041: public void doubleClicked(ITextViewer text) {
042:
043: fPos = text.getSelectedRange().x;
044:
045: if (fPos < 0)
046: return;
047:
048: fText = text;
049:
050: if (!selectBracketBlock())
051: selectWord();
052: }
053:
054: /**
055: * Match the brackets at the current selection. Return <code>true</code> if successful,
056: * <code>false</code> otherwise.
057: *
058: * @return <code>true</code> if brackets match, <code>false</code> otherwise
059: */
060: protected boolean matchBracketsAt() {
061:
062: char prevChar, nextChar;
063:
064: int i;
065: int bracketIndex1 = fgBrackets.length;
066: int bracketIndex2 = fgBrackets.length;
067:
068: fStartPos = -1;
069: fEndPos = -1;
070:
071: // get the chars preceding and following the start position
072: try {
073:
074: IDocument doc = fText.getDocument();
075:
076: prevChar = doc.getChar(fPos - 1);
077: nextChar = doc.getChar(fPos);
078:
079: // is the char either an open or close bracket?
080: for (i = 0; i < fgBrackets.length; i = i + 2) {
081: if (prevChar == fgBrackets[i]) {
082: fStartPos = fPos - 1;
083: bracketIndex1 = i;
084: }
085: }
086: for (i = 1; i < fgBrackets.length; i = i + 2) {
087: if (nextChar == fgBrackets[i]) {
088: fEndPos = fPos;
089: bracketIndex2 = i;
090: }
091: }
092:
093: if (fStartPos > -1 && bracketIndex1 < bracketIndex2) {
094: fEndPos = searchForClosingBracket(fStartPos, prevChar,
095: fgBrackets[bracketIndex1 + 1], doc);
096: if (fEndPos > -1)
097: return true;
098: fStartPos = -1;
099: } else if (fEndPos > -1) {
100: fStartPos = searchForOpenBracket(fEndPos,
101: fgBrackets[bracketIndex2 - 1], nextChar, doc);
102: if (fStartPos > -1)
103: return true;
104: fEndPos = -1;
105: }
106:
107: } catch (BadLocationException x) {
108: }
109:
110: return false;
111: }
112:
113: /**
114: * Select the word at the current selection location. Return <code>true</code> if successful,
115: * <code>false</code> otherwise.
116: *
117: * @return <code>true</code> if a word can be found at the current selection location, <code>false</code> otherwise
118: */
119: protected boolean matchWord() {
120:
121: IDocument doc = fText.getDocument();
122:
123: try {
124:
125: int pos = fPos;
126: char c;
127:
128: while (pos >= 0) {
129: c = doc.getChar(pos);
130: if (!Character.isJavaIdentifierPart(c))
131: break;
132: --pos;
133: }
134:
135: fStartPos = pos;
136:
137: pos = fPos;
138: int length = doc.getLength();
139:
140: while (pos < length) {
141: c = doc.getChar(pos);
142: if (!Character.isJavaIdentifierPart(c))
143: break;
144: ++pos;
145: }
146:
147: fEndPos = pos;
148:
149: return true;
150:
151: } catch (BadLocationException x) {
152: }
153:
154: return false;
155: }
156:
157: /**
158: * Returns the position of the closing bracket after <code>startPosition</code>.
159: *
160: * @param startPosition - the beginning position
161: * @param openBracket - the character that represents the open bracket
162: * @param closeBracket - the character that represents the close bracket
163: * @param document - the document being searched
164: * @return the location of the closing bracket.
165: * @throws BadLocationException in case <code>startPosition</code> is invalid in the document
166: */
167: protected int searchForClosingBracket(int startPosition,
168: char openBracket, char closeBracket, IDocument document)
169: throws BadLocationException {
170: int stack = 1;
171: int closePosition = startPosition + 1;
172: int length = document.getLength();
173: char nextChar;
174:
175: while (closePosition < length && stack > 0) {
176: nextChar = document.getChar(closePosition);
177: if (nextChar == openBracket && nextChar != closeBracket)
178: stack++;
179: else if (nextChar == closeBracket)
180: stack--;
181: closePosition++;
182: }
183:
184: if (stack == 0)
185: return closePosition - 1;
186: return -1;
187:
188: }
189:
190: /**
191: * Returns the position of the open bracket before <code>startPosition</code>.
192: *
193: * @param startPosition - the beginning position
194: * @param openBracket - the character that represents the open bracket
195: * @param closeBracket - the character that represents the close bracket
196: * @param document - the document being searched
197: * @return the location of the starting bracket.
198: * @throws BadLocationException in case <code>startPosition</code> is invalid in the document
199: */
200: protected int searchForOpenBracket(int startPosition,
201: char openBracket, char closeBracket, IDocument document)
202: throws BadLocationException {
203: int stack = 1;
204: int openPos = startPosition - 1;
205: char nextChar;
206:
207: while (openPos >= 0 && stack > 0) {
208: nextChar = document.getChar(openPos);
209: if (nextChar == closeBracket && nextChar != openBracket)
210: stack++;
211: else if (nextChar == openBracket)
212: stack--;
213: openPos--;
214: }
215:
216: if (stack == 0)
217: return openPos + 1;
218: return -1;
219: }
220:
221: /**
222: * Select the area between the selected bracket and the closing bracket.
223: *
224: * @return <code>true</code> if selection was successful, <code>false</code> otherwise
225: */
226: protected boolean selectBracketBlock() {
227: if (matchBracketsAt()) {
228:
229: if (fStartPos == fEndPos)
230: fText.setSelectedRange(fStartPos, 0);
231: else
232: fText.setSelectedRange(fStartPos + 1, fEndPos
233: - fStartPos - 1);
234:
235: return true;
236: }
237: return false;
238: }
239:
240: /**
241: * Select the word at the current selection.
242: */
243: protected void selectWord() {
244: if (matchWord()) {
245:
246: if (fStartPos == fEndPos)
247: fText.setSelectedRange(fStartPos, 0);
248: else
249: fText.setSelectedRange(fStartPos + 1, fEndPos
250: - fStartPos - 1);
251: }
252: }
253: }
|