OSDN Git Service

ADT: reload layout when resources from libraries change.
authorXavier Ducrohet <xav@android.com>
Wed, 3 Mar 2010 20:56:10 +0000 (12:56 -0800)
committerXavier Ducrohet <xav@android.com>
Wed, 3 Mar 2010 23:12:17 +0000 (15:12 -0800)
Change-Id: I49dde5bac355b0321701cddcfc1332a99d8c8efb

eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java

index 19f12b7..50d6f8c 100644 (file)
@@ -16,7 +16,9 @@
 
 package com.android.ide.eclipse.adt.internal.editors.layout;
 
+import com.android.ide.eclipse.adt.AdtPlugin;
 import com.android.ide.eclipse.adt.AndroidConstants;
+import com.android.ide.eclipse.adt.internal.project.ProjectState;
 import com.android.ide.eclipse.adt.internal.resources.ResourceType;
 import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor;
 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceFile;
@@ -25,6 +27,7 @@ import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
 import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFileListener;
 import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IResourceEventListener;
 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager.IResourceListener;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarkerDelta;
@@ -36,6 +39,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.Map.Entry;
 
 /**
@@ -54,7 +58,9 @@ public final class LayoutReloadMonitor {
 
     public final static class ChangeFlags {
         public boolean code = false;
+        /** any non-layout resource changes */
         public boolean resources = false;
+        public boolean layout = false;
         public boolean rClass = false;
         public boolean localeList = false;
 
