• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.ide.eclipse.adt.internal.resources.manager;
18 
19 import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
20 
21 import org.eclipse.core.resources.IFile;
22 import org.eclipse.core.resources.IFolder;
23 import org.eclipse.core.resources.IMarkerDelta;
24 import org.eclipse.core.resources.IProject;
25 import org.eclipse.core.resources.IResource;
26 import org.eclipse.core.resources.IResourceChangeEvent;
27 import org.eclipse.core.resources.IResourceChangeListener;
28 import org.eclipse.core.resources.IResourceDelta;
29 import org.eclipse.core.resources.IResourceDeltaVisitor;
30 import org.eclipse.core.resources.IWorkspace;
31 import org.eclipse.core.resources.IWorkspaceRoot;
32 import org.eclipse.core.runtime.CoreException;
33 import org.eclipse.jdt.core.IJavaModel;
34 import org.eclipse.jdt.core.IJavaProject;
35 import org.eclipse.jdt.core.JavaCore;
36 
37 import java.util.ArrayList;
38 
39 /**
40  * Resource Monitor for the whole editor plugin. Other, more simple, listeners can register to
41  * that one.
42  */
43 public class ResourceMonitor implements IResourceChangeListener {
44 
45     private final static ResourceMonitor sThis = new ResourceMonitor();
46 
47     /**
48      * Classes which implement this interface provide a method that deals
49      * with file change events.
50      */
51     public interface IFileListener {
52         /**
53          * Sent when a file changed.
54          * @param file The file that changed.
55          * @param markerDeltas The marker deltas for the file.
56          * @param kind The change kind. This is equivalent to
57          * {@link IResourceDelta#accept(IResourceDeltaVisitor)}
58          */
fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind)59         public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind);
60     }
61 
62     /**
63      * Classes which implements this interface provide methods dealing with project events.
64      */
65     public interface IProjectListener {
66         /**
67          * Sent for each opened android project at the time the listener is put in place.
68          * @param project the opened project.
69          */
projectOpenedWithWorkspace(IProject project)70         public void projectOpenedWithWorkspace(IProject project);
71         /**
72          * Sent when a project is opened.
73          * @param project the project being opened.
74          */
projectOpened(IProject project)75         public void projectOpened(IProject project);
76         /**
77          * Sent when a project is closed.
78          * @param project the project being closed.
79          */
projectClosed(IProject project)80         public void projectClosed(IProject project);
81         /**
82          * Sent when a project is deleted.
83          * @param project the project about to be deleted.
84          */
projectDeleted(IProject project)85         public void projectDeleted(IProject project);
86     }
87 
88     /**
89      * Classes which implement this interface provide a method that deals
90      * with folder change events
91      */
92     public interface IFolderListener {
93         /**
94          * Sent when a folder changed.
95          * @param folder The file that was changed
96          * @param kind The change kind. This is equivalent to {@link IResourceDelta#getKind()}
97          */
folderChanged(IFolder folder, int kind)98         public void folderChanged(IFolder folder, int kind);
99     }
100 
101     /**
102      * Interface for a listener to be notified when resource change event starts and ends.
103      */
104     public interface IResourceEventListener {
resourceChangeEventStart()105         public void resourceChangeEventStart();
resourceChangeEventEnd()106         public void resourceChangeEventEnd();
107     }
108 
109     /**
110      * Base listener bundle to associate a listener to an event mask.
111      */
112     private static class ListenerBundle {
113         /** Mask value to accept all events */
114         public final static int MASK_NONE = -1;
115 
116         /**
117          * Event mask. Values accepted are IResourceDelta.###
118          * @see IResourceDelta#ADDED
119          * @see IResourceDelta#REMOVED
120          * @see IResourceDelta#CHANGED
121          * @see IResourceDelta#ADDED_PHANTOM
122          * @see IResourceDelta#REMOVED_PHANTOM
123          * */
124         int kindMask;
125     }
126 
127     /**
128      * Listener bundle for file event.
129      */
130     private static class FileListenerBundle extends ListenerBundle {
131 
132         /** The file listener */
133         IFileListener listener;
134     }
135 
136     /**
137      * Listener bundle for folder event.
138      */
139     private static class FolderListenerBundle extends ListenerBundle {
140         /** The file listener */
141         IFolderListener listener;
142     }
143 
144     private final ArrayList<FileListenerBundle> mFileListeners =
145         new ArrayList<FileListenerBundle>();
146 
147     private final ArrayList<FolderListenerBundle> mFolderListeners =
148         new ArrayList<FolderListenerBundle>();
149 
150     private final ArrayList<IProjectListener> mProjectListeners = new ArrayList<IProjectListener>();
151 
152     private final ArrayList<IResourceEventListener> mEventListeners =
153         new ArrayList<IResourceEventListener>();
154 
155     private IWorkspace mWorkspace;
156 
157     /**
158      * Delta visitor for resource changes.
159      */
160     private final class DeltaVisitor implements IResourceDeltaVisitor {
161 
visit(IResourceDelta delta)162         public boolean visit(IResourceDelta delta) {
163             IResource r = delta.getResource();
164             int type = r.getType();
165             if (type == IResource.FILE) {
166                 int kind = delta.getKind();
167                 // notify the listeners.
168                 for (FileListenerBundle bundle : mFileListeners) {
169                     if (bundle.kindMask == ListenerBundle.MASK_NONE
170                             || (bundle.kindMask & kind) != 0) {
171                         bundle.listener.fileChanged((IFile)r, delta.getMarkerDeltas(), kind);
172                     }
173                 }
174                 return false;
175             } else if (type == IResource.FOLDER) {
176                 int kind = delta.getKind();
177                 // notify the listeners.
178                 for (FolderListenerBundle bundle : mFolderListeners) {
179                     if (bundle.kindMask == ListenerBundle.MASK_NONE
180                             || (bundle.kindMask & kind) != 0) {
181                         bundle.listener.folderChanged((IFolder)r, kind);
182                     }
183                 }
184                 return true;
185             } else if (type == IResource.PROJECT) {
186                 int flags = delta.getFlags();
187 
188                 if (flags == IResourceDelta.OPEN) {
189                     // the project is opening or closing.
190                     IProject project = (IProject)r;
191 
192                     if (project.isOpen()) {
193                         // notify the listeners.
194                         for (IProjectListener pl : mProjectListeners) {
195                             pl.projectOpened(project);
196                         }
197                     } else {
198                         // notify the listeners.
199                         for (IProjectListener pl : mProjectListeners) {
200                             pl.projectClosed(project);
201                         }
202                     }
203                 }
204             }
205 
206             return true;
207         }
208     }
209 
getMonitor()210     public static ResourceMonitor getMonitor() {
211         return sThis;
212     }
213 
214 
215     /**
216      * Starts the resource monitoring.
217      * @param ws The current workspace.
218      * @return The monitor object.
219      */
startMonitoring(IWorkspace ws)220     public static ResourceMonitor startMonitoring(IWorkspace ws) {
221         if (sThis != null) {
222             ws.addResourceChangeListener(sThis,
223                     IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE);
224             sThis.mWorkspace = ws;
225         }
226         return sThis;
227     }
228 
229     /**
230      * Stops the resource monitoring.
231      * @param ws The current workspace.
232      */
stopMonitoring(IWorkspace ws)233     public static void stopMonitoring(IWorkspace ws) {
234         if (sThis != null) {
235             ws.removeResourceChangeListener(sThis);
236 
237             sThis.mFileListeners.clear();
238             sThis.mProjectListeners.clear();
239         }
240     }
241 
242     /**
243      * Adds a file listener.
244      * @param listener The listener to receive the events.
245      * @param kindMask The event mask to filter out specific events.
246      * {@link ListenerBundle#MASK_NONE} will forward all events.
247      */
addFileListener(IFileListener listener, int kindMask)248     public synchronized void addFileListener(IFileListener listener, int kindMask) {
249         FileListenerBundle bundle = new FileListenerBundle();
250         bundle.listener = listener;
251         bundle.kindMask = kindMask;
252 
253         mFileListeners.add(bundle);
254     }
255 
256     /**
257      * Removes an existing file listener.
258      * @param listener the listener to remove.
259      */
removeFileListener(IFileListener listener)260     public synchronized void removeFileListener(IFileListener listener) {
261         for (int i = 0 ; i < mFileListeners.size() ; i++) {
262             FileListenerBundle bundle = mFileListeners.get(i);
263             if (bundle.listener == listener) {
264                 mFileListeners.remove(i);
265                 return;
266             }
267         }
268     }
269 
270     /**
271      * Adds a folder listener.
272      * @param listener The listener to receive the events.
273      * @param kindMask The event mask to filter out specific events.
274      * {@link ListenerBundle#MASK_NONE} will forward all events.
275      */
addFolderListener(IFolderListener listener, int kindMask)276     public synchronized void addFolderListener(IFolderListener listener, int kindMask) {
277         FolderListenerBundle bundle = new FolderListenerBundle();
278         bundle.listener = listener;
279         bundle.kindMask = kindMask;
280 
281         mFolderListeners.add(bundle);
282     }
283 
284     /**
285      * Removes an existing folder listener.
286      * @param listener the listener to remove.
287      */
removeFolderListener(IFolderListener listener)288     public synchronized void removeFolderListener(IFolderListener listener) {
289         for (int i = 0 ; i < mFolderListeners.size() ; i++) {
290             FolderListenerBundle bundle = mFolderListeners.get(i);
291             if (bundle.listener == listener) {
292                 mFolderListeners.remove(i);
293                 return;
294             }
295         }
296     }
297 
298     /**
299      * Adds a project listener.
300      * @param listener The listener to receive the events.
301      */
addProjectListener(IProjectListener listener)302     public synchronized void addProjectListener(IProjectListener listener) {
303         mProjectListeners.add(listener);
304 
305         // we need to look at the opened projects and give them to the listener.
306 
307         // get the list of opened android projects.
308         IWorkspaceRoot workspaceRoot = mWorkspace.getRoot();
309         IJavaModel javaModel = JavaCore.create(workspaceRoot);
310         IJavaProject[] androidProjects = BaseProjectHelper.getAndroidProjects(javaModel);
311 
312         for (IJavaProject androidProject : androidProjects) {
313             listener.projectOpenedWithWorkspace(androidProject.getProject());
314         }
315     }
316 
317     /**
318      * Removes an existing project listener.
319      * @param listener the listener to remove.
320      */
removeProjectListener(IProjectListener listener)321     public synchronized void removeProjectListener(IProjectListener listener) {
322         mProjectListeners.remove(listener);
323     }
324 
325     /**
326      * Adds a resource event listener.
327      * @param listener The listener to receive the events.
328      */
addResourceEventListener(IResourceEventListener listener)329     public synchronized void addResourceEventListener(IResourceEventListener listener) {
330         mEventListeners.add(listener);
331     }
332 
333     /**
334      * Removes an existing Resource Event listener.
335      * @param listener the listener to remove.
336      */
removeResourceEventListener(IResourceEventListener listener)337     public synchronized void removeResourceEventListener(IResourceEventListener listener) {
338         mEventListeners.remove(listener);
339     }
340 
341     /**
342      * Processes the workspace resource change events.
343      */
resourceChanged(IResourceChangeEvent event)344     public void resourceChanged(IResourceChangeEvent event) {
345         // notify the event listeners of a start.
346         for (IResourceEventListener listener : mEventListeners) {
347             listener.resourceChangeEventStart();
348         }
349 
350         if (event.getType() == IResourceChangeEvent.PRE_DELETE) {
351             // a project is being deleted. Lets get the project object and remove
352             // its compiled resource list.
353             IResource r = event.getResource();
354             IProject project = r.getProject();
355 
356             // notify the listeners.
357             for (IProjectListener pl : mProjectListeners) {
358                 pl.projectDeleted(project);
359             }
360         } else {
361             // this a regular resource change. We get the delta and go through it with a visitor.
362             IResourceDelta delta = event.getDelta();
363 
364             DeltaVisitor visitor = new DeltaVisitor();
365             try {
366                 delta.accept(visitor);
367             } catch (CoreException e) {
368             }
369         }
370 
371         // we're done, notify the event listeners.
372         for (IResourceEventListener listener : mEventListeners) {
373             listener.resourceChangeEventEnd();
374         }
375     }
376 
377 }
378