KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > text > correction > JavaCorrectionAssistant


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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
12 package org.eclipse.jdt.internal.ui.text.correction;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Iterator JavaDoc;
16
17 import org.eclipse.core.runtime.Assert;
18
19 import org.eclipse.swt.graphics.Color;
20 import org.eclipse.swt.graphics.Point;
21 import org.eclipse.swt.graphics.RGB;
22 import org.eclipse.swt.widgets.Shell;
23
24 import org.eclipse.jface.internal.text.html.HTMLTextPresenter;
25 import org.eclipse.jface.preference.IPreferenceStore;
26 import org.eclipse.jface.preference.PreferenceConverter;
27
28 import org.eclipse.jface.text.BadLocationException;
29 import org.eclipse.jface.text.DefaultInformationControl;
30 import org.eclipse.jface.text.IDocument;
31 import org.eclipse.jface.text.IInformationControl;
32 import org.eclipse.jface.text.IInformationControlCreator;
33 import org.eclipse.jface.text.IRegion;
34 import org.eclipse.jface.text.ITextViewer;
35 import org.eclipse.jface.text.Position;
36 import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
37 import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
38 import org.eclipse.jface.text.source.Annotation;
39 import org.eclipse.jface.text.source.IAnnotationModel;
40 import org.eclipse.jface.text.source.ISourceViewer;
41
42 import org.eclipse.ui.IEditorPart;
43 import org.eclipse.ui.texteditor.IDocumentProvider;
44 import org.eclipse.ui.texteditor.ITextEditor;
45
46 import org.eclipse.jdt.core.ICompilationUnit;
47 import org.eclipse.jdt.core.IJavaElement;
48
49 import org.eclipse.jdt.ui.JavaUI;
50 import org.eclipse.jdt.ui.PreferenceConstants;
51 import org.eclipse.jdt.ui.text.IColorManager;
52 import org.eclipse.jdt.ui.text.JavaTextTools;
53
54 import org.eclipse.jdt.internal.ui.JavaPlugin;
55 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
56
57
58 public class JavaCorrectionAssistant extends QuickAssistAssistant {
59
60     private ITextViewer fViewer;
61     private ITextEditor fEditor;
62     private Position fPosition;
63     private Annotation[] fCurrentAnnotations;
64
65     private QuickAssistLightBulbUpdater fLightBulbUpdater;
66
67
68     /**
69      * Constructor for JavaCorrectionAssistant.
70      */

71     public JavaCorrectionAssistant(ITextEditor editor) {
72         super();
73         Assert.isNotNull(editor);
74         fEditor= editor;
75
76         JavaCorrectionProcessor processor= new JavaCorrectionProcessor(this);
77
78         setQuickAssistProcessor(processor);
79
80         setInformationControlCreator(getInformationControlCreator());
81
82         JavaTextTools textTools= JavaPlugin.getDefault().getJavaTextTools();
83         IColorManager manager= textTools.getColorManager();
84
85         IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
86
87         Color c= getColor(store, PreferenceConstants.CODEASSIST_PROPOSALS_FOREGROUND, manager);
88         setProposalSelectorForeground(c);
89
90         c= getColor(store, PreferenceConstants.CODEASSIST_PROPOSALS_BACKGROUND, manager);
91         setProposalSelectorBackground(c);
92     }
93
94     public IEditorPart getEditor() {
95         return fEditor;
96     }
97
98
99     private IInformationControlCreator getInformationControlCreator() {
100         return new IInformationControlCreator() {
101             public IInformationControl createInformationControl(Shell parent) {
102                 return new DefaultInformationControl(parent, new HTMLTextPresenter());
103             }
104         };
105     }
106
107     private static Color getColor(IPreferenceStore store, String JavaDoc key, IColorManager manager) {
108         RGB rgb= PreferenceConverter.getColor(store, key);
109         return manager.getColor(rgb);
110     }
111
112     /* (non-Javadoc)
113      * @see org.eclipse.jface.text.contentassist.IContentAssistant#install(org.eclipse.jface.text.ITextViewer)
114      */

115     public void install(ISourceViewer sourceViewer) {
116         super.install(sourceViewer);
117         fViewer= sourceViewer;
118
119         fLightBulbUpdater= new QuickAssistLightBulbUpdater(fEditor, sourceViewer);
120         fLightBulbUpdater.install();
121     }
122
123
124
125     /* (non-Javadoc)
126      * @see org.eclipse.jface.text.contentassist.ContentAssistant#uninstall()
127      */

128     public void uninstall() {
129         if (fLightBulbUpdater != null) {
130             fLightBulbUpdater.uninstall();
131             fLightBulbUpdater= null;
132         }
133         super.uninstall();
134     }
135
136     /*
137      * @see org.eclipse.jface.text.quickassist.QuickAssistAssistant#showPossibleQuickAssists()
138      * @since 3.2
139      */

140
141     /**
142      * Show completions at caret position. If current
143      * position does not contain quick fixes look for
144      * next quick fix on same line by moving from left
145      * to right and restarting at end of line if the
146      * beginning of the line is reached.
147      *
148      * @see IQuickAssistAssistant#showPossibleQuickAssists()
149      */

150     public String JavaDoc showPossibleQuickAssists() {
151         fPosition= null;
152         fCurrentAnnotations= null;
153         
154         if (fViewer == null || fViewer.getDocument() == null)
155             // Let superclass deal with this
156
return super.showPossibleQuickAssists();
157
158
159         ArrayList JavaDoc resultingAnnotations= new ArrayList JavaDoc(20);
160         try {
161             Point selectedRange= fViewer.getSelectedRange();
162             int currOffset= selectedRange.x;
163             int currLength= selectedRange.y;
164             boolean goToClosest= (currLength == 0);
165             
166             int newOffset= collectQuickFixableAnnotations(fEditor, currOffset, goToClosest, resultingAnnotations);
167             if (newOffset != currOffset) {
168                 storePosition(currOffset, currLength);
169                 fViewer.setSelectedRange(newOffset, 0);
170                 fViewer.revealRange(newOffset, 0);
171             }
172         } catch (BadLocationException e) {
173             JavaPlugin.log(e);
174         }
175         fCurrentAnnotations= (Annotation[]) resultingAnnotations.toArray(new Annotation[resultingAnnotations.size()]);
176
177         return super.showPossibleQuickAssists();
178     }
179     
180     
181     private static IRegion getRegionOfInterest(ITextEditor editor, int invocationLocation) throws BadLocationException {
182         IDocumentProvider documentProvider= editor.getDocumentProvider();
183         if (documentProvider == null) {
184             return null;
185         }
186         IDocument document= documentProvider.getDocument(editor.getEditorInput());
187         if (document == null) {
188             return null;
189         }
190         return document.getLineInformationOfOffset(invocationLocation);
191     }
192     
193     public static int collectQuickFixableAnnotations(ITextEditor editor, int invocationLocation, boolean goToClosest, ArrayList JavaDoc resultingAnnotations) throws BadLocationException {
194         IAnnotationModel model= JavaUI.getDocumentProvider().getAnnotationModel(editor.getEditorInput());
195         if (model == null) {
196             return invocationLocation;
197         }
198         
199         ensureUpdatedAnnotations(editor);
200         
201         Iterator JavaDoc iter= model.getAnnotationIterator();
202         if (goToClosest) {
203             IRegion lineInfo= getRegionOfInterest(editor, invocationLocation);
204             if (lineInfo == null) {
205                 return invocationLocation;
206             }
207             int rangeStart= lineInfo.getOffset();
208             int rangeEnd= rangeStart + lineInfo.getLength();
209             
210             ArrayList JavaDoc allAnnotations= new ArrayList JavaDoc();
211             ArrayList JavaDoc allPositions= new ArrayList JavaDoc();
212             int bestOffset= Integer.MAX_VALUE;
213             while (iter.hasNext()) {
214                 Annotation annot= (Annotation) iter.next();
215                 if (JavaCorrectionProcessor.isQuickFixableType(annot)) {
216                     Position pos= model.getPosition(annot);
217                     if (pos != null && isInside(pos.offset, rangeStart, rangeEnd)) { // inside our range?
218
allAnnotations.add(annot);
219                         allPositions.add(pos);
220                         bestOffset= processAnnotation(annot, pos, invocationLocation, bestOffset);
221                     }
222                 }
223             }
224             if (bestOffset == Integer.MAX_VALUE) {
225                 return invocationLocation;
226             }
227             for (int i= 0; i < allPositions.size(); i++) {
228                 Position pos= (Position) allPositions.get(i);
229                 if (isInside(bestOffset, pos.offset, pos.offset + pos.length)) {
230                     resultingAnnotations.add(allAnnotations.get(i));
231                 }
232             }
233             return bestOffset;
234         } else {
235             while (iter.hasNext()) {
236                 Annotation annot= (Annotation) iter.next();
237                 if (JavaCorrectionProcessor.isQuickFixableType(annot)) {
238                     Position pos= model.getPosition(annot);
239                     if (pos != null && isInside(invocationLocation, pos.offset, pos.offset + pos.length)) {
240                         resultingAnnotations.add(annot);
241                     }
242                 }
243             }
244             return invocationLocation;
245         }
246     }
247
248     private static void ensureUpdatedAnnotations(ITextEditor editor) {
249         Object JavaDoc inputElement= editor.getEditorInput().getAdapter(IJavaElement.class);
250         if (inputElement instanceof ICompilationUnit) {
251             JavaPlugin.getDefault().getASTProvider().getAST((ICompilationUnit) inputElement, ASTProvider.WAIT_ACTIVE_ONLY, null);
252         }
253     }
254
255     private static int processAnnotation(Annotation annot, Position pos, int invocationLocation, int bestOffset) {
256         int posBegin= pos.offset;
257         int posEnd= posBegin + pos.length;
258         if (isInside(invocationLocation, posBegin, posEnd)) { // covers invocation location?
259
return invocationLocation;
260         } else if (bestOffset != invocationLocation) {
261             int newClosestPosition= computeBestOffset(posBegin, invocationLocation, bestOffset);
262             if (newClosestPosition != -1) {
263                 if (newClosestPosition != bestOffset) { // new best
264
if (JavaCorrectionProcessor.hasCorrections(annot)) { // only jump to it if there are proposals
265
return newClosestPosition;
266                     }
267                 }
268             }
269         }
270         return bestOffset;
271     }
272
273
274     private static boolean isInside(int offset, int start, int end) {
275         return offset == start || offset == end || (offset > start && offset < end); // make sure to handle 0-length ranges
276
}
277
278     /**
279      * Computes and returns the invocation offset given a new
280      * position, the initial offset and the best invocation offset
281      * found so far.
282      * <p>
283      * The closest offset to the left of the initial offset is the
284      * best. If there is no offset on the left, the closest on the
285      * right is the best.</p>
286      * @return -1 is returned if the given offset is not closer or the new best offset
287      */

288     private static int computeBestOffset(int newOffset, int invocationLocation, int bestOffset) {
289         if (newOffset <= invocationLocation) {
290             if (bestOffset > invocationLocation) {
291                 return newOffset; // closest was on the right, prefer on the left
292
} else if (bestOffset <= newOffset) {
293                 return newOffset; // we are closer or equal
294
}
295             return -1; // further away
296
}
297
298         if (newOffset <= bestOffset)
299             return newOffset; // we are closer or equal
300

301         return -1; // further away
302
}
303
304     /*
305      * @see org.eclipse.jface.text.contentassist.ContentAssistant#possibleCompletionsClosed()
306      */

307     protected void possibleCompletionsClosed() {
308         super.possibleCompletionsClosed();
309         restorePosition();
310     }
311
312     private void storePosition(int currOffset, int currLength) {
313         fPosition= new Position(currOffset, currLength);
314     }
315
316     private void restorePosition() {
317         if (fPosition != null && !fPosition.isDeleted() && fViewer.getDocument() != null) {
318             fViewer.setSelectedRange(fPosition.offset, fPosition.length);
319             fViewer.revealRange(fPosition.offset, fPosition.length);
320         }
321         fPosition= null;
322     }
323
324     /**
325      * Returns true if the last invoked completion was called with an updated offset.
326      */

327     public boolean isUpdatedOffset() {
328         return fPosition != null;
329     }
330
331     /**
332      * Returns the annotations at the current offset
333      */

334     public Annotation[] getAnnotationsAtOffset() {
335         return fCurrentAnnotations;
336     }
337 }
338
Popular Tags