@@ -75,9 +81,12 @@ public final class LayoutReloadMonitor {
     public interface ILayoutReloadListener {
         /**
          * Sent when the layout needs to be redrawn
+         *
          * @param flags a {@link ChangeFlags} object indicating what type of resource changed.
+         * @param libraryModified <code>true</code> if the changeFlags are not for the project
+         * associated with the listener, but instead correspond to a library.
          */
-        void reloadLayout(ChangeFlags flags);
+        void reloadLayout(ChangeFlags flags, boolean libraryModified);
     }
 
     /**
@@ -211,16 +220,20 @@ public final class LayoutReloadMonitor {
          */
         public void resourceChangeEventEnd() {
             // for each IProject that was changed, we notify all the listeners.
-            synchronized (mListenerMap) {
-                for (Entry<IProject, ChangeFlags> project : mProjectFlags.entrySet()) {
-                    List<ILayoutReloadListener> listeners = mListenerMap.get(project.getKey());
-
-                    ChangeFlags flags = project.getValue();
-
-                    if (listeners != null) {
-                        for (ILayoutReloadListener listener : listeners) {
-                            listener.reloadLayout(flags);
-                        }
+            for (Entry<IProject, ChangeFlags> entry : mProjectFlags.entrySet()) {
+                IProject project = entry.getKey();
+
+                // notify the project itself.
+                notifyForProject(project, entry.getValue(), false);
+
+                // check if the project is a library, and if it is search for what other
+                // project depends on this one (directly or not)
+                ProjectState state = Sdk.getProject(project);
+                if (state.isLibrary()) {
+                    Set<ProjectState> mainProjects = Sdk.getMainProjectsFor(project);
+                    for (ProjectState mainProject : mainProjects) {
+                        // always give the changeflag of the modified project.
+                        notifyForProject(mainProject.getProject(), entry.getValue(), true);
                     }
                 }
             }
@@ -228,6 +241,30 @@ public final class LayoutReloadMonitor {
             // empty the list.
             mProjectFlags.clear();
         }
+
+        /**
+         * Notifies the listeners for a given project.
+         * @param project the project for which the listeners must be notified
+         * @param flags the change flags to pass to the listener
+         * @param libraryChanged a flag indicating if the change flags are for the give project,
+         * or if they are for a library dependency.
+         */
+        private void notifyForProject(IProject project, ChangeFlags flags,
+                boolean libraryChanged) {
+            synchronized (mListenerMap) {
+                List<ILayoutReloadListener> listeners = mListenerMap.get(project);
+
+                if (listeners != null) {
+                    for (ILayoutReloadListener listener : listeners) {
+                        try {
+                            listener.reloadLayout(flags, libraryChanged);
+                        } catch (Throwable t) {
+                            AdtPlugin.log(t, "Failed to call ILayoutReloadListener.reloadLayout");
+                        }
+                    }
+                }
+            }
+        }
     };
 
     /**
@@ -266,15 +303,16 @@ public final class LayoutReloadMonitor {
 
             // it's unclear why but there has been cases of resTypes being empty!
             if (resTypes.length > 0) {
-                // files that generates > 1 types cannot be layout files.
-                if (resTypes.length > 1 || resTypes[0] != ResourceType.LAYOUT) {
-                    // this is a resource change, that may require a layout redraw!
-                    if (changeFlags == null) {
-                        changeFlags = new ChangeFlags();
-                        mProjectFlags.put(project, changeFlags);
-                    }
+                // this is a resource change, that may require a layout redraw!
+                if (changeFlags == null) {
+                    changeFlags = new ChangeFlags();
+                    mProjectFlags.put(project, changeFlags);
+                }
 
+                if (resTypes[0] != ResourceType.LAYOUT) {
                     changeFlags.resources = true;
+                } else {
+                    changeFlags.layout = true;
                 }
             }
         }
index 5a1f0e6..240d037 100644 (file)
@@ -1136,7 +1136,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
     /*
      * Called when the file changes triggered a redraw of the layout
      */
-    public void reloadLayout(ChangeFlags flags) {
+    public void reloadLayout(ChangeFlags flags, boolean libraryChanged) {
         boolean recompute = false;
 
         if (flags.rClass) {
@@ -1155,7 +1155,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
             mParent.getDisplay().asyncExec(mLocaleUpdaterFromUiRunnable);
         }
 
-        if (flags.resources) {
+        if (flags.resources || (libraryChanged && flags.layout)) {
             recompute = true;
 
             // TODO: differentiate between single and multi resource file changed, and whether the resource change affects the cache.
index 900fbc4..b328848 100755 (executable)
@@ -1159,7 +1159,7 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE
         /*
          * Called when the file changes triggered a redraw of the layout
          */
-        public void reloadLayout(ChangeFlags flags) {
+        public void reloadLayout(ChangeFlags flags, boolean libraryChanged) {
             boolean recompute = false;
 
             if (flags.rClass) {
@@ -1187,7 +1187,9 @@ public class GraphicalEditorPart extends EditorPart implements IGraphicalLayoutE
                 });
             }
 
-            if (flags.resources) {
+            // if a resources was modified.
+            // also, if a layout in a library was modified.
+            if (flags.resources || (libraryChanged && flags.layout)) {
                 recompute = true;
 
                 // TODO: differentiate between single and multi resource file changed, and whether the resource change affects the cache.
index b3d4347..4519350 100644 (file)
@@ -68,6 +68,7 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.Map.Entry;
 
 /**
@@ -627,6 +628,41 @@ public final class Sdk  {
         return mLayoutDeviceManager;
     }
 
+    /**
+     * Returns a list of {@link ProjectState} representing projects depending, directly or
+     * indirectly on a given library project.
+     * @param project the library project.
+     * @return a possibly empty list of ProjectState.
+     */
+    public static Set<ProjectState> getMainProjectsFor(IProject project) {
+        synchronized (sLock) {
+            // first get the project directly depending on this.
+            HashSet<ProjectState> list = new HashSet<ProjectState>();
+
+            // loop on all project and see if ProjectState.getLibrary returns a non null
+            // project.
+            for (Entry<IProject, ProjectState> entry : sProjectStateMap.entrySet()) {
+                if (project != entry.getKey()) {
+                    LibraryState library = entry.getValue().getLibrary(project);
+                    if (library != null) {
+                        list.add(entry.getValue());
+                    }
+                }
+            }
+
+            // now look for projects depending on the projects directly depending on the library.
+            HashSet<ProjectState> result = new HashSet<ProjectState>(list);
+            for (ProjectState p : list) {
+                if (p.isLibrary()) {
+                    Set<ProjectState> set = getMainProjectsFor(p.getProject());
+                    result.addAll(set);
+                }
+            }
+
+            return result;
+        }
+    }
+
     private Sdk(SdkManager manager, AvdManager avdManager) {
         mManager = manager;
         mAvdManager = avdManager;