KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > ui > javaeditor > CompilationUnitDocumentProvider


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.javaeditor;
13
14
15 import java.io.BufferedReader JavaDoc;
16 import java.io.IOException JavaDoc;
17 import java.io.InputStream JavaDoc;
18 import java.io.InputStreamReader JavaDoc;
19 import java.io.Reader JavaDoc;
20 import java.net.URI JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import org.eclipse.core.filesystem.EFS;
28 import org.eclipse.core.filesystem.IFileStore;
29 import org.eclipse.core.filesystem.URIUtil;
30
31 import org.eclipse.core.runtime.Assert;
32 import org.eclipse.core.runtime.CoreException;
33 import org.eclipse.core.runtime.IPath;
34 import org.eclipse.core.runtime.IProgressMonitor;
35 import org.eclipse.core.runtime.ISafeRunnable;
36 import org.eclipse.core.runtime.IStatus;
37 import org.eclipse.core.runtime.ListenerList;
38 import org.eclipse.core.runtime.MultiStatus;
39 import org.eclipse.core.runtime.NullProgressMonitor;
40 import org.eclipse.core.runtime.OperationCanceledException;
41 import org.eclipse.core.runtime.SafeRunner;
42 import org.eclipse.core.runtime.Status;
43 import org.eclipse.core.runtime.SubProgressMonitor;
44 import org.eclipse.core.runtime.jobs.ISchedulingRule;
45
46 import org.eclipse.core.resources.IEncodedStorage;
47 import org.eclipse.core.resources.IFile;
48 import org.eclipse.core.resources.IFileState;
49 import org.eclipse.core.resources.IMarker;
50 import org.eclipse.core.resources.IResource;
51 import org.eclipse.core.resources.IStorage;
52
53 import org.eclipse.swt.SWT;
54 import org.eclipse.swt.graphics.GC;
55 import org.eclipse.swt.graphics.Image;
56 import org.eclipse.swt.graphics.Rectangle;
57 import org.eclipse.swt.widgets.Canvas;
58 import org.eclipse.swt.widgets.Display;
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.Position;
69 import org.eclipse.jface.text.quickassist.IQuickFixableAnnotation;
70 import org.eclipse.jface.text.source.Annotation;
71 import org.eclipse.jface.text.source.AnnotationModel;
72 import org.eclipse.jface.text.source.AnnotationModelEvent;
73 import org.eclipse.jface.text.source.IAnnotationAccessExtension;
74 import org.eclipse.jface.text.source.IAnnotationModel;
75 import org.eclipse.jface.text.source.IAnnotationModelListener;
76 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension;
77 import org.eclipse.jface.text.source.IAnnotationPresentation;
78 import org.eclipse.jface.text.source.ImageUtilities;
79
80 import org.eclipse.ui.IFileEditorInput;
81 import org.eclipse.ui.IStorageEditorInput;
82 import org.eclipse.ui.IURIEditorInput;
83 import org.eclipse.ui.texteditor.AbstractMarkerAnnotationModel;
84 import org.eclipse.ui.texteditor.AnnotationPreference;
85 import org.eclipse.ui.texteditor.AnnotationPreferenceLookup;
86 import org.eclipse.ui.texteditor.IDocumentProvider;
87 import org.eclipse.ui.texteditor.MarkerAnnotation;
88 import org.eclipse.ui.texteditor.MarkerUtilities;
89 import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
90
91 import org.eclipse.ui.editors.text.EditorsUI;
92 import org.eclipse.ui.editors.text.ForwardingDocumentProvider;
93 import org.eclipse.ui.editors.text.TextFileDocumentProvider;
94
95 import org.eclipse.jdt.core.IBuffer;
96 import org.eclipse.jdt.core.IClasspathEntry;
97 import org.eclipse.jdt.core.ICompilationUnit;
98 import org.eclipse.jdt.core.IJavaModel;
99 import org.eclipse.jdt.core.IJavaProject;
100 import org.eclipse.jdt.core.IProblemRequestor;
101 import org.eclipse.jdt.core.JavaCore;
102 import org.eclipse.jdt.core.JavaModelException;
103 import org.eclipse.jdt.core.WorkingCopyOwner;
104 import org.eclipse.jdt.core.compiler.CategorizedProblem;
105 import org.eclipse.jdt.core.compiler.IProblem;
106
107 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
108 import org.eclipse.jdt.internal.corext.util.Messages;
109
110 import org.eclipse.jdt.launching.JavaRuntime;
111
112 import org.eclipse.jdt.ui.JavaUI;
113 import org.eclipse.jdt.ui.PreferenceConstants;
114 import org.eclipse.jdt.ui.text.IJavaPartitions;
115
116 import org.eclipse.jdt.internal.ui.IJavaStatusConstants;
117 import org.eclipse.jdt.internal.ui.JavaPlugin;
118 import org.eclipse.jdt.internal.ui.JavaPluginImages;
119 import org.eclipse.jdt.internal.ui.javaeditor.saveparticipant.IPostSaveListener;
120 import org.eclipse.jdt.internal.ui.text.correction.JavaCorrectionProcessor;
121 import org.eclipse.jdt.internal.ui.text.java.IProblemRequestorExtension;
122 import org.eclipse.jdt.internal.ui.text.spelling.JavaSpellingReconcileStrategy;
123
124
125 public class CompilationUnitDocumentProvider extends TextFileDocumentProvider implements ICompilationUnitDocumentProvider {
126
127         /**
128          * Bundle of all required informations to allow working copy management.
129          */

130         static protected class CompilationUnitInfo extends FileInfo {
131             public ICompilationUnit fCopy;
132         }
133
134         /**
135          * Annotation representing an <code>IProblem</code>.
136          */

137         static public class ProblemAnnotation extends Annotation implements IJavaAnnotation, IAnnotationPresentation, IQuickFixableAnnotation {
138
139             public static final String JavaDoc SPELLING_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.spelling"; //$NON-NLS-1$
140

141             //XXX: To be fully correct these constants should be non-static
142
/**
143              * The layer in which task problem annotations are located.
144              */

145             private static final int TASK_LAYER;
146             /**
147              * The layer in which info problem annotations are located.
148              */

149             private static final int INFO_LAYER;
150             /**
151              * The layer in which warning problem annotations representing are located.
152              */

153             private static final int WARNING_LAYER;
154             /**
155              * The layer in which error problem annotations representing are located.
156              */

157             private static final int ERROR_LAYER;
158
159             static {
160                 AnnotationPreferenceLookup lookup= EditorsUI.getAnnotationPreferenceLookup();
161                 TASK_LAYER= computeLayer("org.eclipse.ui.workbench.texteditor.task", lookup); //$NON-NLS-1$
162
INFO_LAYER= computeLayer("org.eclipse.jdt.ui.info", lookup); //$NON-NLS-1$
163
WARNING_LAYER= computeLayer("org.eclipse.jdt.ui.warning", lookup); //$NON-NLS-1$
164
ERROR_LAYER= computeLayer("org.eclipse.jdt.ui.error", lookup); //$NON-NLS-1$
165
}
166
167             private static int computeLayer(String JavaDoc annotationType, AnnotationPreferenceLookup lookup) {
168                 Annotation annotation= new Annotation(annotationType, false, null);
169                 AnnotationPreference preference= lookup.getAnnotationPreference(annotation);
170                 if (preference != null)
171                     return preference.getPresentationLayer() + 1;
172                 else
173                     return IAnnotationAccessExtension.DEFAULT_LAYER + 1;
174             }
175
176             private static Image fgQuickFixImage;
177             private static Image fgQuickFixErrorImage;
178             private static boolean fgQuickFixImagesInitialized= false;
179
180             private ICompilationUnit fCompilationUnit;
181             private List JavaDoc fOverlaids;
182             private IProblem fProblem;
183             private Image fImage;
184             private boolean fQuickFixImagesInitialized= false;
185             private int fLayer= IAnnotationAccessExtension.DEFAULT_LAYER;
186             private boolean fIsQuickFixable;
187             private boolean fIsQuickFixableStateSet= false;
188
189
190             public ProblemAnnotation(IProblem problem, ICompilationUnit cu) {
191
192                 fProblem= problem;
193                 fCompilationUnit= cu;
194
195                 if (JavaSpellingReconcileStrategy.SPELLING_PROBLEM_ID == fProblem.getID()) {
196                     setType(SPELLING_ANNOTATION_TYPE);
197                     fLayer= WARNING_LAYER;
198                 } else if (IProblem.Task == fProblem.getID()) {
199                     setType(JavaMarkerAnnotation.TASK_ANNOTATION_TYPE);
200                     fLayer= TASK_LAYER;
201                 } else if (fProblem.isWarning()) {
202                     setType(JavaMarkerAnnotation.WARNING_ANNOTATION_TYPE);
203                     fLayer= WARNING_LAYER;
204                 } else if (fProblem.isError()) {
205                     setType(JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE);
206                     fLayer= ERROR_LAYER;
207                 } else {
208                     setType(JavaMarkerAnnotation.INFO_ANNOTATION_TYPE);
209                     fLayer= INFO_LAYER;
210                 }
211             }
212
213             /*
214              * @see org.eclipse.jface.text.source.IAnnotationPresentation#getLayer()
215              */

216             public int getLayer() {
217                 return fLayer;
218             }
219
220             private void initializeImages() {
221                 // http://bugs.eclipse.org/bugs/show_bug.cgi?id=18936
222
if (!fQuickFixImagesInitialized) {
223                     if (!isQuickFixableStateSet())
224                         setQuickFixable(isProblem() && indicateQuixFixableProblems() && JavaCorrectionProcessor.hasCorrections(this)); // no light bulb for tasks
225
if (isQuickFixable()) {
226                         if (!fgQuickFixImagesInitialized) {
227                             fgQuickFixImage= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_PROBLEM);
228                             fgQuickFixErrorImage= JavaPluginImages.get(JavaPluginImages.IMG_OBJS_FIXABLE_ERROR);
229                             fgQuickFixImagesInitialized= true;
230                         }
231                         if (JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE.equals(getType()))
232                             fImage= fgQuickFixErrorImage;
233                         else
234                             fImage= fgQuickFixImage;
235                     }
236                     fQuickFixImagesInitialized= true;
237                 }
238             }
239
240             private boolean indicateQuixFixableProblems() {
241                 return PreferenceConstants.getPreferenceStore().getBoolean(PreferenceConstants.EDITOR_CORRECTION_INDICATION);
242             }
243
244             /*
245              * @see Annotation#paint
246              */

247             public void paint(GC gc, Canvas canvas, Rectangle r) {
248                 initializeImages();
249                 if (fImage != null)
250                     ImageUtilities.drawImage(fImage, gc, canvas, r, SWT.CENTER, SWT.TOP);
251             }
252
253             /*
254              * @see IJavaAnnotation#getImage(Display)
255              */

256             public Image getImage(Display display) {
257                 initializeImages();
258                 return fImage;
259             }
260
261             /*
262              * @see IJavaAnnotation#getMessage()
263              */

264             public String JavaDoc getText() {
265                 return fProblem.getMessage();
266             }
267
268             /*
269              * @see IJavaAnnotation#getArguments()
270              */

271             public String JavaDoc[] getArguments() {
272                 return isProblem() ? fProblem.getArguments() : null;
273             }
274
275             /*
276              * @see IJavaAnnotation#getId()
277              */

278             public int getId() {
279                 return fProblem.getID();
280             }
281
282             /*
283              * @see IJavaAnnotation#isProblem()
284              */

285             public boolean isProblem() {
286                 String JavaDoc type= getType();
287                 return JavaMarkerAnnotation.WARNING_ANNOTATION_TYPE.equals(type) ||
288                             JavaMarkerAnnotation.ERROR_ANNOTATION_TYPE.equals(type) ||
289                             SPELLING_ANNOTATION_TYPE.equals(type);
290             }
291
292             /*
293              * @see IJavaAnnotation#hasOverlay()
294              */

295             public boolean hasOverlay() {
296                 return false;
297             }
298
299             /*
300              * @see org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation#getOverlay()
301              */

302             public IJavaAnnotation getOverlay() {
303                 return null;
304             }
305
306             /*
307              * @see IJavaAnnotation#addOverlaid(IJavaAnnotation)
308              */

309             public void addOverlaid(IJavaAnnotation annotation) {
310                 if (fOverlaids == null)
311                     fOverlaids= new ArrayList JavaDoc(1);
312                 fOverlaids.add(annotation);
313             }
314
315             /*
316              * @see IJavaAnnotation#removeOverlaid(IJavaAnnotation)
317              */

318             public void removeOverlaid(IJavaAnnotation annotation) {
319                 if (fOverlaids != null) {
320                     fOverlaids.remove(annotation);
321                     if (fOverlaids.size() == 0)
322                         fOverlaids= null;
323                 }
324             }
325
326             /*
327              * @see IJavaAnnotation#getOverlaidIterator()
328              */

329             public Iterator JavaDoc getOverlaidIterator() {
330                 if (fOverlaids != null)
331                     return fOverlaids.iterator();
332                 return null;
333             }
334
335             /*
336              * @see org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation#getCompilationUnit()
337              */

338             public ICompilationUnit getCompilationUnit() {
339                 return fCompilationUnit;
340             }
341
342             /*
343              * @see org.eclipse.jdt.internal.ui.javaeditor.IJavaAnnotation#getMarkerType()
344              */

345             public String JavaDoc getMarkerType() {
346                 if (fProblem instanceof CategorizedProblem)
347                     return ((CategorizedProblem) fProblem).getMarkerType();
348                 return null;
349             }
350
351             /*
352              * @see org.eclipse.jface.text.quickassist.IQuickFixableAnnotation#setQuickFixable(boolean)
353              * @since 3.2
354              */

355             public void setQuickFixable(boolean state) {
356                 fIsQuickFixable= state;
357                 fIsQuickFixableStateSet= true;
358             }
359
360             /*
361              * @see org.eclipse.jface.text.quickassist.IQuickFixableAnnotation#isQuickFixableStateSet()
362              * @since 3.2
363              */

364             public boolean isQuickFixableStateSet() {
365                 return fIsQuickFixableStateSet;
366             }
367
368             /*
369              * @see org.eclipse.jface.text.quickassist.IQuickFixableAnnotation#isQuickFixable()
370              * @since 3.2
371              */

372             public boolean isQuickFixable() {
373                 Assert.isTrue(isQuickFixableStateSet());
374                 return fIsQuickFixable;
375             }
376         }
377
378         /**
379          * Internal structure for mapping positions to some value.
380          * The reason for this specific structure is that positions can
381          * change over time. Thus a lookup is based on value and not
382          * on hash value.
383          */

