KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.Arrays JavaDoc;
16 import java.util.Collection JavaDoc;
17
18 import org.eclipse.core.runtime.IConfigurationElement;
19 import org.eclipse.core.runtime.ISafeRunnable;
20 import org.eclipse.core.runtime.IStatus;
21 import org.eclipse.core.runtime.MultiStatus;
22 import org.eclipse.core.runtime.Platform;
23 import org.eclipse.core.runtime.SafeRunner;
24 import org.eclipse.core.runtime.Status;
25
26 import org.eclipse.core.resources.IMarker;
27
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.IQuickAssistInvocationContext;
34 import org.eclipse.jface.text.source.Annotation;
35 import org.eclipse.jface.text.source.IAnnotationModel;
36
37 import org.eclipse.ui.IEditorPart;
38 import org.eclipse.ui.IMarkerHelpRegistry;
39 import org.eclipse.ui.IMarkerResolution;
40 import org.eclipse.ui.texteditor.SimpleMarkerAnnotation;
41
42 import org.eclipse.ui.ide.IDE;
43
44 import org.eclipse.ltk.core.refactoring.NullChange;
45
46 import org.eclipse.jdt.core.ICompilationUnit;
47
48 import org.eclipse.jdt.ui.JavaUI;
49 import org.eclipse.jdt.ui.text.java.CompletionProposalComparator;
50 import org.eclipse.jdt.ui.text.java.IInvocationContext;
51 import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal;
52 import org.eclipse.jdt.ui.text.java.IProblemLocation;
53 import org.eclipse.jdt.ui.text.java.IQuickAssistProcessor;
54 import org.eclipse.jdt.ui.text.java.IQuickFixProcessor;
55
56 import org.eclipse.jdt.internal.ui.JavaPlugin;
57 import org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation;
58
59
60 public class JavaCorrectionProcessor implements org.eclipse.jface.text.quickassist.IQuickAssistProcessor {
61
62     private static final String JavaDoc QUICKFIX_PROCESSOR_CONTRIBUTION_ID= "quickFixProcessors"; //$NON-NLS-1$
63
private static final String JavaDoc QUICKASSIST_PROCESSOR_CONTRIBUTION_ID= "quickAssistProcessors"; //$NON-NLS-1$
64

65     private static ContributedProcessorDescriptor[] fgContributedAssistProcessors= null;
66     private static ContributedProcessorDescriptor[] fgContributedCorrectionProcessors= null;
67
68     private static ContributedProcessorDescriptor[] getProcessorDescriptors(String JavaDoc contributionId, boolean testMarkerTypes) {
69         IConfigurationElement[] elements= Platform.getExtensionRegistry().getConfigurationElementsFor(JavaUI.ID_PLUGIN, contributionId);
70         ArrayList JavaDoc res= new ArrayList JavaDoc(elements.length);
71
72         for (int i= 0; i < elements.length; i++) {
73             ContributedProcessorDescriptor desc= new ContributedProcessorDescriptor(elements[i], testMarkerTypes);
74             IStatus status= desc.checkSyntax();
75             if (status.isOK()) {
76                 res.add(desc);
77             } else {
78                 JavaPlugin.log(status);
79             }
80         }
81         return (ContributedProcessorDescriptor[]) res.toArray(new ContributedProcessorDescriptor[res.size()]);
82     }
83
84     private static ContributedProcessorDescriptor[] getCorrectionProcessors() {
85         if (fgContributedCorrectionProcessors == null) {
86             fgContributedCorrectionProcessors= getProcessorDescriptors(QUICKFIX_PROCESSOR_CONTRIBUTION_ID, true);
87         }
88         return fgContributedCorrectionProcessors;
89     }
90
91     private static ContributedProcessorDescriptor[] getAssistProcessors() {
92         if (fgContributedAssistProcessors == null) {
93             fgContributedAssistProcessors= getProcessorDescriptors(QUICKASSIST_PROCESSOR_CONTRIBUTION_ID, false);
94         }
95         return fgContributedAssistProcessors;
96     }
97
98     public static boolean hasCorrections(ICompilationUnit cu, int problemId, String JavaDoc markerType) {
99         ContributedProcessorDescriptor[] processors= getCorrectionProcessors();
100         SafeHasCorrections collector= new SafeHasCorrections(cu, problemId);
101         for (int i= 0; i < processors.length; i++) {
102             if (processors[i].canHandleMarkerType(markerType)) {
103                 collector.process(processors[i]);
104                 if (collector.hasCorrections()) {
105                     return true;
106                 }
107             }
108         }
109         return false;
110     }
111
112     public static boolean isQuickFixableType(Annotation annotation) {
113         return (annotation instanceof IJavaAnnotation || annotation instanceof SimpleMarkerAnnotation) && !annotation.isMarkedDeleted();
114     }
115
116
117     public static boolean hasCorrections(Annotation annotation) {
118         if (annotation instanceof IJavaAnnotation) {
119             IJavaAnnotation javaAnnotation= (IJavaAnnotation) annotation;
120             int problemId= javaAnnotation.getId();
121             if (problemId != -1) {
122                 ICompilationUnit cu= javaAnnotation.getCompilationUnit();
123                 if (cu != null) {
124                     return hasCorrections(cu, problemId, javaAnnotation.getMarkerType());
125                 }
126             }
127         }
128         if (annotation instanceof SimpleMarkerAnnotation) {
129             return hasCorrections(((SimpleMarkerAnnotation) annotation).getMarker());
130         }
131         return false;
132     }
133
134     private static boolean hasCorrections(IMarker marker) {
135         if (marker == null || !marker.exists())
136             return false;
137
138         IMarkerHelpRegistry registry= IDE.getMarkerHelpRegistry();
139         return registry != null && registry.hasResolutions(marker);
140     }
141
142     public static boolean hasAssists(IInvocationContext context) {
143         ContributedProcessorDescriptor[] processors= getAssistProcessors();
144         SafeHasAssist collector= new SafeHasAssist(context);
145
146         for (int i= 0; i < processors.length; i++) {
147             collector.process(processors[i]);
148             if (collector.hasAssists()) {
149                 return true;
150             }
151         }
152         return false;
153     }
154
155     private JavaCorrectionAssistant fAssistant;
156     private String JavaDoc fErrorMessage;
157
158     /*
159      * Constructor for JavaCorrectionProcessor.
160      */

161     public JavaCorrectionProcessor(JavaCorrectionAssistant assistant) {
162         fAssistant= assistant;
163         fAssistant.addCompletionListener(new ICompletionListener() {
164         
165             public void assistSessionEnded(ContentAssistEvent event) {
166                 fAssistant.setStatusLineVisible(false);
167             }
168         
169             public void assistSessionStarted(ContentAssistEvent event) {
170                 fAssistant.setStatusLineVisible(true);
171             }
172
173             public void selectionChanged(ICompletionProposal proposal, boolean smartToggle) {
174                 if (proposal instanceof IStatusLineProposal) {
175                     IStatusLineProposal statusLineProposal= (IStatusLineProposal)proposal;
176                     String JavaDoc message= statusLineProposal.getStatusMessage();
177                     if (message != null) {
178                         fAssistant.setStatusMessage(message);
179                     } else {
180                         fAssistant.setStatusMessage(""); //$NON-NLS-1$
181
}
182                 } else {
183                     fAssistant.setStatusMessage(""); //$NON-NLS-1$
184
}
185             }
186         });
187     }
188
189     /*
190      * @see IContentAssistProcessor#computeCompletionProposals(ITextViewer, int)
191      */

192     public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext quickAssistContext) {
193         ITextViewer viewer= quickAssistContext.getSourceViewer();
194         int documentOffset= quickAssistContext.getOffset();
195         
196         IEditorPart part= fAssistant.getEditor();
197
198         ICompilationUnit cu= JavaUI.getWorkingCopyManager().getWorkingCopy(part.getEditorInput());
199         IAnnotationModel model= JavaUI.getDocumentProvider().getAnnotationModel(part.getEditorInput());
200         
201         int length= viewer != null ? viewer.getSelectedRange().y : 0;
202         AssistContext context= new AssistContext(cu, documentOffset, length);
203
204         Annotation[] annotations= fAssistant.getAnnotationsAtOffset();
205         
206         fErrorMessage= null;
207         
208         ICompletionProposal[] res= null;
209         if (model != null && annotations != null) {
210             ArrayList JavaDoc proposals= new ArrayList JavaDoc(10);
211             IStatus status= collectProposals(context, model, annotations, true, !fAssistant.isUpdatedOffset(), proposals);
212             res= (ICompletionProposal[]) proposals.toArray(new ICompletionProposal[proposals.size()]);
213             if (!status.isOK()) {
214                 fErrorMessage= status.getMessage();
215                 JavaPlugin.log(status);
216             }
217         }
218         
219         if (res == null || res.length == 0) {
220             return new ICompletionProposal[] { new ChangeCorrectionProposal(CorrectionMessages.NoCorrectionProposal_description, new NullChange(""), 0, null) }; //$NON-NLS-1$
221
}
222         if (res.length > 1) {
223             Arrays.sort(res, new CompletionProposalComparator());
224         }
225         return res;
226     }
227
228     public static IStatus collectProposals(IInvocationContext context, IAnnotationModel model, Annotation[] annotations, boolean addQuickFixes, boolean addQuickAssists, Collection JavaDoc proposals) {
229         ArrayList JavaDoc problems= new ArrayList JavaDoc();
230         
231         // collect problem locations and corrections from marker annotations
232
for (int i= 0; i < annotations.length; i++) {
233             Annotation curr= annotations[i];
234             if (curr instanceof IJavaAnnotation) {
235                 ProblemLocation problemLocation= getProblemLocation((IJavaAnnotation) curr, model);
236                 if (problemLocation != null) {
237                     problems.add(problemLocation);
238                 }
239             } else if (addQuickFixes && curr instanceof SimpleMarkerAnnotation) {
240                 // don't collect if annotation is already a java annotation
241
collectMarkerProposals((SimpleMarkerAnnotation) curr, proposals);
242             }
243         }
244         MultiStatus resStatus= null;
245         
246         IProblemLocation[] problemLocations= (IProblemLocation[]) problems.toArray(new IProblemLocation[problems.size()]);
247         if (addQuickFixes) {
248             IStatus status= collectCorrections(context, problemLocations, proposals);
249             if (!status.isOK()) {
250                 resStatus= new MultiStatus(JavaUI.ID_PLUGIN, IStatus.ERROR, CorrectionMessages.JavaCorrectionProcessor_error_quickfix_message, null);
251                 resStatus.add(status);
252             }
253         }
254         if (addQuickAssists) {
255             IStatus status= collectAssists(context, problemLocations, proposals);
256             if (!status.isOK()) {
257                 if (resStatus == null) {
258                     resStatus= new MultiStatus(JavaUI.ID_PLUGIN, IStatus.ERROR, CorrectionMessages.JavaCorrectionProcessor_error_quickassist_message, null);
259                 }
260                 resStatus.add(status);
261             }
262         }
263         if (resStatus != null) {
264             return resStatus;
265         }
266         return Status.OK_STATUS;
267     }
268     
269     private static ProblemLocation getProblemLocation(IJavaAnnotation javaAnnotation, IAnnotationModel model) {
270         int problemId= javaAnnotation.getId();
271         if (problemId != -1) {
272             Position pos= model.getPosition((Annotation) javaAnnotation);
273             if (pos != null) {
274                 return new ProblemLocation(pos.getOffset(), pos.getLength(), javaAnnotation); // java problems all handled by the quick assist processors
275
}
276         }
277         return null;
278     }
279
280     private static void collectMarkerProposals(SimpleMarkerAnnotation annotation, Collection JavaDoc proposals) {
281         IMarker marker= annotation.getMarker();
282         IMarkerResolution[] res= IDE.getMarkerHelpRegistry().getResolutions(marker);
283         if (res.length > 0) {
284             for (int i= 0; i < res.length; i++) {
285                 proposals.add(new MarkerResolutionProposal(res[i], marker));
286             }
287         }
288     }
289
290     private static abstract class SafeCorrectionProcessorAccess implements ISafeRunnable {
291         private MultiStatus fMulti= null;
292         private ContributedProcessorDescriptor fDescriptor;
293
294         public void process(ContributedProcessorDescriptor[] desc) {
295             for (int i= 0; i < desc.length; i++) {
296                 fDescriptor= desc[i];
297                 SafeRunner.run(this);
298             }
299         }
300
301         public void process(ContributedProcessorDescriptor desc) {
302             fDescriptor= desc;
303             SafeRunner.run(this);
304         }
305
306         public void run() throws Exception JavaDoc {
307             safeRun(fDescriptor);
308         }
309
310         protected abstract void safeRun(ContributedProcessorDescriptor processor) throws Exception JavaDoc;
311
312         public void handleException(Throwable JavaDoc exception) {
313             if (fMulti == null) {
314                 fMulti= new MultiStatus(JavaUI.ID_PLUGIN, IStatus.OK, CorrectionMessages.JavaCorrectionProcessor_error_status, null);
315             }
316             fMulti.merge(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.ERROR, CorrectionMessages.JavaCorrectionProcessor_error_status, exception));
317         }
318
319         public IStatus getStatus() {
320             if (fMulti == null) {
321                 return Status.OK_STATUS;
322             }
323             return fMulti;
324         }
325
326     }
327
328     private static class SafeCorrectionCollector extends SafeCorrectionProcessorAccess {
329         private final IInvocationContext fContext;
330         private final Collection JavaDoc fProposals;
331         private IProblemLocation[] fLocations;
332
333         public SafeCorrectionCollector(IInvocationContext context, Collection JavaDoc proposals) {
334             fContext= context;
335             fProposals= proposals;
336         }
337         
338         public void setProblemLocations(IProblemLocation[] locations) {
339             fLocations= locations;
340         }
341
342         public void safeRun(ContributedProcessorDescriptor desc) throws Exception JavaDoc {
343             IQuickFixProcessor curr= (IQuickFixProcessor) desc.getProcessor(fContext.getCompilationUnit());
344             if (curr != null) {
345                 IJavaCompletionProposal[] res= curr.getCorrections(fContext, fLocations);
346                 if (res != null) {
347                     for (int k= 0; k < res.length; k++) {
348                         fProposals.add(res[k]);
349                     }
350                 }
351             }
352         }
353     }
354
355     private static class SafeAssistCollector extends SafeCorrectionProcessorAccess {
356         private final IInvocationContext fContext;
357         private final IProblemLocation[] fLocations;
358         private final Collection JavaDoc fProposals;
359
360         public SafeAssistCollector(IInvocationContext context, IProblemLocation[] locations, Collection JavaDoc proposals) {
361             fContext= context;
362             fLocations= locations;
363             fProposals= proposals;
364         }
365
366         public void safeRun(ContributedProcessorDescriptor desc) throws Exception JavaDoc {
367             IQuickAssistProcessor curr= (IQuickAssistProcessor) desc.getProcessor(fContext.getCompilationUnit());
368             if (curr != null) {
369                 IJavaCompletionProposal[] res= curr.getAssists(fContext, fLocations);
370                 if (res != null) {
371                     for (int k= 0; k < res.length; k++) {
372                         fProposals.add(res[k]);
373                     }
374                 }
375             }
376         }
377     }
378
379     private static class SafeHasAssist extends SafeCorrectionProcessorAccess {
380         private final IInvocationContext fContext;
381         private boolean fHasAssists;
382
383         public SafeHasAssist(IInvocationContext context) {
384             fContext= context;
385             fHasAssists= false;
386         }
387
388         public boolean hasAssists() {
389             return fHasAssists;
390         }
391
392         public void safeRun(ContributedProcessorDescriptor desc) throws Exception JavaDoc {
393             IQuickAssistProcessor processor= (IQuickAssistProcessor) desc.getProcessor(fContext.getCompilationUnit());
394             if (processor != null && processor.hasAssists(fContext)) {
395                 fHasAssists= true;
396             }
397         }
398     }
399
400     private static class SafeHasCorrections extends SafeCorrectionProcessorAccess {
401         private final ICompilationUnit fCu;
402         private final int fProblemId;
403         private boolean fHasCorrections;
404
405         public SafeHasCorrections(ICompilationUnit cu, int problemId) {
406             fCu= cu;
407             fProblemId= problemId;
408             fHasCorrections= false;
409         }
410
411         public boolean hasCorrections() {
412             return fHasCorrections;
413         }
414
415         public void safeRun(ContributedProcessorDescriptor desc) throws Exception JavaDoc {
416             IQuickFixProcessor processor= (IQuickFixProcessor) desc.getProcessor(fCu);
417             if (processor != null && processor.hasCorrections(fCu, fProblemId)) {
418                 fHasCorrections= true;
419             }
420         }
421     }
422
423
424     public static IStatus collectCorrections(IInvocationContext context, IProblemLocation[] locations, Collection JavaDoc proposals) {
425         ContributedProcessorDescriptor[] processors= getCorrectionProcessors();
426         SafeCorrectionCollector collector= new SafeCorrectionCollector(context, proposals);
427         for (int i= 0; i < processors.length; i++) {
428             ContributedProcessorDescriptor curr= processors[i];
429             IProblemLocation[] handled= getHandledProblems(locations, curr);
430             if (handled != null) {
431                 collector.setProblemLocations(handled);
432                 collector.process(curr);
433             }
434         }
435         return collector.getStatus();
436     }
437
438     private static IProblemLocation[] getHandledProblems(IProblemLocation[] locations, ContributedProcessorDescriptor processor) {
439         // implementation tries to avoid creating a new array
440
boolean allHandled= true;
441         ArrayList JavaDoc res= null;
442         for (int i= 0; i < locations.length; i++) {
443             IProblemLocation curr= locations[i];
444             if (processor.canHandleMarkerType(curr.getMarkerType())) {
445                 if (!allHandled) { // first handled problem
446
if (res == null) {
447                         res= new ArrayList JavaDoc(locations.length - i);
448                     }
449                     res.add(curr);
450                 }
451             } else if (allHandled) {
452                 if (i > 0) { // first non handled problem
453
res= new ArrayList JavaDoc(locations.length - i);
454                     for (int k= 0; k < i; k++) {
455                         res.add(locations[k]);
456                     }
457                 }
458                 allHandled= false;
459             }
460         }
461         if (allHandled) {
462             return locations;
463         }
464         if (res == null) {
465             return null;
466         }
467         return (IProblemLocation[]) res.toArray(new IProblemLocation[res.size()]);
468     }
469
470     public static IStatus collectAssists(IInvocationContext context, IProblemLocation[] locations, Collection JavaDoc proposals) {
471         ContributedProcessorDescriptor[] processors= getAssistProcessors();
472         SafeAssistCollector collector= new SafeAssistCollector(context, locations, proposals);
473         collector.process(processors);
474
475         return collector.getStatus();
476     }
477
478     /*
479      * @see IContentAssistProcessor#getErrorMessage()
480      */

481     public String JavaDoc getErrorMessage() {
482         return fErrorMessage;
483     }
484
485     /*
486      * @see org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canFix(org.eclipse.jface.text.source.Annotation)
487      * @since 3.2
488      */

489     public boolean canFix(Annotation annotation) {
490         return hasCorrections(annotation);
491     }
492
493     /*
494      * @see org.eclipse.jface.text.quickassist.IQuickAssistProcessor#canAssist(org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext)
495      * @since 3.2
496      */

497     public boolean canAssist(IQuickAssistInvocationContext invocationContext) {
498         if (invocationContext instanceof IInvocationContext)
499             return hasAssists((IInvocationContext)invocationContext);
500         return false;
501     }
502     
503 }
504
Popular Tags