From 78a07ff82af290decf252f5982606537f503d5ce Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 7 Jun 2012 21:11:22 +0200 Subject: [PATCH] IDEA-69867 Support services as an artifact type in Griffon projects --- .../groovy/griffon/GriffonFramework.java | 79 +++++- .../griffon/GriffonSourceInspector.java | 250 ++++++++++++++++++ .../griffon/GriffonToolWindowFactory.java | 117 +++++--- .../plugins/groovy/mvc/MvcFramework.java | 10 +- .../groovy/mvc/MvcProjectStructure.java | 7 +- .../projectView/TopLevelDirectoryNode.java | 6 + 6 files changed, 423 insertions(+), 46 deletions(-) create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonSourceInspector.java diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonFramework.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonFramework.java index 68a243a46d54..dac9f767412c 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonFramework.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonFramework.java @@ -18,6 +18,8 @@ package org.jetbrains.plugins.groovy.griffon; import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.JavaParameters; +import com.intellij.lang.properties.IProperty; +import com.intellij.lang.properties.psi.PropertiesFile; import com.intellij.openapi.application.AccessToken; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.module.Module; @@ -36,6 +38,8 @@ import com.intellij.openapi.vcs.changes.IgnoredBeanFactory; import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; import gnu.trove.TIntArrayList; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; @@ -49,7 +53,9 @@ import org.jetbrains.plugins.groovy.mvc.MvcProjectStructure; import javax.swing.*; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -246,7 +252,7 @@ public class GriffonFramework extends MvcFramework { for (final VirtualFile child : dist.getChildren()) { final String name = child.getName(); if (name.endsWith(".jar")) { - if (name.startsWith("griffon-cli-") || name.startsWith("griffon-rt-")) { + if (name.startsWith("griffon-cli-") || name.startsWith("griffon-rt-") || name.startsWith("griffon-resources-")) { params.getClassPath().add(child); } } @@ -296,6 +302,9 @@ public class GriffonFramework extends MvcFramework { final String confpath = griffonHomePath + GROOVY_STARTER_CONF; params.getVMParametersList().add("-Dgroovy.starter.conf=" + confpath); + params.getVMParametersList().add( + "-Dgroovy.sanitized.stacktraces=\"groovy., org.codehaus.groovy., java., javax., sun., gjdk.groovy., gant., org.codehaus.gant.\""); + params.getProgramParametersList().add("--main"); params.getProgramParametersList().add("org.codehaus.griffon.cli.GriffonScriptRunner"); params.getProgramParametersList().add("--conf"); @@ -314,7 +323,7 @@ public class GriffonFramework extends MvcFramework { params.getProgramParametersList().add(argsString); params.setDefaultCharset(module.getProject()); - + return params; } @@ -384,6 +393,24 @@ public class GriffonFramework extends MvcFramework { return EP_NAME.findExtension(GriffonFramework.class); } + public VirtualFile getApplicationPropertiesFile(Module module) { + final VirtualFile appRoot = findAppRoot(module); + return appRoot != null ? appRoot.findChild("application.properties") : null; + } + + @Override + public String getApplicationName(Module module) { + final VirtualFile appProperties = getApplicationPropertiesFile(module); + if (appProperties != null) { + final PsiFile file = PsiManager.getInstance(module.getProject()).findFile(appProperties); + if (file instanceof PropertiesFile) { + final IProperty property = ((PropertiesFile)file).findPropertyByKey("application.name"); + return property != null ? property.getValue() : super.getApplicationName(module); + } + } + return super.getApplicationName(module); + } + private static class GriffonProjectStructure extends MvcProjectStructure { public GriffonProjectStructure(Module module, final boolean auxModule) { super(module, auxModule, getUserHomeGriffon(), GriffonFramework.getInstance().getSdkWorkDir(module)); @@ -395,11 +422,55 @@ public class GriffonFramework extends MvcFramework { } public String[] getSourceFolders() { - return new String[]{"griffon-app/controllers", "griffon-app/models", "griffon-app/views", "src/main", "griffon-app/services"}; + List sourceFolders = new ArrayList(); + + for (VirtualFile file : ModuleRootManager.getInstance(myModule).getContentRoots()) { + handleSrc(file.findChild("src"), sourceFolders); + handleGriffonApp(file.findChild("griffon-app"), sourceFolders); + List sources = + GriffonSourceInspector.processModuleMetadata(myModule); + for (GriffonSourceInspector.GriffonSource source : sources) { + sourceFolders.add(source.getPath()); + } + } + return sourceFolders.toArray(new String[sourceFolders.size()]); + } + + private void handleGriffonApp(VirtualFile griffonApp, List sourceFolders) { + if (griffonApp == null) return; + // Add standard artifacts, i.e, models, views, controllers, services, conf, lifecycle + for (String child : new String[]{"models", "views", "controllers", "services", "conf", "lifecycle"}) { + if (griffonApp.findChild(child) != null) { + sourceFolders.add("griffon-app/" + child); + } + } + } + + private void handleSrc(VirtualFile src, List sourceFolders) { + if (src == null) return; + for (String child : new String[]{"main", "cli"}) { + if (src.findChild(child) != null) { + sourceFolders.add("src/" + child); + } + } + } + + private void handleTest(VirtualFile test, List sourceFolders) { + if (test == null) return; + for (String child : new String[]{"unit", "integration", "shared"}) { + if (test.findChild(child) != null) { + sourceFolders.add("test/" + child); + } + } } public String[] getTestFolders() { - return new String[]{"test/unit", "test/integration"}; + List sourceFolders = new ArrayList(); + + for (VirtualFile file : ModuleRootManager.getInstance(myModule).getContentRoots()) { + handleTest(file.findChild("test"), sourceFolders); + } + return sourceFolders.toArray(new String[sourceFolders.size()]); } public String[] getInvalidSourceFolders() { diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonSourceInspector.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonSourceInspector.java new file mode 100644 index 000000000000..ac81fef51829 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonSourceInspector.java @@ -0,0 +1,250 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.plugins.groovy.griffon; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.util.IconLoader; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.psi.util.CachedValueProvider; +import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.xml.XmlAttribute; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.util.containers.ContainerUtil; + +import javax.swing.*; +import java.io.File; +import java.util.*; + +/** + * @author aalmiray + */ +public class GriffonSourceInspector { + public static List processModuleMetadata(final Module module) { + return CachedValuesManager.getManager(module.getProject()).getCachedValue(module, new CachedValueProvider>() { + @Override + public Result> compute() { + List sources = new ArrayList(); + List dependencies = new ArrayList(); + ContainerUtil.addIfNotNull(dependencies, GriffonFramework.getInstance().getApplicationPropertiesFile(module)); + String applicationName = GriffonFramework.getInstance().getApplicationName(module); + + File sdkWorkDir = GriffonFramework.getInstance().getSdkWorkDir(module); + // construct $griffonWorkDir/projects/$appName/plugins + File pluginsDir = new File(sdkWorkDir, "/projects/" + applicationName + "/plugins/"); + if (pluginsDir.exists() && pluginsDir.canRead() && pluginsDir.isDirectory()) { + //noinspection ConstantConditions + for (File pluginDir : pluginsDir.listFiles()) { + if (!pluginDir.isDirectory() || !pluginDir.canRead()) continue; + File srcIdeSupportDir = new File(pluginDir, "src/ide-support"); + if (!srcIdeSupportDir.exists() || !srcIdeSupportDir.canRead()) continue; + File ideaSupport = new File(srcIdeSupportDir, "idea.xml"); + VirtualFile ideaMetadata = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(ideaSupport); + if (ideaMetadata != null) { + dependencies.add(ideaMetadata); + PsiFile psiFile = PsiManager.getInstance(module.getProject()).findFile(ideaMetadata); + if (psiFile instanceof XmlFile) { + XmlTag rootTag = ((XmlFile)psiFile).getRootTag(); + if (rootTag == null) continue; + /* + Metadata file has the following format + + + + + + */ + + for (XmlTag sourceRootTag : rootTag.findSubTags("source-root")) { + String path = sourceRootTag.getAttributeValue("path"); + XmlTag navigationTag = sourceRootTag.findFirstSubTag("navigation"); + String description = navigationTag == null ? "" : navigationTag.getAttributeValue("description"); + XmlAttribute iconAttr = navigationTag == null ? null : navigationTag.getAttribute("icon"); + XmlAttribute weightAttr = navigationTag == null ? null : navigationTag.getAttribute("weight"); + String icon = iconAttr != null ? iconAttr.getValue() : "groovy-icon"; + int weight = weightAttr != null ? Integer.parseInt(weightAttr.getValue()) : 75; + + sources.add(new GriffonSource(path, new GriffonSource.Navigation(description, icon, weight))); + } + } + } + } + } + return Result.create(sources, dependencies); + } + }); + + } + + public static class GriffonSource { + private final String path; + private final Navigation navigation; + + public GriffonSource(String path, Navigation navigation) { + this.path = path; + this.navigation = navigation; + } + + public String getPath() { + return path; + } + + public Navigation getNavigation() { + return navigation; + } + + @Override + public String toString() { + return "GriffonSource{" + "path='" + path + '\'' + ", navigation=" + navigation + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + GriffonSource that = (GriffonSource)o; + + if (!navigation.equals(that.navigation)) return false; + if (!path.equals(that.path)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = path.hashCode(); + result = 31 * result + navigation.hashCode(); + return result; + } + + public static class Navigation { + private final String description; + private final String icon; + private final int weight; + + public Navigation(String description, String icon, int weight) { + this.description = getNaturalName(description); + this.icon = icon; + this.weight = weight; + } + + public String getDescription() { + return description; + } + + public Icon getIcon() { + String iconStr = icon.endsWith(".png") ? icon : icon + ".png"; + if (iconStr.startsWith("/")) { + return IconLoader.getIcon(iconStr); + } + else { + return IconLoader.getIcon("/icons/griffon/" + iconStr); + } + } + + public int getWeight() { + return weight; + } + + @Override + public String toString() { + return "Navigation{" + "description='" + description + '\'' + ", icon='" + icon + '\'' + ", weight=" + weight + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Navigation)) return false; + + Navigation that = (Navigation)o; + + if (weight != that.weight) return false; + if (description != null ? !description.equals(that.description) : that.description != null) return false; + if (icon != null ? !icon.equals(that.icon) : that.icon != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = description != null ? description.hashCode() : 0; + result = 31 * result + (icon != null ? icon.hashCode() : 0); + result = 31 * result + weight; + return result; + } + } + } + + private static String getNaturalName(String name) { + name = getShortName(name); + List words = new ArrayList(); + int i = 0; + char[] chars = name.toCharArray(); + for (int j = 0; j < chars.length; j++) { + char c = chars[j]; + String w; + if (i >= words.size()) { + w = ""; + words.add(i, w); + } + else { + w = words.get(i); + } + + if (Character.isLowerCase(c) || Character.isDigit(c)) { + if (Character.isLowerCase(c) && w.length() == 0) { + c = Character.toUpperCase(c); + } + else if (w.length() > 1 && Character.isUpperCase(w.charAt(w.length() - 1))) { + w = ""; + words.add(++i, w); + } + + words.set(i, w + c); + } + else if (Character.isUpperCase(c)) { + if ((i == 0 && w.length() == 0) || Character.isUpperCase(w.charAt(w.length() - 1))) { + words.set(i, w + c); + } + else { + words.add(++i, String.valueOf(c)); + } + } + } + + StringBuilder buf = new StringBuilder(); + for (Iterator j = words.iterator(); j.hasNext(); ) { + String word = j.next(); + buf.append(word); + if (j.hasNext()) { + buf.append(' '); + } + } + return buf.toString(); + } + + private static String getShortName(String className) { + return StringUtil.getShortName(className); + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonToolWindowFactory.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonToolWindowFactory.java index d7c0ffa84c13..707a4ebeeb2e 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonToolWindowFactory.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/griffon/GriffonToolWindowFactory.java @@ -20,16 +20,20 @@ import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ModuleRootManager; +import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; -import com.intellij.util.PlatformIcons; +import com.intellij.psi.PsiFile; +import com.intellij.psi.PsiManager; +import com.intellij.util.Icons; +import com.intellij.util.containers.hash.LinkedHashMap; import org.jetbrains.plugins.groovy.GroovyIcons; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.mvc.MvcIcons; import org.jetbrains.plugins.groovy.mvc.projectView.*; import javax.swing.*; import java.util.List; +import java.util.Map; /** * @author peter @@ -42,51 +46,67 @@ public class GriffonToolWindowFactory extends MvcToolWindowDescriptor { @Override public void fillModuleChildren(List result, Module module, ViewSettings viewSettings, VirtualFile root) { final Project project = module.getProject(); - final PsiDirectory domains = findDirectory(project, root, "griffon-app/models"); - if (domains != null) { - result.add(new TopLevelDirectoryNode(module, domains, viewSettings, "Model classes", MvcIcons.DOMAIN_CLASSES_FOLDER, AbstractMvcPsiNodeDescriptor.DOMAIN_CLASSES_FOLDER) { - @Override - protected AbstractTreeNode createClassNode(final GrTypeDefinition typeDefinition) { - return new DomainClassNode(getModule(), typeDefinition, getSettings()); + + // process well-known artifact paths + for (VirtualFile file : ModuleRootManager.getInstance(module).getSourceRoots()) { + PsiDirectory sourceRoot = PsiManager.getInstance(project).findDirectory(file); + if (sourceRoot != null) { + if ("griffon-app".equals(file.getParent().getName())) { + GriffonDirectoryMetadata metadata = DIRECTORY_METADATA.get(file.getName()); + if (metadata == null) continue; + result.add(new TopLevelDirectoryNode(module, sourceRoot, viewSettings, metadata.description, metadata.icon, metadata.weight)); } - }); - } - - final PsiDirectory conf = findDirectory(project, root, "griffon-app/conf"); - if (conf != null) { - result.add(new TopLevelDirectoryNode(module, conf, viewSettings, "Configuration", MvcIcons.CONFIG_FOLDER, AbstractMvcPsiNodeDescriptor.CONFIG_FOLDER)); - } - - final PsiDirectory controllers = findDirectory(project, root, "griffon-app/controllers"); - if (controllers != null) { - result.add(new TopLevelDirectoryNode(module, controllers, viewSettings, "Controllers", MvcIcons.CONTROLLERS_FOLDER, AbstractMvcPsiNodeDescriptor.CONTROLLERS_FOLDER)); - } - - final PsiDirectory services = findDirectory(project, root, "griffon-app/services"); - if (services != null) { - result.add(new TopLevelDirectoryNode(module, services, viewSettings, "Services", MvcIcons.SERVICE, AbstractMvcPsiNodeDescriptor.SERVICES_FOLDER)); - } - - final PsiDirectory views = findDirectory(project, root, "griffon-app/views"); - if (views != null) { - result.add(new TopLevelDirectoryNode(module, views, viewSettings, "Views", GroovyIcons.GROOVY_ICON_16x16, AbstractMvcPsiNodeDescriptor.VIEWS_FOLDER)); + } } + // add standard source folder final PsiDirectory srcMain = findDirectory(project, root, "src/main"); if (srcMain != null) { - result.add(new TopLevelDirectoryNode(module, srcMain, viewSettings, "Project Sources", GroovyIcons.GROOVY_ICON_16x16, AbstractMvcPsiNodeDescriptor.SRC_FOLDERS)); + result.add(new TopLevelDirectoryNode(module, srcMain, viewSettings, "Project Sources", GroovyIcons.GROOVY_ICON_16x16, + AbstractMvcPsiNodeDescriptor.SRC_FOLDERS)); + } + final PsiDirectory srcCli = findDirectory(project, root, "src/cli"); + if (srcCli != null) { + result.add(new TopLevelDirectoryNode(module, srcCli, viewSettings, "Build Sources", GroovyIcons.GROOVY_ICON_16x16, + AbstractMvcPsiNodeDescriptor.SRC_FOLDERS)); } + // add standard test sources final PsiDirectory testsUnit = findDirectory(project, root, "test/unit"); if (testsUnit != null) { - result.add(new TestsTopLevelDirectoryNode(module, testsUnit, viewSettings, "Unit Tests", PlatformIcons.TEST_SOURCE_FOLDER, - PlatformIcons.TEST_SOURCE_FOLDER)); + result.add( + new TestsTopLevelDirectoryNode(module, testsUnit, viewSettings, "Unit Tests", Icons.TEST_SOURCE_FOLDER, Icons.TEST_SOURCE_FOLDER)); } - final PsiDirectory testsIntegration = findDirectory(project, root, "test/integration"); if (testsIntegration != null) { - result.add(new TestsTopLevelDirectoryNode(module, testsIntegration, viewSettings, "Integration Tests", PlatformIcons.TEST_SOURCE_FOLDER, - PlatformIcons.TEST_SOURCE_FOLDER)); + result.add(new TestsTopLevelDirectoryNode(module, testsIntegration, viewSettings, "Integration Tests", Icons.TEST_SOURCE_FOLDER, + Icons.TEST_SOURCE_FOLDER)); + } + final PsiDirectory testsShared = findDirectory(project, root, "test/shared"); + if (testsShared != null) { + result.add(new TestsTopLevelDirectoryNode(module, testsShared, viewSettings, "Shared Test Sources", Icons.TEST_SOURCE_FOLDER, + Icons.TEST_SOURCE_FOLDER)); + } + + // add additional sources provided by plugins + for (VirtualFile file : ModuleRootManager.getInstance(module).getContentRoots()) { + List sources = GriffonSourceInspector.processModuleMetadata(module); + for (GriffonSourceInspector.GriffonSource source : sources) { + final PsiDirectory dir = findDirectory(project, file, source.getPath()); + if (dir != null) { + result.add( + new TopLevelDirectoryNode(module, dir, viewSettings, source.getNavigation().getDescription(), source.getNavigation().getIcon(), + source.getNavigation().getWeight())); + } + } + } + + final VirtualFile applicationPropertiesFile = GriffonFramework.getInstance().getApplicationPropertiesFile(module); + if (applicationPropertiesFile != null) { + PsiFile appProperties = PsiManager.getInstance(module.getProject()).findFile(applicationPropertiesFile); + if (appProperties != null) { + result.add(new FileNode(module, appProperties, null, viewSettings)); + } } } @@ -95,5 +115,30 @@ public class GriffonToolWindowFactory extends MvcToolWindowDescriptor { return GriffonFramework.GRIFFON_ICON; } + private static final Map DIRECTORY_METADATA = new LinkedHashMap(); + static { + DIRECTORY_METADATA.put("models", new GriffonDirectoryMetadata("Models", loadIcon("folder-models"), 20)); + DIRECTORY_METADATA.put("views", new GriffonDirectoryMetadata("Views", loadIcon("folder-views"), 30)); + DIRECTORY_METADATA.put("controllers", new GriffonDirectoryMetadata("Controllers", loadIcon("folder-controllers"), 40)); + DIRECTORY_METADATA.put("services", new GriffonDirectoryMetadata("Services", loadIcon("folder-services"), 50)); + DIRECTORY_METADATA.put("lifecycle", new GriffonDirectoryMetadata("Lifecycle", loadIcon("folder-lifecycle"), 60)); + DIRECTORY_METADATA.put("conf", new GriffonDirectoryMetadata("Configuration", loadIcon("folder-conf"), 65)); + } + + private static Icon loadIcon(String name) { + return IconLoader.getIcon("/icons/griffon/" + name + ".png"); + } + + private static class GriffonDirectoryMetadata { + public final String description; + public final Icon icon; + public final int weight; + + public GriffonDirectoryMetadata(String description, Icon icon, int weight) { + this.description = description; + this.icon = icon; + this.weight = weight; + } + } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java index 5af78e09db0f..83e7f3b66509 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcFramework.java @@ -504,10 +504,16 @@ public abstract class MvcFramework { final File grailsWorkDir = getSdkWorkDir(module); if (grailsWorkDir == null) return null; + final String applicationName = getApplicationName(module); + if (applicationName == null) return null; + + return new File(grailsWorkDir, "projects/" + applicationName + "/plugins"); + } + + public String getApplicationName(Module module) { final VirtualFile root = findAppRoot(module); if (root == null) return null; - - return new File(grailsWorkDir, "projects/" + root.getName() + "/plugins"); + return root.getName(); } protected abstract String getCommonPluginSuffix(); diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcProjectStructure.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcProjectStructure.java index 362ff85dc872..7a5ac5781bf1 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcProjectStructure.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/MvcProjectStructure.java @@ -32,23 +32,22 @@ public abstract class MvcProjectStructure { protected final Module myModule; private final boolean myAuxModule; private final String myUserHomeSdkRoot; - private final String mySdkWorkDir; + private final String mySdkWorkDirPath; public MvcProjectStructure(Module module, boolean auxModule, String userHomeSdkRoot, final File sdkWorkDir) { myAuxModule = auxModule; myModule = module; myUserHomeSdkRoot = userHomeSdkRoot; final VirtualFile sdkWorkDirVFile = MvcModuleStructureUtil.refreshAndFind(sdkWorkDir); - mySdkWorkDir = sdkWorkDirVFile == null ? "" : sdkWorkDirVFile.getPath() + "/"; + mySdkWorkDirPath = sdkWorkDirVFile == null ? "" : sdkWorkDirVFile.getPath() + "/"; } - public boolean isValidContentRoot(@NotNull VirtualFile file) { if (file.getPath().startsWith(myUserHomeSdkRoot)) { if (!myAuxModule) { return false; } - if (!file.getPath().startsWith(mySdkWorkDir)) { + if (!file.getPath().startsWith(mySdkWorkDirPath)) { return false; } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/TopLevelDirectoryNode.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/TopLevelDirectoryNode.java index 407303011dc7..571beead4c35 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/TopLevelDirectoryNode.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/mvc/projectView/TopLevelDirectoryNode.java @@ -18,6 +18,7 @@ package org.jetbrains.plugins.groovy.mvc.projectView; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.projectView.PresentationData; import com.intellij.openapi.module.Module; +import com.intellij.openapi.util.Comparing; import com.intellij.psi.PsiDirectory; import org.jetbrains.annotations.NotNull; @@ -41,6 +42,11 @@ public class TopLevelDirectoryNode extends AbstractFolderNode { myIcon = icon; } + @Override + public boolean equals(Object object) { + return super.equals(object) && Comparing.equal(myTitle, ((TopLevelDirectoryNode) object).myTitle); + } + @Override protected void updateImpl(PresentationData data) { data.setPresentableText(myTitle);