384         protected static class ReverseMap {
385
386             static class Entry {
387                 Position fPosition;
388                 Object JavaDoc fValue;
389             }
390
391             private List JavaDoc fList= new ArrayList JavaDoc(2);
392             private int fAnchor= 0;
393
394             public ReverseMap() {
395             }
396
397             public Object JavaDoc get(Position position) {
398
399                 Entry entry;
400
401                 // behind anchor
402
int length= fList.size();
403                 for (int i= fAnchor; i < length; i++) {
404                     entry= (Entry) fList.get(i);
405                     if (entry.fPosition.equals(position)) {
406                         fAnchor= i;
407                         return entry.fValue;
408                     }
409                 }
410
411                 // before anchor
412
for (int i= 0; i < fAnchor; i++) {
413                     entry= (Entry) fList.get(i);
414                     if (entry.fPosition.equals(position)) {
415                         fAnchor= i;
416                         return entry.fValue;
417                     }
418                 }
419
420                 return null;
421             }
422
423             private int getIndex(Position position) {
424                 Entry entry;
425                 int length= fList.size();
426                 for (int i= 0; i < length; i++) {
427                     entry= (Entry) fList.get(i);
428                     if (entry.fPosition.equals(position))
429                         return i;
430                 }
431                 return -1;
432             }
433
434             public void put(Position position, Object JavaDoc value) {
435                 int index= getIndex(position);
436                 if (index == -1) {
437                     Entry entry= new Entry();
438                     entry.fPosition= position;
439                     entry.fValue= value;
440                     fList.add(entry);
441                 } else {
442                     Entry entry= (Entry) fList.get(index);
443                     entry.fValue= value;
444                 }
445             }
446
447             public void remove(Position position) {
448                 int index= getIndex(position);
449                 if (index > -1)
450                     fList.remove(index);
451             }
452
453             public void clear() {
454                 fList.clear();
455             }
456         }
457
458         /**
459          * Annotation model dealing with java marker annotations and temporary problems.
460          * Also acts as problem requester for its compilation unit. Initially inactive. Must explicitly be
461          * activated.
462          */

