diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java index 5c6977b2ae36..e982b0022e79 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java @@ -15,8 +15,7 @@ public abstract class GradleAbstractDependencyStructureChangesCalculator { @Override - public void calculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context) - { + public void calculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context) { // TODO den process common dependency properties here. doCalculate(gradleEntity, intellijEntity, context); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java index 75a9e5c25a06..b21feae7cbcf 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesPanel.java @@ -49,8 +49,8 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel { UIUtil.invokeLaterIfNeeded(new Runnable() { @Override public void run() { - myTreeModel.update(currentChanges); myTreeModel.processObsoleteChanges(ContainerUtil.subtract(oldChanges, currentChanges)); + myTreeModel.processCurrentChanges(currentChanges); } }); } 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 848cd3317863..7deb8d5e3f8f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -160,7 +160,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { * * @param changes collections that contains all changes between the current gradle and intellij project structures */ - public void update(@NotNull Collection changes) { + public void processCurrentChanges(@NotNull Collection changes) { for (GradleProjectStructureChange change : changes) { change.invite(myNewChangesDispatcher); } @@ -353,7 +353,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { moduleNode.removeFromParent(); } else { - moduleNode.getDescriptor().setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); + moduleNode.setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); } } @@ -387,7 +387,6 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { @Override public void visit(@NotNull GradleModulePresenceChange change) { processNewModulePresenceChange(change); } @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { processNewLibraryDependencyPresenceChange(change); } @Override public void visit(@NotNull GradleModuleDependencyPresenceChange change) { processNewModuleDependencyPresenceChange(change); } - @Override public void visit(@NotNull GradleMismatchedLibraryPathChange change) { processNewMismatchedLibraryPathChange(change); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java index aadfc3359366..c1068610d2b4 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java @@ -103,17 +103,18 @@ public class GradleProjectStructureNode extends Defaul * Does nothing if given node is not a child of the current node. * * @param child target child node + * @return true if child position was changed; false otherwise */ - public void correctChildPositionIfNecessary(@NotNull GradleProjectStructureNode child) { + public boolean correctChildPositionIfNecessary(@NotNull GradleProjectStructureNode child) { int currentPosition = -1; - int desiredPosition = getChildCount(); + int desiredPosition = -1; for (int i = 0; i < getChildCount(); i++) { GradleProjectStructureNode node = getChildAt(i); if (node == child) { currentPosition = i; continue; } - if (NODE_COMPARATOR.compare(child, node) <= 0) { + if (desiredPosition < 0 && NODE_COMPARATOR.compare(child, node) <= 0) { desiredPosition = i; if (currentPosition >= 0) { break; @@ -122,16 +123,20 @@ public class GradleProjectStructureNode extends Defaul } if (currentPosition < 0) { // Given node is not a child of the current node. - return; + return false; + } + if (desiredPosition < 0) { + desiredPosition = getChildCount(); } if (currentPosition < desiredPosition) { desiredPosition--; } if (currentPosition == desiredPosition) { - return; + return false; } remove(currentPosition); insert(child, desiredPosition); + return true; } /** @@ -231,7 +236,15 @@ public class GradleProjectStructureNode extends Defaul public void setAttributes(@NotNull TextAttributesKey key) { myDescriptor.setAttributes(key); - onNodeChanged(this); + final GradleProjectStructureNode parent = getParent(); + if (parent == null) { + onNodeChanged(this); + return; + } + boolean positionChanged = parent.correctChildPositionIfNecessary(this); + if (!positionChanged) { + onNodeChanged(this); + } } public void addListener(@NotNull Listener listener) { diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy index 274e539f7fe8..4f94296362ef 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy @@ -34,7 +34,10 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { module { dependencies { library("lib1") - } } } } + } } } }, + changesSorter: { a, b -> + b.gradleEntity.dependencyName.compareTo(a.gradleEntity.dependencyName) + } ) // Check that the initial projects state is correctly parsed. @@ -214,12 +217,13 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } } checkTree { project { - module1() module2('gradle') { dependencies { lib1('gradle') lib2('gradle') - } } } } + } } + module1() + } } } @Test @@ -241,8 +245,8 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } } checkTree { project { - module1() module2('gradle') + module1() } } // Emulate import gradle module to intellij. @@ -294,13 +298,13 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } } checkTree { project { - module1() { - dependencies { - lib1('conflict') - } } module2('gradle') { dependencies { lib1('gradle') // This is the point of the test. We don't expect to see 'conflict' here. + } } + module1() { + dependencies { + lib1('conflict') } } } } } @@ -480,4 +484,71 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { module2('intellij') } } } } } + + @Test + public void "mismatched library path is highlighted after importing local library dependency"() { + init( + gradle: { + project { + module('module1') { + dependencies { + library('lib1', bin: ['1']) + } } + module('module2') { + dependencies { + library('lib1') + } } } }, + intellij: { + project { + module('module1') { + dependencies { + library('lib1', bin: ['2']) + } } } } + ) + checkChanges { + presence { + module(gradle: gradle.modules['module2']) + libraryDependency(gradle: gradle.libraryDependencies[gradle.modules['module2']]) + } + libraryConflict(entity: intellij.libraries['lib1']) { + binaryPath(gradle: '1', intellij: ['2']) + } } + checkTree { + project { + module2('gradle') { + dependencies { + lib1('gradle') + } } + module1 { + dependencies { + lib1('conflict') + } } } } + + // Emulate importing missing module and library dependencies. Expecting to see the newly imported library dependency node + // highlighted as 'conflict' now. + setState(intellij: { + project { + module('module1') { + dependencies { + library('lib1', bin: ['2']) + } } + module('module2') { + dependencies { + library('lib1') + } } } }) + checkChanges { + libraryConflict(entity: intellij.libraries['lib1']) { + binaryPath(gradle: '1', intellij: ['2']) + } } + checkTree { + project { + module1 { + dependencies { + lib1('conflict') + } } + module2() { + dependencies { + lib1('conflict') + } } } } + } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy index 07a2475e8e86..d97f7288a24e 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy @@ -59,8 +59,8 @@ public abstract class AbstractGradleTest { protected def init(map = [:]) { treeModel = container.getComponentInstance(GradleProjectStructureTreeModel) as GradleProjectStructureTreeModel changesModel.addListener({ old, current -> - treeModel.update(sortChanges(current)) treeModel.processObsoleteChanges(sortChanges(ContainerUtil.subtract(old, current))); + treeModel.processCurrentChanges(sortChanges(current)) } as GradleProjectStructureChangeListener) setState(map, false) treeModel.rebuild()