mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-76142: Gradle support - cannot update IDEA projects once one of build.gradle files changes
1. Changes infrastructure is re-written in order to not hold references to the changed entities (Module, LibraryOrderEntry etc). Reason: their hash code may be changed on state change (e.g. new binary file registered for the library changes its hash code); 2. Added support for showing conflict nodes at the gradle project structure tree; 3. Corresponding tests have been added;
This commit is contained in:
@@ -54,6 +54,11 @@ gradle.sync.change.type.intellij={0} local setting
|
||||
gradle.sync.change.type.conflict=Settings conflict
|
||||
gradle.sync.change.type.unchanged=Unchanged setting
|
||||
gradle.sync.change.type.confirmed=Confirmed settings diff
|
||||
gradle.sync.change.entity.type.module=module
|
||||
gradle.sync.change.entity.type.library.dependency=library dependency
|
||||
gradle.sync.change.library.path=library ''{0}'' binary path
|
||||
gradle.sync.change.project.name.text=project name
|
||||
gradle.sync.change.project.language.level.text=project language level change
|
||||
|
||||
gradle.library.resolve.progress.text=Resolving gradle libraries
|
||||
|
||||
|
||||
@@ -39,9 +39,10 @@
|
||||
<applicationService serviceInterface="org.jetbrains.plugins.gradle.diff.GradleStructureChangesCalculator"
|
||||
serviceImplementation="org.jetbrains.plugins.gradle.diff.GradleProjectStructureChangesCalculator"/>
|
||||
<applicationService serviceImplementation="org.jetbrains.plugins.gradle.diff.GradleModuleStructureChangesCalculator"/>
|
||||
<applicationService serviceImplementation="org.jetbrains.plugins.gradle.diff.GradleLibraryStructureChangesCalculator"/>
|
||||
<applicationService serviceImplementation="org.jetbrains.plugins.gradle.diff.GradleLibraryDependencyStructureChangesCalculator"/>
|
||||
<applicationService serviceInterface="org.jetbrains.plugins.gradle.diff.PlatformFacade"
|
||||
serviceImplementation="org.jetbrains.plugins.gradle.diff.GradleProjectStructureHelperImpl"/>
|
||||
serviceImplementation="org.jetbrains.plugins.gradle.diff.PlatformFacadeImpl"/>
|
||||
<applicationService serviceInterface="org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManager"
|
||||
serviceImplementation="org.jetbrains.plugins.gradle.notification.GradleProgressNotificationManagerImpl"/>
|
||||
|
||||
@@ -62,6 +63,9 @@
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel</implementation-class>
|
||||
</component>
|
||||
<component>
|
||||
<implementation-class>org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper</implementation-class>
|
||||
</component>
|
||||
</project-components>
|
||||
|
||||
<actions>
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.diff.PlatformFacade;
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel;
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesPanel;
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleIcons;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
@@ -24,15 +25,18 @@ import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
public class GradleBootstrap extends AbstractProjectComponent {
|
||||
|
||||
private static final String GRADLE_TOOL_WINDOW_ID = GradleBundle.message("gradle.name");
|
||||
|
||||
|
||||
private final GradleProjectStructureChangesModel myChangesModel;
|
||||
private final PlatformFacade myProjectStructureHelper;
|
||||
private final PlatformFacade myPlatformFacade;
|
||||
private final GradleProjectStructureHelper myProjectStructureHelper;
|
||||
|
||||
public GradleBootstrap(@NotNull Project project,
|
||||
@NotNull GradleProjectStructureChangesModel changesModel,
|
||||
@NotNull PlatformFacade projectStructureHelper) {
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
@NotNull GradleProjectStructureHelper projectStructureHelper) {
|
||||
super(project);
|
||||
myChangesModel = changesModel;
|
||||
myPlatformFacade = platformFacade;
|
||||
myProjectStructureHelper = projectStructureHelper;
|
||||
}
|
||||
|
||||
@@ -52,7 +56,7 @@ public class GradleBootstrap extends AbstractProjectComponent {
|
||||
toolWindow.setIcon(GradleIcons.GRADLE_ICON);
|
||||
String syncTitle = GradleBundle.message("gradle.sync.title.tab");
|
||||
final GradleProjectStructureChangesPanel projectStructureChanges
|
||||
= new GradleProjectStructureChangesPanel(myProject, myChangesModel, myProjectStructureHelper);
|
||||
= new GradleProjectStructureChangesPanel(myProject, myChangesModel, myPlatformFacade, myProjectStructureHelper);
|
||||
toolWindow.getContentManager().addContent(new ContentImpl(projectStructureChanges, syncTitle, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.intellij.util.messages.MessageBusConnection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.diff.PlatformFacade;
|
||||
import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
import org.jetbrains.plugins.gradle.ui.RichTextControlBuilder;
|
||||
|
||||
@@ -43,14 +44,17 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel {
|
||||
private final JPanel myContent = new JPanel(myLayout);
|
||||
|
||||
private final Project myProject;
|
||||
private final PlatformFacade myProjectStructureHelper;
|
||||
private final PlatformFacade myProjectFacade;
|
||||
private final GradleProjectStructureHelper myProjectStructureHelper;
|
||||
|
||||
protected GradleToolWindowPanel(@NotNull Project project,
|
||||
@Nullable PlatformFacade projectStructureHelper,
|
||||
@Nullable PlatformFacade projectFacade,
|
||||
@NotNull GradleProjectStructureHelper projectStructureHelper,
|
||||
@NotNull String place)
|
||||
{
|
||||
super(true);
|
||||
myProject = project;
|
||||
myProjectFacade = projectFacade;
|
||||
myProjectStructureHelper = projectStructureHelper;
|
||||
final ActionManager actionManager = ActionManager.getInstance();
|
||||
final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(TOOL_WINDOW_TOOLBAR_ID);
|
||||
@@ -98,7 +102,12 @@ public abstract class GradleToolWindowPanel extends SimpleToolWindowPanel {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PlatformFacade getProjectStructureHelper() {
|
||||
public PlatformFacade getProjectFacade() {
|
||||
return myProjectFacade;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GradleProjectStructureHelper getProjectStructureHelper() {
|
||||
return myProjectStructureHelper;
|
||||
}
|
||||
|
||||
|
||||
+17
-12
@@ -19,19 +19,25 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Defines contract for change that points to particular property value change.
|
||||
* Defines general contract for a change that encapsulates information about conflicting property value of the matched gradle
|
||||
* and intellij entities.
|
||||
* <p/>
|
||||
* For example we may match particular gradle library to an intellij library but they may have different set of attached binaries.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 11/15/11 7:57 PM
|
||||
* @param <T> target property value type
|
||||
*/
|
||||
public abstract class GradleAbstractPropertyValueChange<T> extends GradleAbstractProjectStructureChange {
|
||||
public abstract class GradleAbstractConflictingPropertyChange<T> extends GradleAbstractProjectStructureChange {
|
||||
|
||||
private final String myPropertyDescription;
|
||||
private final T myGradleValue;
|
||||
private final T myIntellijValue;
|
||||
|
||||
private final String myProperyName;
|
||||
private final T myGradleValue;
|
||||
private final T myIntellijValue;
|
||||
|
||||
public GradleAbstractPropertyValueChange(@NotNull String propertyName, @Nullable T gradleValue, @Nullable T intellijValue) {
|
||||
myProperyName = propertyName;
|
||||
public GradleAbstractConflictingPropertyChange(@NotNull String propertyDescription, @Nullable T gradleValue, @Nullable T intellijValue) {
|
||||
myPropertyDescription = propertyDescription;
|
||||
myGradleValue = gradleValue;
|
||||
myIntellijValue = intellijValue;
|
||||
}
|
||||
@@ -56,7 +62,7 @@ public abstract class GradleAbstractPropertyValueChange<T> extends GradleAbstrac
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + (myGradleValue != null ? myGradleValue.hashCode() : 0);
|
||||
return 31 * result + (myIntellijValue != null ? myIntellijValue.hashCode() : 0);
|
||||
return 31 * result + (myIntellijValue != null ? myIntellijValue.hashCode() : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,16 +71,15 @@ public abstract class GradleAbstractPropertyValueChange<T> extends GradleAbstrac
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
if (!super.equals(o)) return false;
|
||||
|
||||
GradleAbstractPropertyValueChange that = (GradleAbstractPropertyValueChange)o;
|
||||
GradleAbstractConflictingPropertyChange that = (GradleAbstractConflictingPropertyChange)o;
|
||||
|
||||
if (myGradleValue != null ? !myGradleValue.equals(that.myGradleValue) : that.myGradleValue != null) return false;
|
||||
if (myIntellijValue != null ? !myIntellijValue.equals(that.myIntellijValue) : that.myIntellijValue != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s change: gradle='%s', intellij='%s'", myProperyName, myGradleValue, myIntellijValue);
|
||||
return String.format("%s change: gradle='%s', intellij='%s'", myPropertyDescription, myGradleValue, myIntellijValue);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ public class GradleDiffUtil {
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleModule module) {
|
||||
currentChanges.add(new GradleModulePresenceChange(module, null));
|
||||
currentChanges.add(new GradleModulePresenceChange(module.getName(), null));
|
||||
for (GradleDependency dependency : module.getDependencies()) {
|
||||
dependency.invite(this);
|
||||
}
|
||||
@@ -68,11 +68,14 @@ public class GradleDiffUtil {
|
||||
/**
|
||||
* Analogues to {@link #buildLocalChanges} but targets intellij entity.
|
||||
*
|
||||
* @param gradleProject gradle project which structure is being compared to the intellij one
|
||||
* @param module target intellij-local module that doesn't present at the gradle side
|
||||
* @param currentChanges holder for the changes built during the current call
|
||||
*/
|
||||
public static void buildLocalChanges(@NotNull Module module, @NotNull Set<GradleProjectStructureChange> currentChanges) {
|
||||
currentChanges.add(new GradleModulePresenceChange(null, module));
|
||||
public static void buildLocalChanges(@NotNull Module module,
|
||||
@NotNull Set<GradleProjectStructureChange> currentChanges)
|
||||
{
|
||||
currentChanges.add(new GradleModulePresenceChange(null, module.getName()));
|
||||
// TODO den process module sub-entities here (content roots and dependencies).
|
||||
}
|
||||
|
||||
@@ -85,18 +88,20 @@ public class GradleDiffUtil {
|
||||
public static void buildLocalChanges(@NotNull LibraryOrderEntry libraryDependency,
|
||||
@NotNull Set<GradleProjectStructureChange> currentChanges)
|
||||
{
|
||||
currentChanges.add(new GradleLibraryDependencyPresenceChange(null, libraryDependency));
|
||||
final String libraryName = libraryDependency.getLibraryName();
|
||||
if (libraryName != null) {
|
||||
currentChanges.add(new GradleLibraryDependencyPresenceChange(null, libraryDependency));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs argument type-based dispatch and delegates to one of strongly typed <code>'buildLocalChanges()'</code> methods.
|
||||
*
|
||||
* @param gradleProject gradle project which structure is being compared to the intellij one
|
||||
* @param entity target intellij-local entity that doesn't present at the gradle side
|
||||
* @param currentChanges holder for the changes built during the current call
|
||||
*/
|
||||
public static void buildLocalChanges(@NotNull Object entity,
|
||||
@NotNull Set<GradleProjectStructureChange> currentChanges)
|
||||
{
|
||||
public static void buildLocalChanges(@NotNull Object entity, @NotNull Set<GradleProjectStructureChange> currentChanges) {
|
||||
if (entity instanceof GradleEntity) {
|
||||
buildLocalChanges((GradleEntity)entity, currentChanges);
|
||||
}
|
||||
|
||||
+15
-9
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.gradle.diff;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -22,13 +23,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 11/17/11 12:43 PM
|
||||
* @param <G> entity type at Gradle side
|
||||
* @param <I> entity type at IntelliJ IDEA side
|
||||
* @param <T> entity type
|
||||
*/
|
||||
public abstract class GradleEntityPresenceChange<G, I> extends GradleAbstractProjectStructureChange {
|
||||
public abstract class GradleEntityPresenceChange<T> extends GradleAbstractProjectStructureChange {
|
||||
|
||||
private final G myGradleEntity;
|
||||
private final I myIntellijEntity;
|
||||
private final T myGradleEntity;
|
||||
private final T myIntellijEntity;
|
||||
private final String myEntityName;
|
||||
|
||||
/**
|
||||
* Creates new <code>GradleEntityPresenceChange</code> project.
|
||||
@@ -40,7 +41,11 @@ public abstract class GradleEntityPresenceChange<G, I> extends GradleAbstractPro
|
||||
* @throws IllegalArgumentException if both of the given entities are defined or undefined. Expecting this constructor to be
|
||||
* called with one <code>null</code> argument and one non-<code>null</code> argument
|
||||
*/
|
||||
public GradleEntityPresenceChange(@Nullable G gradleEntity, @Nullable I intellijEntity) throws IllegalArgumentException {
|
||||
public GradleEntityPresenceChange(@NotNull String entityName,
|
||||
@Nullable T gradleEntity,
|
||||
@Nullable T intellijEntity)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if (!(gradleEntity == null ^ intellijEntity == null)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Can't construct %s object. Reason: expected that only gradle or intellij entity is null, actual: gradle='%s'; intellij='%s'",
|
||||
@@ -49,15 +54,16 @@ public abstract class GradleEntityPresenceChange<G, I> extends GradleAbstractPro
|
||||
}
|
||||
myGradleEntity = gradleEntity;
|
||||
myIntellijEntity = intellijEntity;
|
||||
myEntityName = entityName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public G getGradleEntity() {
|
||||
public T getGradleEntity() {
|
||||
return myGradleEntity;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public I getIntellijEntity() {
|
||||
public T getIntellijEntity() {
|
||||
return myIntellijEntity;
|
||||
}
|
||||
|
||||
@@ -83,6 +89,6 @@ public abstract class GradleEntityPresenceChange<G, I> extends GradleAbstractPro
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("entity presence change: gradle='%s', intellij='%s'", myGradleEntity, myIntellijEntity);
|
||||
return String.format("%s presence change: gradle='%s', intellij='%s'", myEntityName, myGradleEntity, myIntellijEntity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,16 @@ package org.jetbrains.plugins.gradle.diff;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 11/15/11 8:05 PM
|
||||
*/
|
||||
public class GradleLanguageLevelChange extends GradleAbstractPropertyValueChange<LanguageLevel> {
|
||||
|
||||
public class GradleLanguageLevelChange extends GradleAbstractConflictingPropertyChange<LanguageLevel> {
|
||||
|
||||
public GradleLanguageLevelChange(@Nullable LanguageLevel gradleValue, @Nullable LanguageLevel intellijValue) {
|
||||
super("project language level", gradleValue, intellijValue);
|
||||
super(GradleBundle.message("gradle.sync.change.project.language.level.text"), gradleValue, intellijValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-4
@@ -4,17 +4,21 @@ import com.intellij.openapi.roots.LibraryOrderEntry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.model.GradleLibraryDependency;
|
||||
import org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
import static org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId.of;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 1/24/12 9:48 AM
|
||||
*/
|
||||
public class GradleLibraryDependencyPresenceChange extends GradleEntityPresenceChange<GradleLibraryDependency, LibraryOrderEntry> {
|
||||
public class GradleLibraryDependencyPresenceChange extends GradleEntityPresenceChange<GradleLibraryDependencyId> {
|
||||
|
||||
public GradleLibraryDependencyPresenceChange(@Nullable GradleLibraryDependency gradleEntity, @Nullable LibraryOrderEntry intellijEntity)
|
||||
throws IllegalArgumentException
|
||||
public GradleLibraryDependencyPresenceChange(@Nullable GradleLibraryDependency gradleDependency,
|
||||
@Nullable LibraryOrderEntry intellijDependency) throws IllegalArgumentException
|
||||
{
|
||||
super(gradleEntity, intellijEntity);
|
||||
super(GradleBundle.message("gradle.sync.change.entity.type.library.dependency"), of(gradleDependency), of(intellijDependency));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+13
-3
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.plugins.gradle.diff;
|
||||
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.model.GradleLibraryDependency;
|
||||
|
||||
@@ -13,6 +14,12 @@ import java.util.Set;
|
||||
public class GradleLibraryDependencyStructureChangesCalculator
|
||||
implements GradleStructureChangesCalculator<GradleLibraryDependency, LibraryOrderEntry>
|
||||
{
|
||||
|
||||
private final GradleLibraryStructureChangesCalculator myLibraryCalculator;
|
||||
|
||||
public GradleLibraryDependencyStructureChangesCalculator(@NotNull GradleLibraryStructureChangesCalculator libraryCalculator) {
|
||||
myLibraryCalculator = libraryCalculator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(@NotNull GradleLibraryDependency gradleEntity,
|
||||
@@ -20,7 +27,11 @@ public class GradleLibraryDependencyStructureChangesCalculator
|
||||
@NotNull Set<GradleProjectStructureChange> knownChanges,
|
||||
@NotNull Set<GradleProjectStructureChange> currentChanges)
|
||||
{
|
||||
// TODO den implement
|
||||
final Library library = intellijEntity.getLibrary();
|
||||
if (library == null) {
|
||||
return;
|
||||
}
|
||||
myLibraryCalculator.calculate(gradleEntity.getTarget(), library, knownChanges, currentChanges);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -33,7 +44,6 @@ public class GradleLibraryDependencyStructureChangesCalculator
|
||||
@NotNull
|
||||
@Override
|
||||
public Object getGradleKey(@NotNull GradleLibraryDependency entity, @NotNull Set<GradleProjectStructureChange> knownChanges) {
|
||||
// TODO den consider the known changes
|
||||
return entity.getName();
|
||||
return myLibraryCalculator.getGradleKey(entity.getTarget(), knownChanges);
|
||||
}
|
||||
}
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package org.jetbrains.plugins.gradle.diff;
|
||||
|
||||
import com.intellij.openapi.roots.OrderRootType;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.model.GradleLibrary;
|
||||
import org.jetbrains.plugins.gradle.model.LibraryPathType;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/3/12 11:17 AM
|
||||
*/
|
||||
public class GradleLibraryStructureChangesCalculator implements GradleStructureChangesCalculator<GradleLibrary, Library> {
|
||||
|
||||
private final PlatformFacade myPlatformFacade;
|
||||
|
||||
public GradleLibraryStructureChangesCalculator(@NotNull PlatformFacade platformFacade) {
|
||||
myPlatformFacade = platformFacade;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void calculate(@NotNull GradleLibrary gradleEntity,
|
||||
@NotNull Library intellijEntity,
|
||||
@NotNull Set<GradleProjectStructureChange> knownChanges,
|
||||
@NotNull Set<GradleProjectStructureChange> currentChanges)
|
||||
{
|
||||
final Set<String> gradleBinaryPaths = new HashSet<String>(gradleEntity.getPaths(LibraryPathType.BINARY));
|
||||
for (VirtualFile file : intellijEntity.getFiles(OrderRootType.CLASSES)) {
|
||||
final String path = myPlatformFacade.getLocalFileSystemPath(file);
|
||||
if (!gradleBinaryPaths.remove(path)) {
|
||||
currentChanges.add(new GradleMismatchedLibraryPathChange(intellijEntity, null, path));
|
||||
}
|
||||
}
|
||||
|
||||
for (String binaryPath : gradleBinaryPaths) {
|
||||
currentChanges.add(new GradleMismatchedLibraryPathChange(intellijEntity, binaryPath, null));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object getIntellijKey(@NotNull Library entity) {
|
||||
return entity.getName();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Object getGradleKey(@NotNull GradleLibrary entity, @NotNull Set<GradleProjectStructureChange> knownChanges) {
|
||||
// TODO den consider the known changes
|
||||
return entity.getName();
|
||||
}
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package org.jetbrains.plugins.gradle.diff;
|
||||
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/2/12 1:32 PM
|
||||
*/
|
||||
public class GradleMismatchedLibraryPathChange extends GradleAbstractConflictingPropertyChange<String> {
|
||||
|
||||
private final String myLibraryName;
|
||||
|
||||
public GradleMismatchedLibraryPathChange(@NotNull Library entity,
|
||||
@Nullable String gradleValue,
|
||||
@Nullable String intellijValue)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
super(GradleBundle.message("gradle.sync.change.library.path", entity.getName()), gradleValue, intellijValue);
|
||||
myLibraryName = entity.getName();
|
||||
if (myLibraryName == null) {
|
||||
throw new IllegalArgumentException(String.format("Can't create %s instance. Reason: given library has no name (%s)",
|
||||
getClass().getName(), entity));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getLibraryName() {
|
||||
return myLibraryName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invite(@NotNull GradleProjectStructureChangeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + myLibraryName.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
GradleMismatchedLibraryPathChange that = (GradleMismatchedLibraryPathChange)o;
|
||||
return myLibraryName.equals(that.myLibraryName);
|
||||
}
|
||||
}
|
||||
+6
-5
@@ -15,19 +15,20 @@
|
||||
*/
|
||||
package org.jetbrains.plugins.gradle.diff;
|
||||
|
||||
import com.intellij.openapi.module.Module;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.model.GradleModule;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 11/17/11 12:50 PM
|
||||
*/
|
||||
public class GradleModulePresenceChange extends GradleEntityPresenceChange<GradleModule, Module> {
|
||||
public class GradleModulePresenceChange extends GradleEntityPresenceChange<String> {
|
||||
|
||||
public GradleModulePresenceChange(@Nullable GradleModule gradleEntity, @Nullable Module intellijEntity) throws IllegalArgumentException {
|
||||
super(gradleEntity, intellijEntity);
|
||||
public GradleModulePresenceChange(@Nullable String gradleModuleName, @Nullable String intellijModuleName)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
super(GradleBundle.message("gradle.sync.change.entity.type.module"), gradleModuleName, intellijModuleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jetbrains.plugins.gradle.diff;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
/**
|
||||
* Describes project name change.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 11/3/11 3:54 PM
|
||||
*/
|
||||
public class GradleProjectRenameChange extends GradleAbstractConflictingPropertyChange<String> {
|
||||
|
||||
public GradleProjectRenameChange(@NotNull String gradleName, @NotNull String intellijName) {
|
||||
super(GradleBundle.message("gradle.sync.change.project.name.text"), gradleName, intellijName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invite(@NotNull GradleProjectStructureChangeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -24,8 +24,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
* @since 11/16/11 8:48 PM
|
||||
*/
|
||||
public interface GradleProjectStructureChangeVisitor {
|
||||
void visit(@NotNull GradleRenameChange change);
|
||||
void visit(@NotNull GradleProjectStructureChange change);
|
||||
void visit(@NotNull GradleProjectRenameChange change);
|
||||
void visit(@NotNull GradleLanguageLevelChange change);
|
||||
void visit(@NotNull GradleModulePresenceChange change);
|
||||
void visit(@NotNull GradleLibraryDependencyPresenceChange change);
|
||||
void visit(@NotNull GradleMismatchedLibraryPathChange change);
|
||||
}
|
||||
|
||||
+6
-2
@@ -24,11 +24,11 @@ import org.jetbrains.annotations.NotNull;
|
||||
public class GradleProjectStructureChangeVisitorAdapter implements GradleProjectStructureChangeVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleRenameChange change) {
|
||||
public void visit(@NotNull GradleProjectRenameChange change) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleProjectStructureChange change) {
|
||||
public void visit(@NotNull GradleLanguageLevelChange change) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -38,4 +38,8 @@ public class GradleProjectStructureChangeVisitorAdapter implements GradleProject
|
||||
@Override
|
||||
public void visit(@NotNull GradleLibraryDependencyPresenceChange change) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleMismatchedLibraryPathChange change) {
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -70,13 +70,13 @@ public class GradleProjectStructureChangesCalculator implements GradleStructureC
|
||||
String gradleName = gradleProject.getName();
|
||||
String intellijName = intellijProject.getName();
|
||||
if (!gradleName.equals(intellijName)) {
|
||||
currentChanges.add(new GradleRenameChange(GradleRenameChange.Entity.PROJECT, gradleName, intellijName));
|
||||
currentChanges.add(new GradleProjectRenameChange(gradleName, intellijName));
|
||||
}
|
||||
}
|
||||
|
||||
private void checkLanguageLevel(@NotNull GradleProject gradleProject,
|
||||
@NotNull Project intellijProject,
|
||||
@NotNull Set<GradleProjectStructureChange> currentChanges)
|
||||
@NotNull Project intellijProject,
|
||||
@NotNull Set<GradleProjectStructureChange> currentChanges)
|
||||
{
|
||||
LanguageLevel gradleLevel = gradleProject.getLanguageLevel();
|
||||
LanguageLevel intellijLevel = myStructureHelper.getLanguageLevel(intellijProject);
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package org.jetbrains.plugins.gradle.diff;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Describes particular entity name change.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 11/3/11 3:54 PM
|
||||
*/
|
||||
public class GradleRenameChange extends GradleAbstractPropertyValueChange<String> {
|
||||
|
||||
public enum Entity { PROJECT, MODULE, LIBRARY }
|
||||
|
||||
private final Entity myEntity;
|
||||
|
||||
public GradleRenameChange(@NotNull Entity entity, @NotNull String gradleName, @NotNull String intellijName) {
|
||||
super(entity.toString().toLowerCase(), gradleName, intellijName);
|
||||
myEntity = entity;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Entity getEntity() {
|
||||
return myEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * super.hashCode() + myEntity.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GradleRenameChange that = (GradleRenameChange)o;
|
||||
return myEntity.equals(that.myEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invite(@NotNull GradleProjectStructureChangeVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package org.jetbrains.plugins.gradle.diff;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.OrderEntry;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -41,4 +42,16 @@ public interface PlatformFacade {
|
||||
*/
|
||||
@NotNull
|
||||
Icon getProjectIcon();
|
||||
|
||||
/**
|
||||
* Allows to derive from the given VFS file path that may be compared to the path used by the gradle api.
|
||||
* <p/>
|
||||
* Generally, this method is necessary for processing binary library paths - they point to jar files and VFS uses
|
||||
* <code>'!'</code> marks in their paths internally.
|
||||
*
|
||||
* @param file target file
|
||||
* @return given file's path that may be compared to the one used by the gradle api
|
||||
*/
|
||||
@NotNull
|
||||
String getLocalFileSystemPath(@NotNull VirtualFile file);
|
||||
}
|
||||
|
||||
+16
-1
@@ -1,6 +1,7 @@
|
||||
package org.jetbrains.plugins.gradle.diff;
|
||||
|
||||
import com.intellij.openapi.application.ex.ApplicationInfoEx;
|
||||
import com.intellij.openapi.fileTypes.FileTypes;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
@@ -8,6 +9,8 @@ import com.intellij.openapi.roots.LanguageLevelProjectExtension;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
import com.intellij.openapi.roots.OrderEntry;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.vfs.JarFileSystem;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -19,7 +22,7 @@ import java.util.Collection;
|
||||
* @author Denis Zhdanov
|
||||
* @since 1/26/12 11:54 AM
|
||||
*/
|
||||
public class GradleProjectStructureHelperImpl implements PlatformFacade {
|
||||
public class PlatformFacadeImpl implements PlatformFacade {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -44,4 +47,16 @@ public class GradleProjectStructureHelperImpl implements PlatformFacade {
|
||||
public Icon getProjectIcon() {
|
||||
return IconLoader.getIcon(ApplicationInfoEx.getInstanceEx().getSmallIconUrl());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getLocalFileSystemPath(@NotNull VirtualFile file) {
|
||||
if (file.getFileType() == FileTypes.ARCHIVE) {
|
||||
final VirtualFile jar = JarFileSystem.getInstance().getVirtualFileForJar(file);
|
||||
if (jar != null) {
|
||||
return jar.getPath();
|
||||
}
|
||||
}
|
||||
return file.getPath();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -260,7 +260,7 @@ public class GradleAdjustImportSettingsStep extends AbstractImportFromGradleWiza
|
||||
// We build tree node, its settings control and map them altogether. The only trick here is that nodes can reuse the same
|
||||
// settings control (e.g. more than one node may have the same library as a dependency, so, library dependency node for
|
||||
// every control will use the same settings control).
|
||||
GradleProjectStructureNode result = new GradleProjectStructureNode(myFactory.buildDescriptor(entity));
|
||||
GradleProjectStructureNode<T> result = new GradleProjectStructureNode<T>(myFactory.buildDescriptor(entity));
|
||||
Pair<String, Collection<GradleProjectStructureNode>> pair = processed.get(entity);
|
||||
if (pair == null) {
|
||||
String cardName = String.valueOf(counter);
|
||||
|
||||
+4
-4
@@ -30,9 +30,9 @@ public class GradleProjectStructureFactory {
|
||||
/** Shared instance of the current (stateless) class. */
|
||||
public static final GradleProjectStructureFactory INSTANCE = new GradleProjectStructureFactory();
|
||||
|
||||
@SuppressWarnings("MethodMayBeStatic")
|
||||
@SuppressWarnings({"MethodMayBeStatic", "unchecked"})
|
||||
@NotNull
|
||||
public <T extends GradleEntity> GradleProjectStructureNodeDescriptor buildDescriptor(@NotNull T entity) {
|
||||
public <T extends GradleEntity> GradleProjectStructureNodeDescriptor<T> buildDescriptor(@NotNull T entity) {
|
||||
final Ref<GradleProjectStructureNodeDescriptor<GradleEntity>> result = new Ref<GradleProjectStructureNodeDescriptor<GradleEntity>>();
|
||||
entity.invite(new GradleEntityVisitor() {
|
||||
@Override
|
||||
@@ -70,7 +70,7 @@ public class GradleProjectStructureFactory {
|
||||
visit(dependency.getTarget());
|
||||
}
|
||||
});
|
||||
return result.get();
|
||||
return (GradleProjectStructureNodeDescriptor<T>)result.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("MethodMayBeStatic")
|
||||
@@ -138,7 +138,7 @@ public class GradleProjectStructureFactory {
|
||||
return;
|
||||
}
|
||||
for (GradleProjectStructureNode node : treeNodes) {
|
||||
node.getDescriptor().setName(evt.getNewValue().toString());
|
||||
node.getDescriptor().setText(evt.getNewValue().toString());
|
||||
model.nodeChanged(node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,10 @@ public class GradleLibrary extends AbstractNamedGradleEntity implements Named {
|
||||
paths.add(GradleUtil.toCanonicalPath(path));
|
||||
}
|
||||
|
||||
public void forgetAllPaths() {
|
||||
myPaths.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invite(@NotNull GradleEntityVisitor visitor) {
|
||||
visitor.visit(this);
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package org.jetbrains.plugins.gradle.model;
|
||||
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* This class serves as an id for any library dependency. We can't use library object itself because its hashCode()/equals() may
|
||||
* be changed over time (e.g. source root is added).
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/6/12 12:09 PM
|
||||
*/
|
||||
public class GradleLibraryDependencyId {
|
||||
|
||||
private final String myLibraryName;
|
||||
private final String myModuleName;
|
||||
|
||||
public GradleLibraryDependencyId(@NotNull String libraryName, @NotNull String moduleName) {
|
||||
myLibraryName = libraryName;
|
||||
myModuleName = moduleName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GradleLibraryDependencyId of(@Nullable GradleLibraryDependency dependency) {
|
||||
return dependency == null ? null : new GradleLibraryDependencyId(dependency.getName(), dependency.getOwnerModule().getName());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static GradleLibraryDependencyId of(@Nullable LibraryOrderEntry dependency) {
|
||||
if (dependency == null) {
|
||||
return null;
|
||||
}
|
||||
final String libraryName = dependency.getLibraryName();
|
||||
if (libraryName == null || StringUtil.isEmpty(libraryName)) {
|
||||
return null;
|
||||
}
|
||||
return new GradleLibraryDependencyId(libraryName, dependency.getOwnerModule().getName());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getLibraryName() {
|
||||
return myLibraryName;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getModuleName() {
|
||||
return myModuleName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myLibraryName.hashCode();
|
||||
result = 31 * result + myModuleName.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
GradleLibraryDependencyId id = (GradleLibraryDependencyId)o;
|
||||
|
||||
if (!myLibraryName.equals(id.myLibraryName)) return false;
|
||||
if (!myModuleName.equals(id.myModuleName)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("library dependency: library='%s', module='%s'", myLibraryName, myModuleName);
|
||||
}
|
||||
}
|
||||
+14
-2
@@ -3,6 +3,7 @@ package org.jetbrains.plugins.gradle.sync;
|
||||
import com.intellij.openapi.components.AbstractProjectComponent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange;
|
||||
import org.jetbrains.plugins.gradle.diff.GradleStructureChangesCalculator;
|
||||
import org.jetbrains.plugins.gradle.model.GradleProject;
|
||||
@@ -13,7 +14,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* // TODO den add doc
|
||||
* Manages information about the changes between the gradle and intellij project structures.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
@@ -25,7 +26,9 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent
|
||||
private final Set<GradleProjectStructureChangeListener> myListeners = new CopyOnWriteArraySet<GradleProjectStructureChangeListener>();
|
||||
private final AtomicReference<Set<GradleProjectStructureChange>> myChanges
|
||||
= new AtomicReference<Set<GradleProjectStructureChange>>(new HashSet<GradleProjectStructureChange>());
|
||||
|
||||
|
||||
private final AtomicReference<GradleProject> myGradleProject = new AtomicReference<GradleProject>();
|
||||
|
||||
private final GradleStructureChangesCalculator<GradleProject, Project> myChangesCalculator;
|
||||
|
||||
public GradleProjectStructureChangesModel(@NotNull Project project,
|
||||
@@ -54,6 +57,7 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent
|
||||
* @param gradleProject gradle project to sync with
|
||||
*/
|
||||
public void update(@NotNull GradleProject gradleProject) {
|
||||
myGradleProject.set(gradleProject);
|
||||
Set<GradleProjectStructureChange> knownChanges = new HashSet<GradleProjectStructureChange>(myChanges.get());
|
||||
Set<GradleProjectStructureChange> currentChanges = new HashSet<GradleProjectStructureChange>();
|
||||
myChangesCalculator.calculate(gradleProject, myProject, knownChanges, currentChanges);
|
||||
@@ -66,6 +70,14 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return last known gradle project state
|
||||
*/
|
||||
@Nullable
|
||||
public GradleProject getGradleProject() {
|
||||
return myGradleProject.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers given listener within the current model.
|
||||
*
|
||||
|
||||
+5
-4
@@ -29,9 +29,10 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
|
||||
public GradleProjectStructureChangesPanel(@NotNull Project project,
|
||||
@NotNull GradleProjectStructureChangesModel model,
|
||||
@NotNull PlatformFacade projectStructureHelper)
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
@NotNull GradleProjectStructureHelper projectStructureHelper)
|
||||
{
|
||||
super(project, projectStructureHelper, GradleConstants.TOOL_WINDOW_TOOLBAR_PLACE);
|
||||
super(project, platformFacade, projectStructureHelper, GradleConstants.TOOL_WINDOW_TOOLBAR_PLACE);
|
||||
model.addListener(new GradleProjectStructureChangeListener() {
|
||||
@Override
|
||||
public void onChanges(@NotNull final Collection<GradleProjectStructureChange> oldChanges,
|
||||
@@ -41,7 +42,7 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
@Override
|
||||
public void run() {
|
||||
myTreeModel.update(currentChanges);
|
||||
myTreeModel.pruneObsoleteNodes(ContainerUtil.subtract(oldChanges, currentChanges));
|
||||
myTreeModel.processObsoleteChanges(ContainerUtil.subtract(oldChanges, currentChanges));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -50,7 +51,7 @@ public class GradleProjectStructureChangesPanel extends GradleToolWindowPanel {
|
||||
|
||||
private void init() {
|
||||
myContent = new JPanel(new GridBagLayout());
|
||||
myTreeModel = new GradleProjectStructureTreeModel(getProject(), getProjectStructureHelper());
|
||||
myTreeModel = new GradleProjectStructureTreeModel(getProject(), getProjectFacade(), getProjectStructureHelper());
|
||||
Tree tree = new Tree(myTreeModel);
|
||||
applyInitialAppearance(tree, (DefaultMutableTreeNode)myTreeModel.getRoot());
|
||||
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
package org.jetbrains.plugins.gradle.sync;
|
||||
|
||||
import com.intellij.openapi.components.AbstractProjectComponent;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry;
|
||||
import com.intellij.openapi.roots.OrderEntry;
|
||||
import com.intellij.openapi.roots.RootPolicy;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.diff.PlatformFacade;
|
||||
import org.jetbrains.plugins.gradle.model.*;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 2/6/12 3:28 PM
|
||||
*/
|
||||
public class GradleProjectStructureHelper extends AbstractProjectComponent {
|
||||
|
||||
private final GradleProjectStructureChangesModel myModel;
|
||||
private final PlatformFacade myFacade;
|
||||
|
||||
public GradleProjectStructureHelper(@NotNull Project project,
|
||||
@NotNull GradleProjectStructureChangesModel model,
|
||||
@NotNull PlatformFacade facade)
|
||||
{
|
||||
super(project);
|
||||
myModel = model;
|
||||
myFacade = facade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to answer if target library dependency is still available at the target project.
|
||||
*
|
||||
* @param id target library id
|
||||
* @return <code>true</code> if target library dependency is still available at the target project;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean isIntellijLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) {
|
||||
for (Module module : myFacade.getModules(myProject)) {
|
||||
if (!id.getModuleName().equals(module.getName())) {
|
||||
continue;
|
||||
}
|
||||
RootPolicy<Boolean> visitor = new RootPolicy<Boolean>() {
|
||||
@Override
|
||||
public Boolean visitLibraryOrderEntry(LibraryOrderEntry libraryOrderEntry, Boolean value) {
|
||||
return id.getLibraryName().equals(libraryOrderEntry.getLibraryName());
|
||||
}
|
||||
};
|
||||
for (OrderEntry entry : myFacade.getOrderEntries(module)) {
|
||||
if (entry.accept(visitor, false)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to answer if target library dependency is still available at the target project.
|
||||
*
|
||||
* @param id target library id
|
||||
* @return <code>true</code> if target library dependency is still available at the target project;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean isGradleLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) {
|
||||
final GradleProject project = myModel.getGradleProject();
|
||||
if (project == null) {
|
||||
return false;
|
||||
}
|
||||
final Ref<Boolean> matched = new Ref<Boolean>();
|
||||
GradleEntityVisitor visitor = new GradleEntityVisitorAdapter() {
|
||||
@Override
|
||||
public void visit(@NotNull GradleLibraryDependency dependency) {
|
||||
matched.set(id.getLibraryName().equals(dependency.getName()));
|
||||
}
|
||||
};
|
||||
for (GradleModule module : project.getModules()) {
|
||||
if (!id.getModuleName().equals(module.getName())) {
|
||||
continue;
|
||||
}
|
||||
for (GradleDependency dependency : module.getDependencies()) {
|
||||
dependency.invite(visitor);
|
||||
if (matched.get()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+107
-123
@@ -1,26 +1,23 @@
|
||||
package org.jetbrains.plugins.gradle.sync;
|
||||
|
||||
import com.intellij.openapi.editor.colors.TextAttributesKey;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.LibraryOrderEntry;
|
||||
import com.intellij.openapi.roots.OrderEntry;
|
||||
import com.intellij.openapi.roots.RootPolicy;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.hash.HashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.gradle.config.GradleTextAttributes;
|
||||
import org.jetbrains.plugins.gradle.diff.*;
|
||||
import org.jetbrains.plugins.gradle.model.GradleLibraryDependency;
|
||||
import org.jetbrains.plugins.gradle.model.Named;
|
||||
import org.jetbrains.plugins.gradle.model.GradleLibraryDependencyId;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleIcons;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNode;
|
||||
import org.jetbrains.plugins.gradle.ui.GradleProjectStructureNodeDescriptor;
|
||||
import org.jetbrains.plugins.gradle.util.GradleBundle;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -37,7 +34,9 @@ import java.util.Map;
|
||||
*/
|
||||
public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
|
||||
public static final GradleProjectStructureNodeDescriptor<Object> DEPENDENCIES_NODE_DESCRIPTOR = buildDescriptor(
|
||||
public static final GradleProjectStructureNodeDescriptor<String> DEPENDENCIES_NODE_DESCRIPTOR
|
||||
= new GradleProjectStructureNodeDescriptor<String>(
|
||||
GradleBundle.message("gradle.project.structure.tree.node.dependencies"),
|
||||
GradleBundle.message("gradle.project.structure.tree.node.dependencies"),
|
||||
null
|
||||
);
|
||||
@@ -52,27 +51,33 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
* |_dependency2
|
||||
* </pre>
|
||||
*/
|
||||
private final Map<String, DefaultMutableTreeNode> myModuleDependencies = new HashMap<String, DefaultMutableTreeNode>();
|
||||
private final Map<String, DefaultMutableTreeNode> myModules = new HashMap<String, DefaultMutableTreeNode>();
|
||||
private final Map<String, GradleProjectStructureNode<String>> myModuleDependencies
|
||||
= new HashMap<String, GradleProjectStructureNode<String>>();
|
||||
private final Map<String, GradleProjectStructureNode<String>> myModules
|
||||
= new HashMap<String, GradleProjectStructureNode<String>>();
|
||||
|
||||
private final TreeNode[] myNodeHolder = new TreeNode[1];
|
||||
private final int[] myIndexHolder = new int[1];
|
||||
|
||||
private final Project myProject;
|
||||
private final PlatformFacade myPlatformFacade;
|
||||
private final Project myProject;
|
||||
private final PlatformFacade myPlatformFacade;
|
||||
private final GradleProjectStructureHelper myProjectStructureHelper;
|
||||
|
||||
public GradleProjectStructureTreeModel(@NotNull Project project, @NotNull PlatformFacade platformFacade) {
|
||||
public GradleProjectStructureTreeModel(@NotNull Project project,
|
||||
@NotNull PlatformFacade platformFacade,
|
||||
@NotNull GradleProjectStructureHelper projectStructureHelper) {
|
||||
super(null);
|
||||
myProject = project;
|
||||
myPlatformFacade = platformFacade;
|
||||
myProjectStructureHelper = projectStructureHelper;
|
||||
rebuild();
|
||||
}
|
||||
|
||||
public void rebuild() {
|
||||
myModuleDependencies.clear();
|
||||
myModules.clear();
|
||||
|
||||
DefaultMutableTreeNode root = new DefaultMutableTreeNode(buildDescriptor(getProject()));
|
||||
|
||||
GradleProjectStructureNode<Project> root = buildNode(getProject(), getProject().getName(), myPlatformFacade.getProjectIcon());
|
||||
final Collection<Module> modules = myPlatformFacade.getModules(getProject());
|
||||
RootPolicy<LibraryOrderEntry> policy = new RootPolicy<LibraryOrderEntry>() {
|
||||
@Override
|
||||
@@ -81,19 +86,21 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
}
|
||||
};
|
||||
for (Module module : modules) {
|
||||
final DefaultMutableTreeNode moduleNode = new DefaultMutableTreeNode(buildDescriptor(module));
|
||||
final GradleProjectStructureNode<String> moduleNode = buildNode(module.getName(), GradleIcons.MODULE_ICON);
|
||||
myModules.put(module.getName(), moduleNode); // Assuming that module names are unique.
|
||||
List<LibraryOrderEntry> libraryDependencies = new ArrayList<LibraryOrderEntry>();
|
||||
for (OrderEntry orderEntry : myPlatformFacade.getOrderEntries(module)) {
|
||||
final LibraryOrderEntry libraryDependency = orderEntry.accept(policy, null);
|
||||
if (libraryDependency != null && !StringUtil.isEmpty(libraryDependency.getLibraryName())) {
|
||||
libraryDependencies.add(libraryDependency);
|
||||
}
|
||||
libraryDependencies.add(libraryDependency);
|
||||
}
|
||||
if (!libraryDependencies.isEmpty()) {
|
||||
DefaultMutableTreeNode dependenciesNode = getDependenciesNode(module.getName());
|
||||
GradleProjectStructureNode<String> dependenciesNode = getDependenciesNode(module.getName());
|
||||
for (LibraryOrderEntry dependency : libraryDependencies) {
|
||||
dependenciesNode.add(new DefaultMutableTreeNode(buildDescriptor(dependency)));
|
||||
GradleLibraryDependencyId id = GradleLibraryDependencyId.of(dependency);
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
dependenciesNode.add(buildNode(id, id.getLibraryName(), GradleIcons.LIB_ICON));
|
||||
}
|
||||
moduleNode.add(dependenciesNode);
|
||||
}
|
||||
@@ -108,40 +115,30 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
return myProject;
|
||||
}
|
||||
|
||||
private static GradleProjectStructureNodeDescriptor<Object> buildDescriptor(@NotNull String name, @Nullable Icon icon) {
|
||||
return new GradleProjectStructureNodeDescriptor<Object>(new Object(), name, icon);
|
||||
private static <T> GradleProjectStructureNodeDescriptor<T> buildDescriptor(@NotNull T entity, @NotNull String name, @NotNull Icon icon) {
|
||||
return new GradleProjectStructureNodeDescriptor<T>(entity, name, icon);
|
||||
}
|
||||
|
||||
private static GradleProjectStructureNodeDescriptor<Named> buildDescriptor(@NotNull Named entity, @NotNull Icon icon) {
|
||||
return new GradleProjectStructureNodeDescriptor<Named>(entity, entity.getName(), icon);
|
||||
private static GradleProjectStructureNode<String> buildNode(@NotNull String name, @NotNull Icon icon) {
|
||||
return buildNode(name, name, icon);
|
||||
}
|
||||
|
||||
private GradleProjectStructureNodeDescriptor<Project> buildDescriptor(@NotNull Project project) {
|
||||
return new GradleProjectStructureNodeDescriptor<Project>(project, project.getName(), myPlatformFacade.getProjectIcon());
|
||||
private static <T> GradleProjectStructureNode<T> buildNode(@NotNull T entity, @NotNull String name, @NotNull Icon icon) {
|
||||
return new GradleProjectStructureNode<T>(buildDescriptor(entity, name, icon));
|
||||
}
|
||||
|
||||
private static GradleProjectStructureNodeDescriptor<Module> buildDescriptor(@NotNull Module module) {
|
||||
return new GradleProjectStructureNodeDescriptor<Module>(module, module.getName(), GradleIcons.MODULE_ICON);
|
||||
}
|
||||
|
||||
private static GradleProjectStructureNodeDescriptor<LibraryOrderEntry> buildDescriptor(@NotNull LibraryOrderEntry library) {
|
||||
final String name = library.getLibraryName();
|
||||
assert name != null;
|
||||
return new GradleProjectStructureNodeDescriptor<LibraryOrderEntry>(library, name, GradleIcons.LIB_ICON);
|
||||
}
|
||||
|
||||
private DefaultMutableTreeNode getDependenciesNode(@NotNull String moduleName) {
|
||||
final DefaultMutableTreeNode cached = myModuleDependencies.get(moduleName);
|
||||
|
||||
private GradleProjectStructureNode<String> getDependenciesNode(@NotNull String moduleName) {
|
||||
final GradleProjectStructureNode<String> cached = myModuleDependencies.get(moduleName);
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
DefaultMutableTreeNode moduleNode = myModules.get(moduleName);
|
||||
GradleProjectStructureNode<String> moduleNode = myModules.get(moduleName);
|
||||
if (moduleNode == null) {
|
||||
moduleNode = new DefaultMutableTreeNode(buildDescriptor(moduleName, GradleIcons.MODULE_ICON));
|
||||
moduleNode = buildNode(moduleName, GradleIcons.MODULE_ICON);
|
||||
myModules.put(moduleName, moduleNode);
|
||||
}
|
||||
|
||||
DefaultMutableTreeNode result = new DefaultMutableTreeNode(DEPENDENCIES_NODE_DESCRIPTOR);
|
||||
GradleProjectStructureNode<String> result = new GradleProjectStructureNode<String>(DEPENDENCIES_NODE_DESCRIPTOR);
|
||||
moduleNode.add(result);
|
||||
myModuleDependencies.put(moduleName, result);
|
||||
|
||||
@@ -155,62 +152,40 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
*/
|
||||
public void update(@NotNull Collection<GradleProjectStructureChange> changes) {
|
||||
for (GradleProjectStructureChange change : changes) {
|
||||
change.invite(new GradleProjectStructureChangeVisitor() {
|
||||
change.invite(new GradleProjectStructureChangeVisitorAdapter() {
|
||||
@Override
|
||||
public void visit(@NotNull GradleRenameChange change) {
|
||||
// TODO den implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleProjectStructureChange change) {
|
||||
// TODO den implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleModulePresenceChange change) {
|
||||
// TODO den implement
|
||||
public void visit(@NotNull GradleMismatchedLibraryPathChange change) {
|
||||
for (GradleProjectStructureNode<String> holder : myModuleDependencies.values()) {
|
||||
for (GradleProjectStructureNode<GradleLibraryDependencyId> 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 GradleLibraryDependencyPresenceChange change) {
|
||||
String moduleName;
|
||||
GradleProjectStructureNodeDescriptor<?> descriptor;
|
||||
final GradleLibraryDependency gradleEntity = change.getGradleEntity();
|
||||
final LibraryOrderEntry intellijEntity = change.getIntellijEntity();
|
||||
final Object missingEntity;
|
||||
if (gradleEntity == null && intellijEntity == null) {
|
||||
// Never expect to be here.
|
||||
assert false;
|
||||
GradleLibraryDependencyId id = change.getGradleEntity();
|
||||
TextAttributesKey attributes = GradleTextAttributes.GRADLE_LOCAL_CHANGE;
|
||||
if (id == null) {
|
||||
id = change.getIntellijEntity();
|
||||
attributes = GradleTextAttributes.INTELLIJ_LOCAL_CHANGE;
|
||||
}
|
||||
|
||||
if (gradleEntity == null) {
|
||||
// Particular library dependency is added at the intellij side.
|
||||
moduleName = intellijEntity.getOwnerModule().getName();
|
||||
if (intellijEntity.getLibraryName() == null) {
|
||||
return;
|
||||
}
|
||||
descriptor = buildDescriptor(intellijEntity);
|
||||
descriptor.setAttributes(GradleTextAttributes.INTELLIJ_LOCAL_CHANGE);
|
||||
missingEntity = intellijEntity;
|
||||
}
|
||||
else {
|
||||
// Particular library dependency is added at the gradle side.
|
||||
moduleName = gradleEntity.getOwnerModule().getName();
|
||||
descriptor = buildDescriptor(gradleEntity, GradleIcons.LIB_ICON);
|
||||
descriptor.setAttributes(GradleTextAttributes.GRADLE_LOCAL_CHANGE);
|
||||
missingEntity = gradleEntity;
|
||||
}
|
||||
final DefaultMutableTreeNode dependenciesNode = getDependenciesNode(moduleName);
|
||||
for (int i = 0, max = dependenciesNode.getChildCount(); i < max; i++) {
|
||||
final DefaultMutableTreeNode child = (DefaultMutableTreeNode)dependenciesNode.getChildAt(i);
|
||||
GradleProjectStructureNodeDescriptor<?> d = (GradleProjectStructureNodeDescriptor<?>)child.getUserObject();
|
||||
if (missingEntity.equals(d.getElement())) {
|
||||
d.setAttributes(descriptor.getAttributes());
|
||||
nodeStructureChanged(child);
|
||||
assert id != null;
|
||||
final GradleProjectStructureNode<String> dependenciesNode = getDependenciesNode(id.getModuleName());
|
||||
for (GradleProjectStructureNode<GradleLibraryDependencyId> node : dependenciesNode.getChildren(GradleLibraryDependencyId.class)) {
|
||||
GradleProjectStructureNodeDescriptor<GradleLibraryDependencyId> d = node.getDescriptor();
|
||||
if (id.equals(d.getElement())) {
|
||||
d.setAttributes(attributes);
|
||||
nodeStructureChanged(node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(descriptor);
|
||||
GradleProjectStructureNode<GradleLibraryDependencyId> newNode = buildNode(id, id.getLibraryName(), GradleIcons.LIB_ICON);
|
||||
newNode.getDescriptor().setAttributes(attributes);
|
||||
dependenciesNode.add(newNode);
|
||||
nodeStructureChanged(dependenciesNode);
|
||||
}
|
||||
@@ -219,7 +194,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Asks current model to remove all obsolete nodes for the considering that the given changes are obsolete.
|
||||
* Asks current model to process given changes assuming that they are obsolete.
|
||||
* <p/>
|
||||
* Example:
|
||||
* <pre>
|
||||
@@ -231,63 +206,72 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel {
|
||||
* </ol>
|
||||
* </pre>
|
||||
*/
|
||||
public void pruneObsoleteNodes(Collection<GradleProjectStructureChange> changes) {
|
||||
public void processObsoleteChanges(Collection<GradleProjectStructureChange> changes) {
|
||||
for (GradleProjectStructureChange change : changes) {
|
||||
change.invite(new GradleProjectStructureChangeVisitor() {
|
||||
change.invite(new GradleProjectStructureChangeVisitorAdapter() {
|
||||
@Override
|
||||
public void visit(@NotNull GradleRenameChange change) {
|
||||
// TODO den implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleProjectStructureChange change) {
|
||||
// TODO den implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleModulePresenceChange change) {
|
||||
// TODO den implement
|
||||
public void visit(@NotNull GradleMismatchedLibraryPathChange change) {
|
||||
for (GradleProjectStructureNode<String> holder : myModuleDependencies.values()) {
|
||||
for (GradleProjectStructureNode<GradleLibraryDependencyId> node : holder.getChildren(GradleLibraryDependencyId.class)) {
|
||||
final GradleLibraryDependencyId id = node.getDescriptor().getElement();
|
||||
if (id.getLibraryName().equals(change.getLibraryName())) {
|
||||
node.removeConflictChange(change);
|
||||
nodeChanged(node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull GradleLibraryDependencyPresenceChange change) {
|
||||
// We need to remove the corresponding node then.
|
||||
String moduleName;
|
||||
Object library;
|
||||
final GradleLibraryDependency gradleEntity = change.getGradleEntity();
|
||||
final LibraryOrderEntry intellijEntity = change.getIntellijEntity();
|
||||
assert gradleEntity != null || intellijEntity != null;
|
||||
if (gradleEntity == null) {
|
||||
moduleName = intellijEntity.getOwnerModule().getName();
|
||||
library = intellijEntity;
|
||||
GradleLibraryDependencyId id = change.getGradleEntity();
|
||||
boolean removeNode;
|
||||
if (id == null) {
|
||||
id = change.getIntellijEntity();
|
||||
assert id != null;
|
||||
removeNode = !myProjectStructureHelper.isIntellijLibraryDependencyExist(id);
|
||||
}
|
||||
else {
|
||||
moduleName = gradleEntity.getOwnerModule().getName();
|
||||
library = gradleEntity;
|
||||
removeNode = !myProjectStructureHelper.isGradleLibraryDependencyExist(id);
|
||||
}
|
||||
final DefaultMutableTreeNode holder = myModuleDependencies.get(moduleName);
|
||||
final GradleProjectStructureNode<String> holder = myModuleDependencies.get(id.getModuleName());
|
||||
if (holder == null) {
|
||||
return;
|
||||
}
|
||||
for (DefaultMutableTreeNode node = holder.getFirstLeaf(); node != null; node = node.getNextSibling()) {
|
||||
GradleProjectStructureNodeDescriptor<?> descriptor = (GradleProjectStructureNodeDescriptor<?>)node.getUserObject();
|
||||
if (descriptor.getElement().equals(library)) {
|
||||
removeNode(node);
|
||||
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<GradleLibraryDependencyId> node : holder.getChildren(GradleLibraryDependencyId.class)) {
|
||||
GradleProjectStructureNodeDescriptor<GradleLibraryDependencyId> descriptor = node.getDescriptor();
|
||||
if (!id.equals(descriptor.getElement())) {
|
||||
continue;
|
||||
}
|
||||
if (removeNode) {
|
||||
removeNode(node);
|
||||
}
|
||||
else {
|
||||
descriptor.setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void removeNode(@NotNull TreeNode node) {
|
||||
final MutableTreeNode parent = (MutableTreeNode)node.getParent();
|
||||
private void removeNode(@NotNull GradleProjectStructureNode node) {
|
||||
final GradleProjectStructureNode parent = node.getParent();
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
int i = parent.getIndex(node);
|
||||
if (i <= 0) {
|
||||
if (i < 0) {
|
||||
assert false : node;
|
||||
return;
|
||||
}
|
||||
|
||||
+121
-5
@@ -1,24 +1,140 @@
|
||||
package org.jetbrains.plugins.gradle.ui;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.gradle.config.GradleTextAttributes;
|
||||
import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange;
|
||||
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.MutableTreeNode;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/23/11 3:50 PM
|
||||
* @param <T> type of the target entity {@link GradleProjectStructureNodeDescriptor#getElement() associated} with the current node
|
||||
*/
|
||||
public class GradleProjectStructureNode extends DefaultMutableTreeNode {
|
||||
|
||||
private final GradleProjectStructureNodeDescriptor myDescriptor;
|
||||
public class GradleProjectStructureNode<T> extends DefaultMutableTreeNode implements Iterable<GradleProjectStructureNode<?>> {
|
||||
|
||||
public GradleProjectStructureNode(@NotNull GradleProjectStructureNodeDescriptor descriptor) {
|
||||
private final Set<GradleProjectStructureChange> myConflictChanges = new HashSet<GradleProjectStructureChange>();
|
||||
private final GradleProjectStructureNodeDescriptor<T> myDescriptor;
|
||||
|
||||
public GradleProjectStructureNode(@NotNull GradleProjectStructureNodeDescriptor<T> descriptor) {
|
||||
super(descriptor);
|
||||
myDescriptor = descriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GradleProjectStructureNodeDescriptor getDescriptor() {
|
||||
public GradleProjectStructureNodeDescriptor<T> getDescriptor() {
|
||||
return myDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradleProjectStructureNode<?> getChildAt(int index) {
|
||||
return (GradleProjectStructureNode)super.getChildAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradleProjectStructureNode<?> getParent() {
|
||||
return (GradleProjectStructureNode)super.getParent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(MutableTreeNode newChild) {
|
||||
GradleProjectStructureNode<?> child = (GradleProjectStructureNode)newChild;
|
||||
final String newText = child.getDescriptor().getText();
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
GradleProjectStructureNode<?> node = getChildAt(i);
|
||||
if (newText.compareTo(node.getDescriptor().getText()) < 0) {
|
||||
insert(newChild, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
super.add(newChild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers given change within the given node assuming that it is
|
||||
* {@link GradleTextAttributes#GRADLE_CHANGE_CONFLICT 'conflict change'}. We need to track number of such changes per-node because
|
||||
* of the following possible situation:
|
||||
* <pre>
|
||||
* <ol>
|
||||
* <li>There are two 'conflict changes' for particular node;</li>
|
||||
* <li>
|
||||
* One of those changes is resolved but the node still should be marked as 'conflict' because there is still one conflict change;
|
||||
* </li>
|
||||
* <li>The second conflict change is removed. The node should be marked as 'no change' now;</li>
|
||||
* </ol>
|
||||
* </pre>
|
||||
*
|
||||
* @param change conflict change to register for the current node
|
||||
*/
|
||||
public void addConflictChange(@NotNull GradleProjectStructureChange change) {
|
||||
myConflictChanges.add(change);
|
||||
myDescriptor.setAttributes(GradleTextAttributes.GRADLE_CHANGE_CONFLICT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs reverse operation to {@link #addConflictChange(GradleProjectStructureChange)}.
|
||||
*
|
||||
* @param change conflict change to de-register from the current node
|
||||
*/
|
||||
public void removeConflictChange(@NotNull GradleProjectStructureChange change) {
|
||||
myConflictChanges.remove(change);
|
||||
if (myConflictChanges.isEmpty()) {
|
||||
myDescriptor.setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to query current node for all children that are associated with the entity of the given type.
|
||||
*
|
||||
* @param clazz target entity type
|
||||
* @param <C> target entity type
|
||||
* @return all children nodes that are associated with the entity of the given type if any;
|
||||
* empty collection otherwise
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@NotNull
|
||||
public <C> Collection<GradleProjectStructureNode<C>> getChildren(@NotNull Class<C> clazz) {
|
||||
List<GradleProjectStructureNode<C>> result = null;
|
||||
for (int i = 0; i < getChildCount(); i++) {
|
||||
final GradleProjectStructureNode<?> child = getChildAt(i);
|
||||
final Object element = child.getDescriptor().getElement();
|
||||
if (!clazz.isInstance(element)) {
|
||||
continue;
|
||||
}
|
||||
if (result == null) {
|
||||
result = new ArrayList<GradleProjectStructureNode<C>>();
|
||||
}
|
||||
result.add((GradleProjectStructureNode<C>)child);
|
||||
}
|
||||
if (result == null) {
|
||||
result = Collections.emptyList();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Iterator<GradleProjectStructureNode<?>> iterator() {
|
||||
return new Iterator<GradleProjectStructureNode<?>>() {
|
||||
|
||||
private int i;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i < getChildCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GradleProjectStructureNode<?> next() {
|
||||
return getChildAt(i++);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+7
-1
@@ -40,12 +40,18 @@ public class GradleProjectStructureNodeDescriptor<T> extends PresentableNodeDesc
|
||||
presentation.setClosedIcon(myClosedIcon);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public T getElement() {
|
||||
return myData;
|
||||
}
|
||||
|
||||
public void setName(@NotNull String name) {
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public void setText(@NotNull String name) {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
|
||||
+119
-5
@@ -42,7 +42,9 @@ public class GradleProjectStructureChangesModelTest {
|
||||
container.registerComponentImplementation(GradleStructureChangesCalculator, GradleProjectStructureChangesCalculator)
|
||||
container.registerComponentImplementation(GradleModuleStructureChangesCalculator)
|
||||
container.registerComponentImplementation(GradleLibraryDependencyStructureChangesCalculator)
|
||||
container.registerComponentImplementation(GradleLibraryStructureChangesCalculator)
|
||||
container.registerComponentImplementation(GradleProjectStructureTreeModel)
|
||||
container.registerComponentImplementation(GradleProjectStructureHelper)
|
||||
|
||||
changesModel = container.getComponentInstance(GradleProjectStructureChangesModel) as GradleProjectStructureChangesModel
|
||||
}
|
||||
@@ -56,6 +58,7 @@ public class GradleProjectStructureChangesModelTest {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2")
|
||||
lib(name: "lib3")
|
||||
} } },
|
||||
|
||||
intellij {
|
||||
@@ -69,46 +72,157 @@ public class GradleProjectStructureChangesModelTest {
|
||||
checkChanges {
|
||||
presence {
|
||||
lib(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib2" })
|
||||
lib(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib3" })
|
||||
} }
|
||||
checkTree {
|
||||
project {
|
||||
module("xxx") {
|
||||
module() {
|
||||
dependencies {
|
||||
lib1()
|
||||
lib2('gradle')
|
||||
lib3('gradle')
|
||||
} } } }
|
||||
|
||||
// Define changed project state.
|
||||
// Add the same library at intellij side. Expecting to have the only change now.
|
||||
intellij {
|
||||
module {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2")
|
||||
} } }
|
||||
changesModel.update(gradle.project)
|
||||
checkChanges {
|
||||
presence {
|
||||
lib(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib3" })
|
||||
} }
|
||||
checkTree {
|
||||
project {
|
||||
module() {
|
||||
dependencies {
|
||||
lib1()
|
||||
lib2()
|
||||
lib3('gradle')
|
||||
} } } }
|
||||
|
||||
// Remove the 'gradle local' dependency.
|
||||
gradle {
|
||||
module {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2")
|
||||
} } }
|
||||
|
||||
// Apply the changed project state and check if it's correctly parsed.
|
||||
changesModel.update(gradle.project)
|
||||
checkChanges { } // no changes.
|
||||
assertEquals([].toSet(), changesModel.changes)
|
||||
checkTree {
|
||||
project {
|
||||
module {
|
||||
dependencies {
|
||||
lib1()
|
||||
lib2()
|
||||
} } } }
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void libraryDependenciesWithDifferentPaths() {
|
||||
// Let the model has two differences in a library setup initially.
|
||||
init(
|
||||
gradle {
|
||||
module {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2", bin: ['1', '2'])
|
||||
} } },
|
||||
intellij {
|
||||
module {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2", bin: ['2', '3'])
|
||||
}}}
|
||||
)
|
||||
|
||||
checkChanges {
|
||||
libraryConflict(entity: intellij.libraries['lib2']) {
|
||||
binaryPath(gradle: '1', intellij: null)
|
||||
binaryPath(gradle: null, intellij: '3')
|
||||
} }
|
||||
checkTree {
|
||||
project {
|
||||
module {
|
||||
dependencies {
|
||||
lib1()
|
||||
lib2('conflict')
|
||||
} } } }
|
||||
|
||||
// Remove one difference from the library setup and check that the corresponding node is still marked as conflicted
|
||||
gradle {
|
||||
module {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2", bin: ['2'])
|
||||
} } }
|
||||
intellij {
|
||||
module {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2", bin: ['2', '3'])
|
||||
}}}
|
||||
changesModel.update(gradle.project)
|
||||
checkChanges {
|
||||
libraryConflict(entity: intellij.dependencies.values().flatten().find {it.library.name == 'lib2' }.library) {
|
||||
binaryPath(gradle: null, intellij: '3')
|
||||
} }
|
||||
checkTree {
|
||||
project {
|
||||
module {
|
||||
dependencies {
|
||||
lib1()
|
||||
lib2('conflict')
|
||||
} } } }
|
||||
|
||||
// Match the remaining change and check that the corresponding node is not marked as conflicted anymore.
|
||||
gradle {
|
||||
module {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2", bin: ['2', '3'])
|
||||
} } }
|
||||
intellij {
|
||||
module {
|
||||
dependencies {
|
||||
lib(name: "lib1")
|
||||
lib(name: "lib2", bin: ['2', '3'])
|
||||
}}}
|
||||
changesModel.update(gradle.project)
|
||||
checkChanges { } // No changes
|
||||
checkTree {
|
||||
project {
|
||||
module {
|
||||
dependencies {
|
||||
lib1()
|
||||
lib2()
|
||||
} } } }
|
||||
}
|
||||
|
||||
@SuppressWarnings("GroovyAssignabilityCheck")
|
||||
private def init(gradleProjectInit, intellijProjectInit) {
|
||||
treeModel = container.getComponentInstance(GradleProjectStructureTreeModel) as GradleProjectStructureTreeModel
|
||||
changesModel.addListener({ old, current ->
|
||||
treeModel.update(current)
|
||||
treeModel.pruneObsoleteNodes(ContainerUtil.subtract(old, current));
|
||||
treeModel.processObsoleteChanges(ContainerUtil.subtract(old, current));
|
||||
} as GradleProjectStructureChangeListener)
|
||||
changesModel.update(gradle.project)
|
||||
}
|
||||
|
||||
private def checkChanges(c) {
|
||||
c.delegate = changes
|
||||
assertEquals(c(), changesModel.changes)
|
||||
def expected = c()
|
||||
if (!expected) {
|
||||
expected = [].toSet()
|
||||
}
|
||||
assertEquals(expected, changesModel.changes)
|
||||
}
|
||||
|
||||
private def checkTree(c) {
|
||||
|
||||
+29
-5
@@ -1,19 +1,26 @@
|
||||
package org.jetbrains.plugins.gradle.testutil
|
||||
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.pom.java.LanguageLevel
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 1/25/12 4:06 PM
|
||||
*/
|
||||
public abstract class AbstractProjectBuilder extends BuilderSupport {
|
||||
public abstract class AbstractProjectBuilder extends BuilderSupport {
|
||||
|
||||
private static final def SAME_TOKEN = "same"
|
||||
public static final def SAME_TOKEN = "same"
|
||||
private static int COUNTER
|
||||
|
||||
def project
|
||||
def modules = []
|
||||
def libraries = [:].withDefault { createLibrary(it.name?: same, it.paths?: [:]) }
|
||||
/** Holds (library name; library) pairs for the active configuration. */
|
||||
def libraries = [:]
|
||||
/**
|
||||
* Holds (library name; library) pairs for the whole test. I.e. there is a possible case that we define particular configuration
|
||||
* initially and the adjust it. We need to use the same library instance then in order to pass hashCode()/equals() checks then.
|
||||
* This map works as a test-wide storage.
|
||||
*/
|
||||
def librariesCache = [:]
|
||||
def dependencies = [:].withDefault {[]}
|
||||
|
||||
@Override
|
||||
@@ -43,7 +50,7 @@ public abstract class AbstractProjectBuilder extends BuilderSupport {
|
||||
case "module": def module = createModule(attributes.name?: same); modules << module; return module
|
||||
case "lib":
|
||||
def module = getCurrent()
|
||||
def dep = createLibraryDependency(module, libraries[attributes])
|
||||
def dep = createLibraryDependency(module, getLibrary(attributes))
|
||||
dependencies[module] << dep
|
||||
return dep
|
||||
}
|
||||
@@ -57,10 +64,27 @@ public abstract class AbstractProjectBuilder extends BuilderSupport {
|
||||
protected abstract def createProject(String name, LanguageLevel languageLevel)
|
||||
protected abstract def createModule(String name)
|
||||
protected abstract def createLibrary(String name, Map paths)
|
||||
protected abstract def applyLibraryPaths(library, Map paths)
|
||||
protected abstract def createLibraryDependency(module, library)
|
||||
|
||||
protected String getUnique() { "./${COUNTER++}" }
|
||||
protected String getSame() { SAME_TOKEN }
|
||||
|
||||
private def getLibrary(Map attributes) {
|
||||
def name = attributes.name?: same
|
||||
def result = libraries[name]
|
||||
if (result) return result
|
||||
result = librariesCache[name]
|
||||
if (result) {
|
||||
applyLibraryPaths(result, attributes)
|
||||
}
|
||||
else {
|
||||
result = createLibrary(name, attributes.withDefault { /* empty paths*/ [] })
|
||||
librariesCache[name] = result
|
||||
}
|
||||
libraries[name] = result
|
||||
result
|
||||
}
|
||||
|
||||
private def reset() {
|
||||
[modules, dependencies, libraries]*.clear()
|
||||
|
||||
+32
-5
@@ -2,6 +2,9 @@ package org.jetbrains.plugins.gradle.testutil;
|
||||
|
||||
|
||||
import org.jetbrains.plugins.gradle.diff.GradleLibraryDependencyPresenceChange
|
||||
import org.jetbrains.plugins.gradle.diff.GradleMismatchedLibraryPathChange
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import org.jetbrains.plugins.gradle.util.GradleUtil
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
@@ -17,10 +20,7 @@ public class ChangeBuilder extends BuilderSupport {
|
||||
|
||||
@Override
|
||||
protected Object createNode(Object name) {
|
||||
if (current == null) {
|
||||
changes = []
|
||||
}
|
||||
changes
|
||||
createNode(name, [:])
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -28,13 +28,31 @@ public class ChangeBuilder extends BuilderSupport {
|
||||
|
||||
@Override
|
||||
protected Object createNode(Object name, Map attributes) {
|
||||
if (current == null) {
|
||||
changes = []
|
||||
}
|
||||
switch (name) {
|
||||
case "presence": return changes
|
||||
case "lib":
|
||||
changes.addAll attributes.gradle.collect { new GradleLibraryDependencyPresenceChange(it, null)}
|
||||
changes.addAll attributes.intellij.collect { new GradleLibraryDependencyPresenceChange(null, it)}
|
||||
return
|
||||
return changes
|
||||
case "libraryConflict":
|
||||
def library = attributes.entity
|
||||
if (!library) {
|
||||
throw new IllegalArgumentException("No entity is defined for the library conflict change. Known attributes: $attributes")
|
||||
}
|
||||
if (attributes.gradle) {
|
||||
return register(new GradleMismatchedLibraryPathChange(library, attributes.gradle, attributes.intellij))
|
||||
}
|
||||
return library
|
||||
case "binaryPath":
|
||||
// Assuming that we're processing library binary path conflict here
|
||||
register(new GradleMismatchedLibraryPathChange(
|
||||
current as Library, toCanonicalPath(attributes.gradle), toCanonicalPath(attributes.intellij)
|
||||
))
|
||||
}
|
||||
changes
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,4 +62,13 @@ public class ChangeBuilder extends BuilderSupport {
|
||||
protected Object postNodeCompletion(Object parent, Object node) {
|
||||
parent == null ? changes.toSet() : node
|
||||
}
|
||||
|
||||
protected def register(change) {
|
||||
changes << change
|
||||
change
|
||||
}
|
||||
|
||||
private def toCanonicalPath(String path) {
|
||||
path ? GradleUtil.toCanonicalPath(path) : path
|
||||
}
|
||||
}
|
||||
|
||||
+9
-3
@@ -31,9 +31,7 @@ class GradleProjectBuilder extends AbstractProjectBuilder {
|
||||
@Override
|
||||
protected createLibrary(String name, Map paths) {
|
||||
def result = new GradleLibrary(name)
|
||||
(paths.bin?: [same]).each { result.addPath(LibraryPathType.BINARY, it) }
|
||||
(paths.src?: [same]).each { result.addPath(LibraryPathType.SOURCE, it) }
|
||||
(paths.doc?: [same]).each { result.addPath(LibraryPathType.DOC, it) }
|
||||
applyLibraryPaths(result, paths)
|
||||
result
|
||||
}
|
||||
|
||||
@@ -43,4 +41,12 @@ class GradleProjectBuilder extends AbstractProjectBuilder {
|
||||
module.addDependency(result)
|
||||
result
|
||||
}
|
||||
|
||||
@Override
|
||||
protected applyLibraryPaths(library, Map paths) {
|
||||
library.forgetAllPaths()
|
||||
['bin': LibraryPathType.BINARY, 'src': LibraryPathType.SOURCE, 'doc': LibraryPathType.DOC].each {
|
||||
key, type -> paths[key]?.each { library.addPath(type, it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+29
-2
@@ -9,19 +9,29 @@ import com.intellij.openapi.roots.LibraryOrderEntry
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.IconLoader
|
||||
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import org.jetbrains.plugins.gradle.util.GradleUtil
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 1/25/12 3:09 PM
|
||||
*/
|
||||
class IntellijProjectBuilder extends AbstractProjectBuilder {
|
||||
|
||||
static def LIBRARY_ENTRY_TYPES = [(OrderRootType.CLASSES) : "bin"]
|
||||
static VirtualFile[] DUMMY_VIRTUAL_FILE_ARRAY = new VirtualFile[0]
|
||||
|
||||
def projectStub = [:]
|
||||
def project = projectStub as Project
|
||||
def platformFacade = [
|
||||
getModules: { modules },
|
||||
getOrderEntries: { dependencies[it] },
|
||||
getProjectIcon: { IconLoader.getIcon("/nodes/ideaProject.png") }
|
||||
getProjectIcon: { IconLoader.getIcon("/nodes/ideaProject.png") },
|
||||
getLocalFileSystemPath: { it.path }
|
||||
]
|
||||
/** (library name - (library root type - paths)). */
|
||||
def libraryPaths = [:].withDefault { [:] }
|
||||
|
||||
@Override
|
||||
protected createProject(String name, LanguageLevel languageLevel) {
|
||||
@@ -37,7 +47,17 @@ class IntellijProjectBuilder extends AbstractProjectBuilder {
|
||||
|
||||
@Override
|
||||
protected createLibrary(String name, Map paths) {
|
||||
[ getName: { name }, getPresentableName: { name } ] as Library
|
||||
libraryPaths[name] = paths
|
||||
[
|
||||
getName: { name },
|
||||
getPresentableName: { name },
|
||||
getFiles: {
|
||||
type -> (libraryPaths[name])[LIBRARY_ENTRY_TYPES[type]].findAll { it }.collect {
|
||||
String path = it
|
||||
[getPath: { GradleUtil.toCanonicalPath(path) }] as VirtualFile
|
||||
}.toArray(DUMMY_VIRTUAL_FILE_ARRAY)
|
||||
}
|
||||
] as Library
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -46,6 +66,13 @@ class IntellijProjectBuilder extends AbstractProjectBuilder {
|
||||
def result = stub as LibraryOrderEntry
|
||||
stub.accept = { policy, defaultValue -> policy.visitLibraryOrderEntry(result, defaultValue) }
|
||||
stub.getLibraryName = { library.name }
|
||||
stub.getLibrary = { library }
|
||||
stub.getOwnerModule = { module }
|
||||
result
|
||||
}
|
||||
|
||||
@Override
|
||||
protected applyLibraryPaths(library, Map paths) {
|
||||
libraryPaths[library.name] = paths
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -35,6 +35,9 @@ class ProjectStructureChecker {
|
||||
check it as Node, actual.getChildAt(childIndex++) as DefaultMutableTreeNode
|
||||
}
|
||||
for (it in expected.children().findAll { it instanceof Node}) {
|
||||
if (childIndex >= actual.childCount) {
|
||||
fail "Expected node is not matched: $expected"
|
||||
}
|
||||
check it as Node, actual.getChildAt(childIndex++) as DefaultMutableTreeNode
|
||||
}
|
||||
if (childIndex < actual.childCount) {
|
||||
@@ -43,7 +46,7 @@ class ProjectStructureChecker {
|
||||
}
|
||||
|
||||
private void checkName(Node expected, GradleProjectStructureNodeDescriptor actual) {
|
||||
if (expected.name() == actual.toString()) {
|
||||
if (AbstractProjectBuilder.SAME_TOKEN == actual.toString() || expected.name() == actual.toString()) {
|
||||
return
|
||||
}
|
||||
def clazz = BUILT_IN[expected.name()]
|
||||
|
||||
Reference in New Issue
Block a user