463         protected static class CompilationUnitAnnotationModel extends ResourceMarkerAnnotationModel implements IProblemRequestor, IProblemRequestorExtension {
464
465             private static class ProblemRequestorState {
466                 boolean fInsideReportingSequence= false;
467                 List JavaDoc fReportedProblems;
468             }
469
470             private ThreadLocal JavaDoc fProblemRequestorState= new ThreadLocal JavaDoc();
471             private int fStateCount= 0;
472
473             private ICompilationUnit fCompilationUnit;
474             private List JavaDoc fGeneratedAnnotations= new ArrayList JavaDoc();
475             private IProgressMonitor fProgressMonitor;
476             private boolean fIsActive= false;
477             private boolean fIsHandlingTemporaryProblems;
478
479             private ReverseMap fReverseMap= new ReverseMap();
480             private List JavaDoc fPreviouslyOverlaid= null;
481             private List JavaDoc fCurrentlyOverlaid= new ArrayList JavaDoc();
482             private Thread JavaDoc fActiveThread;
483
484
485             public CompilationUnitAnnotationModel(IResource resource) {
486                 super(resource);
487             }
488
489             public void setCompilationUnit(ICompilationUnit unit) {
490                 fCompilationUnit= unit;
491             }
492
493             protected MarkerAnnotation createMarkerAnnotation(IMarker marker) {
494                 String JavaDoc markerType= MarkerUtilities.getMarkerType(marker);
495                 if (markerType != null && markerType.startsWith(JavaMarkerAnnotation.JAVA_MARKER_TYPE_PREFIX))
496                     return new JavaMarkerAnnotation(marker);
497                 return super.createMarkerAnnotation(marker);
498             }
499
500             /*
501              * @see org.eclipse.jface.text.source.AnnotationModel#createAnnotationModelEvent()
502              */

503             protected AnnotationModelEvent createAnnotationModelEvent() {
504                 return new CompilationUnitAnnotationModelEvent(this, getResource());
505             }
506
507             protected Position createPositionFromProblem(IProblem problem) {
508                 int start= problem.getSourceStart();
509                 if (start < 0)
510                     return null;
511
512                 int length= problem.getSourceEnd() - problem.getSourceStart() + 1;
513                 if (length < 0)
514                     return null;
515
516                 return new Position(start, length);
517             }
518
519             /*
520              * @see IProblemRequestor#beginReporting()
521              */

522             public void beginReporting() {
523                 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get();
524                 if (state == null)
525                     internalBeginReporting(false);
526             }
527
528             /*
529              * @see org.eclipse.jdt.internal.ui.text.java.IProblemRequestorExtension#beginReportingSequence()
530              */

531             public void beginReportingSequence() {
532                 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get();
533                 if (state == null)
534                     internalBeginReporting(true);
535             }
536
537             /**
538              * Sets up the infrastructure necessary for problem reporting.
539              *
540              * @param insideReportingSequence <code>true</code> if this method
541              * call is issued from inside a reporting sequence
542              */

543             private void internalBeginReporting(boolean insideReportingSequence) {
544                 if (fCompilationUnit != null && fCompilationUnit.getJavaProject().isOnClasspath(fCompilationUnit)) {
545                     ProblemRequestorState state= new ProblemRequestorState();
546                     state.fInsideReportingSequence= insideReportingSequence;
547                     state.fReportedProblems= new ArrayList JavaDoc();
548                     synchronized (getLockObject()) {
549                         fProblemRequestorState.set(state);
550                         ++fStateCount;
551                     }
552                 }
553             }
554
555             /*
556              * @see IProblemRequestor#acceptProblem(IProblem)
557              */

558             public void acceptProblem(IProblem problem) {
559                 if (fIsHandlingTemporaryProblems || problem.getID() == JavaSpellingReconcileStrategy.SPELLING_PROBLEM_ID) {
560                     ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get();
561                     if (state != null)
562                         state.fReportedProblems.add(problem);
563                 }
564             }
565
566             /*
567              * @see IProblemRequestor#endReporting()
568              */

569             public void endReporting() {
570                 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get();
571                 if (state != null && !state.fInsideReportingSequence)
572                     internalEndReporting(state);
573             }
574
575             /*
576              * @see org.eclipse.jdt.internal.ui.text.java.IProblemRequestorExtension#endReportingSequence()
577              */

578             public void endReportingSequence() {
579                 ProblemRequestorState state= (ProblemRequestorState) fProblemRequestorState.get();
580                 if (state != null && state.fInsideReportingSequence)
581                     internalEndReporting(state);
582             }
583
584             private void internalEndReporting(ProblemRequestorState state) {
585                 int stateCount= 0;
586                 synchronized(getLockObject()) {
587                     -- fStateCount;
588                     stateCount= fStateCount;
589                     fProblemRequestorState.set(null);
590                 }
591
592                 if (stateCount == 0)
593                     reportProblems(state.fReportedProblems);
594             }
595
596             /**
597              * Signals the end of problem reporting.
598              *
599              * @param reportedProblems the problems to report
600              */

601             private void reportProblems(List JavaDoc reportedProblems) {
602                 if (fProgressMonitor != null && fProgressMonitor.isCanceled())
603                     return;
604
605                 boolean temporaryProblemsChanged= false;
606
607                 synchronized (getLockObject()) {
608
609                     boolean isCanceled= false;
610
611                     fPreviouslyOverlaid= fCurrentlyOverlaid;
612                     fCurrentlyOverlaid= new ArrayList JavaDoc();
613
614                     if (fGeneratedAnnotations.size() > 0) {
615                         temporaryProblemsChanged= true;
616                         removeAnnotations(fGeneratedAnnotations, false, true);
617                         fGeneratedAnnotations.clear();
618                     }
619
620                     if (reportedProblems != null && reportedProblems.size() > 0) {
621
622                         Iterator JavaDoc e= reportedProblems.iterator();
623                         while (e.hasNext()) {
624
625                             if (fProgressMonitor != null && fProgressMonitor.isCanceled()) {
626                                 isCanceled= true;
627                                 break;
628                             }
629
630                             IProblem problem= (IProblem) e.next();
631                             Position position= createPositionFromProblem(problem);
632                             if (position != null) {
633
634                                 try {
635                                     ProblemAnnotation annotation= new ProblemAnnotation(problem, fCompilationUnit);
636                                     overlayMarkers(position, annotation);
637                                     addAnnotation(annotation, position, false);
638                                     fGeneratedAnnotations.add(annotation);
639
640                                     temporaryProblemsChanged= true;
641                                 } catch (BadLocationException x) {
642                                     // ignore invalid position
643
}
644                             }
645                         }
646                     }
647
648                     removeMarkerOverlays(isCanceled);
649                     fPreviouslyOverlaid= null;
650                 }
651
652                 if (temporaryProblemsChanged)
653                     fireModelChanged();
654             }
655
656             private void removeMarkerOverlays(boolean isCanceled) {
657                 if (isCanceled) {
658                     fCurrentlyOverlaid.addAll(fPreviouslyOverlaid);
659                 } else if (fPreviouslyOverlaid != null) {
660                     Iterator JavaDoc e= fPreviouslyOverlaid.iterator();
661                     while (e.hasNext()) {
662                         JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) e.next();
663                         annotation.setOverlay(null);
664                     }
665                 }
666             }
667
668             /**
669              * Overlays value with problem annotation.
670              *
671              * @param value the value
672              * @param problemAnnotation
673              */

