]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-after/ui/org/eclipse/jdt/internal/ui/text/correction/JavaCorrectionAssistant.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / ui / org / eclipse / jdt / internal / ui / text / correction / JavaCorrectionAssistant.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2012 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.correction;
12
13 import java.util.ArrayList;
14 import java.util.Iterator;
15
16 import org.eclipse.swt.graphics.Point;
17 import org.eclipse.swt.widgets.Shell;
18
19 import org.eclipse.core.runtime.Assert;
20 import org.eclipse.core.runtime.IStatus;
21
22 import org.eclipse.jface.text.BadLocationException;
23 import org.eclipse.jface.text.DefaultInformationControl;
24 import org.eclipse.jface.text.IDocument;
25 import org.eclipse.jface.text.IInformationControl;
26 import org.eclipse.jface.text.IInformationControlCreator;
27 import org.eclipse.jface.text.IRegion;
28 import org.eclipse.jface.text.ITextViewer;
29 import org.eclipse.jface.text.Position;
30 import org.eclipse.jface.text.contentassist.ContentAssistEvent;
31 import org.eclipse.jface.text.contentassist.ICompletionListener;
32 import org.eclipse.jface.text.contentassist.ICompletionProposal;
33 import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
34 import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
35 import org.eclipse.jface.text.source.Annotation;
36 import org.eclipse.jface.text.source.IAnnotationModel;
37 import org.eclipse.jface.text.source.ISourceViewer;
38
39 import org.eclipse.ui.IEditorPart;
40 import org.eclipse.ui.IWorkbenchPreferenceConstants;
41 import org.eclipse.ui.PlatformUI;
42 import org.eclipse.ui.keys.IBindingService;
43
44 import org.eclipse.ui.texteditor.IDocumentProvider;
45 import org.eclipse.ui.texteditor.ITextEditor;
46 import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
47
48 import org.eclipse.jdt.core.ICompilationUnit;
49 import org.eclipse.jdt.core.IJavaElement;
50
51 import org.eclipse.jdt.internal.corext.util.Messages;
52
53 import org.eclipse.jdt.ui.JavaUI;
54 import org.eclipse.jdt.ui.SharedASTProvider;
55 import org.eclipse.jdt.ui.text.JavaSourceViewerConfiguration;
56 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
57
58 import org.eclipse.jdt.internal.ui.JavaPlugin;
59
60
61 public class JavaCorrectionAssistant extends QuickAssistAssistant {
62
63         private ITextViewer fViewer;
64         private ITextEditor fEditor;
65         private Position fPosition;
66         private Annotation[] fCurrentAnnotations;
67
68         private QuickAssistLightBulbUpdater fLightBulbUpdater;
69         private boolean fIsCompletionActive;
70         private boolean fIsProblemLocationAvailable;
71
72
73         /**
74          * Constructor for JavaCorrectionAssistant.
75          * @param editor the editor
76          */
77         public JavaCorrectionAssistant(ITextEditor editor) {
78                 super();
79                 Assert.isNotNull(editor);
80                 fEditor= editor;
81
82                 JavaCorrectionProcessor processor= new JavaCorrectionProcessor(this);
83
84                 setQuickAssistProcessor(processor);
85                 enableColoredLabels(PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.USE_COLORED_LABELS));
86
87                 setInformationControlCreator(getInformationControlCreator());
88
89                 addCompletionListener(new ICompletionListener() {
90                         public void assistSessionEnded(ContentAssistEvent event) {
91                                 fIsCompletionActive= false;
92                         }
93
94                         public void assistSessionStarted(ContentAssistEvent event) {
95                                 fIsCompletionActive= true;
96                         }
97
98                         public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
99                         }
100                 });
101         }
102
103         public IEditorPart getEditor() {
104                 return fEditor;
105         }
106
107
108         private IInformationControlCreator getInformationControlCreator() {
109                 return new IInformationControlCreator() {
110                         public IInformationControl createInformationControl(Shell parent) {
111                                 return new DefaultInformationControl(parent, JavaPlugin.getAdditionalInfoAffordanceString());
112                         }
113                 };
114         }
115
116         /* (non-Javadoc)
117          * @see org.eclipse.jface.text.contentassist.IContentAssistant#install(org.eclipse.jface.text.ITextViewer)
118          */
119         @Override
120         public void install(ISourceViewer sourceViewer) {
121                 super.install(sourceViewer);
122                 fViewer= sourceViewer;
123
124                 fLightBulbUpdater= new QuickAssistLightBulbUpdater(fEditor, sourceViewer);
125                 fLightBulbUpdater.install();
126         }
127
128
129
130         /* (non-Javadoc)
131          * @see org.eclipse.jface.text.contentassist.ContentAssistant#uninstall()
132          */
133         @Override
134         public void uninstall() {
135                 if (fLightBulbUpdater != null) {
136                         fLightBulbUpdater.uninstall();
137                         fLightBulbUpdater= null;
138                 }
139                 super.uninstall();
140         }
141
142         /*
143          * @see org.eclipse.jface.text.quickassist.QuickAssistAssistant#showPossibleQuickAssists()
144          * @since 3.2
145          */
146
147         /**
148          * Show completions at caret position. If current
149          * position does not contain quick fixes look for
150          * next quick fix on same line by moving from left
151          * to right and restarting at end of line if the
152          * beginning of the line is reached.
153          *
154          * @see IQuickAssistAssistant#showPossibleQuickAssists()
155          */
156         @Override
157         public String showPossibleQuickAssists() {
158                 boolean isReinvoked= false;
159                 fIsProblemLocationAvailable= false;
160
161                 if (fIsCompletionActive) {
162                         if (isUpdatedOffset()) {
163                                 isReinvoked= true;
164                                 restorePosition();
165                                 hide();
166                                 fIsProblemLocationAvailable= true;
167                         }
168                 }
169
170                 fPosition= null;
171                 fCurrentAnnotations= null;
172
173                 if (fViewer == null || fViewer.getDocument() == null)
174                         // Let superclass deal with this
175                         return super.showPossibleQuickAssists();
176
177
178                 ArrayList<Annotation> resultingAnnotations= new ArrayList<Annotation>(20);
179                 try {
180                         Point selectedRange= fViewer.getSelectedRange();
181                         int currOffset= selectedRange.x;
182                         int currLength= selectedRange.y;
183                         boolean goToClosest= (currLength == 0) && !isReinvoked;
184
185                         int newOffset= collectQuickFixableAnnotations(fEditor, currOffset, goToClosest, resultingAnnotations);
186                         if (newOffset != currOffset) {
187                                 storePosition(currOffset, currLength);
188                                 fViewer.setSelectedRange(newOffset, 0);
189                                 fViewer.revealRange(newOffset, 0);
190                                 fIsProblemLocationAvailable= true;
191                                 if (fIsCompletionActive) {
192                                         hide();
193                                 }
194                         }
195                 } catch (BadLocationException e) {
196                         JavaPlugin.log(e);
197                 }
198                 fCurrentAnnotations= resultingAnnotations.toArray(new Annotation[resultingAnnotations.size()]);
199
200                 return super.showPossibleQuickAssists();
201         }
202
203
204         private static IRegion getRegionOfInterest(ITextEditor editor, int invocationLocation) throws BadLocationException {
205                 IDocumentProvider documentProvider= editor.getDocumentProvider();
206                 if (documentProvider == null) {
207                         return null;
208                 }
209                 IDocument document= documentProvider.getDocument(editor.getEditorInput());
210                 if (document == null) {
211                         return null;
212                 }
213                 return document.getLineInformationOfOffset(invocationLocation);
214         }
215
216         public static int collectQuickFixableAnnotations(ITextEditor editor, int invocationLocation, boolean goToClosest, ArrayList<Annotation> resultingAnnotations) throws BadLocationException {
217                 IAnnotationModel model= JavaUI.getDocumentProvider().getAnnotationModel(editor.getEditorInput());
218                 if (model == null) {
219                         return invocationLocation;
220                 }
221
222                 ensureUpdatedAnnotations(editor);
223
224                 Iterator<Annotation> iter= model.getAnnotationIterator();
225                 if (goToClosest) {
226                         IRegion lineInfo= getRegionOfInterest(editor, invocationLocation);
227                         if (lineInfo == null) {
228                                 return invocationLocation;
229                         }
230                         int rangeStart= lineInfo.getOffset();
231                         int rangeEnd= rangeStart + lineInfo.getLength();
232
233                         ArrayList<Annotation> allAnnotations= new ArrayList<Annotation>();
234                         ArrayList<Position> allPositions= new ArrayList<Position>();
235                         int bestOffset= Integer.MAX_VALUE;
236                         while (iter.hasNext()) {
237                                 Annotation annot= iter.next();
238                                 if (JavaCorrectionProcessor.isQuickFixableType(annot)) {
239                                         Position pos= model.getPosition(annot);
240                                         if (pos != null && isInside(pos.offset, rangeStart, rangeEnd)) { // inside our range?
241                                                 allAnnotations.add(annot);
242                                                 allPositions.add(pos);
243                                                 bestOffset= processAnnotation(annot, pos, invocationLocation, bestOffset);
244                                         }
245                                 }
246                         }
247                         if (bestOffset == Integer.MAX_VALUE) {
248                                 return invocationLocation;
249                         }
250                         for (int i= 0; i < allPositions.size(); i++) {
251                                 Position pos= allPositions.get(i);
252                                 if (isInside(bestOffset, pos.offset, pos.offset + pos.length)) {
253                                         resultingAnnotations.add(allAnnotations.get(i));
254                                 }
255                         }
256                         return bestOffset;
257                 } else {
258                         while (iter.hasNext()) {
259                                 Annotation annot= iter.next();
260                                 if (JavaCorrectionProcessor.isQuickFixableType(annot)) {
261                                         Position pos= model.getPosition(annot);
262                                         if (pos != null && isInside(invocationLocation, pos.offset, pos.offset + pos.length)) {
263                                                 resultingAnnotations.add(annot);
264                                         }
265                                 }
266                         }
267                         return invocationLocation;
268                 }
269         }
270
271         private static void ensureUpdatedAnnotations(ITextEditor editor) {
272                 Object inputElement= editor.getEditorInput().getAdapter(IJavaElement.class);
273                 if (inputElement instanceof ICompilationUnit) {
274                         SharedASTProvider.getAST((ICompilationUnit) inputElement, SharedASTProvider.WAIT_ACTIVE_ONLY, null);
275                 }
276         }
277
278         private static int processAnnotation(Annotation annot, Position pos, int invocationLocation, int bestOffset) {
279                 int posBegin= pos.offset;
280                 int posEnd= posBegin + pos.length;
281                 if (isInside(invocationLocation, posBegin, posEnd) && JavaCorrectionProcessor.hasCorrections(annot)) { // covers invocation location?
282                         return invocationLocation;
283                 } else if (bestOffset != invocationLocation) {
284                         int newClosestPosition= computeBestOffset(posBegin, invocationLocation, bestOffset);
285                         if (newClosestPosition != -1) {
286                                 if (newClosestPosition != bestOffset) { // new best
287                                         if (JavaCorrectionProcessor.hasCorrections(annot)) { // only jump to it if there are proposals
288                                                 return newClosestPosition;
289                                         }
290                                 }
291                         }
292                 }
293                 return bestOffset;
294         }
295
296
297         private static boolean isInside(int offset, int start, int end) {
298                 return offset == start || offset == end || (offset > start && offset < end); // make sure to handle 0-length ranges
299         }
300
301         /**
302          * Computes and returns the invocation offset given a new
303          * position, the initial offset and the best invocation offset
304          * found so far.
305          * <p>
306          * The closest offset to the left of the initial offset is the
307          * best. If there is no offset on the left, the closest on the
308          * right is the best.</p>
309          * @param newOffset the offset to llok at
310          * @param invocationLocation the invocation location
311          * @param bestOffset the current best offset
312          * @return -1 is returned if the given offset is not closer or the new best offset
313          */
314         private static int computeBestOffset(int newOffset, int invocationLocation, int bestOffset) {
315                 if (newOffset <= invocationLocation) {
316                         if (bestOffset > invocationLocation) {
317                                 return newOffset; // closest was on the right, prefer on the left
318                         } else if (bestOffset <= newOffset) {
319                                 return newOffset; // we are closer or equal
320                         }
321                         return -1; // further away
322                 }
323
324                 if (newOffset <= bestOffset)
325                         return newOffset; // we are closer or equal
326
327                 return -1; // further away
328         }
329
330         /*
331          * @see org.eclipse.jface.text.contentassist.ContentAssistant#possibleCompletionsClosed()
332          */
333         @Override
334         protected void possibleCompletionsClosed() {
335                 super.possibleCompletionsClosed();
336                 restorePosition();
337         }
338
339         private void storePosition(int currOffset, int currLength) {
340                 fPosition= new Position(currOffset, currLength);
341         }
342
343         private void restorePosition() {
344                 if (fPosition != null && !fPosition.isDeleted() && fViewer.getDocument() != null) {
345                         fViewer.setSelectedRange(fPosition.offset, fPosition.length);
346                         fViewer.revealRange(fPosition.offset, fPosition.length);
347                 }
348                 fPosition= null;
349         }
350
351         /**
352          * Returns true if the last invoked completion was called with an updated offset.
353          * @return <code> true</code> if the last invoked completion was called with an updated offset.
354          */
355         public boolean isUpdatedOffset() {
356                 return fPosition != null;
357         }
358
359         /**
360          * @return <code>true</code> if a problem exist on the current line and the completion was not invoked at the problem location
361          * @since 3.4
362          */
363         public boolean isProblemLocationAvailable() {
364                 return fIsProblemLocationAvailable;
365         }
366
367         /**
368          * Returns the annotations at the current offset
369          * @return the annotations at the offset
370          */
371         public Annotation[] getAnnotationsAtOffset() {
372                 return fCurrentAnnotations;
373         }
374
375         public void generated_3649133358608219912(final JavaCorrectionProcessor javacorrectionprocessor) {
376                 addCompletionListener(new ICompletionListener() {
377         
378                         public void assistSessionEnded(ContentAssistEvent event) {
379                                 setStatusLineVisible(false);
380                         }
381         
382                         public void assistSessionStarted(ContentAssistEvent event) {
383                                 setStatusLineVisible(true);
384                                 setStatusMessage(javacorrectionprocessor.getJumpHintStatusLineMessage());
385                         }
386         
387                         public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
388                                 if (proposal instanceof IStatusLineProposal) {
389                                         IStatusLineProposal statusLineProposal= (IStatusLineProposal)proposal;
390                                         String message= statusLineProposal.getStatusMessage();
391                                         if (message != null) {
392                                                 setStatusMessage(message);
393                                                 return;
394                                         }
395                                 }
396                                 setStatusMessage(javacorrectionprocessor.getJumpHintStatusLineMessage());
397                         }
398         
399                         private String getJumpHintStatusLineMessage() {
400                                 if (isUpdatedOffset()) {
401                                         String key= javacorrectionprocessor.getQuickAssistBinding();
402                                         if (key == null)
403                                                 return CorrectionMessages.JavaCorrectionProcessor_go_to_original_using_menu;
404                                         else
405                                                 return Messages.format(CorrectionMessages.JavaCorrectionProcessor_go_to_original_using_key, key);
406                                 } else if (isProblemLocationAvailable()) {
407                                         String key= javacorrectionprocessor.getQuickAssistBinding();
408                                         if (key == null)
409                                                 return CorrectionMessages.JavaCorrectionProcessor_go_to_closest_using_menu;
410                                         else
411                                                 return Messages.format(CorrectionMessages.JavaCorrectionProcessor_go_to_closest_using_key, key);
412                                 } else
413                                         return ""; //$NON-NLS-1$
414                         }
415         
416                         private String getQuickAssistBinding() {
417                                 final IBindingService bindingSvc= (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class);
418                                 return bindingSvc.getBestActiveBindingFormattedFor(ITextEditorActionDefinitionIds.QUICK_ASSIST);
419                         }
420                 });
421         }
422
423         public ICompletionProposal[] generated_1438141222580661224(JavaCorrectionProcessor javacorrectionprocessor, ISourceViewer viewer, int documentOffset) {
424                 IEditorPart part= getEditor();
425         
426                 ICompilationUnit cu= JavaUI.getWorkingCopyManager().getWorkingCopy(part.getEditorInput());
427                 IAnnotationModel model= JavaUI.getDocumentProvider().getAnnotationModel(part.getEditorInput());
428         
429                 AssistContext context= null;
430                 if (cu != null) {
431                         int length= viewer != null ? viewer.getSelectedRange().y : 0;
432                         context= new AssistContext(cu, viewer, part, documentOffset, length);
433                 }
434                 
435                 Annotation[] annotations= getAnnotationsAtOffset();
436         
437                 javacorrectionprocessor.fErrorMessage= null;
438         
439                 ICompletionProposal[] res= null;
440                 if (model != null && context != null && annotations != null) {
441                         ArrayList<IJavaCompletionProposal> proposals= new ArrayList<IJavaCompletionProposal>(10);
442                         IStatus status= JavaCorrectionProcessor.collectProposals(context, model, annotations, true, !isUpdatedOffset(), proposals);
443                         res= proposals.toArray(new ICompletionProposal[proposals.size()]);
444                         if (!status.isOK()) {
445                                 javacorrectionprocessor.fErrorMessage= status.getMessage();
446                                 JavaPlugin.log(status);
447                         }
448                 }
449                 return res;
450         }
451
452         public IQuickAssistAssistant generated_4265095813573642237(JavaSourceViewerConfiguration javasourceviewerconfiguration) {
453                 setRestoreCompletionProposalSize(javasourceviewerconfiguration.getSettings("quick_assist_proposal_size")); //$NON-NLS-1$
454                 return this;
455         }
456 }