14517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye/* 24517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Copyright (C) 2010 The Android Open Source Project 34517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 44517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 54517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * you may not use this file except in compliance with the License. 64517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * You may obtain a copy of the License at 74517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 84517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * http://www.eclipse.org/org/documents/epl-v10.php 94517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Unless required by applicable law or agreed to in writing, software 114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * distributed under the License is distributed on an "AS IS" BASIS, 124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * See the License for the specific language governing permissions and 144517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * limitations under the License. 154517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 164517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 174517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyepackage com.android.ide.eclipse.adt.internal.editors.layout.gle2; 184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1912d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.ATTR_LAYOUT; 2012d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.EXT_XML; 2112d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.FD_RESOURCES; 2212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.FD_RES_LAYOUT; 2312d4581faa6438941e65a9dc83213be34c6ca970Tor Norbyeimport static com.android.SdkConstants.VIEW_INCLUDE; 24c3105b949cd2a0f6cbf8a12ec4f30e49b5b5a502Xavier Ducrohetimport static com.android.ide.eclipse.adt.AdtConstants.WS_LAYOUTS; 25c3105b949cd2a0f6cbf8a12ec4f30e49b5b5a502Xavier Ducrohetimport static com.android.ide.eclipse.adt.AdtConstants.WS_SEP; 26da02c18ad5b54d97a1fcfd5f6633062b0c873c22Xavier Ducrohetimport static com.android.resources.ResourceType.LAYOUT; 274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport static org.eclipse.core.resources.IResourceDelta.ADDED; 284517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport static org.eclipse.core.resources.IResourceDelta.CHANGED; 294517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport static org.eclipse.core.resources.IResourceDelta.CONTENT; 304517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport static org.eclipse.core.resources.IResourceDelta.REMOVED; 314517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 321f72cb7cb032538b79e79d6fc7ff3905e9766ce1Xavier Ducrohetimport com.android.annotations.VisibleForTesting; 33026ba97e98e0527d910e15c4e1512893a777a8d2Xavier Ducrohetimport com.android.ide.common.resources.ResourceFile; 34026ba97e98e0527d910e15c4e1512893a777a8d2Xavier Ducrohetimport com.android.ide.common.resources.ResourceFolder; 35026ba97e98e0527d910e15c4e1512893a777a8d2Xavier Ducrohetimport com.android.ide.common.resources.ResourceItem; 364517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport com.android.ide.eclipse.adt.AdtPlugin; 374517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; 384517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources; 394517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager; 404517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager.IResourceListener; 414517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport com.android.ide.eclipse.adt.io.IFileWrapper; 429aa538ffaf7abdcf4fe56c51da75666e60c67a90Xavier Ducrohetimport com.android.io.IAbstractFile; 433bd45f0b16f5ebfafd8080a0f17f71d85c9840edXavier Ducrohetimport com.android.resources.ResourceType; 444517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 454517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.core.resources.IFile; 464517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.core.resources.IMarker; 474517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.core.resources.IProject; 484517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.core.resources.IResource; 494517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.core.runtime.CoreException; 504517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.core.runtime.IStatus; 514517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.core.runtime.QualifiedName; 524517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.swt.widgets.Display; 534517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.wst.sse.core.StructuredModelManager; 544517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.wst.sse.core.internal.provisional.IModelManager; 554517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; 564517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; 574517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.w3c.dom.Document; 584517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.w3c.dom.Element; 594517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport org.w3c.dom.NodeList; 604517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 614517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport java.util.ArrayList; 62da02c18ad5b54d97a1fcfd5f6633062b0c873c22Xavier Ducrohetimport java.util.Collection; 634517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport java.util.Collections; 644517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport java.util.HashMap; 654517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport java.util.HashSet; 66adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbyeimport java.util.LinkedList; 674517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport java.util.List; 684517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport java.util.Map; 694517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyeimport java.util.Set; 704517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 714517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye/** 724517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * The include finder finds other XML files that are including a given XML file, and does 734517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * so efficiently (caching results across IDE sessions etc). 744517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 75eaf6870a9e0f1cf2a8cc18f2904dc05c7192ac20Tor Norbye@SuppressWarnings("restriction") // XML model 764517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbyepublic class IncludeFinder { 774517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Qualified name for the per-project persistent property include-map */ 784517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private final static QualifiedName CONFIG_INCLUDES = new QualifiedName(AdtPlugin.PLUGIN_ID, 794517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye "includes");//$NON-NLS-1$ 804517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 814517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 824517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Qualified name for the per-project non-persistent property storing the 834517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * {@link IncludeFinder} for this project 844517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 854517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private final static QualifiedName INCLUDE_FINDER = new QualifiedName(AdtPlugin.PLUGIN_ID, 864563c4e2f168df1d6c97206a4ac6444dfa2264baTor Norbye "includefinder"); //$NON-NLS-1$ 874517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 884517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Project that the include finder locates includes for */ 894517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private final IProject mProject; 904517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 914517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Map from a layout resource name to a set of layouts included by the given resource */ 924517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private Map<String, List<String>> mIncludes = null; 934517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 944517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 954517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Reverse map of {@link #mIncludes}; points to other layouts that are including a 964517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * given layouts 974517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 984517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private Map<String, List<String>> mIncludedBy = null; 994517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1004517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Flag set during a refresh; ignore updates when this is true */ 1014517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private static boolean sRefreshing; 1024517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1034517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Global (cross-project) resource listener */ 1044517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private static ResourceListener sListener; 1054517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1064517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 1074517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Constructs an {@link IncludeFinder} for the given project. Don't use this method; 1084517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * use the {@link #get} factory method instead. 1094517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 1104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param project project to create an {@link IncludeFinder} for 1114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 1124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private IncludeFinder(IProject project) { 1134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mProject = project; 1144517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 1154517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1164517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 1174517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Returns the {@link IncludeFinder} for the given project 1184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 1194517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param project the project the finder is associated with 1204517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return an {@IncludeFinder} for the given project, never null 1214517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 1224517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public static IncludeFinder get(IProject project) { 1234517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IncludeFinder finder = null; 1244517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 1254517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye finder = (IncludeFinder) project.getSessionProperty(INCLUDE_FINDER); 1264517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } catch (CoreException e) { 1274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Not a problem; we will just create a new one 1284517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 1294517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1304517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (finder == null) { 1314517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye finder = new IncludeFinder(project); 1324517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 1334517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye project.setSessionProperty(INCLUDE_FINDER, finder); 1344517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } catch (CoreException e) { 1354517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye AdtPlugin.log(e, "Can't store IncludeFinder"); 1364517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 1374517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 1384517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1394517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return finder; 1404517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 1414517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1424517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 1434517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Returns a list of resource names that are included by the given resource 1444517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 1454517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param includer the resource name to return included layouts for 1464517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return the layouts included by the given resource 1474517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 1481714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private List<String> getIncludesFrom(String includer) { 1494517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye ensureInitialized(); 1504517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1514517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return mIncludes.get(includer); 1524517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 1534517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 1544517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 155eaf6870a9e0f1cf2a8cc18f2904dc05c7192ac20Tor Norbye * Gets the list of all other layouts that are including the given layout. 1564517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 1574517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param included the file that is included 1584517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return the files that are including the given file, or null or empty 1594517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 1601714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public List<Reference> getIncludedBy(IResource included) { 1611714fd536b42f9963c00e171a9d04319832564f2Tor Norbye ensureInitialized(); 1621714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String mapKey = getMapKey(included); 1631714fd536b42f9963c00e171a9d04319832564f2Tor Norbye List<String> result = mIncludedBy.get(mapKey); 1641714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (result == null) { 1651714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String name = getResourceName(included); 1661714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (!name.equals(mapKey)) { 1671714fd536b42f9963c00e171a9d04319832564f2Tor Norbye result = mIncludedBy.get(name); 1681714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 1691714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 1701714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 1711714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (result != null && result.size() > 0) { 1721714fd536b42f9963c00e171a9d04319832564f2Tor Norbye List<Reference> references = new ArrayList<Reference>(result.size()); 1731714fd536b42f9963c00e171a9d04319832564f2Tor Norbye for (String s : result) { 1741714fd536b42f9963c00e171a9d04319832564f2Tor Norbye references.add(new Reference(mProject, s)); 1751714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 1761714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return references; 1771714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } else { 1781714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return null; 1791714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 1801714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 1811714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 1829bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye /** 1839bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * Returns true if the given resource is included from some other layout in the 1849bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * project 1859bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * 1869bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * @param included the resource to check 1879bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye * @return true if the file is included by some other layout 1889bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye */ 1899bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye public boolean isIncluded(IResource included) { 1909bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye ensureInitialized(); 1919bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye String mapKey = getMapKey(included); 1929bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye List<String> result = mIncludedBy.get(mapKey); 1939bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye if (result == null) { 1949bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye String name = getResourceName(included); 1959bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye if (!name.equals(mapKey)) { 1969bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye result = mIncludedBy.get(name); 1979bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye } 1989bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye } 1999bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye 2009bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye return result != null && result.size() > 0; 2019bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye } 2029bd5e125506d94855fa7f8dff917f20e1b4edb0bTor Norbye 2031714fd536b42f9963c00e171a9d04319832564f2Tor Norbye @VisibleForTesting 2041714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /* package */ List<String> getIncludedBy(String included) { 2054517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye ensureInitialized(); 2064517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return mIncludedBy.get(included); 2074517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2084517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2094517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Initialize the inclusion data structures, if not already done */ 2104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private void ensureInitialized() { 2114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (mIncludes == null) { 2124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Initialize 2134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (!readSettings()) { 2144517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Couldn't read settings: probably the first time this code is running 2154517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // so there is no known data about includes. 2164517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2174517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Yes, these should be multimaps! If we start using Guava replace 2184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // these with multimaps. 2194517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mIncludes = new HashMap<String, List<String>>(); 2204517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mIncludedBy = new HashMap<String, List<String>>(); 2214517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2224517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye scanProject(); 2234517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye saveSettings(); 2244517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2254517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2264517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2284517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // ----- Persistence ----- 2294517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2304517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 2314517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Create a String serialization of the includes map. The map attempts to be compact; 2324517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * it strips out the @layout/ prefix, and eliminates the values for empty string 2334517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * values. The map can be restored by calling {@link #decodeMap}. The encoded String 2344517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * will have sorted keys. 2354517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 2364517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param map the map to be serialized 2374517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return a serialization (never null) of the given map 2384517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 2394517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye @VisibleForTesting 2404517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public static String encodeMap(Map<String, List<String>> map) { 2414517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye StringBuilder sb = new StringBuilder(); 2424517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2434517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (map != null) { 2444517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Process the keys in sorted order rather than just 2454517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // iterating over the entry set to ensure stable output 2464517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> keys = new ArrayList<String>(map.keySet()); 2474517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye Collections.sort(keys); 2484517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (String key : keys) { 2494517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> values = map.get(key); 2504517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2514517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (sb.length() > 0) { 2524517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sb.append(','); 2534517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2544517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sb.append(key); 2554517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (values.size() > 0) { 2564517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sb.append('=').append('>'); 2574517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sb.append('{'); 2584517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye boolean first = true; 2594517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (String value : values) { 2604517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (first) { 2614517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye first = false; 2624517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } else { 2634517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sb.append(','); 2644517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2654517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sb.append(value); 2664517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2674517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sb.append('}'); 2684517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2694517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2704517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2714517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2724517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return sb.toString(); 2734517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 2744517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2754517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 2764517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Decodes the encoding (produced by {@link #encodeMap}) back into the original map, 2774517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * modulo any key sorting differences. 2784517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 2794517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param encoded an encoding of a map created by {@link #encodeMap} 2804517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return a map corresponding to the encoded values, never null 2814517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 2824517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye @VisibleForTesting 2834517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public static Map<String, List<String>> decodeMap(String encoded) { 2844517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye HashMap<String, List<String>> map = new HashMap<String, List<String>>(); 2854517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2864517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (encoded.length() > 0) { 2874517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int i = 0; 2884517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int end = encoded.length(); 2894517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2904517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye while (i < end) { 2914517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 2924517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Find key range 2934517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int keyBegin = i; 2944517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int keyEnd = i; 2954517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye while (i < end) { 2964517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye char c = encoded.charAt(i); 2974517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (c == ',') { 2984517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye break; 2994517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } else if (c == '=') { 3004517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye i += 2; // Skip => 3014517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye break; 3024517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3034517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye i++; 3044517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye keyEnd = i; 3054517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3064517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3074517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> values = new ArrayList<String>(); 3084517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Find values 3094517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (i < end && encoded.charAt(i) == '{') { 3104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye i++; 3114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye while (i < end) { 3124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int valueBegin = i; 3134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int valueEnd = i; 3144517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye char c = 0; 3154517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye while (i < end) { 3164517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye c = encoded.charAt(i); 3174517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (c == ',' || c == '}') { 3184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye valueEnd = i; 3194517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye break; 3204517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3214517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye i++; 3224517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3234517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (valueEnd > valueBegin) { 3244517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye values.add(encoded.substring(valueBegin, valueEnd)); 3254517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3264517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (c == '}') { 3281714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (i < end-1 && encoded.charAt(i+1) == ',') { 3291714fd536b42f9963c00e171a9d04319832564f2Tor Norbye i++; 3301714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 3314517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye break; 3324517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3334517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye assert c == ','; 3344517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye i++; 3354517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3364517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3374517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3384517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String key = encoded.substring(keyBegin, keyEnd); 3394517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye map.put(key, values); 3404517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye i++; 3414517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3424517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3434517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3444517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return map; 3454517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3464517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3474517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 3484517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Stores the settings in the persistent project storage. 3494517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 3504517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private void saveSettings() { 3514517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Serialize the mIncludes map into a compact String. The mIncludedBy map can be 3524517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // inferred from it. 3534517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String encoded = encodeMap(mIncludes); 3544517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3554517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 3564517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (encoded.length() >= 2048) { 3574517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // The maximum length of a setting key is 2KB, according to the javadoc 3584517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // for the project class. It's unlikely that we'll 3594517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // hit this -- even with an average layout root name of 20 characters 3604517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // we can still store over a hundred names. But JUST IN CASE we run 3614517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // into this, we'll clear out the key in this name which means that the 3624517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // information will need to be recomputed in the next IDE session. 3634517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mProject.setPersistentProperty(CONFIG_INCLUDES, null); 3644517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } else { 3654517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String existing = mProject.getPersistentProperty(CONFIG_INCLUDES); 3664517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (!encoded.equals(existing)) { 3674517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mProject.setPersistentProperty(CONFIG_INCLUDES, encoded); 3684517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3694517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3704517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } catch (CoreException e) { 3714517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye AdtPlugin.log(e, "Can't store include settings"); 3724517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3734517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3744517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3754517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 3764517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Reads previously stored settings from the persistent project storage 3774517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 3784517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return true iff settings were restored from the project 3794517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 3804517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private boolean readSettings() { 3814517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 3824517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String encoded = mProject.getPersistentProperty(CONFIG_INCLUDES); 3834517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (encoded != null) { 3844517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mIncludes = decodeMap(encoded); 3854517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3864517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Set up a reverse map, pointing from included files to the files that 3874517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // included them 3884517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mIncludedBy = new HashMap<String, List<String>>(2 * mIncludes.size()); 3894517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (Map.Entry<String, List<String>> entry : mIncludes.entrySet()) { 3904517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // File containing the <include> 3914517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String includer = entry.getKey(); 3924517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Files being <include>'ed by the above file 3934517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> included = entry.getValue(); 3944517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye setIncludedBy(includer, included); 3954517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3964517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 3974517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return true; 3984517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 3994517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } catch (CoreException e) { 4004517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye AdtPlugin.log(e, "Can't read include settings"); 4014517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4024517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4034517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return false; 4044517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4054517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4064517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // ----- File scanning ----- 4074517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4084517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 4094517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Scan the whole project for XML layout resources that are performing includes. 4104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 4114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private void scanProject() { 4124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye ProjectResources resources = ResourceManager.getInstance().getProjectResources(mProject); 4134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (resources != null) { 414da02c18ad5b54d97a1fcfd5f6633062b0c873c22Xavier Ducrohet Collection<ResourceItem> layouts = resources.getResourceItemsOfType(LAYOUT); 415da02c18ad5b54d97a1fcfd5f6633062b0c873c22Xavier Ducrohet for (ResourceItem layout : layouts) { 4164517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<ResourceFile> sources = layout.getSourceFileList(); 4174517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (ResourceFile source : sources) { 4184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye updateFileIncludes(source, false); 4194517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4204517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4214517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4224517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return; 4234517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4244517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4254517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4264517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 4274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Scans the given {@link ResourceFile} and if it is a layout resource, updates the 4284517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * includes in it. 4294517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 4301714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * @param resourceFile the {@link ResourceFile} to be scanned for includes (doesn't 4311714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * have to be only layout XML files; this method will filter the type) 4324517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param singleUpdate true if this is a single file being updated, false otherwise 4334517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * (e.g. during initial project scanning) 4344517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return true if we updated the includes for the resource file 4354517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 4364517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private boolean updateFileIncludes(ResourceFile resourceFile, boolean singleUpdate) { 437da02c18ad5b54d97a1fcfd5f6633062b0c873c22Xavier Ducrohet Collection<ResourceType> resourceTypes = resourceFile.getResourceTypes(); 4384517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (ResourceType type : resourceTypes) { 4394517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (type == ResourceType.LAYOUT) { 4404517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye ensureInitialized(); 4414517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4424517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> includes = Collections.emptyList(); 4434517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (resourceFile.getFile() instanceof IFileWrapper) { 4444517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IFile file = ((IFileWrapper) resourceFile.getFile()).getIFile(); 4454517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4464517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // See if we have an existing XML model for this file; if so, we can 4474517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // just look directly at the parse tree 4484517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye boolean hadXmlModel = false; 4494517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IStructuredModel model = null; 4504517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 4514517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IModelManager modelManager = StructuredModelManager.getModelManager(); 452ae5f1f7f6a5ef8a0b4ca037524c3cd3209343144Tor Norbye model = modelManager.getExistingModelForRead(file); 4534517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (model instanceof IDOMModel) { 4544517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IDOMModel domModel = (IDOMModel) model; 4554517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye Document document = domModel.getDocument(); 4564517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye includes = findIncludesInDocument(document); 4574517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye hadXmlModel = true; 4584517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4594517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } finally { 4604517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (model != null) { 4614517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye model.releaseFromRead(); 4624517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4634517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4644517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 465c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll // If no XML model we have to read the XML contents and (possibly) parse it. 466c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll // The actual file may not exist anymore (e.g. when deleting a layout file 467c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll // or when the workspace is out of sync.) 4684517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (!hadXmlModel) { 4692a58932d3c4e2642cbdbfc161b4f7b884b3d7ea6Tor Norbye String xml = AdtPlugin.readFile(file); 470c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll if (xml != null) { 471c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll includes = findIncludes(xml); 472c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll } 4734517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4744517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } else { 4752a58932d3c4e2642cbdbfc161b4f7b884b3d7ea6Tor Norbye String xml = AdtPlugin.readFile(resourceFile); 476c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll if (xml != null) { 477c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll includes = findIncludes(xml); 478c628731aff0ceaef8deee198f8e9956396ff7855Raphael Moll } 4794517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4804517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4811714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String key = getMapKey(resourceFile); 4821714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (includes.equals(getIncludesFrom(key))) { 4834517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Common case -- so avoid doing settings flush etc 4844517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return false; 4854517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4864517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4874517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye boolean detectCycles = singleUpdate; 4881714fd536b42f9963c00e171a9d04319832564f2Tor Norbye setIncluded(key, includes, detectCycles); 4894517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4904517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (singleUpdate) { 4914517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye saveSettings(); 4924517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4934517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4944517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return true; 4954517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4964517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 4974517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 4984517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return false; 4994517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5004517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5014517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 5024517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Finds the list of includes in the given XML content. It attempts quickly return 5034517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * empty if the file does not include any include tags; it does this by only parsing 5044517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * if it detects the string <include in the file. 5054517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 5064517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private List<String> findIncludes(String xml) { 5072f70fafe0bc1cf6d14cb35241ca252ca3cbe5674Tor Norbye int index = xml.indexOf("<include"); //$NON-NLS-1$ 5084517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (index != -1) { 5094517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return findIncludesInXml(xml); 5104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return Collections.emptyList(); 5134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5144517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5154517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 5164517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Parses the given XML content and extracts all the included URLs and returns them 5174517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 5184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param xml layout XML content to be parsed for includes 5194517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return a list of included urls, or null 5204517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 5214517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private List<String> findIncludesInXml(String xml) { 5226feca9ac5f8add768fef2bc2dc1382a68c158d42Tor Norbye Document document = DomUtilities.parseDocument(xml, false /*logParserErrors*/); 5236feca9ac5f8add768fef2bc2dc1382a68c158d42Tor Norbye if (document != null) { 5244517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return findIncludesInDocument(document); 5254517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5264517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return Collections.emptyList(); 5284517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5294517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5304517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Searches the given DOM document and returns the list of includes, if any */ 5314517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private List<String> findIncludesInDocument(Document document) { 53212d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye NodeList includes = document.getElementsByTagName(VIEW_INCLUDE); 5334517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (includes.getLength() > 0) { 5344517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> urls = new ArrayList<String>(); 5354517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (int i = 0; i < includes.getLength(); i++) { 5364517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye Element element = (Element) includes.item(i); 53712d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye String url = element.getAttribute(ATTR_LAYOUT); 5384517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (url.length() > 0) { 5394517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String resourceName = urlToLocalResource(url); 5404517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (resourceName != null) { 5414517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye urls.add(resourceName); 5424517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5434517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5444517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5454517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5464517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return urls; 5474517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5484517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5494517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return Collections.emptyList(); 5504517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5514517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5524517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 5534517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Returns the layout URL to a local resource name (provided the URL is a local 5544517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * resource, not something in @android etc.) Returns null otherwise. 5554517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 5564517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private static String urlToLocalResource(String url) { 5574517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (!url.startsWith("@")) { //$NON-NLS-1$ 5584517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return null; 5594517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5604517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int typeEnd = url.indexOf('/', 1); 5614517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (typeEnd == -1) { 5624517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return null; 5634517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5644517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int nameBegin = typeEnd + 1; 5654517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int typeBegin = 1; 5664517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int colon = url.lastIndexOf(':', typeEnd); 5674517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (colon != -1) { 5684517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String packageName = url.substring(typeBegin, colon); 5694517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if ("android".equals(packageName)) { //$NON-NLS-1$ 5704517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Don't want to point to non-local resources 5714517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return null; 5724517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5734517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5744517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye typeBegin = colon + 1; 5752f70fafe0bc1cf6d14cb35241ca252ca3cbe5674Tor Norbye assert "layout".equals(url.substring(typeBegin, typeEnd)); //$NON-NLS-1$ 5764517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5774517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5784517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return url.substring(nameBegin); 5794517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5804517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 5814517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 5824517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Record the list of included layouts from the given layout 5834517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 5844517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param includer the layout including other layouts 5854517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param included the layouts that were included by the including layout 5864517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param detectCycles if true, check for cycles and report them as project errors 5874517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 5884517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye @VisibleForTesting 5894517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /* package */ void setIncluded(String includer, List<String> included, boolean detectCycles) { 5904517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Remove previously linked inverse mappings 5914517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> oldIncludes = mIncludes.get(includer); 5924517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (oldIncludes != null && oldIncludes.size() > 0) { 5934517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (String includee : oldIncludes) { 5944517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> includers = mIncludedBy.get(includee); 5954517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (includers != null) { 5964517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye includers.remove(includer); 5974517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5984517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 5994517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6004517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 6014517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mIncludes.put(includer, included); 6024517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Reverse mapping: for included items, point back to including file 6034517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye setIncludedBy(includer, included); 6044517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 6054517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (detectCycles) { 6064517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye detectCycles(includer); 6074517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6084517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6094517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 6104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Record the list of included layouts from the given layout */ 6114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private void setIncludedBy(String includer, List<String> included) { 6124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (String target : included) { 6134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> list = mIncludedBy.get(target); 6144517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (list == null) { 6154517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye list = new ArrayList<String>(2); // We don't expect many includes 6164517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye mIncludedBy.put(target, list); 6174517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (!list.contains(includer)) { 6194517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye list.add(includer); 6204517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6214517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6224517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6234517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 6244517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Start listening on project resources */ 6254517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public static void start() { 6264517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye assert sListener == null; 6274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sListener = new ResourceListener(); 6284517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye ResourceManager.getInstance().addListener(sListener); 6294517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6304517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 6314517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public static void stop() { 6324517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye assert sListener != null; 6334517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye ResourceManager.getInstance().addListener(sListener); 6344517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6354517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 6361714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private static String getMapKey(ResourceFile resourceFile) { 6371714fd536b42f9963c00e171a9d04319832564f2Tor Norbye IAbstractFile file = resourceFile.getFile(); 6381714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String name = file.getName(); 6391714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String folderName = file.getParentFolder().getName(); 6401714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return getMapKey(folderName, name); 6411714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 6421714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 6431714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private static String getMapKey(IResource resourceFile) { 6441714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String folderName = resourceFile.getParent().getName(); 6451714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String name = resourceFile.getName(); 6461714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return getMapKey(folderName, name); 6471714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 6481714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 6491714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private static String getResourceName(IResource resourceFile) { 6501714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String name = resourceFile.getName(); 6511714fd536b42f9963c00e171a9d04319832564f2Tor Norbye int baseEnd = name.length() - EXT_XML.length() - 1; // -1: the dot 6521714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (baseEnd > 0) { 6531714fd536b42f9963c00e171a9d04319832564f2Tor Norbye name = name.substring(0, baseEnd); 6541714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 6551714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 6561714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return name; 6571714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 6581714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 6591714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private static String getMapKey(String folderName, String name) { 6601714fd536b42f9963c00e171a9d04319832564f2Tor Norbye int baseEnd = name.length() - EXT_XML.length() - 1; // -1: the dot 6611714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (baseEnd > 0) { 6621714fd536b42f9963c00e171a9d04319832564f2Tor Norbye name = name.substring(0, baseEnd); 6631714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 6641714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 6651714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // Create a map key for the given resource file 6661714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // This will map 6671714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // /res/layout/foo.xml => "foo" 6681714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // /res/layout-land/foo.xml => "-land/foo" 6691714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 670868a7bbe7c5862c02483ef8f71276fc551d40d60Xavier Ducrohet if (FD_RES_LAYOUT.equals(folderName)) { 6711714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // Normal case -- keep just the basename 6721714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return name; 6731714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } else { 6741714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // Store the relative path from res/ on down, so 6751714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // /res/layout-land/foo.xml becomes "layout-land/foo" 6761714fd536b42f9963c00e171a9d04319832564f2Tor Norbye //if (folderName.startsWith(FD_LAYOUT)) { 6771714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // folderName = folderName.substring(FD_LAYOUT.length()); 6781714fd536b42f9963c00e171a9d04319832564f2Tor Norbye //} 6791714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 6801714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return folderName + WS_SEP + name; 6811714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 6821714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 6831714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 6844517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Listener of resource file saves, used to update layout inclusion data structures */ 6854517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private static class ResourceListener implements IResourceListener { 686ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 6874517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public void fileChanged(IProject project, ResourceFile file, int eventType) { 6884517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (sRefreshing) { 6894517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return; 6904517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6914517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 6924517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if ((eventType & (CHANGED | ADDED | REMOVED | CONTENT)) == 0) { 6934517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return; 6944517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 6954517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 6964517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IncludeFinder finder = get(project); 6974517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (finder != null) { 6984517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (finder.updateFileIncludes(file, true)) { 6994517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye finder.saveSettings(); 7004517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7014517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7024517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7034517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 704ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 7054517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public void folderChanged(IProject project, ResourceFolder folder, int eventType) { 7064517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // We only care about layout resource files 7074517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7084517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7094517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // ----- Cycle detection ----- 7114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private void detectCycles(String from) { 7134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Perform DFS on the include graph and look for a cycle; if we find one, produce 7144517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // a chain of includes on the way back to show to the user 7154517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (mIncludes.size() > 0) { 716d99f34325d9d2ace6968d6f46b57f5e5bf773e31Tor Norbye Set<String> visiting = new HashSet<String>(mIncludes.size()); 717d99f34325d9d2ace6968d6f46b57f5e5bf773e31Tor Norbye String chain = dfs(from, visiting); 7184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (chain != null) { 7194517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye addError(from, chain); 7204517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } else { 7214517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Is there an existing error for us to clean up? 7224517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye removeErrors(from); 7234517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7244517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7254517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7264517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Format to chain include cycles in: a=>b=>c=>d etc */ 7282f70fafe0bc1cf6d14cb35241ca252ca3cbe5674Tor Norbye private final String CHAIN_FORMAT = "%1$s=>%2$s"; //$NON-NLS-1$ 7294517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 730d99f34325d9d2ace6968d6f46b57f5e5bf773e31Tor Norbye private String dfs(String from, Set<String> visiting) { 731d99f34325d9d2ace6968d6f46b57f5e5bf773e31Tor Norbye visiting.add(from); 7324517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7334517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye List<String> includes = mIncludes.get(from); 7344517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (includes != null && includes.size() > 0) { 7354517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (String include : includes) { 736d99f34325d9d2ace6968d6f46b57f5e5bf773e31Tor Norbye if (visiting.contains(include)) { 7374517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return String.format(CHAIN_FORMAT, from, include); 7384517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 739d99f34325d9d2ace6968d6f46b57f5e5bf773e31Tor Norbye String chain = dfs(include, visiting); 7404517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (chain != null) { 7414517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return String.format(CHAIN_FORMAT, from, chain); 7424517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7434517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7444517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7454517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 746d99f34325d9d2ace6968d6f46b57f5e5bf773e31Tor Norbye visiting.remove(from); 747d99f34325d9d2ace6968d6f46b57f5e5bf773e31Tor Norbye 7484517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return null; 7494517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7504517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7514517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private void removeErrors(String from) { 7524517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye final IResource resource = findResource(from); 7534517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (resource != null) { 7544517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 7554517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye final String markerId = IMarker.PROBLEM; 7564517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7574517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IMarker[] markers = resource.findMarkers(markerId, true, IResource.DEPTH_ZERO); 7584517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7594517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (final IMarker marker : markers) { 7604517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String tmpMsg = marker.getAttribute(IMarker.MESSAGE, null); 7614517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (tmpMsg == null || tmpMsg.startsWith(MESSAGE)) { 7624517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Remove 7634517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye runLater(new Runnable() { 764ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 7654517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public void run() { 7664517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 7674517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sRefreshing = true; 7684517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye marker.delete(); 7694517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } catch (CoreException e) { 7704517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye AdtPlugin.log(e, "Can't delete problem marker"); 7714517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } finally { 7724517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sRefreshing = false; 7734517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7744517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7754517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye }); 7764517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7774517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7784517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } catch (CoreException e) { 7794517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // if we couldn't get the markers, then we just mark the file again 7804517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // (since markerAlreadyExists is initialized to false, we do nothing) 7814517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7824517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7834517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 7844517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7854517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** Error message for cycles */ 7864517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private static final String MESSAGE = "Found cyclical <include> chain"; 7874517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7884517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private void addError(String from, String chain) { 7894517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye final IResource resource = findResource(from); 7904517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (resource != null) { 7914517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye final String markerId = IMarker.PROBLEM; 7924517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye final String message = String.format("%1$s: %2$s", MESSAGE, chain); 7934517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye final int lineNumber = 1; 7944517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye final int severity = IMarker.SEVERITY_ERROR; 7954517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 7964517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // check if there's a similar marker already, since aapt is launched twice 7974517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye boolean markerAlreadyExists = false; 7984517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 7994517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IMarker[] markers = resource.findMarkers(markerId, true, IResource.DEPTH_ZERO); 8004517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8014517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye for (IMarker marker : markers) { 8024517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int tmpLine = marker.getAttribute(IMarker.LINE_NUMBER, -1); 8034517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (tmpLine != lineNumber) { 8044517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye break; 8054517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8064517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8074517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye int tmpSeverity = marker.getAttribute(IMarker.SEVERITY, -1); 8084517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (tmpSeverity != severity) { 8094517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye break; 8104517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8114517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8124517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye String tmpMsg = marker.getAttribute(IMarker.MESSAGE, null); 8134517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (tmpMsg == null || tmpMsg.equals(message) == false) { 8144517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye break; 8154517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8164517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8174517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // if we're here, all the marker attributes are equals, we found it 8184517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // and exit 8194517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye markerAlreadyExists = true; 8204517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye break; 8214517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8224517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8234517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } catch (CoreException e) { 8244517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // if we couldn't get the markers, then we just mark the file again 8254517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // (since markerAlreadyExists is initialized to false, we do nothing) 8264517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8274517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8284517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (!markerAlreadyExists) { 8294517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye runLater(new Runnable() { 830ab36f4e7488358dea4ab6b54ee2b7bef3da0232bTor Norbye @Override 8314517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye public void run() { 8324517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye try { 8334517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sRefreshing = true; 8344517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8354517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // Adding a resource will force a refresh on the file; 8364517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // ignore these updates 8374517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye BaseProjectHelper.markResource(resource, markerId, message, lineNumber, 8384517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye severity); 8394517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } finally { 8404517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye sRefreshing = false; 8414517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8424517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8434517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye }); 8444517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8454517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8464517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8474517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8484517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // FIXME: Find more standard Eclipse way to do this. 8494517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // We need to run marker registration/deletion "later", because when the include 8504517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // scanning is running it's in the middle of resource notification, so the IDE 8514517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye // throws an exception 8524517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private static void runLater(Runnable runnable) { 8534517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye Display display = Display.findDisplay(Thread.currentThread()); 8544517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye if (display != null) { 8554517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye display.asyncExec(runnable); 8564517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } else { 8574517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye AdtPlugin.log(IStatus.WARNING, "Could not find display"); 8584517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8594517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8604517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8614517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 8624517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Finds the project resource for the given layout path 8634517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * 8644517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @param from the resource name 8654517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * @return the {@link IResource}, or null if not found 8664517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 8674517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye private IResource findResource(String from) { 8684517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye final IResource resource = mProject.findMember(WS_LAYOUTS + WS_SEP + from + '.' + EXT_XML); 8694517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return resource; 8704517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8714517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye 8724517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /** 8734517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * Creates a blank, project-less {@link IncludeFinder} <b>for use by unit tests 8744517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye * only</b> 8754517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye */ 8764517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye @VisibleForTesting 8774517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye /* package */ static IncludeFinder create() { 8784517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye IncludeFinder finder = new IncludeFinder(null); 8794517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye finder.mIncludes = new HashMap<String, List<String>>(); 8804517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye finder.mIncludedBy = new HashMap<String, List<String>>(); 8814517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye return finder; 8824517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye } 8831714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 8841714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** A reference to a particular file in the project */ 8851714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public static class Reference { 8861714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** The unique id referencing the file, such as (for res/layout-land/main.xml) 8871714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * "layout-land/main") */ 8881714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private final String mId; 8891714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 8901714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** The project containing the file */ 8911714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private final IProject mProject; 8921714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 8931714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** The resource name of the file, such as (for res/layout/main.xml) "main" */ 8941714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private String mName; 8951714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 8961714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** Creates a new include reference */ 8971714fd536b42f9963c00e171a9d04319832564f2Tor Norbye private Reference(IProject project, String id) { 8981714fd536b42f9963c00e171a9d04319832564f2Tor Norbye super(); 8991714fd536b42f9963c00e171a9d04319832564f2Tor Norbye mProject = project; 9001714fd536b42f9963c00e171a9d04319832564f2Tor Norbye mId = id; 9011714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9021714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9031714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** 9041714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * Returns the id identifying the given file within the project 9051714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * 9061714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * @return the id identifying the given file within the project 9071714fd536b42f9963c00e171a9d04319832564f2Tor Norbye */ 9081714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public String getId() { 9091714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return mId; 9101714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9111714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9121714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** 9131714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * Returns the {@link IFile} in the project for the given file. May return null if 9141714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * there is an error in locating the file or if the file no longer exists. 9151714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * 9161714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * @return the project file, or null 9171714fd536b42f9963c00e171a9d04319832564f2Tor Norbye */ 9181714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public IFile getFile() { 9191714fd536b42f9963c00e171a9d04319832564f2Tor Norbye String reference = mId; 9201714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (!reference.contains(WS_SEP)) { 921868a7bbe7c5862c02483ef8f71276fc551d40d60Xavier Ducrohet reference = FD_RES_LAYOUT + WS_SEP + reference; 9221714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9231714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 92412d4581faa6438941e65a9dc83213be34c6ca970Tor Norbye String projectPath = FD_RESOURCES + WS_SEP + reference + '.' + EXT_XML; 9251714fd536b42f9963c00e171a9d04319832564f2Tor Norbye IResource member = mProject.findMember(projectPath); 9261714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (member instanceof IFile) { 9271714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return (IFile) member; 9281714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9291714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9301714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return null; 9311714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9321714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9331714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** 9341714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * Returns a description of this reference, suitable to be shown to the user 9351714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * 9361714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * @return a display name for the reference 9371714fd536b42f9963c00e171a9d04319832564f2Tor Norbye */ 9381714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public String getDisplayName() { 9391714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // The ID is deliberately kept in a pretty user-readable format but we could 9401714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // consider prepending layout/ on ids that don't have it (to make the display 9411714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // more uniform) or ripping out all layout[-constraint] prefixes out and 9421714fd536b42f9963c00e171a9d04319832564f2Tor Norbye // instead prepending @ etc. 9431714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return mId; 9441714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9451714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9461714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** 9471714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * Returns the name of the reference, suitable for resource lookup. For example, 9481714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * for "res/layout/main.xml", as well as for "res/layout-land/main.xml", this 9491714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * would be "main". 9501714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * 9511714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * @return the resource name of the reference 9521714fd536b42f9963c00e171a9d04319832564f2Tor Norbye */ 9531714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public String getName() { 9541714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (mName == null) { 9551714fd536b42f9963c00e171a9d04319832564f2Tor Norbye mName = mId; 9561714fd536b42f9963c00e171a9d04319832564f2Tor Norbye int index = mName.lastIndexOf(WS_SEP); 9571714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (index != -1) { 9581714fd536b42f9963c00e171a9d04319832564f2Tor Norbye mName = mName.substring(index + 1); 9591714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9601714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9611714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9621714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return mName; 9631714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9641714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9651714fd536b42f9963c00e171a9d04319832564f2Tor Norbye @Override 9661714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public int hashCode() { 9671714fd536b42f9963c00e171a9d04319832564f2Tor Norbye final int prime = 31; 9681714fd536b42f9963c00e171a9d04319832564f2Tor Norbye int result = 1; 9691714fd536b42f9963c00e171a9d04319832564f2Tor Norbye result = prime * result + ((mId == null) ? 0 : mId.hashCode()); 9701714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return result; 9711714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9721714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9731714fd536b42f9963c00e171a9d04319832564f2Tor Norbye @Override 9741714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public boolean equals(Object obj) { 9751714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (this == obj) 9761714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return true; 9771714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (obj == null) 9781714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return false; 9791714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (getClass() != obj.getClass()) 9801714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return false; 9811714fd536b42f9963c00e171a9d04319832564f2Tor Norbye Reference other = (Reference) obj; 9821714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (mId == null) { 9831714fd536b42f9963c00e171a9d04319832564f2Tor Norbye if (other.mId != null) 9841714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return false; 9851714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } else if (!mId.equals(other.mId)) 9861714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return false; 9871714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return true; 9881714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9891714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9901714fd536b42f9963c00e171a9d04319832564f2Tor Norbye @Override 9911714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public String toString() { 9922f70fafe0bc1cf6d14cb35241ca252ca3cbe5674Tor Norbye return "Reference [getId()=" + getId() //$NON-NLS-1$ 9932f70fafe0bc1cf6d14cb35241ca252ca3cbe5674Tor Norbye + ", getDisplayName()=" + getDisplayName() //$NON-NLS-1$ 9942f70fafe0bc1cf6d14cb35241ca252ca3cbe5674Tor Norbye + ", getName()=" + getName() //$NON-NLS-1$ 9952f70fafe0bc1cf6d14cb35241ca252ca3cbe5674Tor Norbye + ", getFile()=" + getFile() + "]"; //$NON-NLS-1$ 9961714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 9971714fd536b42f9963c00e171a9d04319832564f2Tor Norbye 9981714fd536b42f9963c00e171a9d04319832564f2Tor Norbye /** 9991714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * Creates a reference to the given file 10001714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * 10011714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * @param file the file to create a reference for 10021714fd536b42f9963c00e171a9d04319832564f2Tor Norbye * @return a reference to the given file 10031714fd536b42f9963c00e171a9d04319832564f2Tor Norbye */ 10041714fd536b42f9963c00e171a9d04319832564f2Tor Norbye public static Reference create(IFile file) { 10051714fd536b42f9963c00e171a9d04319832564f2Tor Norbye return new Reference(file.getProject(), getMapKey(file)); 10061714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 1007adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye 1008adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye /** 1009adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * Returns the resource name of this layout, such as {@code @layout/foo}. 1010adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * 1011adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * @return the resource name 1012adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye */ 1013adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye public String getResourceName() { 1014adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye return '@' + FD_RES_LAYOUT + '/' + getName(); 1015adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1016adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1017adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye 1018adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye /** 1019adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * Returns a collection of layouts (expressed as resource names, such as 1020adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * {@code @layout/foo} which would be invalid includes in the given layout 1021adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * (because it would introduce a cycle) 1022adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * 1023adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * @param layout the layout file to check for cyclic dependencies from 1024adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * @return a collection of layout resources which cannot be included from 1025adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye * the given layout, never null 1026adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye */ 1027adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye public Collection<String> getInvalidIncludes(IFile layout) { 1028adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye IProject project = layout.getProject(); 1029adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye Reference self = Reference.create(layout); 1030adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye 1031adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye // Add anyone who transitively can reach this file via includes. 1032adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye LinkedList<Reference> queue = new LinkedList<Reference>(); 1033adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye List<Reference> invalid = new ArrayList<Reference>(); 1034adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye queue.add(self); 1035adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye invalid.add(self); 1036adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye Set<String> seen = new HashSet<String>(); 1037adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye seen.add(self.getId()); 1038adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye while (!queue.isEmpty()) { 1039adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye Reference reference = queue.removeFirst(); 1040adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye String refId = reference.getId(); 1041adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye 1042adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye // Look up both configuration specific includes as well as includes in the 1043adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye // base versions 1044adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye List<String> included = getIncludedBy(refId); 1045adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye if (refId.indexOf('/') != -1) { 1046adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye List<String> baseIncluded = getIncludedBy(reference.getName()); 1047adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye if (included == null) { 1048adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye included = baseIncluded; 1049adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } else if (baseIncluded != null) { 1050adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye included = new ArrayList<String>(included); 1051adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye included.addAll(baseIncluded); 1052adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1053adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1054adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye 1055adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye if (included != null && included.size() > 0) { 1056adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye for (String id : included) { 1057adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye if (!seen.contains(id)) { 1058adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye seen.add(id); 1059adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye Reference ref = new Reference(project, id); 1060adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye invalid.add(ref); 1061adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye queue.addLast(ref); 1062adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1063adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1064adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1065adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1066adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye 1067adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye List<String> result = new ArrayList<String>(); 1068adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye for (Reference reference : invalid) { 1069adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye result.add(reference.getResourceName()); 1070adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye } 1071adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye 1072adee9788a5ac646a39b516abe4cdd1022911a3f5Tor Norbye return result; 10731714fd536b42f9963c00e171a9d04319832564f2Tor Norbye } 10744517a1f5f4f9fd21b6a611d8a40ac8b81a7bb9c5Tor Norbye} 1075