674             private void setOverlay(Object JavaDoc value, ProblemAnnotation problemAnnotation) {
675                 if (value instanceof JavaMarkerAnnotation) {
676                     JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) value;
677                     if (annotation.isProblem()) {
678                         annotation.setOverlay(problemAnnotation);
679                         fPreviouslyOverlaid.remove(annotation);
680                         fCurrentlyOverlaid.add(annotation);
681                     }
682                 } else {
683                 }
684             }
685
686             private void overlayMarkers(Position position, ProblemAnnotation problemAnnotation) {
687                 Object JavaDoc value= getAnnotations(position);
688                 if (value instanceof List JavaDoc) {
689                     List JavaDoc list= (List JavaDoc) value;
690                     for (Iterator JavaDoc e = list.iterator(); e.hasNext();)
691                         setOverlay(e.next(), problemAnnotation);
692                 } else {
693                     setOverlay(value, problemAnnotation);
694                 }
695             }
696
697             /**
698              * Tells this annotation model to collect temporary problems from now on.
699              */

700             private void startCollectingProblems() {
701                 fGeneratedAnnotations.clear();
702             }
703
704             /**
705              * Tells this annotation model to no longer collect temporary problems.
706              */

707             private void stopCollectingProblems() {
708                 if (fGeneratedAnnotations != null)
709                     removeAnnotations(fGeneratedAnnotations, true, true);
710                 fGeneratedAnnotations.clear();
711             }
712
713             /*
714              * @see IProblemRequestor#isActive()
715              */

716             public synchronized boolean isActive() {
717                 return fIsActive && fActiveThread == Thread.currentThread();
718             }
719
720             /*
721              * @see IProblemRequestorExtension#setProgressMonitor(IProgressMonitor)
722              */

723             public void setProgressMonitor(IProgressMonitor monitor) {
724                 fProgressMonitor= monitor;
725             }
726
727             /*
728              * @see IProblemRequestorExtension#setIsActive(boolean)
729              */

730             public synchronized void setIsActive(boolean isActive) {
731                 Assert.isLegal(!isActive || Display.getCurrent() == null); // must not be enabled from UI threads
732
fIsActive= isActive;
733                 if (fIsActive)
734                     fActiveThread= Thread.currentThread();
735                 else
736                     fActiveThread= null;
737             }
738
739             /*
740              * @see IProblemRequestorExtension#setIsHandlingTemporaryProblems(boolean)
741              * @since 3.1
742              */

743             public void setIsHandlingTemporaryProblems(boolean enable) {
744                 if (fIsHandlingTemporaryProblems != enable) {
745                     fIsHandlingTemporaryProblems= enable;
746                     if (fIsHandlingTemporaryProblems)
747                         startCollectingProblems();
748                     else
749                         stopCollectingProblems();
750                 }
751
752             }
753
754             private Object JavaDoc getAnnotations(Position position) {
755                 synchronized (getLockObject()) {
756                     return fReverseMap.get(position);
757                 }
758             }
759
760             /*
761              * @see AnnotationModel#addAnnotation(Annotation, Position, boolean)
762              */

763             protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) throws BadLocationException {
764                 super.addAnnotation(annotation, position, fireModelChanged);
765
766                 synchronized (getLockObject()) {
767                     Object JavaDoc cached= fReverseMap.get(position);
768                     if (cached == null)
769                         fReverseMap.put(position, annotation);
770                     else if (cached instanceof List JavaDoc) {
771                         List JavaDoc list= (List JavaDoc) cached;
772                         list.add(annotation);
773                     } else if (cached instanceof Annotation) {
774                         List JavaDoc list= new ArrayList JavaDoc(2);
775                         list.add(cached);
776                         list.add(annotation);
777                         fReverseMap.put(position, list);
778                     }
779                 }
780             }
781
782             /*
783              * @see AnnotationModel#removeAllAnnotations(boolean)
784              */

785             protected void removeAllAnnotations(boolean fireModelChanged) {
786                 super.removeAllAnnotations(fireModelChanged);
787                 synchronized (getLockObject()) {
788                     fReverseMap.clear();
789                 }
790             }
791
792             /*
793              * @see AnnotationModel#removeAnnotation(Annotation, boolean)
794              */

795             protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) {
796                 Position position= getPosition(annotation);
797                 synchronized (getLockObject()) {
798                     Object JavaDoc cached= fReverseMap.get(position);
799                     if (cached instanceof List JavaDoc) {
800                         List JavaDoc list= (List JavaDoc) cached;
801                         list.remove(annotation);
802                         if (list.size() == 1) {
803                             fReverseMap.put(position, list.get(0));
804                             list.clear();
805                         }
806                     } else if (cached instanceof Annotation) {
807                         fReverseMap.remove(position);
808                     }
809                 }
810                 super.removeAnnotation(annotation, fireModelChanged);
811             }
812         }
813
814
815         protected static class GlobalAnnotationModelListener implements IAnnotationModelListener, IAnnotationModelListenerExtension {
816
817             private ListenerList fListenerList;
818
819             public GlobalAnnotationModelListener() {
820                 fListenerList= new ListenerList(ListenerList.IDENTITY);
821             }
822
823             /**
824              * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
825              */

826             public void modelChanged(IAnnotationModel model) {
827                 Object JavaDoc[] listeners= fListenerList.getListeners();
828                 for (int i= 0; i < listeners.length; i++) {
829                     ((IAnnotationModelListener) listeners[i]).modelChanged(model);
830                 }
831             }
832
833             /**
834              * @see IAnnotationModelListenerExtension#modelChanged(AnnotationModelEvent)
835              */

836             public void modelChanged(AnnotationModelEvent event) {
837                 Object JavaDoc[] listeners= fListenerList.getListeners();
838                 for (int i= 0; i < listeners.length; i++) {
839                     Object JavaDoc curr= listeners[i];
840                     if (curr instanceof IAnnotationModelListenerExtension) {
841                         ((IAnnotationModelListenerExtension) curr).modelChanged(event);
842                     }
843                 }
844             }
845
846             public void addListener(IAnnotationModelListener listener) {
847                 fListenerList.add(listener);
848             }
849
850             public void removeListener(IAnnotationModelListener listener) {
851                 fListenerList.remove(listener);
852             }
853         }
854
855     /** Preference key for temporary problems */
856     private final static String JavaDoc HANDLE_TEMPORARY_PROBLEMS= PreferenceConstants.EDITOR_EVALUTE_TEMPORARY_PROBLEMS;
857
858
859     /** Indicates whether the save has been initialized by this provider */
860     private boolean fIsAboutToSave= false;
861     /** The save policy used by this provider */
862     private ISavePolicy fSavePolicy;
863     /** Internal property changed listener */
864     private IPropertyChangeListener fPropertyListener;
865     /** Annotation model listener added to all created CU annotation models */
866     private GlobalAnnotationModelListener fGlobalAnnotationModelListener;
867     /**
868      * Element information of all connected elements with a fake CU but no file info.
869      * @since 3.2
870      */

