diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelper.java index d76e3a3ab08c..b21482025706 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/importing/GradleLocalNodeImportHelper.java @@ -4,11 +4,10 @@ import com.intellij.openapi.module.Module; import com.intellij.openapi.roots.LibraryOrderEntry; import com.intellij.openapi.roots.ModuleOrderEntry; import com.intellij.openapi.roots.libraries.Library; -import com.intellij.openapi.util.Ref; import com.intellij.util.containers.Stack; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.config.GradleTextAttributes; -import org.jetbrains.plugins.gradle.model.*; +import org.jetbrains.plugins.gradle.model.GradleEntityType; import org.jetbrains.plugins.gradle.model.gradle.*; import org.jetbrains.plugins.gradle.model.id.GradleEntityId; import org.jetbrains.plugins.gradle.model.id.GradleEntityIdMapper; @@ -38,6 +37,8 @@ import java.util.*; * * * + *

+ * Thread-safe. * * @author Denis Zhdanov * @since 2/10/12 11:51 AM @@ -86,72 +87,14 @@ public class GradleLocalNodeImportHelper { */ @NotNull public List deriveEntitiesToImport(@NotNull Iterable> nodes) { - EntitiesToImport toImport = new EntitiesToImport(); + Context context = new Context(); for (GradleProjectStructureNode node : nodes) { - collectEntitiesToImport(node, toImport); + collectEntitiesToImport(node, context); } - return toImport.getAll(); + return context.getAll(); } - private void collectEntitiesToImport(@NotNull GradleProjectStructureNode node, @NotNull final EntitiesToImport toImport) { - final Ref recursive = new Ref(false); - final GradleEntityVisitor visitor = new GradleEntityVisitorAdapter() { - @Override - public void visit(@NotNull GradleModule module) { - final Module intellijModule = myProjectStructureHelper.findIntellijModule(module); - if (intellijModule != null) { - // Already imported - return; - } - toImport.modules.add(module); - if (!recursive.get()) { - return; - } - for (GradleDependency dependency : module.getDependencies()) { - dependency.invite(this); - } - } - - @Override - public void visit(@NotNull GradleModuleDependency dependency) { - final ModuleOrderEntry intellijModuleDependency = myProjectStructureHelper.findIntellijModuleDependency(dependency); - if (intellijModuleDependency != null) { - // Already imported. - return; - } - toImport.dependencies.add(dependency); - final GradleModule gradleModule = dependency.getTarget(); - final Module intellijModule = myProjectStructureHelper.findIntellijModule(gradleModule); - if (intellijModule != null) { - return; - } - boolean r = recursive.get(); - recursive.set(true); - try { - gradleModule.invite(this); - } - finally { - recursive.set(r); - } - } - - @Override - public void visit(@NotNull GradleLibraryDependency dependency) { - final LibraryOrderEntry intellijDependency - = myProjectStructureHelper.findIntellijLibraryDependency(dependency.getOwnerModule().getName(), dependency.getName()); - if (intellijDependency != null) { - // Already imported. - return; - } - toImport.dependencies.add(dependency); - final GradleLibrary gradleLibrary = dependency.getTarget(); - final Library intellijLibrary = myProjectStructureHelper.findIntellijLibrary(gradleLibrary); - if (intellijLibrary == null) { - toImport.libraries.add(gradleLibrary); - } - } - }; - + private void collectEntitiesToImport(@NotNull GradleProjectStructureNode node, @NotNull Context context) { // Collect up. for (GradleProjectStructureNode n = node.getParent(); n != null; n = n.getParent()) { final GradleProjectStructureNodeDescriptor descriptor = n.getDescriptor(); @@ -165,7 +108,7 @@ public class GradleLocalNodeImportHelper { if (id instanceof GradleEntityId) { final Object entity = myIdMapper.mapIdToEntity((GradleEntityId)id); if (entity instanceof GradleEntity) { - ((GradleEntity)entity).invite(visitor); + ((GradleEntity)entity).invite(context.visitor); } } } @@ -180,15 +123,67 @@ public class GradleLocalNodeImportHelper { } } - recursive.set(true); + context.recursive = true; while (!toProcess.isEmpty()) { final GradleEntity entity = toProcess.pop(); - entity.invite(visitor); + entity.invite(context.visitor); + } + } + + private void collectModuleEntities(@NotNull GradleModule module, @NotNull Context context) { + final Module intellijModule = myProjectStructureHelper.findIntellijModule(module); + if (intellijModule != null) { + // Already imported + return; + } + context.modules.add(module); + if (!context.recursive) { + return; + } + for (GradleDependency dependency : module.getDependencies()) { + dependency.invite(context.visitor); + } + } + + private void collectModuleDependencyEntities(@NotNull GradleModuleDependency dependency, @NotNull Context context) { + final ModuleOrderEntry intellijModuleDependency = myProjectStructureHelper.findIntellijModuleDependency(dependency); + if (intellijModuleDependency != null) { + // Already imported. + return; + } + context.dependencies.add(dependency); + final GradleModule gradleModule = dependency.getTarget(); + final Module intellijModule = myProjectStructureHelper.findIntellijModule(gradleModule); + if (intellijModule != null) { + return; + } + boolean r = context.recursive; + context.recursive = true; + try { + gradleModule.invite(context.visitor); + } + finally { + context.recursive = r; + } + } + + private void collectLibraryDependencyEntities(@NotNull GradleLibraryDependency dependency, @NotNull Context context) { + final LibraryOrderEntry intellijDependency + = myProjectStructureHelper.findIntellijLibraryDependency(dependency.getOwnerModule().getName(), dependency.getName()); + if (intellijDependency != null) { + // Already imported. + return; + } + context.dependencies.add(dependency); + final GradleLibrary gradleLibrary = dependency.getTarget(); + final Library intellijLibrary = myProjectStructureHelper.findIntellijLibrary(gradleLibrary); + if (intellijLibrary == null) { + context.libraries.add(gradleLibrary); } } /** - * Imports given 'gradle-local' entities to the current intellij projcet. + * Imports given 'gradle-local' entities to the current intellij project. * * @param entities target 'gradle-local' entities to import */ @@ -239,11 +234,14 @@ public class GradleLocalNodeImportHelper { } } - private static class EntitiesToImport { - + private class Context { + public final Set modules = new HashSet(); public final Set libraries = new HashSet(); public final Set dependencies = new HashSet(); + public final CollectingVisitor visitor = new CollectingVisitor(this); + + public boolean recursive; @NotNull public List getAll() { @@ -254,4 +252,22 @@ public class GradleLocalNodeImportHelper { return result; } } + + private class CollectingVisitor implements GradleEntityVisitor { + @NotNull private final Context myContext; + + CollectingVisitor(@NotNull Context context) { + myContext = context; + } + + @Override public void visit(@NotNull GradleProject project) { } + @Override public void visit(@NotNull GradleModule module) { collectModuleEntities(module, myContext); } + @Override + public void visit(@NotNull GradleContentRoot contentRoot) { + // TODO den implement + } + @Override public void visit(@NotNull GradleLibrary library) { /* Assuming that a library may be imported only as a dependency */ } + @Override public void visit(@NotNull GradleModuleDependency dependency) { collectModuleDependencyEntities(dependency, myContext); } + @Override public void visit(@NotNull GradleLibraryDependency dependency) { collectLibraryDependencyEntities(dependency, myContext); } + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java index 9c789bdbd309..431c5083497d 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -51,9 +51,11 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { private final Map> myModules = new HashMap>(); - private final TreeNode[] myNodeHolder = new TreeNode[1]; - private final int[] myIndexHolder = new int[1]; - private final NodeListener myNodeListener = new NodeListener(); + private final TreeNode[] myNodeHolder = new TreeNode[1]; + private final int[] myIndexHolder = new int[1]; + private final NodeListener myNodeListener = new NodeListener(); + private final ObsoleteChangesDispatcher myObsoleteChangesDispatcher = new ObsoleteChangesDispatcher(); + private final NewChangesDispatcher myNewChangesDispatcher = new NewChangesDispatcher(); @NotNull private final Project myProject; @NotNull private final PlatformFacade myPlatformFacade; @@ -169,62 +171,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { */ public void update(@NotNull Collection changes) { for (GradleProjectStructureChange change : changes) { - change.invite(new GradleProjectStructureChangeVisitorAdapter() { - @Override - public void visit(@NotNull GradleMismatchedLibraryPathChange change) { - for (GradleProjectStructureNode holder : myModuleDependencies.values()) { - for (GradleProjectStructureNode dependencyNode : holder.getChildren(GradleLibraryDependencyId.class)) { - final GradleLibraryDependencyId id = dependencyNode.getDescriptor().getElement(); - if (change.getLibraryName().equals(id.getLibraryName())) { - dependencyNode.addConflictChange(change); - break; - } - } - } - } - - @Override - public void visit(@NotNull GradleModulePresenceChange change) { - final GradleModuleId id; - final TextAttributesKey key; - if (change.getGradleEntity() == null) { - id = change.getIntellijEntity(); - key = GradleTextAttributes.INTELLIJ_LOCAL_CHANGE; - } - else { - id = change.getGradleEntity(); - key = GradleTextAttributes.GRADLE_LOCAL_CHANGE; - } - assert id != null; - final GradleProjectStructureNode moduleNode = getModuleNode(id); - moduleNode.getDescriptor().setAttributes(key); - nodeChanged(moduleNode); - } - - @Override - public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { - GradleLibraryDependencyId id = change.getGradleEntity(); - TextAttributesKey attributes = GradleTextAttributes.GRADLE_LOCAL_CHANGE; - if (id == null) { - id = change.getIntellijEntity(); - attributes = GradleTextAttributes.INTELLIJ_LOCAL_CHANGE; - } - assert id != null; - final GradleProjectStructureNode dependenciesNode = getDependenciesNode(id.getModuleId()); - for (GradleProjectStructureNode node : dependenciesNode.getChildren(GradleLibraryDependencyId.class)) { - GradleProjectStructureNodeDescriptor d = node.getDescriptor(); - if (id.equals(d.getElement())) { - d.setAttributes(attributes); - nodeStructureChanged(node); - return; - } - } - GradleProjectStructureNode newNode = buildNode(id, id.getLibraryName(), GradleIcons.LIB_ICON); - newNode.getDescriptor().setAttributes(attributes); - dependenciesNode.add(newNode); - nodeStructureChanged(dependenciesNode); - } - }); + change.invite(myNewChangesDispatcher); } } @@ -243,84 +190,139 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { */ public void processObsoleteChanges(Collection changes) { for (GradleProjectStructureChange change : changes) { - change.invite(new GradleProjectStructureChangeVisitor() { - @Override - public void visit(@NotNull GradleMismatchedLibraryPathChange change) { - for (GradleProjectStructureNode holder : myModuleDependencies.values()) { - for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { - final GradleLibraryDependencyId id = node.getDescriptor().getElement(); - if (id.getLibraryName().equals(change.getLibraryName())) { - node.removeConflictChange(change); - nodeChanged(node); - break; - } - } - } - } + change.invite(myObsoleteChangesDispatcher); + } + } - @Override - public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { - // We need to remove the corresponding node then. - GradleLibraryDependencyId id = change.getGradleEntity(); - boolean removeNode; - if (id == null) { - id = change.getIntellijEntity(); - assert id != null; - removeNode = !myProjectStructureHelper.isIntellijLibraryDependencyExist(id); - } - else { - removeNode = !myProjectStructureHelper.isGradleLibraryDependencyExist(id); - } - final GradleProjectStructureNode holder = myModuleDependencies.get(id.getModuleName()); - if (holder == null) { - return; - } - - // There are two possible cases why 'local library dependency' change is obsolete: - // 1. Corresponding dependency has been added at the counterparty; - // 2. The 'local dependency' has been removed; - // We should distinguish between those situations because we need to mark the node as 'synced' at one case and - // completely removed at another one. - - for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { - GradleProjectStructureNodeDescriptor descriptor = node.getDescriptor(); - if (!id.equals(descriptor.getElement())) { - continue; - } - if (removeNode) { - holder.remove(node); - } - else { - descriptor.setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); - holder.correctChildPositionIfNecessary(node); - } - return; - } - } + private void processNewProjectRenameChange(@NotNull GradleProjectRenameChange change) { + // TODO den implement + } - @Override - public void visit(@NotNull GradleProjectRenameChange change) { - // TODO den implement - } + private void processNewLanguageLevelChange(@NotNull GradleLanguageLevelChange change) { + // TODO den implement + } - @Override - public void visit(@NotNull GradleLanguageLevelChange change) { - // TODO den implement + private void processNewMismatchedLibraryPathChange(@NotNull GradleMismatchedLibraryPathChange change) { + for (GradleProjectStructureNode holder : myModuleDependencies.values()) { + for (GradleProjectStructureNode dependencyNode : holder.getChildren(GradleLibraryDependencyId.class)) { + final GradleLibraryDependencyId id = dependencyNode.getDescriptor().getElement(); + if (change.getLibraryName().equals(id.getLibraryName())) { + dependencyNode.addConflictChange(change); + break; } + } + } + } - @Override - public void visit(@NotNull GradleModulePresenceChange change) { - GradleModuleId id = change.getGradleEntity(); - if (id == null) { - id = change.getIntellijEntity(); - } - assert id != null; - final GradleProjectStructureNode moduleNode = myModules.get(id.getModuleName()); - if (moduleNode != null) { - moduleNode.getDescriptor().setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); - } + private void processNewLibraryDependencyPresenceChange(@NotNull GradleLibraryDependencyPresenceChange change) { + GradleLibraryDependencyId id = change.getGradleEntity(); + TextAttributesKey attributes = GradleTextAttributes.GRADLE_LOCAL_CHANGE; + if (id == null) { + id = change.getIntellijEntity(); + attributes = GradleTextAttributes.INTELLIJ_LOCAL_CHANGE; + } + assert id != null; + final GradleProjectStructureNode dependenciesNode = getDependenciesNode(id.getModuleId()); + for (GradleProjectStructureNode node : dependenciesNode.getChildren(GradleLibraryDependencyId.class)) { + GradleProjectStructureNodeDescriptor d = node.getDescriptor(); + if (id.equals(d.getElement())) { + d.setAttributes(attributes); + nodeStructureChanged(node); + return; + } + } + GradleProjectStructureNode newNode = buildNode(id, id.getLibraryName(), GradleIcons.LIB_ICON); + newNode.getDescriptor().setAttributes(attributes); + dependenciesNode.add(newNode); + nodeStructureChanged(dependenciesNode); + } + + private void processNewModulePresenceChange(@NotNull GradleModulePresenceChange change) { + final GradleModuleId id; + final TextAttributesKey key; + if (change.getGradleEntity() == null) { + id = change.getIntellijEntity(); + key = GradleTextAttributes.INTELLIJ_LOCAL_CHANGE; + } + else { + id = change.getGradleEntity(); + key = GradleTextAttributes.GRADLE_LOCAL_CHANGE; + } + assert id != null; + final GradleProjectStructureNode moduleNode = getModuleNode(id); + moduleNode.getDescriptor().setAttributes(key); + nodeChanged(moduleNode); + } + + private void processObsoleteProjectRenameChange(@NotNull GradleProjectRenameChange change) { + // TODO den implement + } + + private void processObsoleteLanguageLevelChange(@NotNull GradleLanguageLevelChange change) { + // TODO den implement + } + + private void processObsoleteMismatchedLibraryPathChange(@NotNull GradleMismatchedLibraryPathChange change) { + for (GradleProjectStructureNode holder : myModuleDependencies.values()) { + for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { + final GradleLibraryDependencyId id = node.getDescriptor().getElement(); + if (id.getLibraryName().equals(change.getLibraryName())) { + node.removeConflictChange(change); + nodeChanged(node); + break; } - }); + } + } + } + + private void processObsoleteLibraryDependencyPresenceChange(@NotNull GradleLibraryDependencyPresenceChange change) { + // We need to remove the corresponding node then. + GradleLibraryDependencyId id = change.getGradleEntity(); + boolean removeNode; + if (id == null) { + id = change.getIntellijEntity(); + assert id != null; + removeNode = !myProjectStructureHelper.isIntellijLibraryDependencyExist(id); + } + else { + removeNode = !myProjectStructureHelper.isGradleLibraryDependencyExist(id); + } + final GradleProjectStructureNode holder = myModuleDependencies.get(id.getModuleName()); + if (holder == null) { + return; + } + + // There are two possible cases why 'local library dependency' change is obsolete: + // 1. Corresponding dependency has been added at the counterparty; + // 2. The 'local dependency' has been removed; + // We should distinguish between those situations because we need to mark the node as 'synced' at one case and + // completely removed at another one. + + for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { + GradleProjectStructureNodeDescriptor descriptor = node.getDescriptor(); + if (!id.equals(descriptor.getElement())) { + continue; + } + if (removeNode) { + holder.remove(node); + } + else { + descriptor.setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); + holder.correctChildPositionIfNecessary(node); + } + return; + } + } + + private void processObsoleteModulePresenceChange(@NotNull GradleModulePresenceChange change) { + GradleModuleId id = change.getGradleEntity(); + if (id == null) { + id = change.getIntellijEntity(); + } + assert id != null; + final GradleProjectStructureNode moduleNode = myModules.get(id.getModuleName()); + if (moduleNode != null) { + moduleNode.getDescriptor().setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); } } @@ -339,4 +341,22 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { nodesWereRemoved(node.getParent(), myIndexHolder, myNodeHolder); } } + + private class NewChangesDispatcher implements GradleProjectStructureChangeVisitor { + @Override public void visit(@NotNull GradleProjectRenameChange change) { processNewProjectRenameChange(change); } + @Override public void visit(@NotNull GradleLanguageLevelChange change) { processNewLanguageLevelChange(change); } + @Override public void visit(@NotNull GradleModulePresenceChange change) { processNewModulePresenceChange(change); } + @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { processNewLibraryDependencyPresenceChange(change); } + @Override public void visit(@NotNull GradleMismatchedLibraryPathChange change) { processNewMismatchedLibraryPathChange(change); } + } + + private class ObsoleteChangesDispatcher implements GradleProjectStructureChangeVisitor { + @Override public void visit(@NotNull GradleProjectRenameChange change) { processObsoleteProjectRenameChange(change); } + @Override public void visit(@NotNull GradleLanguageLevelChange change) { processObsoleteLanguageLevelChange(change); } + @Override public void visit(@NotNull GradleModulePresenceChange change) { processObsoleteModulePresenceChange(change); } + @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { + processObsoleteLibraryDependencyPresenceChange(change); + } + @Override public void visit(@NotNull GradleMismatchedLibraryPathChange change) { processObsoleteMismatchedLibraryPathChange(change); } + } }