aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/IdeScanningContext.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/IdeScanningContext.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/IdeScanningContext.java234
1 files changed, 234 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/IdeScanningContext.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/IdeScanningContext.java
new file mode 100644
index 000000000..d61324937
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/IdeScanningContext.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.eclipse.adt.internal.resources.manager;
+
+import static com.android.SdkConstants.ANDROID_URI;
+import static com.android.ide.eclipse.adt.AdtConstants.MARKER_AAPT_COMPILE;
+import static org.eclipse.core.resources.IResource.DEPTH_ONE;
+import static org.eclipse.core.resources.IResource.DEPTH_ZERO;
+
+import com.android.annotations.NonNull;
+import com.android.annotations.Nullable;
+import com.android.ide.common.resources.ResourceRepository;
+import com.android.ide.common.resources.ScanningContext;
+import com.android.ide.common.resources.platform.AttributeInfo;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.build.AaptParser;
+import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.utils.Pair;
+
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An {@link IdeScanningContext} is a specialized {@link ScanningContext} which
+ * carries extra information about the scanning state, such as which file is
+ * currently being scanned, and which files have been scanned in the past, such
+ * that at the end of a scan we can mark and clear errors, etc.
+ */
+public class IdeScanningContext extends ScanningContext {
+ private final IProject mProject;
+ private final List<IResource> mScannedResources = new ArrayList<IResource>();
+ private IResource mCurrentFile;
+ private List<Pair<IResource, String>> mErrors;
+ private Set<IProject> mFullAaptProjects;
+ private boolean mValidate;
+ private Map<String, AttributeInfo> mAttributeMap;
+ private ResourceRepository mFrameworkResources;
+
+ /**
+ * Constructs a new {@link IdeScanningContext}
+ *
+ * @param repository the associated {@link ResourceRepository}
+ * @param project the associated project
+ * @param validate if true, check that the attributes and resources are
+ * valid and if not request a full AAPT check
+ */
+ public IdeScanningContext(@NonNull ResourceRepository repository, @NonNull IProject project,
+ boolean validate) {
+ super(repository);
+ mProject = project;
+ mValidate = validate;
+
+ Sdk sdk = Sdk.getCurrent();
+ if (sdk != null) {
+ AndroidTargetData targetData = sdk.getTargetData(project);
+ if (targetData != null) {
+ mAttributeMap = targetData.getAttributeMap();
+ mFrameworkResources = targetData.getFrameworkResources();
+ }
+ }
+ }
+
+ @Override
+ public void addError(@NonNull String error) {
+ super.addError(error);
+
+ if (mErrors == null) {
+ mErrors = new ArrayList<Pair<IResource,String>>();
+ }
+ mErrors.add(Pair.of(mCurrentFile, error));
+ }
+
+ /**
+ * Notifies the context that the given resource is about to be scanned.
+ *
+ * @param resource the resource about to be scanned
+ */
+ public void startScanning(@NonNull IResource resource) {
+ assert mCurrentFile == null : mCurrentFile;
+ mCurrentFile = resource;
+ mScannedResources.add(resource);
+ }
+
+ /**
+ * Notifies the context that the given resource has been scanned.
+ *
+ * @param resource the resource that was scanned
+ */
+ public void finishScanning(@NonNull IResource resource) {
+ assert mCurrentFile != null;
+ mCurrentFile = null;
+ }
+
+ /**
+ * Process any errors found to add error markers in the affected files (and
+ * also clear up any aapt errors in files that are no longer applicable)
+ *
+ * @param async if true, delay updating markers until the next display
+ * thread event loop update
+ */
+ public void updateMarkers(boolean async) {
+ // Run asynchronously? This is necessary for example when adding markers
+ // as the result of a resource change notification, since at that point the
+ // resource tree is locked for modifications and attempting to create a
+ // marker will throw a org.eclipse.core.internal.resources.ResourceException.
+ if (async) {
+ AdtPlugin.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ updateMarkers(false);
+ }
+ });
+ return;
+ }
+
+ // First clear out old/previous markers
+ for (IResource resource : mScannedResources) {
+ try {
+ if (resource.exists()) {
+ int depth = resource instanceof IFolder ? DEPTH_ONE : DEPTH_ZERO;
+ resource.deleteMarkers(MARKER_AAPT_COMPILE, true, depth);
+ }
+ } catch (CoreException ce) {
+ // Pass
+ }
+ }
+
+ // Add new errors
+ if (mErrors != null && mErrors.size() > 0) {
+ List<String> errors = new ArrayList<String>();
+ for (Pair<IResource, String> pair : mErrors) {
+ errors.add(pair.getSecond());
+ }
+ AaptParser.parseOutput(errors, mProject);
+ }
+ }
+
+ @Override
+ public boolean needsFullAapt() {
+ // returns true if it was explicitly requested or if a file that has errors was modified.
+ // This handles the case where an edit doesn't add any new id but fix a compile error.
+ return super.needsFullAapt() || hasModifiedFilesWithErrors();
+ }
+
+ /**
+ * Returns true if any of the scanned resources has an error marker on it.
+ */
+ private boolean hasModifiedFilesWithErrors() {
+ for (IResource resource : mScannedResources) {
+ try {
+ int depth = resource instanceof IFolder ? DEPTH_ONE : DEPTH_ZERO;
+ if (resource.exists()) {
+ IMarker[] markers = resource.findMarkers(IMarker.PROBLEM,
+ true /*includeSubtypes*/, depth);
+ for (IMarker marker : markers) {
+ if (marker.getAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO) ==
+ IMarker.SEVERITY_ERROR) {
+ return true;
+ }
+ }
+ }
+ } catch (CoreException ce) {
+ // Pass
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ protected void requestFullAapt() {
+ super.requestFullAapt();
+
+ if (mCurrentFile != null) {
+ if (mFullAaptProjects == null) {
+ mFullAaptProjects = new HashSet<IProject>();
+ }
+ mFullAaptProjects.add(mCurrentFile.getProject());
+ } else {
+ assert false : "No current context to apply IdeScanningContext to";
+ }
+ }
+
+ /**
+ * Returns the collection of projects that scanned resources have requested
+ * a full aapt for.
+ *
+ * @return a collection of projects that scanned resources requested full
+ * aapt runs for, or null
+ */
+ public Collection<IProject> getAaptRequestedProjects() {
+ return mFullAaptProjects;
+ }
+
+ @Override
+ public boolean checkValue(@Nullable String uri, @NonNull String name, @NonNull String value) {
+ if (!mValidate) {
+ return true;
+ }
+
+ if (!needsFullAapt() && mAttributeMap != null && ANDROID_URI.equals(uri)) {
+ AttributeInfo info = mAttributeMap.get(name);
+ if (info != null && !info.isValid(value, mRepository, mFrameworkResources)) {
+ return false;
+ }
+ }
+
+ return super.checkValue(uri, name, value);
+ }
+}