871     private final Map JavaDoc fFakeCUMapForMissingInfo= new HashMap JavaDoc();
872
873
874     /**
875      * Constructor
876      */

877     public CompilationUnitDocumentProvider() {
878
879         IDocumentProvider provider= new TextFileDocumentProvider();
880         provider= new ForwardingDocumentProvider(IJavaPartitions.JAVA_PARTITIONING, new JavaDocumentSetupParticipant(), provider);
881         setParentDocumentProvider(provider);
882
883         fGlobalAnnotationModelListener= new GlobalAnnotationModelListener();
884         fPropertyListener= new IPropertyChangeListener() {
885             public void propertyChange(PropertyChangeEvent event) {
886                 if (HANDLE_TEMPORARY_PROBLEMS.equals(event.getProperty()))
887                     enableHandlingTemporaryProblems();
888             }
889         };
890         JavaPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPropertyListener);
891     }
892
893     /**
894      * Creates a compilation unit from the given file.
895      *
896      * @param file the file from which to create the compilation unit
897      * @return the fake compilation unit
898      */

899     protected ICompilationUnit createCompilationUnit(IFile file) {
900         Object JavaDoc element= JavaCore.create(file);
901         if (element instanceof ICompilationUnit)
902             return (ICompilationUnit) element;
903         return null;
904     }
905
906     /*
907      * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createEmptyFileInfo()
908      */

909     protected FileInfo createEmptyFileInfo() {
910         return new CompilationUnitInfo();
911     }
912
913     /*
914      * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createAnnotationModel(org.eclipse.core.resources.IFile)
915      */

916     protected IAnnotationModel createAnnotationModel(IFile file) {
917         return new CompilationUnitAnnotationModel(file);
918     }
919
920     /*
921      * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createFileInfo(java.lang.Object)
922      */

923     protected FileInfo createFileInfo(Object JavaDoc element) throws CoreException {
924         ICompilationUnit original= null;
925         if (element instanceof IFileEditorInput) {
926             IFileEditorInput input= (IFileEditorInput) element;
927             original= createCompilationUnit(input.getFile());
928             if (original == null)
929                 return null;
930         }
931         
932         FileInfo info= super.createFileInfo(element);
933         if (!(info instanceof CompilationUnitInfo))
934             return null;
935         
936         if (original == null)
937             original= createFakeCompiltationUnit(element, false);
938         if (original == null)
939             return null;
940
941         CompilationUnitInfo cuInfo= (CompilationUnitInfo) info;
942         setUpSynchronization(cuInfo);
943
944         IProblemRequestor requestor= cuInfo.fModel instanceof IProblemRequestor ? (IProblemRequestor) cuInfo.fModel : null;
945         if (requestor instanceof IProblemRequestorExtension) {
946             IProblemRequestorExtension extension= (IProblemRequestorExtension) requestor;
947             extension.setIsActive(false);
948             extension.setIsHandlingTemporaryProblems(isHandlingTemporaryProblems());
949         }
950
951         if (JavaModelUtil.isPrimary(original))
952             original.becomeWorkingCopy(requestor, getProgressMonitor());
953         cuInfo.fCopy= original;
954
955         if (cuInfo.fModel instanceof CompilationUnitAnnotationModel) {
956             CompilationUnitAnnotationModel model= (CompilationUnitAnnotationModel) cuInfo.fModel;
957             model.setCompilationUnit(cuInfo.fCopy);
958         }
959
960         if (cuInfo.fModel != null)
961             cuInfo.fModel.addAnnotationModelListener(fGlobalAnnotationModelListener);
962
963         return cuInfo;
964     }
965     
966     /**
967      * Creates a fake compilation unit.
968      *
969      * @param element the element
970      * @param setContents tells whether to read and set the contents to the new CU
971      * @return the fake compilation unit
972      * @since 3.2
973      */

974     private ICompilationUnit createFakeCompiltationUnit(Object JavaDoc element, boolean setContents) {
975         if (element instanceof IStorageEditorInput)
976             return createFakeCompiltationUnit((IStorageEditorInput)element, setContents);
977         else if (element instanceof IURIEditorInput)
978             return createFakeCompiltationUnit((IURIEditorInput)element);
979         return null;
980     }
981     
982     /**
983      * Creates a fake compilation unit.
984      *
985      * @param editorInput the storage editor input
986      * @param setContents tells whether to read and set the contents to the new CU
987      * @return the fake compilation unit
988      * @since 3.2
989      */

990     private ICompilationUnit createFakeCompiltationUnit(IStorageEditorInput editorInput, boolean setContents) {
991         try {
992             final IStorage storage= editorInput.getStorage();
993             final IPath storagePath= storage.getFullPath();
994             if (storage.getName() == null || storagePath == null)
995                 return null;
996             
997             final IPath documentPath;
998             if (storage instanceof IFileState)
999                 documentPath= storagePath.append(Long.toString(((IFileState)storage).getModificationTime()));
1000            else
1001                documentPath= storagePath;
1002            
1003            WorkingCopyOwner woc= new WorkingCopyOwner() {
1004                /*
1005                 * @see org.eclipse.jdt.core.WorkingCopyOwner#createBuffer(org.eclipse.jdt.core.ICompilationUnit)
1006                 * @since 3.2
1007                 */

1008                public IBuffer createBuffer(ICompilationUnit workingCopy) {
1009                    return new DocumentAdapter(workingCopy, documentPath);
1010                }
1011            };
1012
1013            IClasspathEntry[] cpEntries= null;
1014            IJavaProject jp= findJavaProject(storagePath);
1015            if (jp != null)
1016                cpEntries= jp.getResolvedClasspath(true);
1017            
1018            if (cpEntries == null || cpEntries.length == 0)
1019                cpEntries= new IClasspathEntry[] { JavaRuntime.getDefaultJREContainerEntry() };
1020
1021            final ICompilationUnit cu= woc.newWorkingCopy(storage.getName(), cpEntries, getProgressMonitor());
1022            if (setContents) {
1023                int READER_CHUNK_SIZE= 2048;
1024                int BUFFER_SIZE= 8 * READER_CHUNK_SIZE;
1025                
1026                String JavaDoc charsetName= null;
1027                if (storage instanceof IEncodedStorage)
1028                    charsetName= ((IEncodedStorage)storage).getCharset();
1029                if (charsetName == null)
1030                    charsetName= getDefaultEncoding();
1031                
1032                Reader JavaDoc in= null;
1033                InputStream JavaDoc contents= storage.getContents();
1034                try {
1035                    in= new BufferedReader JavaDoc(new InputStreamReader JavaDoc(contents, charsetName));
1036                    StringBuffer JavaDoc buffer= new StringBuffer JavaDoc(BUFFER_SIZE);
1037                    char[] readBuffer= new char[READER_CHUNK_SIZE];
1038                    int n;
1039                    n= in.read(readBuffer);
1040                    while (n > 0) {
1041                        buffer.append(readBuffer, 0, n);
1042                        n= in.read(readBuffer);
1043                    }
1044                    cu.getBuffer().setContents(buffer.toString());
1045                } catch (IOException JavaDoc e) {
1046                    JavaPlugin.log(e);
1047                    return null;
1048                } finally {
1049                    try {
1050                        if (in != null)
1051                            in.close();
1052                        else
1053                            contents.close();
1054                    } catch (IOException JavaDoc x) {
1055                    }
1056                }
1057            }
1058            
1059            if (!isModifiable(editorInput))
1060                JavaModelUtil.reconcile(cu);
1061            
1062            return cu;
1063        } catch (CoreException ex) {
1064            JavaPlugin.log(ex.getStatus());
1065            return null;
1066        }
1067    }
1068
1069    /**
1070     * Creates a fake compilation unit.
1071     *
1072     * @param editorInput the URI editor input
1073     * @return the fake compilation unit
1074     * @since 3.3
1075     */

