diff options
author | Siva Velusamy <vsiva@google.com> | 2014-08-05 17:46:09 -0700 |
---|---|---|
committer | Siva Velusamy <vsiva@google.com> | 2014-08-05 17:56:24 -0700 |
commit | 261b2fe692c401e9b79619a7b89a4d688f6b92ed (patch) | |
tree | b8ba797f49f81560825e75a858dd3d1f0d874d24 /android | |
parent | 87d28ed8e3100d8e2287069c6544a67a0379dc3c (diff) | |
download | idea-261b2fe692c401e9b79619a7b89a4d688f6b92ed.tar.gz |
navigator: Handle overlapping source sets
Gradle projects, especially those migrated from Eclipse contain
overlapping source sets for different source types. e.g.:
java.srcDirs = ['src']
aidl.srcDirs = ['src']
resources.srcDirs = ['src', 'resources']
Currently, this will show up as separate nodes (java, aidl and resources),
with all of them showing the sources within their source folders. This
is not only odd, but causes issues where the navigator would expand multiple
nodes seemingly randomly when expanding a particular node. This happens
because we have a single folder present in multiple locations inside
the tree.
This CL improves this scenario by:
- If the source roots for a particular source type is a subset of
a previously shown source type's roots, then we just don't show
this source type. e.g. in the above case, we don't show aidl at
all since it is completely present inside java.
- If the set of source roots is an improper subset, we only show
those folders that have not already been shown. In the above example,
for resources, we only show the contents of the 'resources' folder
and not the 'src' folder.
Fixes https://code.google.com/p/android/issues/detail?id=74243 and
https://code.google.com/p/android/issues/detail?id=73928
Change-Id: I4a9c056e96096d6bf29239e5da41fca1746eb70e
Diffstat (limited to 'android')
15 files changed, 227 insertions, 99 deletions
diff --git a/android/src/com/android/tools/idea/navigator/AndroidProjectViewPane.java b/android/src/com/android/tools/idea/navigator/AndroidProjectViewPane.java index 230d1e2dc16..30561d8d7ce 100644 --- a/android/src/com/android/tools/idea/navigator/AndroidProjectViewPane.java +++ b/android/src/com/android/tools/idea/navigator/AndroidProjectViewPane.java @@ -47,6 +47,7 @@ import com.intellij.psi.PsiFile; import com.intellij.psi.search.GlobalSearchScope; import icons.AndroidIcons; import org.jetbrains.android.facet.AndroidFacet; +import org.jetbrains.android.facet.IdeaSourceProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -88,6 +89,13 @@ public class AndroidProjectViewPane extends AbstractProjectViewPSIPane { return 142; } + @NotNull + public static List<IdeaSourceProvider> getSourceProviders(@NotNull AndroidFacet facet) { + List<IdeaSourceProvider> sourceProviders = IdeaSourceProvider.getCurrentSourceProviders(facet); + sourceProviders.addAll(IdeaSourceProvider.getCurrentTestSourceProviders(facet)); + return sourceProviders; + } + @Override public SelectInTarget createSelectInTarget() { return new ProjectPaneSelectInTarget(myProject); diff --git a/android/src/com/android/tools/idea/navigator/nodes/AndroidManifestFileNode.java b/android/src/com/android/tools/idea/navigator/nodes/AndroidManifestFileNode.java index 97444e0c145..13b460d7311 100644 --- a/android/src/com/android/tools/idea/navigator/nodes/AndroidManifestFileNode.java +++ b/android/src/com/android/tools/idea/navigator/nodes/AndroidManifestFileNode.java @@ -16,7 +16,9 @@ package com.android.tools.idea.navigator.nodes; import com.android.SdkConstants; +import com.android.tools.idea.navigator.AndroidProjectViewPane; import com.intellij.ide.projectView.PresentationData; +import com.intellij.ide.projectView.ProjectView; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.projectView.impl.nodes.PsiFileNode; import com.intellij.ide.util.treeView.AbstractTreeNode; @@ -31,16 +33,13 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class AndroidManifestFileNode extends PsiFileNode implements AndroidProjectViewNode { - @NotNull private final IdeaSourceProvider mySourceProvider; @NotNull private final AndroidFacet myFacet; public AndroidManifestFileNode(@NotNull Project project, @NotNull PsiFile psiFile, @NotNull ViewSettings settings, - @NotNull IdeaSourceProvider provider, - AndroidFacet facet) { + @NotNull AndroidFacet facet) { super(project, psiFile, settings); - mySourceProvider = provider; myFacet = facet; } @@ -49,14 +48,25 @@ public class AndroidManifestFileNode extends PsiFileNode implements AndroidProje super.update(data); // if it is not part of the main source set, then append the provider name - if (!SdkConstants.FD_MAIN.equals(mySourceProvider.getName())) { + IdeaSourceProvider sourceProvider = getSourceProvider(getValue()); + if (sourceProvider != null && !SdkConstants.FD_MAIN.equals(sourceProvider.getName())) { PsiFile file = getValue(); data.addText(file.getName(), SimpleTextAttributes.REGULAR_ATTRIBUTES); - data.addText(" (" + mySourceProvider.getName() + ")", SimpleTextAttributes.GRAY_ATTRIBUTES); + data.addText(" (" + sourceProvider.getName() + ")", SimpleTextAttributes.GRAY_ATTRIBUTES); data.setPresentableText(file.getName()); } } + @Nullable + private IdeaSourceProvider getSourceProvider(@NotNull PsiFile file) { + for (IdeaSourceProvider provider : AndroidProjectViewPane.getSourceProviders(myFacet)) { + if (file.getVirtualFile().equals(provider.getManifestFile())) { + return provider; + } + } + return null; + } + @NotNull @Override public AndroidFacet getAndroidFacet() { @@ -76,7 +86,7 @@ public class AndroidManifestFileNode extends PsiFileNode implements AndroidProje PsiFile file = getValue(); sb.append(file.getName()); sb.append(" ("); - sb.append(mySourceProvider.getName()); + sb.append(getSourceProvider(getValue()).getName()); sb.append(")"); return sb.toString(); } diff --git a/android/src/com/android/tools/idea/navigator/nodes/AndroidManifestsGroupNode.java b/android/src/com/android/tools/idea/navigator/nodes/AndroidManifestsGroupNode.java index 15d39e18ed7..81bce3709f9 100644 --- a/android/src/com/android/tools/idea/navigator/nodes/AndroidManifestsGroupNode.java +++ b/android/src/com/android/tools/idea/navigator/nodes/AndroidManifestsGroupNode.java @@ -29,35 +29,29 @@ import com.intellij.psi.PsiManager; import com.intellij.ui.SimpleTextAttributes; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidSourceType; -import org.jetbrains.android.facet.IdeaSourceProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.util.Collection; import java.util.List; +import java.util.Set; public class AndroidManifestsGroupNode extends ProjectViewNode<AndroidFacet> implements AndroidProjectViewNode { private static final String MANIFESTS_NODE = "manifests"; - @NotNull private final List<IdeaSourceProvider> mySourceProviders; + @NotNull private final Set<VirtualFile> mySources; protected AndroidManifestsGroupNode(@NotNull Project project, @NotNull AndroidFacet facet, @NotNull ViewSettings viewSettings, - @NotNull List<IdeaSourceProvider> sourceProviders) { + @NotNull Set<VirtualFile> sources) { super(project, facet, viewSettings); - mySourceProviders = sourceProviders; + mySources = sources; } @Override public boolean contains(@NotNull VirtualFile file) { - for (IdeaSourceProvider provider : mySourceProviders) { - VirtualFile manifestFile = provider.getManifestFile(); - if (file.equals(manifestFile)) { - return true; - } - } - return false; + return mySources.contains(file); } @NotNull @@ -66,15 +60,10 @@ public class AndroidManifestsGroupNode extends ProjectViewNode<AndroidFacet> imp PsiManager psiManager = PsiManager.getInstance(myProject); List<AbstractTreeNode> children = Lists.newArrayList(); - for (IdeaSourceProvider provider : mySourceProviders) { - VirtualFile manifest = provider.getManifestFile(); - if (manifest == null) { - continue; - } - + for (VirtualFile manifest : mySources) { PsiFile psiFile = psiManager.findFile(manifest); if (psiFile != null) { - children.add(new AndroidManifestFileNode(myProject, psiFile, getSettings(), provider, getValue())); + children.add(new AndroidManifestFileNode(myProject, psiFile, getSettings(), getValue())); } } return children; diff --git a/android/src/com/android/tools/idea/navigator/nodes/AndroidModuleNode.java b/android/src/com/android/tools/idea/navigator/nodes/AndroidModuleNode.java index d90ad66b52c..a4f41087ece 100644 --- a/android/src/com/android/tools/idea/navigator/nodes/AndroidModuleNode.java +++ b/android/src/com/android/tools/idea/navigator/nodes/AndroidModuleNode.java @@ -16,7 +16,11 @@ package com.android.tools.idea.navigator.nodes; import com.android.tools.idea.navigator.AndroidProjectViewPane; +import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.intellij.codeInsight.dataflow.SetUtil; +import com.intellij.ide.projectView.ProjectView; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.projectView.impl.nodes.PackageViewModuleNode; import com.intellij.ide.util.treeView.AbstractTreeNode; @@ -32,6 +36,7 @@ import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; +import java.util.Set; /** * {@link com.intellij.ide.projectView.impl.nodes.PackageViewModuleNode} does not classify source types, and just assumes that all source @@ -58,9 +63,7 @@ public class AndroidModuleNode extends PackageViewModuleNode { return super.getChildren(); } - List<IdeaSourceProvider> sourceProviders = IdeaSourceProvider.getCurrentSourceProviders(facet); - sourceProviders.addAll(IdeaSourceProvider.getCurrentTestSourceProviders(facet)); - return getChildren(facet, getSettings(), myProjectViewPane, sourceProviders); + return getChildren(facet, getSettings(), myProjectViewPane, AndroidProjectViewPane.getSourceProviders(facet)); } public static Collection<AbstractTreeNode> getChildren(AndroidFacet facet, @@ -70,29 +73,58 @@ public class AndroidModuleNode extends PackageViewModuleNode { Project project = facet.getModule().getProject(); List<AbstractTreeNode> result = Lists.newArrayList(); - for (AndroidSourceType sourceType : AndroidSourceType.values()) { - List<VirtualFile> sources = getSources(sourceType, providers); - if (sources.isEmpty()) { - continue; - } + HashMultimap<AndroidSourceType,VirtualFile> sourcesByType = getSourcesBySourceType(providers); + for (AndroidSourceType sourceType : sourcesByType.keySet()) { if (sourceType == AndroidSourceType.MANIFEST) { - result.add(new AndroidManifestsGroupNode(project, facet, settings, providers)); + result.add(new AndroidManifestsGroupNode(project, facet, settings, sourcesByType.get(sourceType))); } else if (sourceType == AndroidSourceType.RES) { - result.add(new AndroidResFolderNode(project, facet, settings, providers, pane)); + result.add(new AndroidResFolderNode(project, facet, settings, sourcesByType.get(sourceType), pane)); } else { - result.add(new AndroidSourceTypeNode(project, facet, settings, sourceType, providers, pane)); + result.add(new AndroidSourceTypeNode(project, facet, settings, sourceType, sourcesByType.get(sourceType), pane)); } } return result; } + private static HashMultimap<AndroidSourceType,VirtualFile> getSourcesBySourceType(List<IdeaSourceProvider> providers) { + HashMultimap<AndroidSourceType,VirtualFile> sourcesByType = HashMultimap.create(); + + // Multiple source types can sometimes be present in the same source folder, e.g.: + // sourcesSets.main.java.srcDirs = sourceSets.main.aidl.srcDirs = ['src'] + // in such a case, we only want to show one of them. Source sets can be either proper or improper subsets. It is not entirely + // obvious there is a perfect solution here, but since this is not a common occurence, we resort to the easiest solution here: + // If a set of sources has partially been included as part of another source type's source set, then we simply don't include it + // as part of this source type. + Set<VirtualFile> allSources = Sets.newHashSet(); + + for (AndroidSourceType sourceType : AndroidSourceType.values()) { + Set<VirtualFile> sources = getSources(sourceType, providers); + if (sources.isEmpty()) { + continue; + } + + if (SetUtil.intersect(allSources, sources).isEmpty()) { + // if we haven't seen any of these source folders, then create a new source type folder + sourcesByType.putAll(sourceType, sources); + } else if (!allSources.containsAll(sources)) { + // if we have a partial overlap, we put just the non overlapping sources into this source type + sources.removeAll(allSources); + sourcesByType.putAll(sourceType, sources); + } + + allSources.addAll(sources); + } + + return sourcesByType; + } + @NotNull - private static List<VirtualFile> getSources(AndroidSourceType sourceType, Iterable<IdeaSourceProvider> providers) { - List<VirtualFile> sources = Lists.newArrayList(); + private static Set<VirtualFile> getSources(AndroidSourceType sourceType, Iterable<IdeaSourceProvider> providers) { + Set<VirtualFile> sources = Sets.newHashSet(); for (IdeaSourceProvider provider : providers) { sources.addAll(sourceType.getSources(provider)); diff --git a/android/src/com/android/tools/idea/navigator/nodes/AndroidResFileNode.java b/android/src/com/android/tools/idea/navigator/nodes/AndroidResFileNode.java index b9ecbe02802..bd47d7327c9 100644 --- a/android/src/com/android/tools/idea/navigator/nodes/AndroidResFileNode.java +++ b/android/src/com/android/tools/idea/navigator/nodes/AndroidResFileNode.java @@ -17,6 +17,7 @@ package com.android.tools.idea.navigator.nodes; import com.android.SdkConstants; import com.android.resources.ResourceConstants; +import com.android.tools.idea.navigator.AndroidProjectViewPane; import com.google.common.base.Joiner; import com.intellij.ide.projectView.PresentationData; import com.intellij.ide.projectView.ViewSettings; @@ -26,6 +27,7 @@ import com.intellij.openapi.ui.Queryable; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.ui.SimpleTextAttributes; +import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.IdeaSourceProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -33,14 +35,14 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public class AndroidResFileNode extends PsiFileNode { - private final List<IdeaSourceProvider> mySourceProviders; + private final AndroidFacet myFacet; public AndroidResFileNode(@NotNull Project project, @NotNull PsiFile psiFile, @NotNull ViewSettings settings, - @NotNull List<IdeaSourceProvider> sourceProviders) { + @NotNull AndroidFacet facet) { super(project, psiFile, settings); - mySourceProviders = sourceProviders; + myFacet = facet; } @Override @@ -105,7 +107,7 @@ public class AndroidResFileNode extends PsiFileNode { @Nullable private IdeaSourceProvider findSourceProviderForResFolder(@NotNull PsiDirectory resDirectory) { - for (IdeaSourceProvider provider : mySourceProviders) { + for (IdeaSourceProvider provider : AndroidProjectViewPane.getSourceProviders(myFacet)) { if (provider.getResDirectories().contains(resDirectory.getVirtualFile())) { return provider; } diff --git a/android/src/com/android/tools/idea/navigator/nodes/AndroidResFolderNode.java b/android/src/com/android/tools/idea/navigator/nodes/AndroidResFolderNode.java index 6d494930293..cfee1df830b 100644 --- a/android/src/com/android/tools/idea/navigator/nodes/AndroidResFolderNode.java +++ b/android/src/com/android/tools/idea/navigator/nodes/AndroidResFolderNode.java @@ -23,6 +23,7 @@ import com.google.common.collect.Lists; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.facet.AndroidSourceType; @@ -37,9 +38,9 @@ public class AndroidResFolderNode extends AndroidSourceTypeNode { public AndroidResFolderNode(@NotNull Project project, @NotNull AndroidFacet facet, @NotNull ViewSettings viewSettings, - @NotNull List<IdeaSourceProvider> sourceProviders, + @NotNull Set<VirtualFile> sourceRoots, @NotNull AndroidProjectViewPane projectViewPane) { - super(project, facet, viewSettings, AndroidSourceType.RES, sourceProviders, projectViewPane); + super(project, facet, viewSettings, AndroidSourceType.RES, sourceRoots, projectViewPane); } /** @@ -68,8 +69,7 @@ public class AndroidResFolderNode extends AndroidSourceTypeNode { for (ResourceFolderType type : foldersByResourceType.keySet()) { Set<PsiDirectory> folders = foldersByResourceType.get(type); final AndroidResFolderTypeNode androidResFolderTypeNode = - new AndroidResFolderTypeNode(myProject, getValue(), Lists.newArrayList(folders), getSettings(), type, mySourceProviders, - myProjectViewPane); + new AndroidResFolderTypeNode(myProject, getValue(), Lists.newArrayList(folders), getSettings(), type, myProjectViewPane); children.add(androidResFolderTypeNode); // Inform the tree builder of the node that this particular virtual file maps to diff --git a/android/src/com/android/tools/idea/navigator/nodes/AndroidResFolderTypeNode.java b/android/src/com/android/tools/idea/navigator/nodes/AndroidResFolderTypeNode.java index 0314b40a8a1..cf068ab167e 100644 --- a/android/src/com/android/tools/idea/navigator/nodes/AndroidResFolderTypeNode.java +++ b/android/src/com/android/tools/idea/navigator/nodes/AndroidResFolderTypeNode.java @@ -17,7 +17,9 @@ package com.android.tools.idea.navigator.nodes; import com.android.resources.ResourceFolderType; import com.android.tools.idea.navigator.AndroidProjectViewPane; -import com.google.common.collect.*; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; import com.intellij.ide.projectView.PresentationData; import com.intellij.ide.projectView.ProjectViewNode; import com.intellij.ide.projectView.ViewSettings; @@ -30,22 +32,16 @@ import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiFile; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.PlatformIcons; -import com.intellij.util.containers.ContainerUtil; -import com.siyeh.ig.psiutils.IteratorUtils; import org.jetbrains.android.facet.AndroidFacet; -import org.jetbrains.android.facet.IdeaSourceProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.List; -import java.util.Map; -import java.util.Set; public class AndroidResFolderTypeNode extends ProjectViewNode<List<PsiDirectory>> implements AndroidProjectViewNode { @NotNull private final AndroidFacet myFacet; @NotNull private final ResourceFolderType myFolderType; - @NotNull private final List<IdeaSourceProvider> mySourceProviders; @NotNull private final AndroidProjectViewPane myProjectViewPane; public AndroidResFolderTypeNode(@NotNull Project project, @@ -53,12 +49,10 @@ public class AndroidResFolderTypeNode extends ProjectViewNode<List<PsiDirectory> @NotNull List<PsiDirectory> folders, @NotNull ViewSettings settings, @NotNull ResourceFolderType folderType, - @NotNull List<IdeaSourceProvider> sourceProviders, @NotNull AndroidProjectViewPane projectViewPane) { super(project, folders, settings); myFacet = facet; myFolderType = folderType; - mySourceProviders = sourceProviders; myProjectViewPane = projectViewPane; } @@ -105,9 +99,9 @@ public class AndroidResFolderTypeNode extends ProjectViewNode<List<PsiDirectory> for (String resName : multimap.keySet()) { List<PsiFile> files = Lists.newArrayList(multimap.get(resName)); if (files.size() > 1) { - children.add(new AndroidResGroupNode(myProject, myFacet, files, resName, getSettings(), mySourceProviders)); + children.add(new AndroidResGroupNode(myProject, myFacet, files, resName, getSettings())); } else { - children.add(new AndroidResFileNode(myProject, files.get(0), getSettings(), mySourceProviders)); + children.add(new AndroidResFileNode(myProject, files.get(0), getSettings(), myFacet)); } } return children; diff --git a/android/src/com/android/tools/idea/navigator/nodes/AndroidResGroupNode.java b/android/src/com/android/tools/idea/navigator/nodes/AndroidResGroupNode.java index e93fa1be3f4..32b57a140ac 100644 --- a/android/src/com/android/tools/idea/navigator/nodes/AndroidResGroupNode.java +++ b/android/src/com/android/tools/idea/navigator/nodes/AndroidResGroupNode.java @@ -29,7 +29,6 @@ import com.intellij.psi.PsiFile; import com.intellij.ui.SimpleTextAttributes; import com.intellij.util.PlatformIcons; import org.jetbrains.android.facet.AndroidFacet; -import org.jetbrains.android.facet.IdeaSourceProvider; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -41,19 +40,16 @@ public class AndroidResGroupNode extends ProjectViewNode<List<PsiFile>> implemen @NotNull private final String myResName; @NotNull private final AndroidFacet myFacet; @NotNull private final List<PsiFile> myFiles; - @NotNull private final List<IdeaSourceProvider> mySourceProviders; public AndroidResGroupNode(@NotNull Project project, @NotNull AndroidFacet facet, @NotNull List<PsiFile> files, @NotNull String resName, - @NotNull ViewSettings settings, - List<IdeaSourceProvider> sourceProviders) { + @NotNull ViewSettings settings) { super(project, files, settings); myResName = resName; myFacet = facet; myFiles = files; - mySourceProviders = sourceProviders; } @NotNull @@ -89,7 +85,7 @@ public class AndroidResGroupNode extends ProjectViewNode<List<PsiFile>> implemen public Collection<? extends AbstractTreeNode> getChildren() { List<PsiFileNode> children = Lists.newArrayListWithExpectedSize(myFiles.size()); for (PsiFile file : myFiles) { - children.add(new AndroidResFileNode(myProject, file, getSettings(), mySourceProviders)); + children.add(new AndroidResFileNode(myProject, file, getSettings(), myFacet)); } return children; } diff --git a/android/src/com/android/tools/idea/navigator/nodes/AndroidSourceTypeNode.java b/android/src/com/android/tools/idea/navigator/nodes/AndroidSourceTypeNode.java index 0f0959d7565..45cac1e5c4f 100644 --- a/android/src/com/android/tools/idea/navigator/nodes/AndroidSourceTypeNode.java +++ b/android/src/com/android/tools/idea/navigator/nodes/AndroidSourceTypeNode.java @@ -18,7 +18,6 @@ package com.android.tools.idea.navigator.nodes; import com.android.tools.idea.navigator.AndroidProjectTreeBuilder; import com.android.tools.idea.navigator.AndroidProjectViewPane; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import com.intellij.ide.projectView.PresentationData; import com.intellij.ide.projectView.ProjectViewNode; import com.intellij.ide.projectView.ViewSettings; @@ -27,7 +26,6 @@ import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Queryable; -import com.intellij.openapi.util.Key; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; @@ -50,18 +48,18 @@ import java.util.Set; */ public class AndroidSourceTypeNode extends ProjectViewNode<AndroidFacet> implements AndroidProjectViewNode { @NotNull private final AndroidSourceType mySourceType; - @NotNull protected final List<IdeaSourceProvider> mySourceProviders; + @NotNull private final Set<VirtualFile> mySourceRoots; @NotNull protected final AndroidProjectViewPane myProjectViewPane; public AndroidSourceTypeNode(@NotNull Project project, @NotNull AndroidFacet facet, @NotNull ViewSettings viewSettings, @NotNull AndroidSourceType sourceType, - @NotNull List<IdeaSourceProvider> sourceProviders, + @NotNull Set<VirtualFile> sources, @NotNull AndroidProjectViewPane projectViewPane) { super(project, facet, viewSettings); mySourceType = sourceType; - mySourceProviders = sourceProviders; + mySourceRoots = sources; myProjectViewPane = projectViewPane; } @@ -94,7 +92,7 @@ public class AndroidSourceTypeNode extends ProjectViewNode<AndroidFacet> impleme for (AbstractTreeNode child : directoryChildren) { if (child instanceof PsiDirectoryNode) { PsiDirectory directory = ((PsiDirectoryNode)child).getValue(); - children.add(new AndroidPsiDirectoryNode(myProject, directory, getSettings(), findSourceProvider(directory.getVirtualFile()))); + children.add(new AndroidPsiDirectoryNode(myProject, directory, getSettings(), findJavaSourceProvider(directory.getVirtualFile()))); } else { children.add(child); } @@ -104,8 +102,8 @@ public class AndroidSourceTypeNode extends ProjectViewNode<AndroidFacet> impleme } @Nullable - private IdeaSourceProvider findSourceProvider(VirtualFile virtualFile) { - for (IdeaSourceProvider provider : mySourceProviders) { + private IdeaSourceProvider findJavaSourceProvider(VirtualFile virtualFile) { + for (IdeaSourceProvider provider : AndroidProjectViewPane.getSourceProviders(getValue())) { if (provider.containsFile(virtualFile)) { return provider; } @@ -116,14 +114,12 @@ public class AndroidSourceTypeNode extends ProjectViewNode<AndroidFacet> impleme protected List<PsiDirectory> getSourceDirectories() { PsiManager psiManager = PsiManager.getInstance(myProject); - List<PsiDirectory> psiDirectories = Lists.newArrayList(); - - for (IdeaSourceProvider sourceProvider : mySourceProviders) { - for (VirtualFile file : mySourceType.getSources(sourceProvider)) { - final PsiDirectory directory = psiManager.findDirectory(file); - if (directory != null) { - psiDirectories.add(directory); - } + List<PsiDirectory> psiDirectories = Lists.newArrayListWithExpectedSize(mySourceRoots.size()); + + for (VirtualFile root : mySourceRoots) { + final PsiDirectory directory = psiManager.findDirectory(root); + if (directory != null) { + psiDirectories.add(directory); } } @@ -151,11 +147,9 @@ public class AndroidSourceTypeNode extends ProjectViewNode<AndroidFacet> impleme public boolean contains(@NotNull VirtualFile file) { //TODO: first check if the file is of my source type - for (IdeaSourceProvider sourceProvider : mySourceProviders) { - for (VirtualFile folder : mySourceType.getSources(sourceProvider)) { - if (VfsUtilCore.isAncestor(folder, file, false)) { - return true; - } + for (VirtualFile root : mySourceRoots) { + if (VfsUtilCore.isAncestor(root, file, false)) { + return true; } } @@ -177,15 +171,15 @@ public class AndroidSourceTypeNode extends ProjectViewNode<AndroidFacet> impleme AndroidSourceTypeNode that = (AndroidSourceTypeNode)o; if (mySourceType != that.mySourceType) return false; - return mySourceProviders.equals(that.mySourceProviders); + return mySourceRoots.equals(that.mySourceRoots); } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + mySourceType.hashCode(); - for (IdeaSourceProvider provider : mySourceProviders) { - result = 31 * result + provider.hashCode(); + for (VirtualFile root : mySourceRoots) { + result = 31 * result + root.hashCode(); } return result; } @@ -199,18 +193,7 @@ public class AndroidSourceTypeNode extends ProjectViewNode<AndroidFacet> impleme @NotNull @Override public PsiDirectory[] getDirectories() { - PsiManager psiManager = PsiManager.getInstance(myProject); - Set<PsiDirectory> folders = Sets.newHashSet(); - - for (IdeaSourceProvider provider : mySourceProviders) { - for (VirtualFile vf : mySourceType.getSources(provider)) { - PsiDirectory folder = psiManager.findDirectory(vf); - if (folder != null) { - folders.add(folder); - } - } - } - + List<PsiDirectory> folders = getSourceDirectories(); return folders.toArray(new PsiDirectory[folders.size()]); } } diff --git a/android/testData/projects/navigator/packageview/commonroots/AndroidManifest.xml b/android/testData/projects/navigator/packageview/commonroots/AndroidManifest.xml new file mode 100644 index 00000000000..0af21be139a --- /dev/null +++ b/android/testData/projects/navigator/packageview/commonroots/AndroidManifest.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.example.canon.app" > + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" + android:theme="@style/AppTheme" > + <activity + android:name="com.example.canon.app.MainActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest> diff --git a/android/testData/projects/navigator/packageview/commonroots/build.gradle b/android/testData/projects/navigator/packageview/commonroots/build.gradle new file mode 100644 index 00000000000..e3930be2dd5 --- /dev/null +++ b/android/testData/projects/navigator/packageview/commonroots/build.gradle @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +buildscript { + repositories { + mavenCentral() + if (System.getenv("MAVEN_URL") != null) { + maven {url System.getenv("MAVEN_URL")} + } + } + dependencies { + classpath 'com.android.tools.build:gradle:0.12.+' + } +} + +apply plugin: 'com.android.application' + +android { + compileSdkVersion 19 + buildToolsVersion '19.1.0' + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 19 + versionCode 10 + versionName "1.0" + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + aidl.srcDirs = ['src'] + resources.srcDirs = ['src', 'resources'] + res.srcDirs = ['res'] + } + } +}
\ No newline at end of file diff --git a/android/testData/projects/navigator/packageview/commonroots/res/values-w820dp/dimens.xml b/android/testData/projects/navigator/packageview/commonroots/res/values-w820dp/dimens.xml new file mode 100644 index 00000000000..63fc8164446 --- /dev/null +++ b/android/testData/projects/navigator/packageview/commonroots/res/values-w820dp/dimens.xml @@ -0,0 +1,6 @@ +<resources> + <!-- Example customization of dimensions originally defined in res/values/dimens.xml + (such as screen margins) for screens with more than 820dp of available width. This + would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> + <dimen name="activity_horizontal_margin">64dp</dimen> +</resources> diff --git a/android/testData/projects/navigator/packageview/commonroots/resources/sample_resource.txt b/android/testData/projects/navigator/packageview/commonroots/resources/sample_resource.txt new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/android/testData/projects/navigator/packageview/commonroots/resources/sample_resource.txt diff --git a/android/testData/projects/navigator/packageview/commonroots/src/com/foo/Foo.java b/android/testData/projects/navigator/packageview/commonroots/src/com/foo/Foo.java new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/android/testData/projects/navigator/packageview/commonroots/src/com/foo/Foo.java diff --git a/android/testSrc/com/android/tools/idea/navigator/AndroidProjectViewTest.java b/android/testSrc/com/android/tools/idea/navigator/AndroidProjectViewTest.java index 054d6587e59..67855adbe2b 100644 --- a/android/testSrc/com/android/tools/idea/navigator/AndroidProjectViewTest.java +++ b/android/testSrc/com/android/tools/idea/navigator/AndroidProjectViewTest.java @@ -114,6 +114,42 @@ public class AndroidProjectViewTest extends AndroidGradleTestCase { printInfo); } + public void testCommonRoots() throws Exception { + loadProject("projects/navigator/packageview/commonroots"); + + myPane = createPane(); + TestAndroidTreeStructure structure = new TestAndroidTreeStructure(getProject(), myTestRootDisposable); + + Queryable.PrintInfo printInfo = new Queryable.PrintInfo(); + PsiDirectory dir = getBaseFolder(); + assertNotNull(dir); + + Module[] modules = ModuleManager.getInstance(getProject()).getModules(); + assertEquals(1, modules.length); + + String projectName = getProject().getName(); + String expected = + projectName + "\n" + + " Gradle Scripts\n" + + " build.gradle (" + modules[0].getName() + ")\n" + + " gradle-wrapper.properties\n" + + " " + modules[0].getName() + " (Android)\n" + + " java\n" + + " foo (main)\n" + + " Foo.java\n" + + " manifests\n" + + " AndroidManifest.xml (main)\n" + + " res\n" + + " values\n" + + " dimens.xml (w820dp)\n" + + " resources\n" + + " sample_resource.txt\n"; + int numLines = expected.split("\n").length; + ProjectViewTestUtil + .assertStructureEqual(structure, expected, numLines, PlatformTestUtil.createComparator(printInfo), structure.getRootElement(), + printInfo); + } + @Nullable private PsiDirectory getBaseFolder() throws Exception { VirtualFile folder = getProject().getBaseDir(); |