1 /* 2 * Copyright (C) 2011 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 package com.android.ide.eclipse.adt.internal.resources.manager; 17 18 import static com.android.ide.eclipse.adt.AdtConstants.MARKER_AAPT_COMPILE; 19 import static org.eclipse.core.resources.IResource.DEPTH_ONE; 20 import static org.eclipse.core.resources.IResource.DEPTH_ZERO; 21 22 import com.android.ide.common.resources.ResourceRepository; 23 import com.android.ide.common.resources.ScanningContext; 24 import com.android.ide.eclipse.adt.AdtPlugin; 25 import com.android.ide.eclipse.adt.internal.build.AaptParser; 26 import com.android.util.Pair; 27 28 import org.eclipse.core.resources.IFolder; 29 import org.eclipse.core.resources.IProject; 30 import org.eclipse.core.resources.IResource; 31 import org.eclipse.core.runtime.CoreException; 32 33 import java.util.ArrayList; 34 import java.util.Collection; 35 import java.util.HashSet; 36 import java.util.List; 37 import java.util.Set; 38 39 /** 40 * An {@link IdeScanningContext} is a specialized {@link ScanningContext} which 41 * carries extra information about the scanning state, such as which file is 42 * currently being scanned, and which files have been scanned in the past, such 43 * that at the end of a scan we can mark and clear errors, etc. 44 */ 45 public class IdeScanningContext extends ScanningContext { 46 private final IProject mProject; 47 private final List<IResource> mScannedResources = new ArrayList<IResource>(); 48 private IResource mCurrentFile; 49 private List<Pair<IResource, String>> mErrors; 50 private Set<IProject> mFullAaptProjects; 51 52 /** 53 * Constructs a new {@link IdeScanningContext} 54 * 55 * @param repository the associated {@link ResourceRepository} 56 * @param project the associated project 57 */ IdeScanningContext(ResourceRepository repository, IProject project)58 public IdeScanningContext(ResourceRepository repository, IProject project) { 59 super(repository); 60 mProject = project; 61 } 62 63 @Override addError(String error)64 public void addError(String error) { 65 super.addError(error); 66 67 if (mErrors == null) { 68 mErrors = new ArrayList<Pair<IResource,String>>(); 69 } 70 mErrors.add(Pair.of(mCurrentFile, error)); 71 } 72 73 /** 74 * Notifies the context that the given resource is about to be scanned. 75 * 76 * @param resource the resource about to be scanned 77 */ startScanning(IResource resource)78 public void startScanning(IResource resource) { 79 assert mCurrentFile == null : mCurrentFile; 80 mCurrentFile = resource; 81 mScannedResources.add(resource); 82 } 83 84 /** 85 * Notifies the context that the given resource has been scanned. 86 * 87 * @param resource the resource that was scanned 88 */ finishScanning(IResource resource)89 public void finishScanning(IResource resource) { 90 assert mCurrentFile != null; 91 mCurrentFile = null; 92 } 93 94 /** 95 * Process any errors found to add error markers in the affected files (and 96 * also clear up any aapt errors in files that are no longer applicable) 97 * 98 * @param async if true, delay updating markers until the next display 99 * thread event loop update 100 */ updateMarkers(boolean async)101 public void updateMarkers(boolean async) { 102 // Run asynchronously? This is necessary for example when adding markers 103 // as the result of a resource change notification, since at that point the 104 // resource tree is locked for modifications and attempting to create a 105 // marker will throw a org.eclipse.core.internal.resources.ResourceException. 106 if (async) { 107 AdtPlugin.getDisplay().asyncExec(new Runnable() { 108 public void run() { 109 updateMarkers(false); 110 } 111 }); 112 return; 113 } 114 115 // First clear out old/previous markers 116 for (IResource resource :mScannedResources) { 117 try { 118 if (resource.exists()) { 119 int depth = resource instanceof IFolder ? DEPTH_ONE : DEPTH_ZERO; 120 resource.deleteMarkers(MARKER_AAPT_COMPILE, true, depth); 121 } 122 } catch (CoreException ce) { 123 // Pass 124 } 125 } 126 127 // Add new errors 128 if (mErrors != null && mErrors.size() > 0) { 129 List<String> errors = new ArrayList<String>(); 130 for (Pair<IResource, String> pair : mErrors) { 131 errors.add(pair.getSecond()); 132 } 133 AaptParser.parseOutput(errors, mProject); 134 } 135 } 136 137 @Override needsFullAapt()138 public boolean needsFullAapt() { 139 return super.needsFullAapt(); 140 } 141 142 @Override requestFullAapt()143 protected void requestFullAapt() { 144 super.requestFullAapt(); 145 146 if (mCurrentFile != null) { 147 if (mFullAaptProjects == null) { 148 mFullAaptProjects = new HashSet<IProject>(); 149 } 150 mFullAaptProjects.add(mCurrentFile.getProject()); 151 } else { 152 assert false : "No current context to apply IdeScanningContext to"; 153 } 154 } 155 156 /** 157 * Returns the collection of projects that scanned resources have requested 158 * a full aapt for. 159 * 160 * @return a collection of projects that scanned resources requested full 161 * aapt runs for, or null 162 */ getAaptRequestedProjects()163 public Collection<IProject> getAaptRequestedProjects() { 164 return mFullAaptProjects; 165 } 166 } 167