]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-before/ui/org/eclipse/jdt/internal/ui/javaeditor/ClassFileDocumentProvider.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / ui / org / eclipse / jdt / internal / ui / javaeditor / ClassFileDocumentProvider.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2011 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.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16
17 import org.eclipse.core.runtime.CoreException;
18
19 import org.eclipse.core.resources.IResource;
20
21 import org.eclipse.core.filebuffers.FileBuffers;
22 import org.eclipse.core.filebuffers.LocationKind;
23
24 import org.eclipse.jface.text.IDocument;
25 import org.eclipse.jface.text.ISynchronizable;
26 import org.eclipse.jface.text.source.IAnnotationModel;
27
28 import org.eclipse.ui.IEditorInput;
29 import org.eclipse.ui.IFileEditorInput;
30
31 import org.eclipse.ui.editors.text.FileDocumentProvider;
32
33 import org.eclipse.jdt.core.ElementChangedEvent;
34 import org.eclipse.jdt.core.IClassFile;
35 import org.eclipse.jdt.core.IElementChangedListener;
36 import org.eclipse.jdt.core.IJavaElement;
37 import org.eclipse.jdt.core.IJavaElementDelta;
38 import org.eclipse.jdt.core.IJavaProject;
39 import org.eclipse.jdt.core.IPackageFragmentRoot;
40 import org.eclipse.jdt.core.IType;
41 import org.eclipse.jdt.core.JavaCore;
42 import org.eclipse.jdt.core.JavaModelException;
43
44 import org.eclipse.jdt.ui.text.IJavaPartitions;
45 import org.eclipse.jdt.ui.text.JavaTextTools;
46
47 import org.eclipse.jdt.internal.ui.IResourceLocator;
48 import org.eclipse.jdt.internal.ui.JavaPlugin;
49
50
51 /**
52  * A document provider for class files. Class files can be either inside
53  */
54 public class ClassFileDocumentProvider extends FileDocumentProvider {
55
56         /**
57          * An input change listener to request the editor to reread the input.
58          */
59         public interface InputChangeListener {
60                 void inputChanged(IClassFileEditorInput input);
61         }
62
63         /**
64          * Synchronizes the document with external resource changes.
65          */
66         protected class ClassFileSynchronizer implements IElementChangedListener {
67
68                 protected IClassFileEditorInput fInput;
69                 protected IPackageFragmentRoot fPackageFragmentRoot;
70
71                 /**
72                  * Default constructor.
73                  * 
74                  * @param input the class file editor input
75                  */
76                 public ClassFileSynchronizer(IClassFileEditorInput input) {
77
78                         fInput= input;
79
80                         IJavaElement parent= fInput.getClassFile().getParent();
81                         while (parent != null && !(parent instanceof IPackageFragmentRoot)) {
82                                 parent= parent.getParent();
83                         }
84                         fPackageFragmentRoot= (IPackageFragmentRoot) parent;
85                 }
86
87                 /**
88                  * Installs the synchronizer.
89                  */
90                 public void install() {
91                         JavaCore.addElementChangedListener(this);
92                 }
93
94                 /**
95                  * Uninstalls the synchronizer.
96                  */
97                 public void uninstall() {
98                         JavaCore.removeElementChangedListener(this);
99                 }
100
101                 /*
102                  * @see IElementChangedListener#elementChanged
103                  */
104                 public void elementChanged(ElementChangedEvent e) {
105                         check(fPackageFragmentRoot, e.getDelta());
106                 }
107
108                 /**
109                  * Recursively check whether the class file has been deleted.
110                  * 
111                  * @param input the package fragment root
112                  * @param delta the Java element delta
113                  * @return <code>true</code> if delta processing can be stopped
114                  */
115                 protected boolean check(IPackageFragmentRoot input, IJavaElementDelta delta) {
116                         IJavaElement element= delta.getElement();
117
118                         if ((delta.getKind() & IJavaElementDelta.REMOVED) != 0 || (delta.getFlags() & IJavaElementDelta.F_CLOSED) != 0) {
119                                 // http://dev.eclipse.org/bugs/show_bug.cgi?id=19023
120                                 if (element.equals(input.getJavaProject()) || element.equals(input)) {
121                                         handleDeleted(fInput);
122                                         return true;
123                                 }
124                         }
125
126                         if (((delta.getFlags() & IJavaElementDelta.F_ARCHIVE_CONTENT_CHANGED) != 0) && input.equals(element)) {
127                                 handleDeleted(fInput);
128                                 return true;
129                         }
130
131                         if (((delta.getFlags() & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) != 0) && input.equals(element)) {
132                                 handleDeleted(fInput);
133                                 return true;
134                         }
135
136                         IJavaElementDelta[] subdeltas= delta.getAffectedChildren();
137                         for (int i= 0; i < subdeltas.length; i++) {
138                                 if (check(input, subdeltas[i]))
139                                         return true;
140                         }
141
142                         if ((delta.getFlags() & IJavaElementDelta.F_SOURCEDETACHED) != 0 ||
143                                 (delta.getFlags() & IJavaElementDelta.F_SOURCEATTACHED) != 0)
144                         {
145                                 IClassFile file= fInput != null ? fInput.getClassFile() : null;
146                                 IJavaProject project= input != null ? input.getJavaProject() : null;
147
148                                 boolean isOnClasspath= false;
149                                 if (file != null && project != null)
150                                         isOnClasspath= project.isOnClasspath(file);
151
152                                 if (isOnClasspath) {
153                                         fireInputChanged(fInput);
154                                         return false;
155                                 } else {
156                                         handleDeleted(fInput);
157                                         return true;
158                                 }
159                         }
160
161                         return false;
162                 }
163         }
164
165         /**
166          * Correcting the visibility of <code>FileSynchronizer</code>.
167          */
168         protected class _FileSynchronizer extends FileSynchronizer {
169                 public _FileSynchronizer(IFileEditorInput fileEditorInput) {
170                         super(fileEditorInput);
171                 }
172         }
173
174         /**
175          * Bundle of all required informations.
176          */
177         protected class ClassFileInfo extends FileInfo {
178
179                 ClassFileSynchronizer fClassFileSynchronizer= null;
180
181                 ClassFileInfo(IDocument document, IAnnotationModel model, _FileSynchronizer fileSynchronizer) {
182                         super(document, model, fileSynchronizer);
183                 }
184
185                 ClassFileInfo(IDocument document, IAnnotationModel model, ClassFileSynchronizer classFileSynchronizer) {
186                         super(document, model, null);
187                         fClassFileSynchronizer= classFileSynchronizer;
188                 }
189         }
190
191         /** Input change listeners. */
192         private List<InputChangeListener> fInputListeners= new ArrayList<InputChangeListener>();
193
194         /**
195          * Creates a new document provider.
196          */
197         public ClassFileDocumentProvider() {
198                 super();
199         }
200
201         /*
202          * @see StorageDocumentProvider#setDocumentContent(IDocument, IEditorInput)
203          */
204         @Override
205         protected boolean setDocumentContent(IDocument document, IEditorInput editorInput, String encoding) throws CoreException {
206                 if (editorInput instanceof IClassFileEditorInput) {
207                         IClassFile classFile= ((IClassFileEditorInput) editorInput).getClassFile();
208                         String source= classFile.getSource();
209                         if (source == null)
210                                 source= ""; //$NON-NLS-1$
211                         document.set(source);
212                         return true;
213                 }
214                 return super.setDocumentContent(document, editorInput, encoding);
215         }
216
217         /**
218          * Creates an annotation model derived from the given class file editor input.
219          *
220          * @param classFileEditorInput the editor input from which to query the annotations
221          * @return the created annotation model
222          * @exception CoreException if the editor input could not be accessed
223          */
224         protected IAnnotationModel createClassFileAnnotationModel(IClassFileEditorInput classFileEditorInput) throws CoreException {
225                 IResource resource= null;
226                 IClassFile classFile= classFileEditorInput.getClassFile();
227
228                 IResourceLocator locator= (IResourceLocator) classFile.getAdapter(IResourceLocator.class);
229                 if (locator != null)
230                         resource= locator.getContainingResource(classFile);
231
232                 if (resource != null) {
233                         ClassFileMarkerAnnotationModel model= new ClassFileMarkerAnnotationModel(resource);
234                         model.setClassFile(classFile);
235                         return model;
236                 }
237
238                 return null;
239         }
240
241         /*
242          * @see org.eclipse.ui.editors.text.StorageDocumentProvider#createEmptyDocument()
243          * @since 3.1
244          */
245         @Override
246         protected IDocument createEmptyDocument() {
247                 IDocument document= FileBuffers.getTextFileBufferManager().createEmptyDocument(null, LocationKind.IFILE);
248                 if (document instanceof ISynchronizable)
249                         ((ISynchronizable)document).setLockObject(new Object());
250                 return document;
251         }
252
253         /*
254          * @see AbstractDocumentProvider#createDocument(Object)
255          */
256         @Override
257         protected IDocument createDocument(Object element) throws CoreException {
258                 IDocument document= super.createDocument(element);
259                 if (document != null) {
260                         JavaTextTools tools= JavaPlugin.getDefault().getJavaTextTools();
261                         tools.setupJavaDocumentPartitioner(document, IJavaPartitions.JAVA_PARTITIONING);
262                 }
263                 return document;
264         }
265
266         /*
267          * @see AbstractDocumentProvider#createElementInfo(Object)
268          */
269         @Override
270         protected ElementInfo createElementInfo(Object element) throws CoreException {
271
272                 if (element instanceof IClassFileEditorInput) {
273
274                         IClassFileEditorInput input = (IClassFileEditorInput) element;
275                         ExternalClassFileEditorInput external= null;
276                         if (input instanceof ExternalClassFileEditorInput)
277                                 external= (ExternalClassFileEditorInput) input;
278
279                         if (external != null) {
280                                 try {
281                                         refreshFile(external.getFile());
282                                 } catch (CoreException x) {
283                                         handleCoreException(x, JavaEditorMessages.ClassFileDocumentProvider_error_createElementInfo);
284                                 }
285                         }
286
287                         IDocument d= createDocument(input);
288                         IAnnotationModel m= createClassFileAnnotationModel(input);
289
290                         if (external != null) {
291                                 ClassFileInfo info= new ClassFileInfo(d, m,  (_FileSynchronizer) null);
292                                 info.fModificationStamp= computeModificationStamp(external.getFile());
293                                 info.fEncoding= getPersistedEncoding(element);
294                                 return info;
295                         } else if (input instanceof InternalClassFileEditorInput) {
296                                 ClassFileSynchronizer s= new ClassFileSynchronizer(input);
297                                 s.install();
298                                 ClassFileInfo info= new ClassFileInfo(d, m, s);
299                                 info.fEncoding= getPersistedEncoding(element);
300                                 return info;
301                         }
302                 }
303
304                 return null;
305         }
306
307         /*
308          * @see FileDocumentProvider#disposeElementInfo(Object, ElementInfo)
309          */
310         @Override
311         protected void disposeElementInfo(Object element, ElementInfo info) {
312                 ClassFileInfo classFileInfo= (ClassFileInfo) info;
313                 if (classFileInfo.fClassFileSynchronizer != null) {
314                         classFileInfo.fClassFileSynchronizer.uninstall();
315                         classFileInfo.fClassFileSynchronizer= null;
316                 }
317
318                 super.disposeElementInfo(element, info);
319         }
320
321         /*
322          * @see org.eclipse.ui.texteditor.IDocumentProviderExtension3#isSynchronized(java.lang.Object)
323          * @since 3.0
324          */
325         @Override
326         public boolean isSynchronized(Object element) {
327                 Object elementInfo= getElementInfo(element);
328                 if (elementInfo instanceof ClassFileInfo) {
329                         IClassFileEditorInput input= (IClassFileEditorInput)element;
330                         IResource resource;
331                         try {
332                                 resource= input.getClassFile().getUnderlyingResource();
333                         } catch (JavaModelException e) {
334                                 return true;
335                         }
336                         return resource == null || resource.isSynchronized(IResource.DEPTH_ZERO);
337                 }
338                 return false;
339         }
340
341         /**
342          * Handles the deletion of the element underlying the given class file editor input.
343          * @param input the editor input
344          */
345         protected void handleDeleted(IClassFileEditorInput input) {
346                 if (input == null) {
347                         fireElementDeleted(input);
348                         return;
349                 }
350
351                 if (input.exists())
352                         return;
353
354                 IClassFile cf= input.getClassFile();
355                 try {
356                         /*
357                          * Let's try to find the class file - maybe the JAR changed
358                          */
359                         IType type= cf.getType();
360                         IJavaProject project= cf.getJavaProject();
361                         if (project != null) {
362                                 type= project.findType(type.getFullyQualifiedName());
363                                 if (type != null) {
364                                         IEditorInput editorInput= EditorUtility.getEditorInput(type.getParent());
365                                         if (editorInput instanceof IClassFileEditorInput) {
366                                                 fireInputChanged((IClassFileEditorInput)editorInput);
367                                                 return;
368                                         }
369                                 }
370                         }
371                 } catch (JavaModelException x) {
372                         // Don't log and fall through: element deleted
373                 }
374
375                 fireElementDeleted(input);
376
377         }
378
379         /**
380          * Fires input changes to input change listeners.
381          * 
382          * @param input the class file editor input
383          */
384         protected void fireInputChanged(IClassFileEditorInput input) {
385                 List<InputChangeListener> list= new ArrayList<InputChangeListener>(fInputListeners);
386                 for (Iterator<InputChangeListener> i = list.iterator(); i.hasNext();)
387                         i.next().inputChanged(input);
388         }
389
390         /**
391          * Adds an input change listener.
392          * 
393          * @param listener the input change listener
394          */
395         public void addInputChangeListener(InputChangeListener listener) {
396                 fInputListeners.add(listener);
397         }
398
399         /**
400          * Removes an input change listener.
401          * 
402          * @param listener the input change listener
403          */
404         public void removeInputChangeListener(InputChangeListener listener) {
405                 fInputListeners.remove(listener);
406         }
407
408 }