aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosiah Gaskin <josiahgaskin@google.com>2011-08-02 13:02:07 -0700
committerAndroid Code Review <code-review@android.com>2011-08-02 13:02:07 -0700
commit8651dc6544f46ef0dc001946c9606d53cb40cab9 (patch)
tree10e06a1383d8ebf803e7ec395cb547c12ca7e81b
parent74542d2f169ffc9dd7ad56c1ba6b7b5cf152adcb (diff)
parent71a45a665af932984fd996027a9df2d09f5068aa (diff)
downloadsdk-8651dc6544f46ef0dc001946c9606d53cb40cab9.zip
sdk-8651dc6544f46ef0dc001946c9606d53cb40cab9.tar.gz
sdk-8651dc6544f46ef0dc001946c9606d53cb40cab9.tar.bz2
Merge "ADT Resource Repo stores IDs and Called Once"
-rw-r--r--common/src/com/android/resources/FolderTypeRelationship.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java34
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java71
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java296
-rw-r--r--ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java215
-rw-r--r--ide_common/src/com/android/ide/common/resources/IdResourceParser.java54
-rw-r--r--ide_common/src/com/android/ide/common/resources/ResourceFolder.java8
9 files changed, 486 insertions, 204 deletions
diff --git a/common/src/com/android/resources/FolderTypeRelationship.java b/common/src/com/android/resources/FolderTypeRelationship.java
index 34961a3..61a6d85 100644
--- a/common/src/com/android/resources/FolderTypeRelationship.java
+++ b/common/src/com/android/resources/FolderTypeRelationship.java
@@ -53,7 +53,9 @@ public final class FolderTypeRelationship {
add(ResourceType.INTEGER, ResourceFolderType.VALUES);
add(ResourceType.INTERPOLATOR, ResourceFolderType.INTERPOLATOR);
add(ResourceType.LAYOUT, ResourceFolderType.LAYOUT);
+ add(ResourceType.ID, ResourceFolderType.LAYOUT);
add(ResourceType.MENU, ResourceFolderType.MENU);
+ add(ResourceType.ID, ResourceFolderType.MENU);
add(ResourceType.MIPMAP, ResourceFolderType.MIPMAP);
add(ResourceType.PLURALS, ResourceFolderType.VALUES);
add(ResourceType.PUBLIC, ResourceFolderType.VALUES);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
index 672995f..0163401 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java
@@ -30,6 +30,7 @@ import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
import com.android.ide.eclipse.adt.internal.project.FixLaunchConfig;
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.BasicXmlErrorListener;
+import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.ide.eclipse.adt.io.IFileWrapper;
@@ -253,6 +254,8 @@ public class PreCompilerBuilder extends BaseBuilder {
} else {
dv = new PreCompilerDeltaVisitor(this, sourceFolderPathList, mProcessors);
delta.accept(dv);
+ // Notify the ResourceManager:
+ ResourceManager.getInstance().processDelta(delta);
// record the state
mMustCompileResources |= dv.getCompileResources();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
index 172f471..c917d1c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/CompiledResourcesMonitor.java
@@ -17,8 +17,8 @@
package com.android.ide.eclipse.adt.internal.resources.manager;
import com.android.ide.common.resources.IntArrayWrapper;
-import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.AdtConstants;
+import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper;
import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFileListener;
@@ -32,6 +32,7 @@ import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
@@ -78,7 +79,9 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
* @see IFileListener#fileChanged
*/
public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
- if (file.getName().equals(AdtConstants.FN_COMPILED_RESOURCE_CLASS)) {
+ // Don't execute if we're autobuilding, let the precompiler take care of the delta
+ if (file.getName().equals(AdtConstants.FN_COMPILED_RESOURCE_CLASS)
+ && ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding() == false) {
loadAndParseRClass(file.getProject());
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java
index cc615ec..f2e6485 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/GlobalProjectMonitor.java
@@ -131,6 +131,14 @@ public final class GlobalProjectMonitor {
}
/**
+ * Interface for a listener that gets passed the raw delta without processing.
+ *
+ */
+ public interface IRawDeltaListener {
+ public void visitDelta(IResourceDelta delta);
+ }
+
+ /**
* Base listener bundle to associate a listener to an event mask.
*/
private static class ListenerBundle {
@@ -176,6 +184,9 @@ public final class GlobalProjectMonitor {
private final ArrayList<IResourceEventListener> mEventListeners =
new ArrayList<IResourceEventListener>();
+ private final ArrayList<IRawDeltaListener> mRawDeltaListeners =
+ new ArrayList<IRawDeltaListener>();
+
private IWorkspace mWorkspace;
/**
@@ -184,6 +195,11 @@ public final class GlobalProjectMonitor {
private final class DeltaVisitor implements IResourceDeltaVisitor {
public boolean visit(IResourceDelta delta) {
+ // notify the raw delta listeners
+ for (IRawDeltaListener listener : mRawDeltaListeners) {
+ listener.visitDelta(delta);
+ }
+ // Find the other resource listeners to notify
IResource r = delta.getResource();
int type = r.getType();
if (type == IResource.FILE) {
@@ -395,7 +411,23 @@ public final class GlobalProjectMonitor {
mEventListeners.remove(listener);
}
- private IResourceChangeListener mResourceChangeListener = new IResourceChangeListener() {
+ /**
+ * Adds a raw delta listener.
+ * @param listener The listener to receive the deltas.
+ */
+ public synchronized void addRawDeltaListener(IRawDeltaListener listener) {
+ mRawDeltaListeners.add(listener);
+ }
+
+ /**
+ * Removes an existing Raw Delta listener.
+ * @param listener the listener to remove.
+ */
+ public synchronized void removeRawDeltaListener(IRawDeltaListener listener) {
+ mRawDeltaListeners.remove(listener);
+ }
+
+ private final IResourceChangeListener mResourceChangeListener = new IResourceChangeListener() {
/**
* Processes the workspace resource change events.
*
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
index ec8b717..6d15f89 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ProjectResources.java
@@ -17,7 +17,6 @@
package com.android.ide.eclipse.adt.internal.resources.manager;
import com.android.ide.common.rendering.api.ResourceValue;
-import com.android.ide.common.resources.InlineResourceItem;
import com.android.ide.common.resources.IntArrayWrapper;
import com.android.ide.common.resources.ResourceFolder;
import com.android.ide.common.resources.ResourceItem;
@@ -32,7 +31,6 @@ import com.android.util.Pair;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
-import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
@@ -290,74 +288,5 @@ public class ProjectResources extends ResourceRepository {
mResourceValueMap = resourceValueMap;
mResIdValueToNameMap = resIdValueToNameMap;
mStyleableValueToNameMap = styleableValueMap;
- mergeIdResources();
- }
-
- @Override
- protected void postUpdate() {
- super.postUpdate();
- mergeIdResources();
- }
-
- /**
- * Merges the list of ID resource coming from R.java and the list of ID resources
- * coming from XML declaration into the cached list {@link #mIdResourceList}.
- */
- void mergeIdResources() {
- if (mResourceValueMap == null) {
- return;
- }
-
- // get the current ID values
- List<ResourceItem> resources = mResourceMap.get(ResourceType.ID);
-
- // get the ID values coming from the R class.
- Map<String, Integer> rResources = mResourceValueMap.get(ResourceType.ID);
-
- if (rResources != null) {
- Map<String, Integer> copy;
-
- if (resources == null) {
- resources = new ArrayList<ResourceItem>(rResources.entrySet().size());
- mResourceMap.put(ResourceType.ID, resources);
- copy = rResources;
- } else {
- // make a copy of the compiled Resources.
- // As we loop on the full resources, we'll check with this copy map and remove
- // from it all the resources we find in the full list.
- // At the end, whatever is in the copy of the compile list is not in the full map,
- // and should be added as inlined resource items.
- copy = new HashMap<String, Integer>(rResources);
-
- for (int i = 0 ; i < resources.size(); ) {
- ResourceItem item = resources.get(i);
- String name = item.getName();
- if (item.isDeclaredInline()) {
- // This ID is declared inline in the full resource map.
- // Check if it's also in the compiled version, in which case we can keep it.
- // Otherwise, if it doesn't exist in the compiled map, remove it from the
- // full map.
- // Since we're going to remove it from the copy map either way, we can use
- // remove to test if it's there
- if (copy.remove(name) != null) {
- // there is a match in the compiled list, do nothing, keep current one.
- i++;
- } else {
- // the ID is now gone, remove it from the list
- resources.remove(i);
- }
- } else {
- // not an inline item, remove it from the copy.
- copy.remove(name);
- i++;
- }
- }
- }
-
- // now add what's left in copy to the list
- for (String name : copy.keySet()) {
- resources.add(new InlineResourceItem(name));
- }
- }
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java
index 7935800..c014601 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java
@@ -23,9 +23,8 @@ import com.android.ide.common.resources.ResourceRepository;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.resources.ResourceHelper;
-import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFileListener;
-import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IFolderListener;
import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IProjectListener;
+import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IRawDeltaListener;
import com.android.ide.eclipse.adt.internal.resources.manager.GlobalProjectMonitor.IResourceEventListener;
import com.android.ide.eclipse.adt.io.IFileWrapper;
import com.android.ide.eclipse.adt.io.IFolderWrapper;
@@ -41,6 +40,8 @@ import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
@@ -111,10 +112,7 @@ public final class ResourceManager {
public static void setup(GlobalProjectMonitor monitor) {
monitor.addResourceEventListener(sThis.mResourceEventListener);
monitor.addProjectListener(sThis.mProjectListener);
-
- int mask = IResourceDelta.ADDED | IResourceDelta.REMOVED | IResourceDelta.CHANGED;
- monitor.addFolderListener(sThis.mFolderListener, mask);
- monitor.addFileListener(sThis.mFileListener, mask);
+ monitor.addRawDeltaListener(sThis.mRawDeltaListener);
CompiledResourcesMonitor.setupMonitor(monitor);
}
@@ -157,6 +155,45 @@ public final class ResourceManager {
}
}
+ /**
+ * Update the resource repository with a delta
+ * @param delta the resource changed delta to process.
+ */
+ public void processDelta(IResourceDelta delta) {
+ // Skip over deltas that don't fit our mask
+ int mask = IResourceDelta.ADDED | IResourceDelta.REMOVED | IResourceDelta.CHANGED;
+ int kind = delta.getKind();
+ if ( (mask & kind) == 0) {
+ return;
+ }
+ // If our delta was handed to us from the PreCompiler then it's a single delta
+ // with lots of children. GlobalProjectMonitor will hand us a delta for each
+ // item in the tree of modifications so we only need to recurse into delta
+ // children if we're autobuilding.
+ if (ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding()) {
+ IResourceDelta[] children = delta.getAffectedChildren();
+ for (IResourceDelta child : children) {
+ processDelta(child);
+ }
+ }
+
+ // Process this delta
+ IResource r = delta.getResource();
+ int type = r.getType();
+
+ if (type == IResource.FILE) {
+ updateFile((IFile)r, delta.getMarkerDeltas(), kind);
+ } else if (type == IResource.FOLDER) {
+ updateFolder((IFolder)r, kind);
+ } // We only care about files and folders.
+ // Project deltas are handled by our project listener
+ }
+
+ /**
+ * Private implementation of a resource event listener that registers with
+ * GlobalProjectMonitor.
+ *
+ */
private class ResourceEventListener implements IResourceEventListener {
private final List<IProject> mChangedProjects = new ArrayList<IProject>();
@@ -166,8 +203,6 @@ public final class ResourceManager {
synchronized (mMap) {
resources = mMap.get(project);
}
-
- resources.postUpdate();
}
mChangedProjects.clear();
@@ -188,160 +223,150 @@ public final class ResourceManager {
* Delegate listener for resource changes. This is called before and after any calls to the
* project and file listeners (for a given resource change event).
*/
- private ResourceEventListener mResourceEventListener = new ResourceEventListener();
-
+ private final ResourceEventListener mResourceEventListener = new ResourceEventListener();
/**
- * Implementation of the {@link IFolderListener} as an internal class so that the methods
- * do not appear in the public API of {@link ResourceManager}.
+ * Update a resource folder that we know about
+ * @param folder the folder that was updated
+ * @param kind the delta type (added/removed/updated)
*/
- private IFolderListener mFolderListener = new IFolderListener() {
- public void folderChanged(IFolder folder, int kind) {
- ProjectResources resources;
+ private void updateFolder(IFolder folder, int kind) {
+ ProjectResources resources;
- final IProject project = folder.getProject();
+ final IProject project = folder.getProject();
- try {
- if (project.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
- return;
- }
- } catch (CoreException e) {
- // can't get the project nature? return!
+ try {
+ if (project.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
return;
}
+ } catch (CoreException e) {
+ // can't get the project nature? return!
+ return;
+ }
- mResourceEventListener.addProject(project);
+ mResourceEventListener.addProject(project);
- switch (kind) {
- case IResourceDelta.ADDED:
- // checks if the folder is under res.
- IPath path = folder.getFullPath();
-
- // the path will be project/res/<something>
- if (path.segmentCount() == 3) {
- if (isInResFolder(path)) {
- // get the project and its resource object.
- synchronized (mMap) {
- resources = mMap.get(project);
-
- // if it doesn't exist, we create it.
- if (resources == null) {
- resources = new ProjectResources(project);
- mMap.put(project, resources);
- }
- }
+ switch (kind) {
+ case IResourceDelta.ADDED:
+ // checks if the folder is under res.
+ IPath path = folder.getFullPath();
- ResourceFolder newFolder = resources.processFolder(
- new IFolderWrapper(folder));
- if (newFolder != null) {
- notifyListenerOnFolderChange(project, newFolder, kind);
+ // the path will be project/res/<something>
+ if (path.segmentCount() == 3) {
+ if (isInResFolder(path)) {
+ // get the project and its resource object.
+ synchronized (mMap) {
+ resources = mMap.get(project);
+
+ // if it doesn't exist, we create it.
+ if (resources == null) {
+ resources = new ProjectResources(project);
+ mMap.put(project, resources);
}
}
- }
- break;
- case IResourceDelta.CHANGED:
- // only call the listeners.
- synchronized (mMap) {
- resources = mMap.get(folder.getProject());
- }
- if (resources != null) {
- ResourceFolder resFolder = resources.getResourceFolder(folder);
- if (resFolder != null) {
- notifyListenerOnFolderChange(project, resFolder, kind);
- }
- }
- break;
- case IResourceDelta.REMOVED:
- synchronized (mMap) {
- resources = mMap.get(folder.getProject());
- }
- if (resources != null) {
- // lets get the folder type
- ResourceFolderType type = ResourceFolderType.getFolderType(
- folder.getName());
- ResourceFolder removedFolder = resources.removeFolder(type,
+ ResourceFolder newFolder = resources.processFolder(
new IFolderWrapper(folder));
- if (removedFolder != null) {
- notifyListenerOnFolderChange(project, removedFolder, kind);
+ if (newFolder != null) {
+ notifyListenerOnFolderChange(project, newFolder, kind);
}
}
- break;
- }
+ }
+ break;
+ case IResourceDelta.CHANGED:
+ // only call the listeners.
+ synchronized (mMap) {
+ resources = mMap.get(folder.getProject());
+ }
+ if (resources != null) {
+ ResourceFolder resFolder = resources.getResourceFolder(folder);
+ if (resFolder != null) {
+ notifyListenerOnFolderChange(project, resFolder, kind);
+ }
+ }
+ break;
+ case IResourceDelta.REMOVED:
+ synchronized (mMap) {
+ resources = mMap.get(folder.getProject());
+ }
+ if (resources != null) {
+ // lets get the folder type
+ ResourceFolderType type = ResourceFolderType.getFolderType(
+ folder.getName());
+
+ ResourceFolder removedFolder = resources.removeFolder(type,
+ new IFolderWrapper(folder));
+ if (removedFolder != null) {
+ notifyListenerOnFolderChange(project, removedFolder, kind);
+ }
+ }
+ break;
}
- };
+ }
/**
- * Implementation of the {@link IFileListener} as an internal class so that the methods
- * do not appear in the public API of {@link ResourceManager}.
+ * Called when a delta indicates that a file has changed.
+ * Depending on the file being changed, and the type of change
+ * (ADDED, REMOVED, CHANGED), the file change is processed to update the resource
+ * manager data.
+ *
+ * @param file The file that changed.
+ * @param markerDeltas The marker deltas for the file.
+ * @param kind The change kind. This is equivalent to
+ * {@link IResourceDelta#accept(IResourceDeltaVisitor)}
*/
- private IFileListener mFileListener = new IFileListener() {
- /* (non-Javadoc)
- * Sent when a file changed. Depending on the file being changed, and the type of change
- * (ADDED, REMOVED, CHANGED), the file change is processed to update the resource
- * manager data.
- *
- * @param file The file that changed.
- * @param markerDeltas The marker deltas for the file.
- * @param kind The change kind. This is equivalent to
- * {@link IResourceDelta#accept(IResourceDeltaVisitor)}
- *
- * @see IFileListener#fileChanged
- */
- public void fileChanged(IFile file, IMarkerDelta[] markerDeltas, int kind) {
- final IProject project = file.getProject();
+ private void updateFile(IFile file, IMarkerDelta[] markerDeltas, int kind) {
+ final IProject project = file.getProject();
- try {
- if (project.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
- return;
- }
- } catch (CoreException e) {
- // can't get the project nature? return!
+ try {
+ if (project.hasNature(AdtConstants.NATURE_DEFAULT) == false) {
return;
}
+ } catch (CoreException e) {
+ // can't get the project nature? return!
+ return;
+ }
- // get the project resources
- ProjectResources resources;
- synchronized (mMap) {
- resources = mMap.get(project);
- }
+ // get the project resources
+ ProjectResources resources;
+ synchronized (mMap) {
+ resources = mMap.get(project);
+ }
- if (resources == null) {
- return;
- }
+ if (resources == null) {
+ return;
+ }
- // checks if the file is under res/something.
- IPath path = file.getFullPath();
-
- if (path.segmentCount() == 4) {
- if (isInResFolder(path)) {
- IContainer container = file.getParent();
- if (container instanceof IFolder) {
-
- ResourceFolder folder = resources.getResourceFolder(
- (IFolder)container);
-
- // folder can be null as when the whole folder is deleted, the
- // REMOVED event for the folder comes first. In this case, the
- // folder will have taken care of things.
- if (folder != null) {
- ResourceFile resFile = folder.processFile(
- new IFileWrapper(file),
- ResourceHelper.getResourceDeltaKind(kind));
- notifyListenerOnFileChange(project, resFile, kind);
- }
+ // checks if the file is under res/something.
+ IPath path = file.getFullPath();
+
+ if (path.segmentCount() == 4) {
+ if (isInResFolder(path)) {
+ IContainer container = file.getParent();
+ if (container instanceof IFolder) {
+
+ ResourceFolder folder = resources.getResourceFolder(
+ (IFolder)container);
+
+ // folder can be null as when the whole folder is deleted, the
+ // REMOVED event for the folder comes first. In this case, the
+ // folder will have taken care of things.
+ if (folder != null) {
+ ResourceFile resFile = folder.processFile(
+ new IFileWrapper(file),
+ ResourceHelper.getResourceDeltaKind(kind));
+ notifyListenerOnFileChange(project, resFile, kind);
}
}
}
}
- };
-
+ }
/**
* Implementation of the {@link IProjectListener} as an internal class so that the methods
* do not appear in the public API of {@link ResourceManager}.
*/
- private IProjectListener mProjectListener = new IProjectListener() {
+ private final IProjectListener mProjectListener = new IProjectListener() {
public void projectClosed(IProject project) {
synchronized (mMap) {
mMap.remove(project);
@@ -368,6 +393,21 @@ public final class ResourceManager {
};
/**
+ * Implementation of {@link IRawDeltaListener} as an internal class so that the methods
+ * do not appear in the public API of {@link ResourceManager}. Delta processing can be
+ * accessed through the {@link ResourceManager#visitDelta(IResourceDelta delta)} method.
+ */
+ private final IRawDeltaListener mRawDeltaListener = new IRawDeltaListener() {
+ public void visitDelta(IResourceDelta delta) {
+ // If we're autobuilding, then PreCompilerBuilder will pass us deltas
+ if (ResourcesPlugin.getWorkspace().getDescription().isAutoBuilding()) {
+ return;
+ }
+ processDelta(delta);
+ }
+ };
+
+ /**
* Returns the {@link ResourceFolder} for the given file or <code>null</code> if none exists.
*/
public ResourceFolder getResourceFolder(IFile file) {
@@ -475,8 +515,6 @@ public final class ResourceManager {
}
}
}
-
- projectResources.postUpdate();
} catch (CoreException e) {
// This happens if the project is closed or if the folder doesn't exist.
// Since we already test for that, we can ignore this exception.
diff --git a/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java b/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java
new file mode 100644
index 0000000..fa8d0e7
--- /dev/null
+++ b/ide_common/src/com/android/ide/common/resources/IdGeneratingResourceFile.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.common.resources;
+
+import com.android.ide.common.rendering.api.DensityBasedResourceValue;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.ValueResourceParser.IValueResourceRepository;
+import com.android.ide.common.resources.configuration.DensityQualifier;
+import com.android.io.IAbstractFile;
+import com.android.io.StreamException;
+import com.android.resources.ResourceType;
+
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+/**
+ * Represents a resource file that also generates ID resources.
+ * <p/>
+ * This is typically an XML file in res/layout or res/menu
+ */
+public final class IdGeneratingResourceFile extends ResourceFile
+ implements IValueResourceRepository {
+
+ private final static SAXParserFactory sParserFactory = SAXParserFactory.newInstance();
+ static {
+ sParserFactory.setNamespaceAware(true);
+ }
+
+ private final Map<String, ResourceValue> mIdResources =
+ new HashMap<String, ResourceValue>();
+
+ private final Collection<ResourceType> mResourceTypeList;
+
+ private final String mFileName;
+
+ private final ResourceType mFileType;
+
+ private final ResourceValue mFileValue;
+
+ public IdGeneratingResourceFile(IAbstractFile file, ResourceFolder folder, ResourceType type) {
+ super(file, folder);
+
+ mFileType = type;
+
+ // Set up our resource types
+ mResourceTypeList = new HashSet<ResourceType>();
+ mResourceTypeList.add(mFileType);
+ mResourceTypeList.add(ResourceType.ID);
+
+ // compute the resource name
+ mFileName = getFileName(type);
+
+ // Get the resource value of this file as a whole layout
+ mFileValue = getFileValue(file,folder);
+ }
+
+ @Override
+ protected void load() {
+ // Parse the file and look for @+id/ entries
+ parseFileForIds();
+
+ // create the resource items in the repository
+ updateResourceItems();
+ }
+
+ @Override
+ protected void update() {
+ // remove this file from all existing ResourceItem.
+ getFolder().getRepository().removeFile(mResourceTypeList, this);
+
+ // reset current content.
+ mIdResources.clear();
+
+ // need to parse the file and find the IDs.
+ parseFileForIds();
+
+ // Notify the repository about any changes
+ updateResourceItems();
+ }
+
+ @Override
+ protected void dispose() {
+ // Remove declarations from this file from the repository
+ getFolder().getRepository().removeFile(mResourceTypeList, this);
+ }
+
+ @Override
+ public Collection<ResourceType> getResourceTypes() {
+ return mResourceTypeList;
+ }
+
+ @Override
+ public boolean hasResources(ResourceType type) {
+ return (type == mFileType) || (type == ResourceType.ID && !mIdResources.isEmpty());
+ }
+
+ @Override
+ public ResourceValue getValue(ResourceType type, String name) {
+ // Check to see if they're asking for one of the right types:
+ if (type != mFileType && type != ResourceType.ID) {
+ return null;
+ }
+
+ // If they're looking for a resource of this type with this name give them the whole file
+ if (type == mFileType && name.equals(mFileName)) {
+ return mFileValue;
+ } else {
+ // Otherwise try to return them an ID
+ // the map will return null if it's not found
+ return mIdResources.get(name);
+ }
+ }
+
+ /**
+ * Looks through the file represented for Ids and adds them to
+ * our id repository
+ */
+ private void parseFileForIds() {
+ try {
+ SAXParser parser = sParserFactory.newSAXParser();
+ parser.parse(getFile().getContents(), new IdResourceParser(this, isFramework()));
+ } catch (ParserConfigurationException e) {
+ } catch (SAXException e) {
+ } catch (IOException e) {
+ } catch (StreamException e) {
+ }
+ }
+
+ /**
+ * Add the resources represented by this file to the repository
+ */
+ private void updateResourceItems() {
+ ResourceRepository repository = getRepository();
+
+ // First add this as a layout file
+ ResourceItem item = repository.getResourceItem(mFileType, mFileName);
+ item.add(this);
+
+ // Now iterate through our IDs and add
+ for (String idName : mIdResources.keySet()) {
+ item = repository.getResourceItem(ResourceType.ID, idName);
+ // add this file to the list of files generating ID resources.
+ item.add(this);
+ }
+ }
+
+ /**
+ * Returns the resource value associated with this whole file as a layout resource
+ * @param file the file handler that represents this file
+ * @param folder the folder this file is under
+ * @return a resource value associated with this layout
+ */
+ private ResourceValue getFileValue(IAbstractFile file, ResourceFolder folder) {
+ // test if there's a density qualifier associated with the resource
+ DensityQualifier qualifier = folder.getConfiguration().getDensityQualifier();
+
+ ResourceValue value;
+ if (qualifier == null) {
+ value = new ResourceValue(mFileType, mFileName,
+ file.getOsLocation(), isFramework());
+ } else {
+ value = new DensityBasedResourceValue(
+ mFileType, mFileName,
+ file.getOsLocation(),
+ qualifier.getValue(),
+ isFramework());
+ }
+ return value;
+ }
+
+
+ /**
+ * Returns the name of this resource.
+ */
+ private String getFileName(ResourceType type) {
+ // get the name from the filename.
+ String name = getFile().getName();
+
+ int pos = name.indexOf('.');
+ if (pos != -1) {
+ name = name.substring(0, pos);
+ }
+
+ return name;
+ }
+
+ public void addResourceValue(ResourceValue value) {
+ // Just overwrite collisions. We're only interested in the unique
+ // IDs declared
+ mIdResources.put(value.getName(), value);
+ }
+}
diff --git a/ide_common/src/com/android/ide/common/resources/IdResourceParser.java b/ide_common/src/com/android/ide/common/resources/IdResourceParser.java
new file mode 100644
index 0000000..27195a9
--- /dev/null
+++ b/ide_common/src/com/android/ide/common/resources/IdResourceParser.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.common.resources;
+
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.ValueResourceParser.IValueResourceRepository;
+import com.android.resources.ResourceType;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+public class IdResourceParser extends DefaultHandler {
+
+ private final IValueResourceRepository mRepository;
+ private final boolean mIsFramework;
+
+ public IdResourceParser(IValueResourceRepository repository, boolean isFramework) {
+ super();
+ mRepository = repository;
+ mIsFramework = isFramework;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attributes)
+ throws SAXException {
+ for (int i = 0; i < attributes.getLength(); ++i) {
+ // Let's look up the value to look for the @+*id/ pattern
+ String candidate = attributes.getValue(i);
+ // Right now the only things that start with the @+ pattern are IDs. If this changes
+ // in the future we'll have to change this line
+ if (candidate != null && candidate.startsWith("@+")) {
+ // Strip out the @+id/ or @+android:id/ section
+ String id = candidate.substring(candidate.indexOf('/') + 1);
+ ResourceValue newId = new ResourceValue(ResourceType.ID, id, mIsFramework);
+ mRepository.addResourceValue(newId);
+ }
+ }
+ }
+}
diff --git a/ide_common/src/com/android/ide/common/resources/ResourceFolder.java b/ide_common/src/com/android/ide/common/resources/ResourceFolder.java
index abdf200..135fbeb 100644
--- a/ide_common/src/com/android/ide/common/resources/ResourceFolder.java
+++ b/ide_common/src/com/android/ide/common/resources/ResourceFolder.java
@@ -73,7 +73,9 @@ public final class ResourceFolder implements Configurable {
// create a ResourceFile for it.
// check if that's a single or multi resource type folder. For now we define this by
- // the number of possible resource type output by files in the folder. This does
+ // the number of possible resource type output by files in the folder.
+ // We have a special case for layout/menu folders which can also generate IDs.
+ // This does
// not make the difference between several resource types from a single file or
// the ability to have 2 files in the same folder generating 2 different types of
// resource. The former is handled by MultiResourceFile properly while we don't
@@ -82,6 +84,10 @@ public final class ResourceFolder implements Configurable {
if (types.size() == 1) {
resFile = new SingleResourceFile(file, this);
+ } else if (types.contains(ResourceType.LAYOUT)){
+ resFile = new IdGeneratingResourceFile(file, this, ResourceType.LAYOUT);
+ } else if (types.contains(ResourceType.MENU)) {
+ resFile = new IdGeneratingResourceFile(file, this, ResourceType.MENU);
} else {
resFile = new MultiResourceFile(file, this);
}