1076    private ICompilationUnit createFakeCompiltationUnit(IURIEditorInput editorInput) {
1077        try {
1078            final URI JavaDoc uri= editorInput.getURI();
1079            final IFileStore fileStore= EFS.getStore(uri);
1080            final IPath path= URIUtil.toPath(uri);
1081            if (fileStore.getName() == null || path == null)
1082                return null;
1083            
1084            WorkingCopyOwner woc= new WorkingCopyOwner() {
1085                /*
1086                 * @see org.eclipse.jdt.core.WorkingCopyOwner#createBuffer(org.eclipse.jdt.core.ICompilationUnit)
1087                 * @since 3.2
1088                 */

1089                public IBuffer createBuffer(ICompilationUnit workingCopy) {
1090                    return new DocumentAdapter(workingCopy, path);
1091                }
1092            };
1093            
1094            IClasspathEntry[] cpEntries= null;
1095            IJavaProject jp= findJavaProject(path);
1096            if (jp != null)
1097                cpEntries= jp.getResolvedClasspath(true);
1098            
1099            if (cpEntries == null || cpEntries.length == 0)
1100                cpEntries= new IClasspathEntry[] { JavaRuntime.getDefaultJREContainerEntry() };
1101            
1102            final ICompilationUnit cu= woc.newWorkingCopy(fileStore.getName(), cpEntries, getProgressMonitor());
1103            
1104            if (!isModifiable(editorInput))
1105                JavaModelUtil.reconcile(cu);
1106
1107            return cu;
1108        } catch (CoreException ex) {
1109            return null;
1110        }
1111    }
1112    
1113    /**
1114     * Fuzzy search for Java project in the workspace that matches
1115     * the given path.
1116     *
1117     * @param path the path to match
1118     * @return the matching Java project or <code>null</code>
1119     * @since 3.2
1120     */

1121    private IJavaProject findJavaProject(IPath path) {
1122        if (path == null)
1123            return null;
1124
1125        String JavaDoc[] pathSegments= path.segments();
1126        IJavaModel model= JavaCore.create(JavaPlugin.getWorkspace().getRoot());
1127        IJavaProject[] projects;
1128        try {
1129            projects= model.getJavaProjects();
1130        } catch (JavaModelException e) {
1131            return null; // ignore - use default JRE
1132
}
1133        for (int i= 0; i < projects.length; i++) {
1134            IPath projectPath= projects[i].getProject().getFullPath();
1135            String JavaDoc projectSegment= projectPath.segments()[0];
1136            for (int j= 0; j < pathSegments.length; j++)
1137                if (projectSegment.equals(pathSegments[j]))
1138                    return projects[i];
1139        }
1140        return null;
1141    }
1142
1143    /*
1144     * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#disposeFileInfo(java.lang.Object, org.eclipse.ui.editors.text.TextFileDocumentProvider.FileInfo)
1145     */

1146    protected void disposeFileInfo(Object JavaDoc element, FileInfo info) {
1147        if (info instanceof CompilationUnitInfo) {
1148            CompilationUnitInfo cuInfo= (CompilationUnitInfo) info;
1149
1150            try {
1151                cuInfo.fCopy.discardWorkingCopy();
1152            } catch (JavaModelException x) {
1153                handleCoreException(x, x.getMessage());
1154            }
1155
1156            if (cuInfo.fModel != null)
1157                cuInfo.fModel.removeAnnotationModelListener(fGlobalAnnotationModelListener);
1158        }
1159        super.disposeFileInfo(element, info);
1160    }
1161    
1162    /*
1163     * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#connect(java.lang.Object)
1164     * @since 3.2
1165     */

1166    public void connect(Object JavaDoc element) throws CoreException {
1167        super.connect(element);
1168        if (getFileInfo(element) != null)
1169            return;
1170
1171        CompilationUnitInfo info= (CompilationUnitInfo)fFakeCUMapForMissingInfo.get(element);
1172        if (info == null) {
1173            ICompilationUnit cu= createFakeCompiltationUnit(element, true);
1174            if (cu == null)
1175                return;
1176            info= new CompilationUnitInfo();
1177            info.fCopy= cu;
1178            info.fElement= element;
1179            info.fModel= new AnnotationModel();
1180            fFakeCUMapForMissingInfo.put(element, info);
1181        }
1182        info.fCount++;
1183    }
1184    
1185    /*
1186     * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#getAnnotationModel(java.lang.Object)
1187     * @since 3.2
1188     */

1189    public IAnnotationModel getAnnotationModel(Object JavaDoc element) {
1190        IAnnotationModel model= super.getAnnotationModel(element);
1191        if (model != null)
1192            return model;
1193        
1194        FileInfo info= (FileInfo)fFakeCUMapForMissingInfo.get(element);
1195        if (info != null) {
1196            if (info.fModel != null)
1197                return info.fModel;
1198            if (info.fTextFileBuffer != null)
1199                return info.fTextFileBuffer.getAnnotationModel();
1200        }
1201        
1202        return null;
1203    }
1204    
1205    /*
1206     * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#disconnect(java.lang.Object)
1207     * @since 3.2
1208     */

1209    public void disconnect(Object JavaDoc element) {
1210        CompilationUnitInfo info= (CompilationUnitInfo)fFakeCUMapForMissingInfo.get(element);
1211        if (info != null) {
1212            if (info.fCount == 1) {
1213                fFakeCUMapForMissingInfo.remove(element);
1214                info.fModel= null;
1215                // Destroy and unregister fake working copy
1216
try {
1217                    info.fCopy.discardWorkingCopy();
1218                } catch (JavaModelException ex) {
1219                    handleCoreException(ex, ex.getMessage());
1220                }
1221            } else
1222                info.fCount--;
1223        }
1224        super.disconnect(element);
1225    }
1226    
1227
1228    /**
1229     * Creates and returns a new sub-progress monitor for the
1230     * given parent monitor.
1231     *
1232     * @param monitor the parent progress monitor
1233     * @param ticks the number of work ticks allocated from the parent monitor
1234     * @return the new sub-progress monitor
1235     */

