]>
Commit | Line | Data |
---|---|---|
1b2798f6 EK |
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.javaeditor; | |
12 | ||
13 | import java.io.BufferedReader; | |
14 | import java.io.IOException; | |
15 | import java.io.InputStream; | |
16 | import java.io.InputStreamReader; | |
17 | import java.io.Reader; | |
18 | import java.net.URI; | |
19 | import java.util.ArrayList; | |
20 | import java.util.HashMap; | |
21 | import java.util.Iterator; | |
22 | import java.util.List; | |
23 | import java.util.Map; | |
24 | ||
25 | import org.eclipse.swt.SWT; | |
26 | import org.eclipse.swt.graphics.GC; | |
27 | import org.eclipse.swt.graphics.Image; | |
28 | import org.eclipse.swt.graphics.Rectangle; | |
29 | import org.eclipse.swt.widgets.Canvas; | |
30 | import org.eclipse.swt.widgets.Display; | |
31 | ||
32 | import org.eclipse.core.filesystem.EFS; | |
33 | import org.eclipse.core.filesystem.IFileStore; | |
34 | import org.eclipse.core.filesystem.URIUtil; | |
35 | ||
36 | import org.eclipse.core.runtime.Assert; | |
37 | import org.eclipse.core.runtime.CoreException; | |
38 | import org.eclipse.core.runtime.IPath; | |
39 | import org.eclipse.core.runtime.IProgressMonitor; | |
40 | import org.eclipse.core.runtime.ISafeRunnable; | |
41 | import org.eclipse.core.runtime.IStatus; | |
42 | import org.eclipse.core.runtime.ListenerList; | |
43 | import org.eclipse.core.runtime.MultiStatus; | |
44 | import org.eclipse.core.runtime.NullProgressMonitor; | |
45 | import org.eclipse.core.runtime.SafeRunner; | |
46 | import org.eclipse.core.runtime.Status; | |
47 | import org.eclipse.core.runtime.SubProgressMonitor; | |
48 | import org.eclipse.core.runtime.jobs.ISchedulingRule; | |
49 | ||
50 | import org.eclipse.core.resources.IEncodedStorage; | |
51 | import org.eclipse.core.resources.IFile; | |
52 | import org.eclipse.core.resources.IFileState; | |
53 | import org.eclipse.core.resources.IMarker; | |
54 | import org.eclipse.core.resources.IResource; | |
55 | import org.eclipse.core.resources.IStorage; | |
56 | import org.eclipse.core.resources.ResourcesPlugin; | |
57 | ||
58 | import org.eclipse.core.filebuffers.IAnnotationModelFactory; | |
59 | ||
60 | import org.eclipse.jface.preference.IPreferenceStore; | |
61 | import org.eclipse.jface.util.IPropertyChangeListener; | |
62 | import org.eclipse.jface.util.PropertyChangeEvent; | |
63 | ||
64 | import org.eclipse.jface.text.BadLocationException; | |
65 | import org.eclipse.jface.text.DefaultLineTracker; | |
66 | import org.eclipse.jface.text.IDocument; | |
67 | import org.eclipse.jface.text.ILineTracker; | |
68 | import org.eclipse.jface.text.IRegion; | |
69 | import org.eclipse.jface.text.Position; | |
70 | import org.eclipse.jface.text.quickassist.IQuickFixableAnnotation; | |
71 | import org.eclipse.jface.text.source.Annotation; | |
72 | import org.eclipse.jface.text.source.AnnotationModel; | |
73 | import org.eclipse.jface.text.source.AnnotationModelEvent; | |
74 | import org.eclipse.jface.text.source.IAnnotationAccessExtension; | |
75 | import org.eclipse.jface.text.source.IAnnotationModel; | |
76 | import org.eclipse.jface.text.source.IAnnotationModelListener; | |
77 | import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; | |
78 | import org.eclipse.jface.text.source.IAnnotationPresentation; | |
79 | import org.eclipse.jface.text.source.ImageUtilities; | |
80 | ||
81 | import org.eclipse.ui.IEditorInput; | |
82 | import org.eclipse.ui.IFileEditorInput; | |
83 | import org.eclipse.ui.ISharedImages; | |
84 | import org.eclipse.ui.IStorageEditorInput; | |
85 | import org.eclipse.ui.IURIEditorInput; | |
86 | import org.eclipse.ui.PlatformUI; | |
87 | import org.eclipse.ui.ide.IDE.SharedImages; | |
88 | ||
89 | import org.eclipse.ui.texteditor.AbstractMarkerAnnotationModel; | |
90 | import org.eclipse.ui.texteditor.AnnotationPreference; | |
91 | import org.eclipse.ui.texteditor.AnnotationPreferenceLookup; | |
92 | import org.eclipse.ui.texteditor.IDocumentProvider; | |
93 | import org.eclipse.ui.texteditor.MarkerAnnotation; | |
94 | import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel; | |
95 | ||
96 | import org.eclipse.ui.editors.text.EditorsUI; | |
97 | import org.eclipse.ui.editors.text.ForwardingDocumentProvider; | |
98 | import org.eclipse.ui.editors.text.TextFileDocumentProvider; | |
99 | ||
100 | import org.eclipse.jdt.core.IBuffer; | |
101 | import org.eclipse.jdt.core.IClasspathEntry; | |
102 | import org.eclipse.jdt.core.ICompilationUnit; | |
103 | import org.eclipse.jdt.core.IJavaModel; | |
104 | import org.eclipse.jdt.core.IJavaProject; | |
105 | import org.eclipse.jdt.core.IProblemRequestor; | |
106 | import org.eclipse.jdt.core.JavaCore; | |
107 | import org.eclipse.jdt.core.JavaModelException; | |
108 | import org.eclipse.jdt.core.WorkingCopyOwner; | |
109 | import org.eclipse.jdt.core.compiler.CategorizedProblem; | |
110 | import org.eclipse.jdt.core.compiler.IProblem; | |
111 | ||
112 | import org.eclipse.jdt.internal.corext.util.JavaModelUtil; | |
113 | import org.eclipse.jdt.internal.corext.util.Messages; | |
114 | ||
115 | import org.eclipse.jdt.launching.JavaRuntime; | |
116 | ||
117 | import org.eclipse.jdt.ui.JavaUI; | |
118 | import org.eclipse.jdt.ui.PreferenceConstants; | |
119 | import org.eclipse.jdt.ui.text.IJavaPartitions; | |
120 | ||
121 | import org.eclipse.jdt.internal.ui.IJavaStatusConstants; | |
122 | import org.eclipse.jdt.internal.ui.JavaPlugin; | |
123 | import org.eclipse.jdt.internal.ui.JavaPluginImages; | |
124 | import org.eclipse.jdt.internal.ui.javaeditor.saveparticipant.IPostSaveListener; | |
125 | import org.eclipse.jdt.internal.ui.javaeditor.saveparticipant.SaveParticipantRegistry; | |
126 | import org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionProcessor; | |
127 | import org.eclipse.jdt.internal.ui.text.java.IProblemRequestorExtension; | |
128 | import org.eclipse.jdt.internal.ui.text.spelling.JavaSpellingReconcileStrategy; | |
129 | ||
130 | ||
131 | public class CompilationUnitDocumentProvider extends TextFileDocumentProvider implements ICompilationUnitDocumentProvider, IAnnotationModelFactory { | |
132 | ||
133 | /** | |
134 | * Bundle of all required informations to allow working copy management. | |
135 | */ | |
136 | static protected class CompilationUnitInfo extends FileInfo { | |
137 | public ICompilationUnit fCopy; | |
138 | } | |
139 | ||
140 | /** | |
141 | * Annotation representing an <code>IProblem</code>. | |
142 | */ | |
143 | static public class ProblemAnnotation extends Annotation implements IJavaAnnotation, IAnnotationPresentation, IQuickFixableAnnotation { | |
144 | ||
145 | public static final String SPELLING_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.spelling"; //$NON-NLS-1$ | |
146 | ||
147 | //XXX: To be fully correct these constants should be non-static | |
148 | /** | |
149 | * The layer in which task problem annotations are located. | |
150 | */ | |
151 | private static final int TASK_LAYER; | |
152 | /** | |
153 | * The layer in which info problem annotations are located. | |
154 | */ | |
155 | private static final int INFO_LAYER; | |
156 | /** | |
157 | * The layer in which warning problem annotations representing are located. | |
158 | */ | |
159 | private static final int WARNING_LAYER; | |
160 | /** | |
161 | * The layer in which error problem annotations representing are located. | |
162 | */ | |
163 | private static final int ERROR_LAYER; | |
164 | ||
165 | static { | |
166 | AnnotationPreferenceLookup lookup= EditorsUI.getAnnotationPreferenceLookup(); | |
167 | TASK_LAYER= computeLayer("org.eclipse.ui.workbench.texteditor.task", lookup); //$NON-NLS-1$ | |
168 | INFO_LAYER= computeLayer("org.eclipse.jdt.ui.info", lookup); //$NON-NLS-1$ | |
169 | WARNING_LAYER= computeLayer("org.eclipse.jdt.ui.warning", lookup); //$NON-NLS-1$ | |
170 | ERROR_LAYER= computeLayer("org.eclipse.jdt.ui.error", lookup); //$NON-NLS-1$ | |
171 | } | |
172 | ||
173 | private static int computeLayer(String annotationType, AnnotationPreferenceLookup lookup) { | |
174 | Annotation annotation= new Annotation(annotationType, false, null); | |
175 | AnnotationPreference preference= lookup.getAnnotationPreference(annotation); | |
176 | if (preference != null) | |
177 | return preference.getPresentationLayer() + 1; | |
178 | else | |
179 | return IAnnotationAccessExtension.DEFAULT_LAYER + 1; | |
180 | } | |
181 | ||
182 | private static Image fgQuickFixImage; | |
183 | private static Image fgQuickFixErrorImage; | |
184 | private static Image fgTaskImage; | |
185 | private static Image fgInfoImage; | |
186 | private static Image fgWarningImage; | |
187 | private static Image fgErrorImage; | |
188 | private static boolean fgImagesInitialized= false; | |
189 | ||
190 | private ICompilationUnit fCompilationUnit; | |
191 | private List<IJavaAnnotation> fOverlaids; | |
192 | private IProblem fProblem; | |
193 | private Image fImage; | |
194 | private boolean fImageInitialized= false; | |
195 | private int fLayer= IAnnotationAccessExtension.DEFAULT_LAYER; | |
196 | private boolean fIsQuickFixable; | |
197 | private boolean fIsQuickFixableStateSet= false; | |
198 | ||
199 | ||
200 | public ProblemAnnotation(IProblem problem, ICompilationUnit cu) { | |
201 | ||
202 | fProblem= problem; | |
203 | fCompilationUnit= cu; | |
204 | ||
205 | if (JavaSpellingReconcileStrategy.SPELLING_PROBLEM_ID == fProblem.getID()) { | |
206 | setType(SPELLING_ANNOTATION_TYPE); | |
207 | fLayer= WARNING_LAYER; | |
208 | } else if (IProblem.Task == fProblem.getID()) { | |
209 | setType(JavaMarkerAnnotation.TASK_ANNOTATION_TYPE); | |
210 | fLayer= TASK_LAYER; | |
211 | } else if (fProblem.isWarning()) { | |
212 | setType(JavaMarkerAnnotation.WARNING_ANNOTATION_TYPE); | |
213 | fLayer= WARNING_LAYER; | |
214 | } else if (fProblem.isError()) { | |
215 | setType(JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE); | |
216 | fLayer= ERROR_LAYER; | |
217 | } else { | |
218 | setType(JavaMarkerAnnotation.INFO_ANNOTATION_TYPE); | |
219 | fLayer= INFO_LAYER; | |
220 | } | |
221 | } | |
222 | ||
223 | /* | |
224 | * @see org.eclipse.jface.text.source.IAnnotationPresentation#getLayer() | |
225 | */ | |
226 | public int getLayer() { | |
227 | return fLayer; | |
228 | } | |
229 | ||
230 | private void initializeImage() { | |
231 | // http://bugs.eclipse.org/bugs/show_bug.cgi?id=18936 | |
232 | if (!fImageInitialized) { | |
233 | initializeImages(); | |
234 | if (!isQuickFixableStateSet()) | |
235 | setQuickFixable(isProblem() && indicateQuixFixableProblems() && JavaCorrectionProcessor.hasCorrections(this)); // no light bulb for tasks | |
236 | if (isQuickFixable()) { | |
237 | if (JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE.equals(getType())) | |
238 | fImage= fgQuickFixErrorImage; | |
239 | else | |
240 | fImage= fgQuickFixImage; | |
241 | } else { | |
242 | String type= getType(); | |
243 | if (JavaMarkerAnnotation.TASK_ANNOTATION_TYPE.equals(type)) | |
244 | fImage= fgTaskImage; | |
245 | else if (JavaMarkerAnnotation.INFO_ANNOTATION_TYPE.equals(type)) | |
246 | fImage= fgInfoImage; | |
247 | else if (JavaMarkerAnnotation.WARNING_ANNOTATION_TYPE.equals(type)) | |
248 | fImage= fgWarningImage; | |
249 | else if (JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE.equals(type)) | |
250 | fImage= fgErrorImage; | |
251 | } | |
252 | fImageInitialized= true; | |
253 | } | |
254 | } | |
255 | ||
256 | private void initializeImages() { | |
257 | if (fgImagesInitialized) | |
258 | return; | |
259 | ||
260 | fgQuickFixImage= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_PROBLEM); | |
261 | fgQuickFixErrorImage= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_ERROR); | |
262 | ||
263 | ISharedImages sharedImages= PlatformUI.getWorkbench().getSharedImages(); | |
264 | fgTaskImage= sharedImages.getImage(SharedImages.IMG_OBJS_TASK_TSK); | |
265 | fgInfoImage= sharedImages.getImage(ISharedImages.IMG_OBJS_INFO_TSK); | |
266 | fgWarningImage= sharedImages.getImage(ISharedImages.IMG_OBJS_WARN_TSK); | |
267 | fgErrorImage= sharedImages.getImage(ISharedImages.IMG_OBJS_ERROR_TSK); | |
268 | ||
269 | fgImagesInitialized= true; | |
270 | } | |
271 | ||
272 | private boolean indicateQuixFixableProblems() { | |
273 | return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CORRECTION_INDICATION); | |
274 | } | |
275 | ||
276 | /* | |
277 | * @see Annotation#paint | |
278 | */ | |
279 | public void paint(GC gc, Canvas canvas, Rectangle r) { | |
280 | initializeImage(); | |
281 | if (fImage != null) | |
282 | ImageUtilities.drawImage(fImage, gc, canvas, r, SWT.CENTER, SWT.TOP); | |
283 | } | |
284 | ||
285 | /* | |
286 | * @see IJavaAnnotation#getMessage() | |
287 | */ | |
288 | @Override | |
289 | public String getText() { | |
290 | return fProblem.getMessage(); | |
291 | } | |
292 | ||
293 | /* | |
294 | * @see IJavaAnnotation#getArguments() | |
295 | */ | |
296 | public String[] getArguments() { | |
297 | return isProblem() ? fProblem.getArguments() : null; | |
298 | } | |
299 | ||
300 | /* | |
301 | * @see IJavaAnnotation#getId() | |
302 | */ | |
303 | public int getId() { | |
304 | return fProblem.getID(); | |
305 | } | |
306 | ||
307 | /* | |
308 | * @see IJavaAnnotation#isProblem() | |
309 | */ | |
310 | public boolean isProblem() { | |
311 | String type= getType(); | |
312 | return JavaMarkerAnnotation.WARNING_ANNOTATION_TYPE.equals(type) || | |
313 | JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE.equals(type) || | |
314 | SPELLING_ANNOTATION_TYPE.equals(type); | |
315 | } | |
316 | ||
317 | /* | |
318 | * @see IJavaAnnotation#hasOverlay() | |
319 | */ | |
320 | public boolean hasOverlay() { | |
321 | return false; | |
322 | } | |
323 | ||
324 | /* | |
325 | * @see org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation#getOverlay() | |
326 | */ | |
327 | public IJavaAnnotation getOverlay() { | |
328 | return null; | |
329 | } | |
330 | ||
331 | /* | |
332 | * @see IJavaAnnotation#addOverlaid(IJavaAnnotation) | |
333 | */ | |
334 | public void addOverlaid(IJavaAnnotation annotation) { | |
335 | if (fOverlaids == null) | |
336 | fOverlaids= new ArrayList<IJavaAnnotation>(1); | |
337 | fOverlaids.add(annotation); | |
338 | } | |
339 | ||
340 | /* | |
341 | * @see IJavaAnnotation#removeOverlaid(IJavaAnnotation) | |
342 | */ | |
343 | public void removeOverlaid(IJavaAnnotation annotation) { | |
344 | if (fOverlaids != null) { | |
345 | fOverlaids.remove(annotation); | |
346 | if (fOverlaids.size() == 0) | |
347 | fOverlaids= null; | |
348 | } | |
349 | } | |
350 | ||
351 | /* | |
352 | * @see IJavaAnnotation#getOverlaidIterator() | |
353 | */ | |
354 | public Iterator<IJavaAnnotation> getOverlaidIterator() { | |
355 | if (fOverlaids != null) | |
356 | return fOverlaids.iterator(); | |
357 | return null; | |
358 | } | |
359 | ||
360 | /* | |
361 | * @see org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation#getCompilationUnit() | |
362 | */ | |
363 | public ICompilationUnit getCompilationUnit() { | |
364 | return fCompilationUnit; | |
365 | } | |
366 | ||
367 | /* | |
368 | * @see org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation#getMarkerType() | |
369 | */ | |
370 | public String getMarkerType() { | |
371 | if (fProblem instanceof CategorizedProblem) | |
372 | return ((CategorizedProblem) fProblem).getMarkerType(); | |
373 | return null; | |
374 | } | |
375 | ||
376 | /* | |
377 | * @see org.eclipse.jface.text.quickassist.IQuickFixableAnnotation#setQuickFixable(boolean) | |
378 | * @since 3.2 | |
379 | */ | |
380 | public void setQuickFixable(boolean state) { | |
381 | fIsQuickFixable= state; | |
382 | fIsQuickFixableStateSet= true; | |
383 | } | |
384 | ||
385 | /* | |
386 | * @see org.eclipse.jface.text.quickassist.IQuickFixableAnnotation#isQuickFixableStateSet() | |
387 | * @since 3.2 | |
388 | */ | |
389 | public boolean isQuickFixableStateSet() { | |
390 | return fIsQuickFixableStateSet; | |
391 | } | |
392 | ||
393 | /* | |
394 | * @see org.eclipse.jface.text.quickassist.IQuickFixableAnnotation#isQuickFixable() | |
395 | * @since 3.2 | |
396 | */ | |
397 | public boolean isQuickFixable() { | |
398 | Assert.isTrue(isQuickFixableStateSet()); | |
399 | return fIsQuickFixable; | |
400 | } | |
401 | } | |
402 | ||
403 | /** | |
404 | * Internal structure for mapping positions to some value. | |
405 | * The reason for this specific structure is that positions can | |
406 | * change over time. Thus a lookup is based on value and not | |
407 | * on hash value. | |
408 | */ | |
409 | protected static class ReverseMap { | |
410 | ||
411 | static class Entry { | |
412 | Position fPosition; | |
413 | Object fValue; | |
414 | } | |
415 | ||
416 | private List<Entry> fList= new ArrayList<Entry>(2); | |
417 | private int fAnchor= 0; | |
418 | ||
419 | public ReverseMap() { | |
420 | } | |
421 | ||
422 | public Object get(Position position) { | |
423 | ||
424 | Entry entry; | |
425 | ||
426 | // behind anchor | |
427 | int length= fList.size(); | |
428 | for (int i= fAnchor; i < length; i++) { | |
429 | entry= fList.get(i); | |
430 | if (entry.fPosition.equals(position)) { | |
431 | fAnchor= i; | |
432 | return entry.fValue; | |
433 | } | |
434 | } | |
435 | ||
436 | // before anchor | |
437 | for (int i= 0; i < fAnchor; i++) { | |
438 | entry= fList.get(i); | |
439 | if (entry.fPosition.equals(position)) { | |
440 | fAnchor= i; | |
441 | return entry.fValue; | |
442 | } | |
443 | } | |
444 | ||
445 | return null; | |
446 | } | |
447 | ||
448 | private int getIndex(Position position) { | |
449 | Entry entry; | |
450 | int length= fList.size(); | |
451 | for (int i= 0; i < length; i++) { | |
452 | entry= fList.get(i); | |
453 | if (entry.fPosition.equals(position)) | |
454 | return i; | |
455 | } | |
456 | return -1; | |
457 | } | |
458 | ||
459 | public void put(Position position, Object value) { | |
460 | int index= getIndex(position); | |
461 | if (index == -1) { | |
462 | Entry entry= new Entry(); | |
463 | entry.fPosition= position; | |
464 | entry.fValue= value; | |
465 | fList.add(entry); | |
466 | } else { | |
467 | Entry entry= fList.get(index); | |
468 | entry.fValue= value; | |
469 | } | |
470 | } | |
471 | ||
472 | public void remove(Position position) { | |
473 | int index= getIndex(position); | |
474 | if (index > -1) | |
475 | fList.remove(index); | |
476 | } | |
477 | ||
478 | public void clear() { | |
479 | fList.clear(); | |
480 | } | |
481 | } | |
482 | ||
483 | /** | |
484 | * Annotation model dealing with java marker annotations and temporary problems. | |
485 | * Also acts as problem requester for its compilation unit. Initially inactive. Must explicitly be | |
486 | * activated. | |
487 | */ | |
488 | protected static class CompilationUnitAnnotationModel extends ResourceMarkerAnnotationModel implements IProblemRequestor, IProblemRequestorExtension { | |
489 | ||
490 | private static class ProblemRequestorState { | |
491 | boolean fInsideReportingSequence= false; | |
492 | List<IProblem> fReportedProblems; | |
493 | } | |
494 | ||
495 | private ThreadLocal<ProblemRequestorState> fProblemRequestorState= new ThreadLocal<ProblemRequestorState>(); | |
496 | private int fStateCount= 0; | |
497 | ||
498 | private ICompilationUnit fCompilationUnit; | |
499 | private final List<ProblemAnnotation> fGeneratedAnnotations= new ArrayList<ProblemAnnotation>(); | |
500 | private IProgressMonitor fProgressMonitor; | |
501 | private boolean fIsActive= false; | |
502 | private boolean fIsHandlingTemporaryProblems; | |
503 | ||
504 | private ReverseMap fReverseMap= new ReverseMap(); | |
505 | private List<JavaMarkerAnnotation> fPreviouslyOverlaid= null; | |
506 | private List<JavaMarkerAnnotation> fCurrentlyOverlaid= new ArrayList<JavaMarkerAnnotation>(); | |
507 | private Thread fActiveThread; | |
508 | ||
509 | ||
510 | public CompilationUnitAnnotationModel(IResource resource) { | |
511 | super(resource); | |
512 | } | |
513 | ||
514 | public void setCompilationUnit(ICompilationUnit unit) { | |
515 | fCompilationUnit= unit; | |
516 | } | |
517 | ||
518 | @Override | |
519 | protected MarkerAnnotation createMarkerAnnotation(IMarker marker) { | |
520 | if (JavaMarkerAnnotation.isJavaAnnotation(marker)) | |
521 | return new JavaMarkerAnnotation(marker); | |
522 | return super.createMarkerAnnotation(marker); | |
523 | } | |
524 | ||
525 | /* | |
526 | * @see org.eclipse.jface.text.source.AnnotationModel#createAnnotationModelEvent() | |
527 | */ | |
528 | @Override | |
529 | protected AnnotationModelEvent createAnnotationModelEvent() { | |
530 | return new CompilationUnitAnnotationModelEvent(this, getResource()); | |
531 | } | |
532 | ||
533 | protected Position createPositionFromProblem(IProblem problem) { | |
534 | int start= problem.getSourceStart(); | |
535 | int end= problem.getSourceEnd(); | |
536 | ||
537 | if (start == -1 && end == -1) | |
538 | return new Position(0); | |
539 | ||
540 | if (start == -1) | |
541 | return new Position(end); | |
542 | ||
543 | if (end == -1) | |
544 | return new Position(start); | |
545 | ||
546 | int length= end - start + 1; | |
547 | if (length < 0) | |
548 | return null; | |
549 | ||
550 | return new Position(start, length); | |
551 | } | |
552 | ||
553 | /* | |
554 | * @see IProblemRequestor#beginReporting() | |
555 | */ | |
556 | public void beginReporting() { | |
557 | ProblemRequestorState state= fProblemRequestorState.get(); | |
558 | if (state == null) | |
559 | internalBeginReporting(false); | |
560 | } | |
561 | ||
562 | /* | |
563 | * @see org.eclipse.jdt.internal.ui.text.java.IProblemRequestorExtension#beginReportingSequence() | |
564 | */ | |
565 | public void beginReportingSequence() { | |
566 | ProblemRequestorState state= fProblemRequestorState.get(); | |
567 | if (state == null) | |
568 | internalBeginReporting(true); | |
569 | } | |
570 | ||
571 | /** | |
572 | * Sets up the infrastructure necessary for problem reporting. | |
573 | * | |
574 | * @param insideReportingSequence <code>true</code> if this method | |
575 | * call is issued from inside a reporting sequence | |
576 | */ | |
577 | private void internalBeginReporting(boolean insideReportingSequence) { | |
578 | if (fCompilationUnit != null && fCompilationUnit.getJavaProject().isOnClasspath(fCompilationUnit)) { | |
579 | ProblemRequestorState state= new ProblemRequestorState(); | |
580 | state.fInsideReportingSequence= insideReportingSequence; | |
581 | state.fReportedProblems= new ArrayList<IProblem>(); | |
582 | synchronized (getLockObject()) { | |
583 | fProblemRequestorState.set(state); | |
584 | ++fStateCount; | |
585 | } | |
586 | } | |
587 | } | |
588 | ||
589 | /* | |
590 | * @see IProblemRequestor#acceptProblem(IProblem) | |
591 | */ | |
592 | public void acceptProblem(IProblem problem) { | |
593 | if (fIsHandlingTemporaryProblems || problem.getID() == JavaSpellingReconcileStrategy.SPELLING_PROBLEM_ID) { | |
594 | ProblemRequestorState state= fProblemRequestorState.get(); | |
595 | if (state != null) | |
596 | state.fReportedProblems.add(problem); | |
597 | } | |
598 | } | |
599 | ||
600 | /* | |
601 | * @see IProblemRequestor#endReporting() | |
602 | */ | |
603 | public void endReporting() { | |
604 | ProblemRequestorState state= fProblemRequestorState.get(); | |
605 | if (state != null && !state.fInsideReportingSequence) | |
606 | internalEndReporting(state); | |
607 | } | |
608 | ||
609 | /* | |
610 | * @see org.eclipse.jdt.internal.ui.text.java.IProblemRequestorExtension#endReportingSequence() | |
611 | */ | |
612 | public void endReportingSequence() { | |
613 | ProblemRequestorState state= fProblemRequestorState.get(); | |
614 | if (state != null && state.fInsideReportingSequence) | |
615 | internalEndReporting(state); | |
616 | } | |
617 | ||
618 | private void internalEndReporting(ProblemRequestorState state) { | |
619 | int stateCount= 0; | |
620 | synchronized(getLockObject()) { | |
621 | -- fStateCount; | |
622 | stateCount= fStateCount; | |
623 | fProblemRequestorState.set(null); | |
624 | } | |
625 | ||
626 | if (stateCount == 0) | |
627 | reportProblems(state.fReportedProblems); | |
628 | } | |
629 | ||
630 | /** | |
631 | * Signals the end of problem reporting. | |
632 | * | |
633 | * @param reportedProblems the problems to report | |
634 | */ | |
635 | private void reportProblems(List<IProblem> reportedProblems) { | |
636 | if (fProgressMonitor != null && fProgressMonitor.isCanceled()) | |
637 | return; | |
638 | ||
639 | boolean temporaryProblemsChanged= false; | |
640 | ||
641 | synchronized (getLockObject()) { | |
642 | ||
643 | boolean isCanceled= false; | |
644 | ||
645 | fPreviouslyOverlaid= fCurrentlyOverlaid; | |
646 | fCurrentlyOverlaid= new ArrayList<JavaMarkerAnnotation>(); | |
647 | ||
648 | if (fGeneratedAnnotations.size() > 0) { | |
649 | temporaryProblemsChanged= true; | |
650 | removeAnnotations(fGeneratedAnnotations, false, true); | |
651 | fGeneratedAnnotations.clear(); | |
652 | } | |
653 | ||
654 | if (reportedProblems != null && reportedProblems.size() > 0) { | |
655 | ||
656 | Iterator<IProblem> e= reportedProblems.iterator(); | |
657 | while (e.hasNext()) { | |
658 | ||
659 | if (fProgressMonitor != null && fProgressMonitor.isCanceled()) { | |
660 | isCanceled= true; | |
661 | break; | |
662 | } | |
663 | ||
664 | IProblem problem= e.next(); | |
665 | Position position= createPositionFromProblem(problem); | |
666 | if (position != null) { | |
667 | ||
668 | try { | |
669 | ProblemAnnotation annotation= new ProblemAnnotation(problem, fCompilationUnit); | |
670 | overlayMarkers(position, annotation); | |
671 | addAnnotation(annotation, position, false); | |
672 | fGeneratedAnnotations.add(annotation); | |
673 | ||
674 | temporaryProblemsChanged= true; | |
675 | } catch (BadLocationException x) { | |
676 | // ignore invalid position | |
677 | } | |
678 | } | |
679 | } | |
680 | } | |
681 | ||
682 | removeMarkerOverlays(isCanceled); | |
683 | fPreviouslyOverlaid= null; | |
684 | } | |
685 | ||
686 | if (temporaryProblemsChanged) | |
687 | fireModelChanged(); | |
688 | } | |
689 | ||
690 | private void removeMarkerOverlays(boolean isCanceled) { | |
691 | if (isCanceled) { | |
692 | fCurrentlyOverlaid.addAll(fPreviouslyOverlaid); | |
693 | } else if (fPreviouslyOverlaid != null) { | |
694 | Iterator<JavaMarkerAnnotation> e= fPreviouslyOverlaid.iterator(); | |
695 | while (e.hasNext()) { | |
696 | JavaMarkerAnnotation annotation= e.next(); | |
697 | annotation.setOverlay(null); | |
698 | } | |
699 | } | |
700 | } | |
701 | ||
702 | /** | |
703 | * Overlays value with problem annotation. | |
704 | * | |
705 | * @param value the value | |
706 | * @param problemAnnotation the problem annotation | |
707 | */ | |
708 | private void setOverlay(Object value, ProblemAnnotation problemAnnotation) { | |
709 | if (value instanceof JavaMarkerAnnotation) { | |
710 | JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) value; | |
711 | if (annotation.isProblem()) { | |
712 | annotation.setOverlay(problemAnnotation); | |
713 | fPreviouslyOverlaid.remove(annotation); | |
714 | fCurrentlyOverlaid.add(annotation); | |
715 | } | |
716 | } else { | |
717 | } | |
718 | } | |
719 | ||
720 | private void overlayMarkers(Position position, ProblemAnnotation problemAnnotation) { | |
721 | Object value= getAnnotations(position); | |
722 | if (value instanceof List) { | |
723 | List<?> list= (List<?>) value; | |
724 | for (Iterator<?> e = list.iterator(); e.hasNext();) | |
725 | setOverlay(e.next(), problemAnnotation); | |
726 | } else { | |
727 | setOverlay(value, problemAnnotation); | |
728 | } | |
729 | } | |
730 | ||
731 | /** | |
732 | * Tells this annotation model to collect temporary problems from now on. | |
733 | */ | |
734 | private void startCollectingProblems() { | |
735 | fGeneratedAnnotations.clear(); | |
736 | } | |
737 | ||
738 | /** | |
739 | * Tells this annotation model to no longer collect temporary problems. | |
740 | */ | |
741 | private void stopCollectingProblems() { | |
742 | removeAnnotations(fGeneratedAnnotations, true, true); | |
743 | fGeneratedAnnotations.clear(); | |
744 | } | |
745 | ||
746 | /* | |
747 | * @see IProblemRequestor#isActive() | |
748 | */ | |
749 | public synchronized boolean isActive() { | |
750 | return fIsActive && fActiveThread == Thread.currentThread(); | |
751 | } | |
752 | ||
753 | /* | |
754 | * @see IProblemRequestorExtension#setProgressMonitor(IProgressMonitor) | |
755 | */ | |
756 | public void setProgressMonitor(IProgressMonitor monitor) { | |
757 | fProgressMonitor= monitor; | |
758 | } | |
759 | ||
760 | /* | |
761 | * @see IProblemRequestorExtension#setIsActive(boolean) | |
762 | */ | |
763 | public synchronized void setIsActive(boolean isActive) { | |
764 | Assert.isLegal(!isActive || Display.getCurrent() == null); // must not be enabled from UI threads | |
765 | fIsActive= isActive; | |
766 | if (fIsActive) | |
767 | fActiveThread= Thread.currentThread(); | |
768 | else | |
769 | fActiveThread= null; | |
770 | } | |
771 | ||
772 | /* | |
773 | * @see IProblemRequestorExtension#setIsHandlingTemporaryProblems(boolean) | |
774 | * @since 3.1 | |
775 | */ | |
776 | public void setIsHandlingTemporaryProblems(boolean enable) { | |
777 | if (fIsHandlingTemporaryProblems != enable) { | |
778 | fIsHandlingTemporaryProblems= enable; | |
779 | if (fIsHandlingTemporaryProblems) | |
780 | startCollectingProblems(); | |
781 | else | |
782 | stopCollectingProblems(); | |
783 | } | |
784 | ||
785 | } | |
786 | ||
787 | private Object getAnnotations(Position position) { | |
788 | synchronized (getLockObject()) { | |
789 | return fReverseMap.get(position); | |
790 | } | |
791 | } | |
792 | ||
793 | /* | |
794 | * @see AnnotationModel#addAnnotation(Annotation, Position, boolean) | |
795 | */ | |
796 | @Override | |
797 | protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) throws BadLocationException { | |
798 | super.addAnnotation(annotation, position, fireModelChanged); | |
799 | ||
800 | synchronized (getLockObject()) { | |
801 | Object cached= fReverseMap.get(position); | |
802 | if (cached == null) | |
803 | fReverseMap.put(position, annotation); | |
804 | else if (cached instanceof List) { | |
805 | @SuppressWarnings("unchecked") | |
806 | List<Object> list= (List<Object>) cached; | |
807 | list.add(annotation); | |
808 | } else if (cached instanceof Annotation) { | |
809 | List<Object> list= new ArrayList<Object>(2); | |
810 | list.add(cached); | |
811 | list.add(annotation); | |
812 | fReverseMap.put(position, list); | |
813 | } | |
814 | } | |
815 | } | |
816 | ||
817 | /* | |
818 | * @see AnnotationModel#removeAllAnnotations(boolean) | |
819 | */ | |
820 | @Override | |
821 | protected void removeAllAnnotations(boolean fireModelChanged) { | |
822 | super.removeAllAnnotations(fireModelChanged); | |
823 | synchronized (getLockObject()) { | |
824 | fReverseMap.clear(); | |
825 | } | |
826 | } | |
827 | ||
828 | /* | |
829 | * @see AnnotationModel#removeAnnotation(Annotation, boolean) | |
830 | */ | |
831 | @Override | |
832 | protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) { | |
833 | Position position= getPosition(annotation); | |
834 | synchronized (getLockObject()) { | |
835 | Object cached= fReverseMap.get(position); | |
836 | if (cached instanceof List) { | |
837 | @SuppressWarnings("unchecked") | |
838 | List<Object> list= (List<Object>) cached; | |
839 | list.remove(annotation); | |
840 | if (list.size() == 1) { | |
841 | fReverseMap.put(position, list.get(0)); | |
842 | list.clear(); | |
843 | } | |
844 | } else if (cached instanceof Annotation) { | |
845 | fReverseMap.remove(position); | |
846 | } | |
847 | } | |
848 | super.removeAnnotation(annotation, fireModelChanged); | |
849 | } | |
850 | } | |
851 | ||
852 | ||
853 | protected static class GlobalAnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension { | |
854 | ||
855 | private ListenerList fListenerList; | |
856 | ||
857 | public GlobalAnnotationModelListener() { | |
858 | fListenerList= new ListenerList(ListenerList.IDENTITY); | |
859 | } | |
860 | ||
861 | /** | |
862 | * @see IAnnotationModelListener#modelChanged(IAnnotationModel) | |
863 | */ | |
864 | public void modelChanged(IAnnotationModel model) { | |
865 | Object[] listeners= fListenerList.getListeners(); | |
866 | for (int i= 0; i < listeners.length; i++) { | |
867 | ((IAnnotationModelListener) listeners[i]).modelChanged(model); | |
868 | } | |
869 | } | |
870 | ||
871 | /** | |
872 | * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent) | |
873 | */ | |
874 | public void modelChanged(AnnotationModelEvent event) { | |
875 | Object[] listeners= fListenerList.getListeners(); | |
876 | for (int i= 0; i < listeners.length; i++) { | |
877 | Object curr= listeners[i]; | |
878 | if (curr instanceof IAnnotationModelListenerExtension) { | |
879 | ((IAnnotationModelListenerExtension) curr).modelChanged(event); | |
880 | } | |
881 | } | |
882 | } | |
883 | ||
884 | public void addListener(IAnnotationModelListener listener) { | |
885 | fListenerList.add(listener); | |
886 | } | |
887 | ||
888 | public void removeListener(IAnnotationModelListener listener) { | |
889 | fListenerList.remove(listener); | |
890 | } | |
891 | } | |
892 | ||
893 | ||
894 | ||
895 | /** Preference key for temporary problems */ | |
896 | private final static String HANDLE_TEMPORARY_PROBLEMS= PreferenceConstants.EDITOR_EVALUTE_TEMPORARY_PROBLEMS; | |
897 | ||
898 | ||
899 | /** Indicates whether the save has been initialized by this provider */ | |
900 | private boolean fIsAboutToSave= false; | |
901 | /** The save policy used by this provider */ | |
902 | private ISavePolicy fSavePolicy; | |
903 | /** Internal property changed listener */ | |
904 | private IPropertyChangeListener fPropertyListener; | |
905 | /** Annotation model listener added to all created CU annotation models */ | |
906 | private GlobalAnnotationModelListener fGlobalAnnotationModelListener; | |
907 | /** | |
908 | * Element information of all connected elements with a fake CU but no file info. | |
909 | * @since 3.2 | |
910 | */ | |
911 | private final Map<Object, CompilationUnitInfo> fFakeCUMapForMissingInfo= new HashMap<Object, CompilationUnitInfo>(); | |
912 | ||
913 | ||
914 | /** | |
915 | * Constructor | |
916 | */ | |
917 | public CompilationUnitDocumentProvider() { | |
918 | ||
919 | IDocumentProvider provider= new TextFileDocumentProvider(); | |
920 | provider= new ForwardingDocumentProvider(IJavaPartitions.JAVA_PARTITIONING, new JavaDocumentSetupParticipant(), provider); | |
921 | setParentDocumentProvider(provider); | |
922 | ||
923 | fGlobalAnnotationModelListener= new GlobalAnnotationModelListener(); | |
924 | fPropertyListener= new IPropertyChangeListener() { | |
925 | public void propertyChange(PropertyChangeEvent event) { | |
926 | if (HANDLE_TEMPORARY_PROBLEMS.equals(event.getProperty())) | |
927 | enableHandlingTemporaryProblems(); | |
928 | } | |
929 | }; | |
930 | JavaPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPropertyListener); | |
931 | } | |
932 | ||
933 | /** | |
934 | * Creates a compilation unit from the given file. | |
935 | * | |
936 | * @param file the file from which to create the compilation unit | |
937 | * @return the fake compilation unit | |
938 | */ | |
939 | protected ICompilationUnit createCompilationUnit(IFile file) { | |
940 | Object element= JavaCore.create(file); | |
941 | if (element instanceof ICompilationUnit) | |
942 | return (ICompilationUnit) element; | |
943 | return null; | |
944 | } | |
945 | ||
946 | /* | |
947 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createEmptyFileInfo() | |
948 | */ | |
949 | @Override | |
950 | protected FileInfo createEmptyFileInfo() { | |
951 | return new CompilationUnitInfo(); | |
952 | } | |
953 | ||
954 | /* | |
955 | * @see org.eclipse.core.filebuffers.IAnnotationModelFactory#createAnnotationModel(org.eclipse.core.runtime.IPath) | |
956 | * @since 3.4 | |
957 | */ | |
958 | public IAnnotationModel createAnnotationModel(IPath path) { | |
959 | IResource file= ResourcesPlugin.getWorkspace().getRoot().findMember(path); | |
960 | if (file instanceof IFile) | |
961 | return new CompilationUnitAnnotationModel(file); | |
962 | return new AnnotationModel(); | |
963 | } | |
964 | ||
965 | /* | |
966 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createFileInfo(java.lang.Object) | |
967 | */ | |
968 | @Override | |
969 | protected FileInfo createFileInfo(Object element) throws CoreException { | |
970 | ICompilationUnit original= null; | |
971 | if (element instanceof IFileEditorInput) { | |
972 | IFileEditorInput input= (IFileEditorInput) element; | |
973 | original= createCompilationUnit(input.getFile()); | |
974 | if (original == null) | |
975 | return null; | |
976 | } | |
977 | ||
978 | FileInfo info= super.createFileInfo(element); | |
979 | if (!(info instanceof CompilationUnitInfo)) | |
980 | return null; | |
981 | ||
982 | if (original == null) | |
983 | original= createFakeCompiltationUnit(element, false); | |
984 | if (original == null) | |
985 | return null; | |
986 | ||
987 | CompilationUnitInfo cuInfo= (CompilationUnitInfo) info; | |
988 | setUpSynchronization(cuInfo); | |
989 | ||
990 | IProblemRequestor requestor= cuInfo.fModel instanceof IProblemRequestor ? (IProblemRequestor) cuInfo.fModel : null; | |
991 | if (requestor instanceof IProblemRequestorExtension) { | |
992 | IProblemRequestorExtension extension= (IProblemRequestorExtension) requestor; | |
993 | extension.setIsActive(false); | |
994 | extension.setIsHandlingTemporaryProblems(isHandlingTemporaryProblems()); | |
995 | } | |
996 | ||
997 | IResource resource= original.getResource(); | |
998 | if (JavaModelUtil.isPrimary(original) && (resource == null || resource.exists())) | |
999 | original.becomeWorkingCopy(requestor, getProgressMonitor()); | |
1000 | cuInfo.fCopy= original; | |
1001 | ||
1002 | if (cuInfo.fModel instanceof CompilationUnitAnnotationModel) { | |
1003 | CompilationUnitAnnotationModel model= (CompilationUnitAnnotationModel) cuInfo.fModel; | |
1004 | model.setCompilationUnit(cuInfo.fCopy); | |
1005 | } | |
1006 | ||
1007 | if (cuInfo.fModel != null) | |
1008 | cuInfo.fModel.addAnnotationModelListener(fGlobalAnnotationModelListener); | |
1009 | ||
1010 | return cuInfo; | |
1011 | } | |
1012 | ||
1013 | /** | |
1014 | * Creates a fake compilation unit. | |
1015 | * | |
1016 | * @param element the element | |
1017 | * @param setContents tells whether to read and set the contents to the new CU | |
1018 | * @return the fake compilation unit | |
1019 | * @since 3.2 | |
1020 | */ | |
1021 | private ICompilationUnit createFakeCompiltationUnit(Object element, boolean setContents) { | |
1022 | if (element instanceof IStorageEditorInput) | |
1023 | return createFakeCompiltationUnit((IStorageEditorInput)element, setContents); | |
1024 | else if (element instanceof IURIEditorInput) | |
1025 | return createFakeCompiltationUnit((IURIEditorInput)element); | |
1026 | return null; | |
1027 | } | |
1028 | ||
1029 | /** | |
1030 | * Creates a fake compilation unit. | |
1031 | * | |
1032 | * @param editorInput the storage editor input | |
1033 | * @param setContents tells whether to read and set the contents to the new CU | |
1034 | * @return the fake compilation unit | |
1035 | * @since 3.2 | |
1036 | */ | |
1037 | private ICompilationUnit createFakeCompiltationUnit(IStorageEditorInput editorInput, boolean setContents) { | |
1038 | try { | |
1039 | final IStorage storage= editorInput.getStorage(); | |
1040 | final IPath storagePath= storage.getFullPath(); | |
1041 | if (storage.getName() == null || storagePath == null) | |
1042 | return null; | |
1043 | ||
1044 | final IPath documentPath; | |
1045 | if (storage instanceof IFileState) | |
1046 | documentPath= storagePath.append(Long.toString(((IFileState)storage).getModificationTime())); | |
1047 | else if (isFileRevisionEditorInput(editorInput)) | |
1048 | documentPath= storagePath.append(Long.toString(System.currentTimeMillis())); | |
1049 | else | |
1050 | documentPath= storagePath; | |
1051 | ||
1052 | WorkingCopyOwner woc= new WorkingCopyOwner() { | |
1053 | /* | |
1054 | * @see org.eclipse.jdt.core.WorkingCopyOwner#createBuffer(org.eclipse.jdt.core.ICompilationUnit) | |
1055 | * @since 3.2 | |
1056 | */ | |
1057 | @Override | |
1058 | public IBuffer createBuffer(ICompilationUnit workingCopy) { | |
1059 | return new DocumentAdapter(workingCopy, documentPath); | |
1060 | } | |
1061 | }; | |
1062 | ||
1063 | IClasspathEntry[] cpEntries= null; | |
1064 | IJavaProject jp= findJavaProject(storagePath); | |
1065 | if (jp != null) | |
1066 | cpEntries= jp.getResolvedClasspath(true); | |
1067 | ||
1068 | if (cpEntries == null || cpEntries.length == 0) | |
1069 | cpEntries= new IClasspathEntry[] { JavaRuntime.getDefaultJREContainerEntry() }; | |
1070 | ||
1071 | final ICompilationUnit cu= woc.newWorkingCopy(storage.getName(), cpEntries, getProgressMonitor()); | |
1072 | if (setContents) { | |
1073 | int READER_CHUNK_SIZE= 2048; | |
1074 | int BUFFER_SIZE= 8 * READER_CHUNK_SIZE; | |
1075 | ||
1076 | String charsetName= null; | |
1077 | if (storage instanceof IEncodedStorage) | |
1078 | charsetName= ((IEncodedStorage)storage).getCharset(); | |
1079 | if (charsetName == null) | |
1080 | charsetName= getDefaultEncoding(); | |
1081 | ||
1082 | Reader in= null; | |
1083 | InputStream contents= storage.getContents(); | |
1084 | try { | |
1085 | in= new BufferedReader(new InputStreamReader(contents, charsetName)); | |
1086 | StringBuffer buffer= new StringBuffer(BUFFER_SIZE); | |
1087 | char[] readBuffer= new char[READER_CHUNK_SIZE]; | |
1088 | int n; | |
1089 | n= in.read(readBuffer); | |
1090 | while (n > 0) { | |
1091 | buffer.append(readBuffer, 0, n); | |
1092 | n= in.read(readBuffer); | |
1093 | } | |
1094 | cu.getBuffer().setContents(buffer.toString()); | |
1095 | } catch (IOException e) { | |
1096 | JavaPlugin.log(e); | |
1097 | return null; | |
1098 | } finally { | |
1099 | try { | |
1100 | if (in != null) | |
1101 | in.close(); | |
1102 | else | |
1103 | contents.close(); | |
1104 | } catch (IOException x) { | |
1105 | } | |
1106 | } | |
1107 | } | |
1108 | ||
1109 | if (!isModifiable(editorInput)) | |
1110 | JavaModelUtil.reconcile(cu); | |
1111 | ||
1112 | return cu; | |
1113 | } catch (CoreException ex) { | |
1114 | JavaPlugin.log(ex.getStatus()); | |
1115 | return null; | |
1116 | } | |
1117 | } | |
1118 | ||
1119 | /** | |
1120 | * Tests whether the given editor input is an instance of | |
1121 | * <code>org.eclipse.team.internal.ui.history.FileRevisionEditorInput</code>. | |
1122 | * <p> | |
1123 | * XXX: Workaround for https://bugs.eclipse.org/307756, see comment 2 on how a better solution | |
1124 | * could look like. | |
1125 | * </p> | |
1126 | * | |
1127 | * @param editorInput the editor input to test | |
1128 | * @return <code>true</code> if it is an instance of | |
1129 | * <code>org.eclipse.team.internal.ui.history.FileRevisionEditorInput</code> | |
1130 | * @since 3.6 | |
1131 | */ | |
1132 | private static boolean isFileRevisionEditorInput(IEditorInput editorInput) { | |
1133 | try { | |
1134 | return Class.forName("org.eclipse.team.internal.ui.history.FileRevisionEditorInput").isInstance(editorInput); //$NON-NLS-1$ | |
1135 | } catch (ClassNotFoundException ex) { | |
1136 | return false; | |
1137 | } | |
1138 | } | |
1139 | ||
1140 | /** | |
1141 | * Creates a fake compilation unit. | |
1142 | * | |
1143 | * @param editorInput the URI editor input | |
1144 | * @return the fake compilation unit | |
1145 | * @since 3.3 | |
1146 | */ | |
1147 | private ICompilationUnit createFakeCompiltationUnit(IURIEditorInput editorInput) { | |
1148 | try { | |
1149 | final URI uri= editorInput.getURI(); | |
1150 | final IFileStore fileStore= EFS.getStore(uri); | |
1151 | final IPath path= URIUtil.toPath(uri); | |
1152 | String fileStoreName= fileStore.getName(); | |
1153 | if (fileStoreName == null || path == null) | |
1154 | return null; | |
1155 | ||
1156 | WorkingCopyOwner woc= new WorkingCopyOwner() { | |
1157 | /* | |
1158 | * @see org.eclipse.jdt.core.WorkingCopyOwner#createBuffer(org.eclipse.jdt.core.ICompilationUnit) | |
1159 | * @since 3.2 | |
1160 | */ | |
1161 | @Override | |
1162 | public IBuffer createBuffer(ICompilationUnit workingCopy) { | |
1163 | return new DocumentAdapter(workingCopy, fileStore, path); | |
1164 | } | |
1165 | }; | |
1166 | ||
1167 | IClasspathEntry[] cpEntries= null; | |
1168 | IJavaProject jp= findJavaProject(path); | |
1169 | if (jp != null) | |
1170 | cpEntries= jp.getResolvedClasspath(true); | |
1171 | ||
1172 | if (cpEntries == null || cpEntries.length == 0) | |
1173 | cpEntries= new IClasspathEntry[] { JavaRuntime.getDefaultJREContainerEntry() }; | |
1174 | ||
1175 | final ICompilationUnit cu= woc.newWorkingCopy(fileStoreName, cpEntries, getProgressMonitor()); | |
1176 | ||
1177 | if (!isModifiable(editorInput)) | |
1178 | JavaModelUtil.reconcile(cu); | |
1179 | ||
1180 | return cu; | |
1181 | } catch (CoreException ex) { | |
1182 | return null; | |
1183 | } | |
1184 | } | |
1185 | ||
1186 | /** | |
1187 | * Fuzzy search for Java project in the workspace that matches | |
1188 | * the given path. | |
1189 | * | |
1190 | * @param path the path to match | |
1191 | * @return the matching Java project or <code>null</code> | |
1192 | * @since 3.2 | |
1193 | */ | |
1194 | private IJavaProject findJavaProject(IPath path) { | |
1195 | if (path == null) | |
1196 | return null; | |
1197 | ||
1198 | String[] pathSegments= path.segments(); | |
1199 | IJavaModel model= JavaCore.create(JavaPlugin.getWorkspace().getRoot()); | |
1200 | IJavaProject[] projects; | |
1201 | try { | |
1202 | projects= model.getJavaProjects(); | |
1203 | } catch (JavaModelException e) { | |
1204 | return null; // ignore - use default JRE | |
1205 | } | |
1206 | for (int i= 0; i < projects.length; i++) { | |
1207 | IPath projectPath= projects[i].getProject().getFullPath(); | |
1208 | String projectSegment= projectPath.segments()[0]; | |
1209 | for (int j= 0; j < pathSegments.length; j++) | |
1210 | if (projectSegment.equals(pathSegments[j])) | |
1211 | return projects[i]; | |
1212 | } | |
1213 | return null; | |
1214 | } | |
1215 | ||
1216 | /* | |
1217 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#disposeFileInfo(java.lang.Object, org.eclipse.ui.editors.text.TextFileDocumentProvider.FileInfo) | |
1218 | */ | |
1219 | @Override | |
1220 | protected void disposeFileInfo(Object element, FileInfo info) { | |
1221 | if (info instanceof CompilationUnitInfo) { | |
1222 | CompilationUnitInfo cuInfo= (CompilationUnitInfo) info; | |
1223 | ||
1224 | try { | |
1225 | cuInfo.fCopy.discardWorkingCopy(); | |
1226 | } catch (JavaModelException x) { | |
1227 | handleCoreException(x, x.getMessage()); | |
1228 | } | |
1229 | ||
1230 | if (cuInfo.fModel != null) | |
1231 | cuInfo.fModel.removeAnnotationModelListener(fGlobalAnnotationModelListener); | |
1232 | } | |
1233 | super.disposeFileInfo(element, info); | |
1234 | } | |
1235 | ||
1236 | /* | |
1237 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#connect(java.lang.Object) | |
1238 | * @since 3.2 | |
1239 | */ | |
1240 | @Override | |
1241 | public void connect(Object element) throws CoreException { | |
1242 | super.connect(element); | |
1243 | if (getFileInfo(element) != null) | |
1244 | return; | |
1245 | ||
1246 | CompilationUnitInfo info= fFakeCUMapForMissingInfo.get(element); | |
1247 | if (info == null) { | |
1248 | ICompilationUnit cu= createFakeCompiltationUnit(element, true); | |
1249 | if (cu == null) | |
1250 | return; | |
1251 | info= new CompilationUnitInfo(); | |
1252 | info.fCopy= cu; | |
1253 | info.fElement= element; | |
1254 | info.fModel= new AnnotationModel(); | |
1255 | fFakeCUMapForMissingInfo.put(element, info); | |
1256 | } | |
1257 | info.fCount++; | |
1258 | } | |
1259 | ||
1260 | /* | |
1261 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#getAnnotationModel(java.lang.Object) | |
1262 | * @since 3.2 | |
1263 | */ | |
1264 | @Override | |
1265 | public IAnnotationModel getAnnotationModel(Object element) { | |
1266 | IAnnotationModel model= super.getAnnotationModel(element); | |
1267 | if (model != null) | |
1268 | return model; | |
1269 | ||
1270 | FileInfo info= fFakeCUMapForMissingInfo.get(element); | |
1271 | if (info != null) { | |
1272 | if (info.fModel != null) | |
1273 | return info.fModel; | |
1274 | if (info.fTextFileBuffer != null) | |
1275 | return info.fTextFileBuffer.getAnnotationModel(); | |
1276 | } | |
1277 | ||
1278 | return null; | |
1279 | } | |
1280 | ||
1281 | /* | |
1282 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#disconnect(java.lang.Object) | |
1283 | * @since 3.2 | |
1284 | */ | |
1285 | @Override | |
1286 | public void disconnect(Object element) { | |
1287 | CompilationUnitInfo info= fFakeCUMapForMissingInfo.get(element); | |
1288 | if (info != null) { | |
1289 | if (info.fCount == 1) { | |
1290 | fFakeCUMapForMissingInfo.remove(element); | |
1291 | info.fModel= null; | |
1292 | // Destroy and unregister fake working copy | |
1293 | try { | |
1294 | info.fCopy.discardWorkingCopy(); | |
1295 | } catch (JavaModelException ex) { | |
1296 | handleCoreException(ex, ex.getMessage()); | |
1297 | } | |
1298 | } else | |
1299 | info.fCount--; | |
1300 | } | |
1301 | super.disconnect(element); | |
1302 | } | |
1303 | ||
1304 | ||
1305 | /** | |
1306 | * Creates and returns a new sub-progress monitor for the | |
1307 | * given parent monitor. | |
1308 | * | |
1309 | * @param monitor the parent progress monitor | |
1310 | * @param ticks the number of work ticks allocated from the parent monitor | |
1311 | * @return the new sub-progress monitor | |
1312 | */ | |
1313 | private IProgressMonitor getSubProgressMonitor(IProgressMonitor monitor, int ticks) { | |
1314 | if (monitor != null) | |
1315 | return new SubProgressMonitor(monitor, ticks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK); | |
1316 | ||
1317 | return new NullProgressMonitor(); | |
1318 | } | |
1319 | ||
1320 | protected void commitWorkingCopy(IProgressMonitor monitor, Object element, final CompilationUnitInfo info, boolean overwrite) throws CoreException { | |
1321 | ||
1322 | if (monitor == null) | |
1323 | monitor= new NullProgressMonitor(); | |
1324 | ||
1325 | monitor.beginTask("", 100); //$NON-NLS-1$ | |
1326 | ||
1327 | try { | |
1328 | IDocument document= info.fTextFileBuffer.getDocument(); | |
1329 | IResource resource= info.fCopy.getResource(); | |
1330 | ||
1331 | Assert.isTrue(resource instanceof IFile); | |
1332 | ||
1333 | boolean isSynchronized= resource.isSynchronized(IResource.DEPTH_ZERO); | |
1334 | ||
1335 | /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=98327 | |
1336 | * Make sure file gets save in commit() if the underlying file has been deleted */ | |
1337 | if (!isSynchronized && isDeleted(element)) | |
1338 | info.fTextFileBuffer.setDirty(true); | |
1339 | ||
1340 | if (!resource.exists()) { | |
1341 | // underlying resource has been deleted, just recreate file, ignore the rest | |
1342 | createFileFromDocument(monitor, (IFile) resource, document); | |
1343 | return; | |
1344 | } | |
1345 | ||
1346 | if (fSavePolicy != null) | |
1347 | fSavePolicy.preSave(info.fCopy); | |
1348 | ||
1349 | IProgressMonitor subMonitor= null; | |
1350 | try { | |
1351 | fIsAboutToSave= true; | |
1352 | ||
1353 | IPostSaveListener[] listeners= JavaPlugin.getDefault().getSaveParticipantRegistry().getEnabledPostSaveListeners(info.fCopy.getJavaProject().getProject()); | |
1354 | ||
1355 | CoreException changedRegionException= null; | |
1356 | boolean needsChangedRegions= false; | |
1357 | try { | |
1358 | if (listeners.length > 0) | |
1359 | needsChangedRegions= SaveParticipantRegistry.isChangedRegionsRequired(info.fCopy); | |
1360 | } catch (CoreException ex) { | |
1361 | changedRegionException= ex; | |
1362 | } | |
1363 | ||
1364 | IRegion[] changedRegions= null; | |
1365 | if (needsChangedRegions) { | |
1366 | try { | |
1367 | changedRegions= EditorUtility.calculateChangedLineRegions(info.fTextFileBuffer, getSubProgressMonitor(monitor, 20)); | |
1368 | } catch (CoreException ex) { | |
1369 | changedRegionException= ex; | |
1370 | } finally { | |
1371 | subMonitor= getSubProgressMonitor(monitor, 50); | |
1372 | } | |
1373 | } else | |
1374 | subMonitor= getSubProgressMonitor(monitor, listeners.length > 0 ? 70 : 100); | |
1375 | ||
1376 | info.fCopy.commitWorkingCopy(isSynchronized || overwrite, subMonitor); | |
1377 | if (listeners.length > 0) | |
1378 | notifyPostSaveListeners(info, changedRegions, listeners, getSubProgressMonitor(monitor, 30)); | |
1379 | ||
1380 | if (changedRegionException != null) { | |
1381 | throw changedRegionException; | |
1382 | } | |
1383 | } catch (CoreException x) { | |
1384 | // inform about the failure | |
1385 | fireElementStateChangeFailed(element); | |
1386 | throw x; | |
1387 | } catch (RuntimeException x) { | |
1388 | // inform about the failure | |
1389 | fireElementStateChangeFailed(element); | |
1390 | throw x; | |
1391 | } finally { | |
1392 | fIsAboutToSave= false; | |
1393 | if (subMonitor != null) | |
1394 | subMonitor.done(); | |
1395 | } | |
1396 | ||
1397 | // If here, the dirty state of the editor will change to "not dirty". | |
1398 | // Thus, the state changing flag will be reset. | |
1399 | if (info.fModel instanceof AbstractMarkerAnnotationModel) { | |
1400 | AbstractMarkerAnnotationModel model= (AbstractMarkerAnnotationModel) info.fModel; | |
1401 | model.updateMarkers(document); | |
1402 | } | |
1403 | ||
1404 | if (fSavePolicy != null) { | |
1405 | ICompilationUnit unit= fSavePolicy.postSave(info.fCopy); | |
1406 | if (unit != null && info.fModel instanceof AbstractMarkerAnnotationModel) { | |
1407 | IResource r= unit.getResource(); | |
1408 | IMarker[] markers= r.findMarkers(IMarker.MARKER, true, IResource.DEPTH_ZERO); | |
1409 | if (markers != null && markers.length > 0) { | |
1410 | AbstractMarkerAnnotationModel model= (AbstractMarkerAnnotationModel) info.fModel; | |
1411 | for (int i= 0; i < markers.length; i++) | |
1412 | model.updateMarker(document, markers[i], null); | |
1413 | } | |
1414 | } | |
1415 | } | |
1416 | } finally { | |
1417 | monitor.done(); | |
1418 | } | |
1419 | } | |
1420 | ||
1421 | /* | |
1422 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createSaveOperation(java.lang.Object, org.eclipse.jface.text.IDocument, boolean) | |
1423 | */ | |
1424 | @Override | |
1425 | protected DocumentProviderOperation createSaveOperation(final Object element, final IDocument document, final boolean overwrite) throws CoreException { | |
1426 | final FileInfo info= getFileInfo(element); | |
1427 | if (info instanceof CompilationUnitInfo) { | |
1428 | ||
1429 | // Delegate handling of non-primary CUs | |
1430 | ICompilationUnit cu= ((CompilationUnitInfo)info).fCopy; | |
1431 | if (cu != null && !JavaModelUtil.isPrimary(cu)) | |
1432 | return super.createSaveOperation(element, document, overwrite); | |
1433 | ||
1434 | if (info.fTextFileBuffer.getDocument() != document) { | |
1435 | // the info exists, but not for the given document | |
1436 | // -> saveAs was executed with a target that is already open | |
1437 | // in another editor | |
1438 | // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=85519 | |
1439 | Status status= new Status(IStatus.WARNING, EditorsUI.PLUGIN_ID, IStatus.ERROR, JavaEditorMessages.CompilationUnitDocumentProvider_saveAsTargetOpenInEditor, null); | |
1440 | throw new CoreException(status); | |
1441 | } | |
1442 | ||
1443 | return new DocumentProviderOperation() { | |
1444 | /* | |
1445 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider.DocumentProviderOperation#execute(org.eclipse.core.runtime.IProgressMonitor) | |
1446 | */ | |
1447 | @Override | |
1448 | protected void execute(IProgressMonitor monitor) throws CoreException { | |
1449 | commitWorkingCopy(monitor, element, (CompilationUnitInfo) info, overwrite); | |
1450 | } | |
1451 | /* | |
1452 | * @see org.eclipse.ui.editors.text.TextFileDocumentProvider.DocumentProviderOperation#getSchedulingRule() | |
1453 | */ | |
1454 | @Override | |
1455 | public ISchedulingRule getSchedulingRule() { | |
1456 | if (info.fElement instanceof IFileEditorInput) { | |
1457 | IFile file= ((IFileEditorInput) info.fElement).getFile(); | |
1458 | return computeSchedulingRule(file); | |
1459 | } else | |
1460 | return null; | |
1461 | } | |
1462 | }; | |
1463 | } | |
1464 | ||
1465 | return null; | |
1466 | } | |
1467 | ||
1468 | /** | |
1469 | * Returns the preference whether handling temporary problems is enabled. | |
1470 | * | |
1471 | * @return <code>true</code> if temporary problems are handled | |
1472 | */ | |
1473 | protected boolean isHandlingTemporaryProblems() { | |
1474 | IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore(); | |
1475 | return store.getBoolean(HANDLE_TEMPORARY_PROBLEMS); | |
1476 | } | |
1477 | ||
1478 | /** | |
1479 | * Switches the state of problem acceptance according to the value in the preference store. | |
1480 | */ | |
1481 | protected void enableHandlingTemporaryProblems() { | |
1482 | boolean enable= isHandlingTemporaryProblems(); | |
1483 | for (Iterator<FileInfo> iter= getFileInfosIterator(); iter.hasNext();) { | |
1484 | FileInfo info= iter.next(); | |
1485 | if (info.fModel instanceof IProblemRequestorExtension) { | |
1486 | IProblemRequestorExtension extension= (IProblemRequestorExtension) info.fModel; | |
1487 | extension.setIsHandlingTemporaryProblems(enable); | |
1488 | } | |
1489 | } | |
1490 | } | |
1491 | ||
1492 | /* | |
1493 | * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#setSavePolicy(org.eclipse.jdt.internal.ui.javaeditor.ISavePolicy) | |
1494 | */ | |
1495 | public void setSavePolicy(ISavePolicy savePolicy) { | |
1496 | fSavePolicy= savePolicy; | |
1497 | } | |
1498 | ||
1499 | /* | |
1500 | * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#addGlobalAnnotationModelListener(org.eclipse.jface.text.source.IAnnotationModelListener) | |
1501 | */ | |
1502 | public void addGlobalAnnotationModelListener(IAnnotationModelListener listener) { | |
1503 | fGlobalAnnotationModelListener.addListener(listener); | |
1504 | } | |
1505 | ||
1506 | /* | |
1507 | * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#removeGlobalAnnotationModelListener(org.eclipse.jface.text.source.IAnnotationModelListener) | |
1508 | */ | |
1509 | public void removeGlobalAnnotationModelListener(IAnnotationModelListener listener) { | |
1510 | fGlobalAnnotationModelListener.removeListener(listener); | |
1511 | } | |
1512 | ||
1513 | /* | |
1514 | * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#getWorkingCopy(java.lang.Object) | |
1515 | */ | |
1516 | public ICompilationUnit getWorkingCopy(Object element) { | |
1517 | FileInfo fileInfo= getFileInfo(element); | |
1518 | if (fileInfo instanceof CompilationUnitInfo) { | |
1519 | CompilationUnitInfo info= (CompilationUnitInfo)fileInfo; | |
1520 | return info.fCopy; | |
1521 | } | |
1522 | CompilationUnitInfo cuInfo= fFakeCUMapForMissingInfo.get(element); | |
1523 | if (cuInfo != null) | |
1524 | return cuInfo.fCopy; | |
1525 | ||
1526 | return null; | |
1527 | } | |
1528 | ||
1529 | /* | |
1530 | * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#shutdown() | |
1531 | */ | |
1532 | public void shutdown() { | |
1533 | JavaPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPropertyListener); | |
1534 | Iterator<?> e= getConnectedElementsIterator(); | |
1535 | while (e.hasNext()) | |
1536 | disconnect(e.next()); | |
1537 | fFakeCUMapForMissingInfo.clear(); | |
1538 | } | |
1539 | ||
1540 | /* | |
1541 | * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#saveDocumentContent(org.eclipse.core.runtime.IProgressMonitor, java.lang.Object, org.eclipse.jface.text.IDocument, boolean) | |
1542 | */ | |
1543 | public void saveDocumentContent(IProgressMonitor monitor, Object element, IDocument document, boolean overwrite) throws CoreException { | |
1544 | if (!fIsAboutToSave) | |
1545 | return; | |
1546 | super.saveDocument(monitor, element, document, overwrite); | |
1547 | } | |
1548 | ||
1549 | /* | |
1550 | * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#createLineTracker(java.lang.Object) | |
1551 | */ | |
1552 | public ILineTracker createLineTracker(Object element) { | |
1553 | return new DefaultLineTracker(); | |
1554 | } | |
1555 | ||
1556 | /** | |
1557 | * Notify post save listeners. | |
1558 | * <p> | |
1559 | * <strong>Note:</strong> Post save listeners are not allowed to save the file and they must not | |
1560 | * assumed to be called in the UI thread i.e. if they open a dialog they must ensure it ends up | |
1561 | * in the UI thread. | |
1562 | * </p> | |
1563 | * | |
1564 | * @param info compilation unit info | |
1565 | * @param changedRegions the array with the changed regions | |
1566 | * @param listeners the listeners to notify | |
1567 | * @param monitor the progress monitor | |
1568 | * @throws CoreException if something goes wrong | |
1569 | * @see IPostSaveListener | |
1570 | * @since 3.3 | |
1571 | */ | |
1572 | protected void notifyPostSaveListeners(final CompilationUnitInfo info, final IRegion[] changedRegions, IPostSaveListener[] listeners, final IProgressMonitor monitor) throws CoreException { | |
1573 | final ICompilationUnit unit= info.fCopy; | |
1574 | final IBuffer buffer= unit.getBuffer(); | |
1575 | ||
1576 | String message= JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantProblem; | |
1577 | final MultiStatus errorStatus= new MultiStatus(JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, message, null); | |
1578 | ||
1579 | monitor.beginTask(JavaEditorMessages.CompilationUnitDocumentProvider_progressNotifyingSaveParticipants, listeners.length * 5); | |
1580 | try { | |
1581 | for (int i= 0; i < listeners.length; i++) { | |
1582 | final IPostSaveListener listener= listeners[i]; | |
1583 | final String participantName= listener.getName(); | |
1584 | SafeRunner.run(new ISafeRunnable() { | |
1585 | public void run() { | |
1586 | try { | |
1587 | long stamp= unit.getResource().getModificationStamp(); | |
1588 | ||
1589 | listener.saved(unit, changedRegions, getSubProgressMonitor(monitor, 4)); | |
1590 | ||
1591 | if (stamp != unit.getResource().getModificationStamp()) { | |
1592 | String msg= Messages.format(JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantSavedFile, participantName); | |
1593 | errorStatus.add(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, null)); | |
1594 | } | |
1595 | ||
1596 | if (buffer.hasUnsavedChanges()) | |
1597 | buffer.save(getSubProgressMonitor(monitor, 1), true); | |
1598 | ||
1599 | } catch (CoreException ex) { | |
1600 | handleException(ex); | |
1601 | } finally { | |
1602 | monitor.worked(1); | |
1603 | } | |
1604 | } | |
1605 | ||
1606 | public void handleException(Throwable ex) { | |
1607 | String msg= Messages.format("The save participant ''{0}'' caused an exception: {1}", new String[] { listener.getId(), ex.toString()}); //$NON-NLS-1$ | |
1608 | JavaPlugin.log(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, ex)); | |
1609 | ||
1610 | msg= Messages.format(JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantFailed, new String[] { participantName, ex.toString()}); | |
1611 | errorStatus.add(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, null)); | |
1612 | ||
1613 | // Revert the changes | |
1614 | if (buffer.hasUnsavedChanges()) { | |
1615 | try { | |
1616 | info.fTextFileBuffer.revert(getSubProgressMonitor(monitor, 1)); | |
1617 | } catch (CoreException e) { | |
1618 | msg= Messages.format("Error on revert after failure of save participant ''{0}''.", participantName); //$NON-NLS-1$ | |
1619 | IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, ex); | |
1620 | JavaPlugin.getDefault().getLog().log(status); | |
1621 | } | |
1622 | ||
1623 | if (info.fModel instanceof AbstractMarkerAnnotationModel) { | |
1624 | AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel)info.fModel; | |
1625 | markerModel.resetMarkers(); | |
1626 | } | |
1627 | } | |
1628 | ||
1629 | // XXX: Work in progress 'Save As' case | |
1630 | // else if (buffer.hasUnsavedChanges()) { | |
1631 | // try { | |
1632 | // buffer.save(getSubProgressMonitor(monitor, 1), true); | |
1633 | // } catch (JavaModelException e) { | |
1634 | // message= Messages.format("Error reverting changes after failure of save participant ''{0}''.", participantName); //$NON-NLS-1$ | |
1635 | // IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, message, ex); | |
1636 | // JavaPlugin.getDefault().getLog().log(status); | |
1637 | // } | |
1638 | // } | |
1639 | } | |
1640 | }); | |
1641 | } | |
1642 | } finally { | |
1643 | monitor.done(); | |
1644 | if (!errorStatus.isOK()) | |
1645 | throw new CoreException(errorStatus); | |
1646 | } | |
1647 | } | |
1648 | } |