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;
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;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.Map.Entry;
/**
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;
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);
}
/**
*/
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);
}
}
}
// 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");
+ }
+ }
+ }
+ }
+ }
};
/**
// 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;
}
}
}
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.Map.Entry;
/**
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;