1236    private IProgressMonitor getSubProgressMonitor(IProgressMonitor monitor, int ticks) {
1237        if (monitor != null)
1238            return new SubProgressMonitor(monitor, ticks, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
1239
1240        return new NullProgressMonitor();
1241    }
1242
1243    protected void commitWorkingCopy(IProgressMonitor monitor, Object JavaDoc element, final CompilationUnitInfo info, boolean overwrite) throws CoreException {
1244
1245        if (monitor == null)
1246            monitor= new NullProgressMonitor();
1247
1248        monitor.beginTask("", 120); //$NON-NLS-1$
1249

1250        try {
1251            final IProgressMonitor subMonitor1= getSubProgressMonitor(monitor, 50);
1252
1253            try {
1254                SafeRunner.run(new ISafeRunnable() {
1255                    public void run() {
1256                        try {
1257                            info.fCopy.reconcile(ICompilationUnit.NO_AST, false, null, subMonitor1);
1258                        } catch (JavaModelException ex) {
1259                            handleException(ex);
1260                        } catch (OperationCanceledException ex) {
1261                            // do not log this
1262
}
1263                    }
1264                    public void handleException(Throwable JavaDoc ex) {
1265                        IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, "Error in JDT Core during reconcile while saving", ex); //$NON-NLS-1$
1266
JavaPlugin.getDefault().getLog().log(status);
1267                    }
1268                });
1269            } finally {
1270                subMonitor1.done();
1271            }
1272
1273            IDocument document= info.fTextFileBuffer.getDocument();
1274            IResource resource= info.fCopy.getResource();
1275
1276            Assert.isTrue(resource instanceof IFile);
1277
1278            boolean isSynchronized= resource.isSynchronized(IResource.DEPTH_ZERO);
1279            
1280            /* https://bugs.eclipse.org/bugs/show_bug.cgi?id=98327
1281             * Make sure file gets save in commit() if the underlying file has been deleted */

1282            if (!isSynchronized && isDeleted(element))
1283                info.fTextFileBuffer.setDirty(true);
1284
1285            if (!resource.exists()) {
1286                // underlying resource has been deleted, just recreate file, ignore the rest
1287
IProgressMonitor subMonitor2= getSubProgressMonitor(monitor, 70);
1288                try {
1289                    createFileFromDocument(subMonitor2, (IFile) resource, document);
1290                } finally {
1291                    subMonitor2.done();
1292                }
1293                return;
1294            }
1295
1296            if (fSavePolicy != null)
1297                fSavePolicy.preSave(info.fCopy);
1298
1299            IProgressMonitor subMonitor3= getSubProgressMonitor(monitor, 50);
1300            try {
1301                fIsAboutToSave= true;
1302                info.fCopy.commitWorkingCopy(isSynchronized || overwrite, subMonitor3);
1303                notifyPostSaveListeners(info.fCopy, info, getSubProgressMonitor(monitor, 20));
1304            } catch (CoreException x) {
1305                // inform about the failure
1306
fireElementStateChangeFailed(element);
1307                throw x;
1308            } catch (RuntimeException JavaDoc x) {
1309                // inform about the failure
1310
fireElementStateChangeFailed(element);
1311                throw x;
1312            } finally {
1313                fIsAboutToSave= false;
1314                subMonitor3.done();
1315            }
1316
1317            // If here, the dirty state of the editor will change to "not dirty".
1318
// Thus, the state changing flag will be reset.
1319
if (info.fModel instanceof AbstractMarkerAnnotationModel) {
1320                AbstractMarkerAnnotationModel model= (AbstractMarkerAnnotationModel) info.fModel;
1321                model.updateMarkers(document);
1322            }
1323
1324            if (fSavePolicy != null) {
1325                ICompilationUnit unit= fSavePolicy.postSave(info.fCopy);
1326                if (unit != null && info.fModel instanceof AbstractMarkerAnnotationModel) {
1327                    IResource r= unit.getResource();
1328                    IMarker[] markers= r.findMarkers(IMarker.MARKER, true, IResource.DEPTH_ZERO);
1329                    if (markers != null && markers.length > 0) {
1330                        AbstractMarkerAnnotationModel model= (AbstractMarkerAnnotationModel) info.fModel;
1331                        for (int i= 0; i < markers.length; i++)
1332                            model.updateMarker(document, markers[i], null);
1333                    }
1334                }
1335            }
1336        } finally {
1337            monitor.done();
1338        }
1339    }
1340
1341    /*
1342     * @see org.eclipse.ui.editors.text.TextFileDocumentProvider#createSaveOperation(java.lang.Object, org.eclipse.jface.text.IDocument, boolean)
1343     */

1344    protected DocumentProviderOperation createSaveOperation(final Object JavaDoc element, final IDocument document, final boolean overwrite) throws CoreException {
1345        final FileInfo info= getFileInfo(element);
1346        if (info instanceof CompilationUnitInfo) {
1347            
1348            // Delegate handling of non-primary CUs
1349
ICompilationUnit cu= ((CompilationUnitInfo)info).fCopy;
1350            if (cu != null && !JavaModelUtil.isPrimary(cu))
1351                return super.createSaveOperation(element, document, overwrite);
1352
1353            if (info.fTextFileBuffer.getDocument() != document) {
1354                // the info exists, but not for the given document
1355
// -> saveAs was executed with a target that is already open
1356
// in another editor
1357
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=85519
1358
Status status= new Status(IStatus.WARNING, EditorsUI.PLUGIN_ID, IStatus.ERROR, JavaEditorMessages.CompilationUnitDocumentProvider_saveAsTargetOpenInEditor, null);
1359                throw new CoreException(status);
1360            }
1361
1362            return new DocumentProviderOperation() {
1363                /*
1364                 * @see org.eclipse.ui.editors.text.TextFileDocumentProvider.DocumentProviderOperation#execute(org.eclipse.core.runtime.IProgressMonitor)
1365                 */

1366                protected void execute(IProgressMonitor monitor) throws CoreException {
1367                    commitWorkingCopy(monitor, element, (CompilationUnitInfo) info, overwrite);
1368                }
1369                /*
1370                 * @see org.eclipse.ui.editors.text.TextFileDocumentProvider.DocumentProviderOperation#getSchedulingRule()
1371                 */

1372                public ISchedulingRule getSchedulingRule() {
1373                    if (info.fElement instanceof IFileEditorInput) {
1374                        IFile file= ((IFileEditorInput) info.fElement).getFile();
1375                        return computeSchedulingRule(file);
1376                    } else
1377                        return null;
1378                }
1379            };
1380        }
1381        
1382        return null;
1383    }
1384
1385    /**
1386     * Returns the preference whether handling temporary problems is enabled.
1387     *
1388     * @return <code>true</code> if temporary problems are handled
1389     */

1390    protected boolean isHandlingTemporaryProblems() {
1391        IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
1392        return store.getBoolean(HANDLE_TEMPORARY_PROBLEMS);
1393    }
1394
1395        /**
1396         * Switches the state of problem acceptance according to the value in the preference store.
1397         */

1398        protected void enableHandlingTemporaryProblems() {
1399            boolean enable= isHandlingTemporaryProblems();
1400            for (Iterator JavaDoc iter= getFileInfosIterator(); iter.hasNext();) {
1401                FileInfo info= (FileInfo) iter.next();
1402                if (info.fModel instanceof IProblemRequestorExtension) {
1403                    IProblemRequestorExtension extension= (IProblemRequestorExtension) info.fModel;
1404                    extension.setIsHandlingTemporaryProblems(enable);
1405                }
1406            }
1407        }
1408
1409    /*
1410     * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#setSavePolicy(org.eclipse.jdt.internal.ui.javaeditor.ISavePolicy)
1411     */

1412    public void setSavePolicy(ISavePolicy savePolicy) {
1413        fSavePolicy= savePolicy;
1414    }
1415
1416    /*
1417     * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#addGlobalAnnotationModelListener(org.eclipse.jface.text.source.IAnnotationModelListener)
1418     */

1419    public void addGlobalAnnotationModelListener(IAnnotationModelListener listener) {
1420        fGlobalAnnotationModelListener.addListener(listener);
1421    }
1422
1423    /*
1424     * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#removeGlobalAnnotationModelListener(org.eclipse.jface.text.source.IAnnotationModelListener)
1425     */

1426    public void removeGlobalAnnotationModelListener(IAnnotationModelListener listener) {
1427        fGlobalAnnotationModelListener.removeListener(listener);
1428    }
1429
1430    /*
1431     * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#getWorkingCopy(java.lang.Object)
1432     */

1433    public ICompilationUnit getWorkingCopy(Object JavaDoc element) {
1434        FileInfo fileInfo= getFileInfo(element);
1435        if (fileInfo instanceof CompilationUnitInfo) {
1436            CompilationUnitInfo info= (CompilationUnitInfo)fileInfo;
1437            return info.fCopy;
1438        }
1439        CompilationUnitInfo cuInfo= (CompilationUnitInfo)fFakeCUMapForMissingInfo.get(element);
1440        if (cuInfo != null)
1441            return cuInfo.fCopy;
1442        
1443        return null;
1444    }
1445
1446    /*
1447     * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#shutdown()
1448     */

1449    public void shutdown() {
1450        JavaPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPropertyListener);
1451        Iterator JavaDoc e= getConnectedElementsIterator();
1452        while (e.hasNext())
1453            disconnect(e.next());
1454        fFakeCUMapForMissingInfo.clear();
1455    }
1456
1457    /*
1458     * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#saveDocumentContent(org.eclipse.core.runtime.IProgressMonitor, java.lang.Object, org.eclipse.jface.text.IDocument, boolean)
1459     */

1460    public void saveDocumentContent(IProgressMonitor monitor, Object JavaDoc element, IDocument document, boolean overwrite) throws CoreException {
1461        if (!fIsAboutToSave)
1462            return;
1463        super.saveDocument(monitor, element, document, overwrite);
1464    }
1465
1466    /*
1467     * @see org.eclipse.jdt.internal.ui.javaeditor.ICompilationUnitDocumentProvider#createLineTracker(java.lang.Object)
1468     */

1469    public ILineTracker createLineTracker(Object JavaDoc element) {
1470        return new DefaultLineTracker();
1471    }
1472
1473    /**
1474     * Notify post save listeners.
1475     * <p>
1476     * <strong>Note:</strong> Post save listeners are not
1477     * allowed to save the file and they must not assumed to be
1478     * called in the UI thread i.e. if they open a dialog they
1479     * must ensure it ends up in the UI thread.
1480     * </p>
1481     *
1482     * @param unit the compilation unit
1483     * @param info compilation unit info
1484     * @param monitor the progress monitor
1485     * @throws CoreException
1486     * @see IPostSaveListener
1487     * @since 3.3
1488     */

1489    protected void notifyPostSaveListeners(final ICompilationUnit unit, final CompilationUnitInfo info, final IProgressMonitor monitor) throws CoreException {
1490        final IBuffer buffer= unit.getBuffer();
1491        IPostSaveListener[] listeners= JavaPlugin.getDefault().getSaveParticipantRegistry().getEnabledPostSaveListeners(unit.getJavaProject().getProject());
1492        
1493        String JavaDoc message= JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantProblem;
1494        final MultiStatus errorStatus= new MultiStatus(JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, message, null);
1495        
1496        monitor.beginTask(JavaEditorMessages.CompilationUnitDocumentProvider_progressNotifyingSaveParticipants, listeners.length * 5);
1497        try {
1498            for (int i= 0; i < listeners.length; i++) {
1499                final IPostSaveListener listener= listeners[i];
1500                final String JavaDoc participantName= listener.getName();
1501                SafeRunner.run(new ISafeRunnable() {
1502                    public void run() {
1503                        try {
1504                            long stamp= unit.getResource().getModificationStamp();
1505                            
1506                            listener.saved(unit, getSubProgressMonitor(monitor, 4));
1507                            
1508                            if (stamp != unit.getResource().getModificationStamp()) {
1509                                String JavaDoc msg= Messages.format(JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantSavedFile, participantName);
1510                                errorStatus.add(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, null));
1511                            }
1512
1513                            if (buffer.hasUnsavedChanges())
1514                                buffer.save(getSubProgressMonitor(monitor, 1), true);
1515
1516                        } catch (CoreException ex) {
1517                            handleException(ex);
1518                        } finally {
1519                            monitor.worked(1);
1520                        }
1521                    }
1522
1523                    public void handleException(Throwable JavaDoc ex) {
1524                        String JavaDoc msg= Messages.format("The save participant ''{0}'' caused an exception: {1}", new String JavaDoc[] { listener.getId(), ex.toString()}); //$NON-NLS-1$
1525
JavaPlugin.log(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, null));
1526                        
1527                        msg= Messages.format(JavaEditorMessages.CompilationUnitDocumentProvider_error_saveParticipantFailed, new String JavaDoc[] { participantName, ex.toString()});
1528                        errorStatus.add(new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, null));
1529                        
1530                        // Revert the changes
1531
if (info != null && buffer.hasUnsavedChanges()) {
1532                            try {
1533                                info.fTextFileBuffer.revert(getSubProgressMonitor(monitor, 1));
1534                            } catch (CoreException e) {
1535                                msg= Messages.format("Error on revert after failure of save participant ''{0}''.", participantName); //$NON-NLS-1$
1536
IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IJavaStatusConstants.EDITOR_POST_SAVE_NOTIFICATION, msg, ex);
1537                                JavaPlugin.getDefault().getLog().log(status);
1538                            }
1539
1540                            if (info.fModel instanceof AbstractMarkerAnnotationModel) {
1541                                AbstractMarkerAnnotationModel markerModel= (AbstractMarkerAnnotationModel)info.fModel;
1542                                markerModel.resetMarkers();
1543                            }
1544                        }
1545                        
1546                        // XXX: Work in progress 'Save As' case
1547
// else if (buffer.hasUnsavedChanges()) {
1548
// try {
1549
// buffer.save(getSubProgressMonitor(monitor, 1), true);
1550
// } catch (JavaModelException e) {
1551
// message= Messages.format("Error reverting changes after failure of save participant ''{0}''.", participantName); //$NON-NLS-1$
1552
// IStatus status= new Status(IStatus.ERROR, JavaUI.ID_PLUGIN, IStatus.OK, message, ex);
1553
// JavaPlugin.getDefault().getLog().log(status);
1554
// }
1555
// }
1556
}
1557                });
1558            }
1559        } finally {
1560            monitor.done();
1561            if (!errorStatus.isOK())
1562                throw new CoreException(errorStatus);
1563        }
1564    }
1565
1566}
1567
Popular Tags