diff --git a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java index ed97f1ea86c7..8abbe757472b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/CompileServerManager.java @@ -280,7 +280,8 @@ public class CompileServerManager implements ApplicationComponent{ continue; } final RequestFuture future = submitCompilationTask(project, false, true, Collections.emptyList(), Collections.emptyList(), - Collections.emptyList(), new AutoMakeResponseHandler(project)); + Collections.emptyList(), Collections.emptyMap(), new AutoMakeResponseHandler(project) + ); if (future != null) { futures.add(future); synchronized (myAutomakeFutures) { @@ -312,9 +313,10 @@ public class CompileServerManager implements ApplicationComponent{ } @Nullable - public RequestFuture submitCompilationTask(final Project project, final boolean isRebuild, final boolean isMake, - final Collection modules, final Collection artifacts, - final Collection paths, final JpsServerResponseHandler handler) { + public RequestFuture submitCompilationTask(final Project project, final boolean isRebuild, final boolean isMake, + final Collection modules, final Collection artifacts, + final Collection paths, + final Map userData, final JpsServerResponseHandler handler) { final String projectId = project.getLocation(); final Ref futureRef = new Ref(null); final RunnableFuture future = myTaskExecutor.submit(new Runnable() { @@ -324,7 +326,7 @@ public class CompileServerManager implements ApplicationComponent{ if (client != null) { final RequestFuture requestFuture = isRebuild ? client.sendRebuildRequest(projectId, handler) : - client.sendCompileRequest(isMake, projectId, modules, artifacts, paths, handler); + client.sendCompileRequest(isMake, projectId, modules, artifacts, paths, userData, handler); futureRef.set(requestFuture); } else { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 0b1bf1f4605c..8d6d0f39f63d 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -430,7 +430,24 @@ public class CompileDriver { final CompileServerManager csManager = CompileServerManager.getInstance(); final MessageBus messageBus = myProject.getMessageBus(); csManager.cancelAutoMakeTasks(myProject); - return csManager.submitCompilationTask(myProject, compileContext.isRebuild(), compileContext.isMake(), moduleNames, artifactNames, paths, new JpsServerResponseHandler() { + final CompileScope scope = compileContext.getCompileScope(); + final Map userData; + // need to pass scope's user data to server + if (scope instanceof UserDataHolderBase) { // hack + userData = new HashMap(); + ((UserDataHolderBase)scope).copyUserDataTo(new UserDataHolderBase() { + @Override + public void putUserData(@NotNull Key key, @Nullable T value) { + final String _key = key.toString(); + final String _value = value != null? value.toString() : ""; + userData.put(_key, _value); + } + }); + } + else { + userData = Collections.emptyMap(); + } + return csManager.submitCompilationTask(myProject, compileContext.isRebuild(), compileContext.isMake(), moduleNames, artifactNames, paths, userData, new JpsServerResponseHandler() { @Override public void handleCompileMessage(JpsRemoteProto.Message.Response.CompileMessage compilerMessage) { diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/resourceCompiler/ResourceCompiler.java b/java/compiler/impl/src/com/intellij/compiler/impl/resourceCompiler/ResourceCompiler.java index e3729d8142c1..f6e0f4013b0a 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/resourceCompiler/ResourceCompiler.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/resourceCompiler/ResourceCompiler.java @@ -50,6 +50,7 @@ public class ResourceCompiler implements TranslatingCompiler { private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.resourceCompiler.ResourceCompiler"); private final Project myProject; private final CompilerConfiguration myConfiguration; + private final ResourceCompilerExtension[] myResourceCompilerExtensions = ResourceCompilerExtension.EP_NAME.getExtensions(); private static final FileTypeManager FILE_TYPE_MANAGER = FileTypeManager.getInstance(); public ResourceCompiler(Project project, CompilerConfiguration compilerConfiguration) { @@ -68,6 +69,11 @@ public class ResourceCompiler implements TranslatingCompiler { } public boolean isCompilableFile(VirtualFile file, CompileContext context) { + final Module module = context.getModuleByFile(file); + if (module != null && skipStandardResourceCompiler(module)) { + return false; + } + return !StdFileTypes.JAVA.equals(file.getFileType()) && myConfiguration.isResourceFile(file); } @@ -81,8 +87,6 @@ public class ResourceCompiler implements TranslatingCompiler { ApplicationManager.getApplication().runReadAction(new Runnable() { public void run() { final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(myProject).getFileIndex(); - - OUTER: for (final VirtualFile file : files) { if (context.getProgressIndicator().isCanceled()) { break; @@ -91,13 +95,6 @@ public class ResourceCompiler implements TranslatingCompiler { if (module == null) { continue; // looks like file invalidated } - - for (ResourceCompilerExtension extension : ResourceCompilerExtension.EP_NAME.getExtensions()) { - if (extension.skipStandardResourceCompiler(module)) { - continue OUTER; - } - } - final VirtualFile fileRoot = MakeUtil.getSourceRoot(context, module, file); if (fileRoot == null) { continue; @@ -164,6 +161,15 @@ public class ResourceCompiler implements TranslatingCompiler { context.getProgressIndicator().popState(); } + private boolean skipStandardResourceCompiler(final Module module) { + for (ResourceCompilerExtension extension : myResourceCompilerExtensions) { + if (extension.skipStandardResourceCompiler(module)) { + return true; + } + } + return false; + } + private static void addToMap(Map> map, String outputDir, OutputItem item) { Collection list = map.get(outputDir); if (list == null) { diff --git a/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java b/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java index 89cc65ebeeaf..85a5b51e1337 100644 --- a/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java +++ b/java/execution/openapi/src/com/intellij/execution/JavaExecutionUtil.java @@ -162,10 +162,7 @@ public class JavaExecutionUtil { public static String getShortClassName(final String fqName) { if (fqName == null) return ""; - final int dotIndex = fqName.lastIndexOf('.'); - if (dotIndex == fqName.length() - 1) return ""; - if (dotIndex < 0) return fqName; - return fqName.substring(dotIndex + 1, fqName.length()); + return StringUtil.getShortName(fqName); } public static void showExecutionErrorMessage(final ExecutionException e, final String title, final Project project) { diff --git a/jps/jps-builders/proto/jps_remote_proto.proto b/jps/jps-builders/proto/jps_remote_proto.proto index 03eabce9567f..730a59e33544 100644 --- a/jps/jps-builders/proto/jps_remote_proto.proto +++ b/jps/jps-builders/proto/jps_remote_proto.proto @@ -10,6 +10,11 @@ message Message { required sint64 least_sig_bits = 2; } + message KeyValuePair { + required string key = 1; + required string value = 2; + } + enum Type { REQUEST = 1; RESPONSE = 2; @@ -44,6 +49,7 @@ message Message { repeated string module_name = 3; repeated string file_path = 4; repeated string artifact_name = 5; + repeated KeyValuePair builder_parameter = 6; } message ShutdownCommand { @@ -56,11 +62,6 @@ message Message { message SetupCommand { - message PathVariable { - required string name = 1; - required string value = 2; - } - message GlobalLibrary { required string name = 1; optional string homePath = 2; @@ -69,7 +70,7 @@ message Message { repeated string path = 5; } - repeated PathVariable path_variable = 1; + repeated KeyValuePair path_variable = 1; repeated GlobalLibrary global_library = 2; optional string global_encoding = 3; } diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java b/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java index cf6dd424fbba..424a1ef5e08c 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/JpsRemoteProto.java @@ -359,6 +359,305 @@ public final class JpsRemoteProto { // @@protoc_insertion_point(class_scope:org.jetbrains.jpsservice.Message.UUID) } + public static final class KeyValuePair extends + com.google.protobuf.GeneratedMessageLite { + // Use KeyValuePair.newBuilder() to construct. + private KeyValuePair() { + initFields(); + } + private KeyValuePair(boolean noInit) {} + + private static final KeyValuePair defaultInstance; + public static KeyValuePair getDefaultInstance() { + return defaultInstance; + } + + public KeyValuePair getDefaultInstanceForType() { + return defaultInstance; + } + + // required string key = 1; + public static final int KEY_FIELD_NUMBER = 1; + private boolean hasKey; + private java.lang.String key_ = ""; + public boolean hasKey() { return hasKey; } + public java.lang.String getKey() { return key_; } + + // required string value = 2; + public static final int VALUE_FIELD_NUMBER = 2; + private boolean hasValue; + private java.lang.String value_ = ""; + public boolean hasValue() { return hasValue; } + public java.lang.String getValue() { return value_; } + + private void initFields() { + } + public final boolean isInitialized() { + if (!hasKey) return false; + if (!hasValue) return false; + return true; + } + + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + getSerializedSize(); + if (hasKey()) { + output.writeString(1, getKey()); + } + if (hasValue()) { + output.writeString(2, getValue()); + } + } + + private int memoizedSerializedSize = -1; + public int getSerializedSize() { + int size = memoizedSerializedSize; + if (size != -1) return size; + + size = 0; + if (hasKey()) { + size += com.google.protobuf.CodedOutputStream + .computeStringSize(1, getKey()); + } + if (hasValue()) { + size += com.google.protobuf.CodedOutputStream + .computeStringSize(2, getValue()); + } + memoizedSerializedSize = size; + return size; + } + + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).buildParsed(); + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return newBuilder().mergeFrom(data, extensionRegistry) + .buildParsed(); + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseFrom(java.io.InputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + Builder builder = newBuilder(); + if (builder.mergeDelimitedFrom(input, extensionRegistry)) { + return builder.buildParsed(); + } else { + return null; + } + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return newBuilder().mergeFrom(input).buildParsed(); + } + public static org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return newBuilder().mergeFrom(input, extensionRegistry) + .buildParsed(); + } + + public static Builder newBuilder() { return Builder.create(); } + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder(org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair prototype) { + return newBuilder().mergeFrom(prototype); + } + public Builder toBuilder() { return newBuilder(this); } + + public static final class Builder extends + com.google.protobuf.GeneratedMessageLite.Builder< + org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair, Builder> { + private org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair result; + + // Construct using org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.newBuilder() + private Builder() {} + + private static Builder create() { + Builder builder = new Builder(); + builder.result = new org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair(); + return builder; + } + + protected org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair internalGetResult() { + return result; + } + + public Builder clear() { + if (result == null) { + throw new IllegalStateException( + "Cannot call clear() after build()."); + } + result = new org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair(); + return this; + } + + public Builder clone() { + return create().mergeFrom(result); + } + + public org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair getDefaultInstanceForType() { + return org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.getDefaultInstance(); + } + + public boolean isInitialized() { + return result.isInitialized(); + } + public org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair build() { + if (result != null && !isInitialized()) { + throw newUninitializedMessageException(result); + } + return buildPartial(); + } + + private org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair buildParsed() + throws com.google.protobuf.InvalidProtocolBufferException { + if (!isInitialized()) { + throw newUninitializedMessageException( + result).asInvalidProtocolBufferException(); + } + return buildPartial(); + } + + public org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair buildPartial() { + if (result == null) { + throw new IllegalStateException( + "build() has already been called on this Builder."); + } + org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair returnMe = result; + result = null; + return returnMe; + } + + public Builder mergeFrom(org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair other) { + if (other == org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.getDefaultInstance()) return this; + if (other.hasKey()) { + setKey(other.getKey()); + } + if (other.hasValue()) { + setValue(other.getValue()); + } + return this; + } + + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + return this; + default: { + if (!parseUnknownField(input, extensionRegistry, tag)) { + return this; + } + break; + } + case 10: { + setKey(input.readString()); + break; + } + case 18: { + setValue(input.readString()); + break; + } + } + } + } + + + // required string key = 1; + public boolean hasKey() { + return result.hasKey(); + } + public java.lang.String getKey() { + return result.getKey(); + } + public Builder setKey(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasKey = true; + result.key_ = value; + return this; + } + public Builder clearKey() { + result.hasKey = false; + result.key_ = getDefaultInstance().getKey(); + return this; + } + + // required string value = 2; + public boolean hasValue() { + return result.hasValue(); + } + public java.lang.String getValue() { + return result.getValue(); + } + public Builder setValue(java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + result.hasValue = true; + result.value_ = value; + return this; + } + public Builder clearValue() { + result.hasValue = false; + result.value_ = getDefaultInstance().getValue(); + return this; + } + + // @@protoc_insertion_point(builder_scope:org.jetbrains.jpsservice.Message.KeyValuePair) + } + + static { + defaultInstance = new KeyValuePair(true); + org.jetbrains.jps.api.JpsRemoteProto.internalForceInit(); + defaultInstance.initFields(); + } + + // @@protoc_insertion_point(class_scope:org.jetbrains.jpsservice.Message.KeyValuePair) + } + public static final class Failure extends com.google.protobuf.GeneratedMessageLite { // Use Failure.newBuilder() to construct. @@ -869,11 +1168,26 @@ public final class JpsRemoteProto { return artifactName_.get(index); } + // repeated .org.jetbrains.jpsservice.Message.KeyValuePair builder_parameter = 6; + public static final int BUILDER_PARAMETER_FIELD_NUMBER = 6; + private java.util.List builderParameter_ = + java.util.Collections.emptyList(); + public java.util.List getBuilderParameterList() { + return builderParameter_; + } + public int getBuilderParameterCount() { return builderParameter_.size(); } + public org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair getBuilderParameter(int index) { + return builderParameter_.get(index); + } + private void initFields() { commandType_ = org.jetbrains.jps.api.JpsRemoteProto.Message.Request.CompilationRequest.Type.REBUILD; } public final boolean isInitialized() { if (!hasCommandType) return false; + for (org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair element : getBuilderParameterList()) { + if (!element.isInitialized()) return false; + } return true; } @@ -895,6 +1209,9 @@ public final class JpsRemoteProto { for (java.lang.String element : getArtifactNameList()) { output.writeString(5, element); } + for (org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair element : getBuilderParameterList()) { + output.writeMessage(6, element); + } } private int memoizedSerializedSize = -1; @@ -938,6 +1255,10 @@ public final class JpsRemoteProto { size += dataSize; size += 1 * getArtifactNameList().size(); } + for (org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair element : getBuilderParameterList()) { + size += com.google.protobuf.CodedOutputStream + .computeMessageSize(6, element); + } memoizedSerializedSize = size; return size; } @@ -1087,6 +1408,10 @@ public final class JpsRemoteProto { result.artifactName_ = java.util.Collections.unmodifiableList(result.artifactName_); } + if (result.builderParameter_ != java.util.Collections.EMPTY_LIST) { + result.builderParameter_ = + java.util.Collections.unmodifiableList(result.builderParameter_); + } org.jetbrains.jps.api.JpsRemoteProto.Message.Request.CompilationRequest returnMe = result; result = null; return returnMe; @@ -1118,6 +1443,12 @@ public final class JpsRemoteProto { } result.artifactName_.addAll(other.artifactName_); } + if (!other.builderParameter_.isEmpty()) { + if (result.builderParameter_.isEmpty()) { + result.builderParameter_ = new java.util.ArrayList(); + } + result.builderParameter_.addAll(other.builderParameter_); + } return this; } @@ -1160,6 +1491,12 @@ public final class JpsRemoteProto { addArtifactName(input.readString()); break; } + case 50: { + org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.Builder subBuilder = org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.newBuilder(); + input.readMessage(subBuilder, extensionRegistry); + addBuilderParameter(subBuilder.buildPartial()); + break; + } } } } @@ -1327,6 +1664,57 @@ public final class JpsRemoteProto { return this; } + // repeated .org.jetbrains.jpsservice.Message.KeyValuePair builder_parameter = 6; + public java.util.List getBuilderParameterList() { + return java.util.Collections.unmodifiableList(result.builderParameter_); + } + public int getBuilderParameterCount() { + return result.getBuilderParameterCount(); + } + public org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair getBuilderParameter(int index) { + return result.getBuilderParameter(index); + } + public Builder setBuilderParameter(int index, org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair value) { + if (value == null) { + throw new NullPointerException(); + } + result.builderParameter_.set(index, value); + return this; + } + public Builder setBuilderParameter(int index, org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.Builder builderForValue) { + result.builderParameter_.set(index, builderForValue.build()); + return this; + } + public Builder addBuilderParameter(org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair value) { + if (value == null) { + throw new NullPointerException(); + } + if (result.builderParameter_.isEmpty()) { + result.builderParameter_ = new java.util.ArrayList(); + } + result.builderParameter_.add(value); + return this; + } + public Builder addBuilderParameter(org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.Builder builderForValue) { + if (result.builderParameter_.isEmpty()) { + result.builderParameter_ = new java.util.ArrayList(); + } + result.builderParameter_.add(builderForValue.build()); + return this; + } + public Builder addAllBuilderParameter( + java.lang.Iterable values) { + if (result.builderParameter_.isEmpty()) { + result.builderParameter_ = new java.util.ArrayList(); + } + super.addAll(values, result.builderParameter_); + return this; + } + public Builder clearBuilderParameter() { + result.builderParameter_ = java.util.Collections.emptyList(); + return this; + } + // @@protoc_insertion_point(builder_scope:org.jetbrains.jpsservice.Message.Request.CompilationRequest) } @@ -1656,305 +2044,6 @@ public final class JpsRemoteProto { return defaultInstance; } - public static final class PathVariable extends - com.google.protobuf.GeneratedMessageLite { - // Use PathVariable.newBuilder() to construct. - private PathVariable() { - initFields(); - } - private PathVariable(boolean noInit) {} - - private static final PathVariable defaultInstance; - public static PathVariable getDefaultInstance() { - return defaultInstance; - } - - public PathVariable getDefaultInstanceForType() { - return defaultInstance; - } - - // required string name = 1; - public static final int NAME_FIELD_NUMBER = 1; - private boolean hasName; - private java.lang.String name_ = ""; - public boolean hasName() { return hasName; } - public java.lang.String getName() { return name_; } - - // required string value = 2; - public static final int VALUE_FIELD_NUMBER = 2; - private boolean hasValue; - private java.lang.String value_ = ""; - public boolean hasValue() { return hasValue; } - public java.lang.String getValue() { return value_; } - - private void initFields() { - } - public final boolean isInitialized() { - if (!hasName) return false; - if (!hasValue) return false; - return true; - } - - public void writeTo(com.google.protobuf.CodedOutputStream output) - throws java.io.IOException { - getSerializedSize(); - if (hasName()) { - output.writeString(1, getName()); - } - if (hasValue()) { - output.writeString(2, getValue()); - } - } - - private int memoizedSerializedSize = -1; - public int getSerializedSize() { - int size = memoizedSerializedSize; - if (size != -1) return size; - - size = 0; - if (hasName()) { - size += com.google.protobuf.CodedOutputStream - .computeStringSize(1, getName()); - } - if (hasValue()) { - size += com.google.protobuf.CodedOutputStream - .computeStringSize(2, getValue()); - } - memoizedSerializedSize = size; - return size; - } - - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseFrom( - com.google.protobuf.ByteString data) - throws com.google.protobuf.InvalidProtocolBufferException { - return newBuilder().mergeFrom(data).buildParsed(); - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseFrom( - com.google.protobuf.ByteString data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return newBuilder().mergeFrom(data, extensionRegistry) - .buildParsed(); - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseFrom(byte[] data) - throws com.google.protobuf.InvalidProtocolBufferException { - return newBuilder().mergeFrom(data).buildParsed(); - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseFrom( - byte[] data, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws com.google.protobuf.InvalidProtocolBufferException { - return newBuilder().mergeFrom(data, extensionRegistry) - .buildParsed(); - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseFrom(java.io.InputStream input) - throws java.io.IOException { - return newBuilder().mergeFrom(input).buildParsed(); - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return newBuilder().mergeFrom(input, extensionRegistry) - .buildParsed(); - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseDelimitedFrom(java.io.InputStream input) - throws java.io.IOException { - Builder builder = newBuilder(); - if (builder.mergeDelimitedFrom(input)) { - return builder.buildParsed(); - } else { - return null; - } - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseDelimitedFrom( - java.io.InputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - Builder builder = newBuilder(); - if (builder.mergeDelimitedFrom(input, extensionRegistry)) { - return builder.buildParsed(); - } else { - return null; - } - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseFrom( - com.google.protobuf.CodedInputStream input) - throws java.io.IOException { - return newBuilder().mergeFrom(input).buildParsed(); - } - public static org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable parseFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - return newBuilder().mergeFrom(input, extensionRegistry) - .buildParsed(); - } - - public static Builder newBuilder() { return Builder.create(); } - public Builder newBuilderForType() { return newBuilder(); } - public static Builder newBuilder(org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable prototype) { - return newBuilder().mergeFrom(prototype); - } - public Builder toBuilder() { return newBuilder(this); } - - public static final class Builder extends - com.google.protobuf.GeneratedMessageLite.Builder< - org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable, Builder> { - private org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable result; - - // Construct using org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable.newBuilder() - private Builder() {} - - private static Builder create() { - Builder builder = new Builder(); - builder.result = new org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable(); - return builder; - } - - protected org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable internalGetResult() { - return result; - } - - public Builder clear() { - if (result == null) { - throw new IllegalStateException( - "Cannot call clear() after build()."); - } - result = new org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable(); - return this; - } - - public Builder clone() { - return create().mergeFrom(result); - } - - public org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable getDefaultInstanceForType() { - return org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable.getDefaultInstance(); - } - - public boolean isInitialized() { - return result.isInitialized(); - } - public org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable build() { - if (result != null && !isInitialized()) { - throw newUninitializedMessageException(result); - } - return buildPartial(); - } - - private org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable buildParsed() - throws com.google.protobuf.InvalidProtocolBufferException { - if (!isInitialized()) { - throw newUninitializedMessageException( - result).asInvalidProtocolBufferException(); - } - return buildPartial(); - } - - public org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable buildPartial() { - if (result == null) { - throw new IllegalStateException( - "build() has already been called on this Builder."); - } - org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable returnMe = result; - result = null; - return returnMe; - } - - public Builder mergeFrom(org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable other) { - if (other == org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable.getDefaultInstance()) return this; - if (other.hasName()) { - setName(other.getName()); - } - if (other.hasValue()) { - setValue(other.getValue()); - } - return this; - } - - public Builder mergeFrom( - com.google.protobuf.CodedInputStream input, - com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - while (true) { - int tag = input.readTag(); - switch (tag) { - case 0: - return this; - default: { - if (!parseUnknownField(input, extensionRegistry, tag)) { - return this; - } - break; - } - case 10: { - setName(input.readString()); - break; - } - case 18: { - setValue(input.readString()); - break; - } - } - } - } - - - // required string name = 1; - public boolean hasName() { - return result.hasName(); - } - public java.lang.String getName() { - return result.getName(); - } - public Builder setName(java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - result.hasName = true; - result.name_ = value; - return this; - } - public Builder clearName() { - result.hasName = false; - result.name_ = getDefaultInstance().getName(); - return this; - } - - // required string value = 2; - public boolean hasValue() { - return result.hasValue(); - } - public java.lang.String getValue() { - return result.getValue(); - } - public Builder setValue(java.lang.String value) { - if (value == null) { - throw new NullPointerException(); - } - result.hasValue = true; - result.value_ = value; - return this; - } - public Builder clearValue() { - result.hasValue = false; - result.value_ = getDefaultInstance().getValue(); - return this; - } - - // @@protoc_insertion_point(builder_scope:org.jetbrains.jpsservice.Message.Request.SetupCommand.PathVariable) - } - - static { - defaultInstance = new PathVariable(true); - org.jetbrains.jps.api.JpsRemoteProto.internalForceInit(); - defaultInstance.initFields(); - } - - // @@protoc_insertion_point(class_scope:org.jetbrains.jpsservice.Message.Request.SetupCommand.PathVariable) - } - public static final class GlobalLibrary extends com.google.protobuf.GeneratedMessageLite { // Use GlobalLibrary.newBuilder() to construct. @@ -2415,15 +2504,15 @@ public final class JpsRemoteProto { // @@protoc_insertion_point(class_scope:org.jetbrains.jpsservice.Message.Request.SetupCommand.GlobalLibrary) } - // repeated .org.jetbrains.jpsservice.Message.Request.SetupCommand.PathVariable path_variable = 1; + // repeated .org.jetbrains.jpsservice.Message.KeyValuePair path_variable = 1; public static final int PATH_VARIABLE_FIELD_NUMBER = 1; - private java.util.List pathVariable_ = + private java.util.List pathVariable_ = java.util.Collections.emptyList(); - public java.util.List getPathVariableList() { + public java.util.List getPathVariableList() { return pathVariable_; } public int getPathVariableCount() { return pathVariable_.size(); } - public org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable getPathVariable(int index) { + public org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair getPathVariable(int index) { return pathVariable_.get(index); } @@ -2449,7 +2538,7 @@ public final class JpsRemoteProto { private void initFields() { } public final boolean isInitialized() { - for (org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable element : getPathVariableList()) { + for (org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair element : getPathVariableList()) { if (!element.isInitialized()) return false; } for (org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.GlobalLibrary element : getGlobalLibraryList()) { @@ -2461,7 +2550,7 @@ public final class JpsRemoteProto { public void writeTo(com.google.protobuf.CodedOutputStream output) throws java.io.IOException { getSerializedSize(); - for (org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable element : getPathVariableList()) { + for (org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair element : getPathVariableList()) { output.writeMessage(1, element); } for (org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.GlobalLibrary element : getGlobalLibraryList()) { @@ -2478,7 +2567,7 @@ public final class JpsRemoteProto { if (size != -1) return size; size = 0; - for (org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable element : getPathVariableList()) { + for (org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair element : getPathVariableList()) { size += com.google.protobuf.CodedOutputStream .computeMessageSize(1, element); } @@ -2644,7 +2733,7 @@ public final class JpsRemoteProto { if (other == org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.getDefaultInstance()) return this; if (!other.pathVariable_.isEmpty()) { if (result.pathVariable_.isEmpty()) { - result.pathVariable_ = new java.util.ArrayList(); + result.pathVariable_ = new java.util.ArrayList(); } result.pathVariable_.addAll(other.pathVariable_); } @@ -2676,7 +2765,7 @@ public final class JpsRemoteProto { break; } case 10: { - org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable.Builder subBuilder = org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable.newBuilder(); + org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.Builder subBuilder = org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.newBuilder(); input.readMessage(subBuilder, extensionRegistry); addPathVariable(subBuilder.buildPartial()); break; @@ -2696,48 +2785,48 @@ public final class JpsRemoteProto { } - // repeated .org.jetbrains.jpsservice.Message.Request.SetupCommand.PathVariable path_variable = 1; - public java.util.List getPathVariableList() { + // repeated .org.jetbrains.jpsservice.Message.KeyValuePair path_variable = 1; + public java.util.List getPathVariableList() { return java.util.Collections.unmodifiableList(result.pathVariable_); } public int getPathVariableCount() { return result.getPathVariableCount(); } - public org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable getPathVariable(int index) { + public org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair getPathVariable(int index) { return result.getPathVariable(index); } - public Builder setPathVariable(int index, org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable value) { + public Builder setPathVariable(int index, org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair value) { if (value == null) { throw new NullPointerException(); } result.pathVariable_.set(index, value); return this; } - public Builder setPathVariable(int index, org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable.Builder builderForValue) { + public Builder setPathVariable(int index, org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.Builder builderForValue) { result.pathVariable_.set(index, builderForValue.build()); return this; } - public Builder addPathVariable(org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable value) { + public Builder addPathVariable(org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair value) { if (value == null) { throw new NullPointerException(); } if (result.pathVariable_.isEmpty()) { - result.pathVariable_ = new java.util.ArrayList(); + result.pathVariable_ = new java.util.ArrayList(); } result.pathVariable_.add(value); return this; } - public Builder addPathVariable(org.jetbrains.jps.api.JpsRemoteProto.Message.Request.SetupCommand.PathVariable.Builder builderForValue) { + public Builder addPathVariable(org.jetbrains.jps.api.JpsRemoteProto.Message.KeyValuePair.Builder builderForValue) { if (result.pathVariable_.isEmpty()) { - result.pathVariable_ = new java.util.ArrayList(); + result.pathVariable_ = new java.util.ArrayList(); } result.pathVariable_.add(builderForValue.build()); return this; } public Builder addAllPathVariable( - java.lang.Iterable values) { + java.lang.Iterable values) { if (result.pathVariable_.isEmpty()) { - result.pathVariable_ = new java.util.ArrayList(); + result.pathVariable_ = new java.util.ArrayList(); } super.addAll(values, result.pathVariable_); return this; diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java b/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java index 5df797fd4519..b93378dddacb 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/ProtoUtil.java @@ -28,23 +28,34 @@ public class ProtoUtil { return builder.build(); } - public static JpsRemoteProto.Message.Request createMakeRequest(String project, Collection modules, Collection artifacts) { - return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.MAKE, project, modules, artifacts, Collections.emptyList()); + public static JpsRemoteProto.Message.Request createMakeRequest(String project, + Collection modules, + Collection artifacts, + final Map userData) { + return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.MAKE, project, modules, artifacts, + userData, Collections.emptyList()); } public static JpsRemoteProto.Message.Request createForceCompileRequest(String project, Collection modules, - Collection artifacts, Collection paths) { - return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.FORCED_COMPILATION, project, modules, artifacts, paths); + Collection artifacts, + Collection paths, + final Map userData) { + return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.FORCED_COMPILATION, project, modules, artifacts, + userData, paths); } - public static JpsRemoteProto.Message.Request createRebuildRequest(String project) { + public static JpsRemoteProto.Message.Request createRebuildRequest(String project, final Map userData) { return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.REBUILD, project, Collections.emptyList(), - Collections.emptyList(), Collections.emptyList()); + Collections.emptyList(), userData, Collections.emptyList()); } - public static JpsRemoteProto.Message.Request createCleanRequest(String project, Collection modules, Collection artifacts) { - return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.CLEAN, project, modules, artifacts, Collections.emptyList()); + public static JpsRemoteProto.Message.Request createCleanRequest(String project, + Collection modules, + Collection artifacts, + final Map userData) { + return createCompileRequest(JpsRemoteProto.Message.Request.CompilationRequest.Type.CLEAN, project, modules, artifacts, + userData, Collections.emptyList()); } public static JpsRemoteProto.Message.Request createCancelRequest(UUID compileSessionId) { @@ -53,22 +64,34 @@ public class ProtoUtil { return JpsRemoteProto.Message.Request.newBuilder().setRequestType(JpsRemoteProto.Message.Request.Type.CANCEL_BUILD_COMMAND).setCancelBuildCommand(builder.build()).build(); } - public static JpsRemoteProto.Message.Request createCompileRequest(final JpsRemoteProto.Message.Request.CompilationRequest.Type command, String project, Collection modules, - Collection artifacts, Collection paths) { + public static JpsRemoteProto.Message.Request createCompileRequest( + final JpsRemoteProto.Message.Request.CompilationRequest.Type command, + String project, + Collection modules, + Collection artifacts, Map userData, Collection paths) { + final JpsRemoteProto.Message.Request.CompilationRequest.Builder builder = JpsRemoteProto.Message.Request.CompilationRequest.newBuilder().setCommandType( command); builder.setProjectId(project); - if (modules.size() > 0) { + if (!modules.isEmpty()) { builder.addAllModuleName(modules); } - if (artifacts.size() > 0) { + if (!artifacts.isEmpty()) { builder.addAllArtifactName(artifacts); } - if (paths.size() > 0) { + if (!userData.isEmpty()) { + for (Map.Entry entry : userData.entrySet()) { + final String key = entry.getKey(); + final String value = entry.getValue(); + if (key != null && value != null) { + builder.addBuilderParameter(createPair(key, value)); + } + } + } + if (!paths.isEmpty()) { builder.addAllFilePath(paths); } - return JpsRemoteProto.Message.Request.newBuilder().setRequestType(JpsRemoteProto.Message.Request.Type.COMPILE_REQUEST).setCompileRequest( - builder.build()).build(); + return JpsRemoteProto.Message.Request.newBuilder().setRequestType(JpsRemoteProto.Message.Request.Type.COMPILE_REQUEST).setCompileRequest(builder.build()).build(); } public static JpsRemoteProto.Message.Request createShutdownRequest(boolean cancelRunningBuilds) { @@ -101,9 +124,7 @@ public class ProtoUtil { final String var = entry.getKey(); final String value = entry.getValue(); if (var != null && value != null) { - final JpsRemoteProto.Message.Request.SetupCommand.PathVariable.Builder pathVarBuilder = - JpsRemoteProto.Message.Request.SetupCommand.PathVariable.newBuilder(); - cmdBuilder.addPathVariable(pathVarBuilder.setName(var).setValue(value).build()); + cmdBuilder.addPathVariable(createPair(var, value)); } } } @@ -131,6 +152,10 @@ public class ProtoUtil { return JpsRemoteProto.Message.Request.newBuilder().setRequestType(JpsRemoteProto.Message.Request.Type.SETUP_COMMAND).setSetupCommand(cmdBuilder.build()).build(); } + public static JpsRemoteProto.Message.KeyValuePair createPair(String key, String value) { + return JpsRemoteProto.Message.KeyValuePair.newBuilder().setKey(key).setValue(value).build(); + } + public static JpsRemoteProto.Message.Response createBuildStartedEvent(@Nullable String description) { return createBuildEvent(JpsRemoteProto.Message.Response.BuildEvent.Type.BUILD_STARTED, description, null, null); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java b/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java index 139eaa703e74..49b2e2a9a1d3 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java +++ b/jps/jps-builders/src/org/jetbrains/jps/client/CompileServerClient.java @@ -5,10 +5,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jps.api.*; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; /** * @author Eugene Zhuravlev @@ -28,18 +25,20 @@ public class CompileServerClient extends SimpleProtobufClient modules, final Collection artifacts, - Collection paths, JpsServerResponseHandler handler) throws Exception{ + Collection paths, + final Map userData, + JpsServerResponseHandler handler) throws Exception{ checkConnected(); final JpsRemoteProto.Message.Request request = isMake? - ProtoUtil.createMakeRequest(projectId, modules, artifacts) : - ProtoUtil.createForceCompileRequest(projectId, modules, artifacts, paths); + ProtoUtil.createMakeRequest(projectId, modules, artifacts, userData) : + ProtoUtil.createForceCompileRequest(projectId, modules, artifacts, paths, userData); return sendRequest(request, handler); } @NotNull public RequestFuture sendRebuildRequest(String projectId, JpsServerResponseHandler handler) throws Exception{ checkConnected(); - return sendRequest(ProtoUtil.createRebuildRequest(projectId), handler); + return sendRequest(ProtoUtil.createRebuildRequest(projectId, Collections.emptyMap()), handler); } @NotNull diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java index d500daa21dc0..95a64bbeb63b 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/CompileContext.java @@ -41,6 +41,7 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler private volatile boolean myErrorsFound = false; private final long myCompilationStartStamp; private final TimestampStorage myTsStorage; + private final Map myBuilderParams; private final CanceledStatus myCancelStatus; private float myDone = -1.0f; @@ -49,8 +50,15 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler boolean isProjectRebuild, ProjectChunks productionChunks, ProjectChunks testChunks, - FSState fsState, final BuildDataManager dataManager, TimestampStorage tsStorage, MessageHandler delegateMessageHandler, final ModuleRootsIndex rootsIndex, CanceledStatus cancelStatus) throws ProjectBuildException { + FSState fsState, + final BuildDataManager dataManager, + TimestampStorage tsStorage, + MessageHandler delegateMessageHandler, + final ModuleRootsIndex rootsIndex, + Map builderParams, + CanceledStatus cancelStatus) throws ProjectBuildException { myTsStorage = tsStorage; + myBuilderParams = Collections.unmodifiableMap(builderParams); myCancelStatus = cancelStatus; myCompilationStartStamp = System.currentTimeMillis(); myScope = scope; @@ -82,6 +90,11 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler return myIsProjectRebuild; } + @Nullable + public String getBuilderParameter(String paramName) { + return myBuilderParams.get(paramName); + } + public void markDirty(final File file) throws IOException { final RootDescriptor descriptor = getModuleAndRoot(file); if (descriptor != null) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java index 97fc6b25399f..bfc942b296ae 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java +++ b/jps/jps-builders/src/org/jetbrains/jps/incremental/IncProjectBuilder.java @@ -37,6 +37,7 @@ public class IncProjectBuilder { private final ProjectDescriptor myProjectDescriptor; private final BuilderRegistry myBuilderRegistry; + private final Map myBuilderParams; private final CanceledStatus myCancelStatus; private ProjectChunks myProductionChunks; private ProjectChunks myTestChunks; @@ -53,9 +54,10 @@ public class IncProjectBuilder { private final float myTotalModulesWork; private final int myTotalModuleLevelBuilderCount; - public IncProjectBuilder(ProjectDescriptor pd, BuilderRegistry builderRegistry, CanceledStatus cs) { + public IncProjectBuilder(ProjectDescriptor pd, BuilderRegistry builderRegistry, Map builderParams, CanceledStatus cs) { myProjectDescriptor = pd; myBuilderRegistry = builderRegistry; + myBuilderParams = builderParams; myCancelStatus = cs; myProductionChunks = new ProjectChunks(pd.project, ClasspathKind.PRODUCTION_COMPILE); myTestChunks = new ProjectChunks(pd.project, ClasspathKind.TEST_COMPILE); @@ -182,8 +184,10 @@ public class IncProjectBuilder { final FSState fsState = myProjectDescriptor.fsState; final ModuleRootsIndex rootsIndex = myProjectDescriptor.rootsIndex; final BuildDataManager dataManager = myProjectDescriptor.dataManager; - return new CompileContext(scope, isMake, isProjectRebuild, myProductionChunks, myTestChunks, fsState, dataManager, tsStorage, - myMessageDispatcher, rootsIndex, myCancelStatus); + return new CompileContext( + scope, isMake, isProjectRebuild, myProductionChunks, myTestChunks, fsState, dataManager, tsStorage, myMessageDispatcher, rootsIndex, + myBuilderParams, myCancelStatus + ); } private void cleanOutputRoots(CompileContext context) throws ProjectBuildException { diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java b/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java index 2dc966b51c51..bc3739d5ae61 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ServerMessageHandler.java @@ -69,8 +69,8 @@ class ServerMessageHandler extends SimpleChannelHandler { case SETUP_COMMAND: final Map pathVars = new HashMap(); final JpsRemoteProto.Message.Request.SetupCommand setupCommand = request.getSetupCommand(); - for (JpsRemoteProto.Message.Request.SetupCommand.PathVariable variable : setupCommand.getPathVariableList()) { - pathVars.put(variable.getName(), variable.getValue()); + for (JpsRemoteProto.Message.KeyValuePair variable : setupCommand.getPathVariableList()) { + pathVars.put(variable.getKey(), variable.getValue()); } final List libs = new ArrayList(); for (JpsRemoteProto.Message.Request.SetupCommand.GlobalLibrary library : setupCommand.getGlobalLibraryList()) { @@ -187,8 +187,14 @@ class ServerMessageHandler extends SimpleChannelHandler { case REBUILD: { channelContext.setAttachment(sessionId); final BuildType buildType = convertCompileType(compileType); - final CompilationTask task = new CompilationTask(sessionId, channelContext, projectId, buildType, compileRequest.getModuleNameList(), - compileRequest.getArtifactNameList(), compileRequest.getFilePathList()); + final List modules = compileRequest.getModuleNameList(); + final List artifacts = compileRequest.getArtifactNameList(); + final List paths = compileRequest.getFilePathList(); + final Map builderParams = new HashMap(); + for (JpsRemoteProto.Message.KeyValuePair pair : compileRequest.getBuilderParameterList()) { + builderParams.put(pair.getKey(), pair.getValue()); + } + final CompilationTask task = new CompilationTask(sessionId, channelContext, projectId, buildType, modules, artifacts, builderParams, paths); final RunnableFuture future = getCompileTaskExecutor(projectId).submit(task); myBuildsInProgress.add(new Pair(future, task)); return null; @@ -230,6 +236,7 @@ class ServerMessageHandler extends SimpleChannelHandler { private final String myProjectPath; private final BuildType myBuildType; private final Collection myArtifacts; + private final Map myBuilderParams; private final Collection myPaths; private final Set myModules; private volatile boolean myCanceled = false; @@ -240,12 +247,13 @@ class ServerMessageHandler extends SimpleChannelHandler { BuildType buildType, Collection modules, Collection artifacts, - Collection paths) { + Map builderParams, Collection paths) { mySessionId = sessionId; myChannelContext = channelContext; myProjectPath = projectId; myBuildType = buildType; myArtifacts = artifacts; + myBuilderParams = builderParams; myPaths = paths; myModules = new HashSet(modules); } @@ -264,7 +272,7 @@ class ServerMessageHandler extends SimpleChannelHandler { final Ref hasErrors = new Ref(false); final Ref markedFilesUptodate = new Ref(false); try { - ServerState.getInstance().startBuild(myProjectPath, myBuildType, myModules, myArtifacts, myPaths, new MessageHandler() { + ServerState.getInstance().startBuild(myProjectPath, myBuildType, myModules, myArtifacts, myBuilderParams, myPaths, new MessageHandler() { public void processMessage(BuildMessage buildMessage) { final JpsRemoteProto.Message.Response response; if (buildMessage instanceof FileGeneratedEvent) { diff --git a/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java b/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java index d8b201ba316c..30b878bf2e76 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java +++ b/jps/jps-builders/src/org/jetbrains/jps/server/ServerState.java @@ -124,7 +124,7 @@ class ServerState { } public void startBuild(String projectPath, BuildType buildType, Set modules, Collection artifacts, - Collection paths, final MessageHandler msgHandler, CanceledStatus cs) throws Throwable{ + Map builderParams, Collection paths, final MessageHandler msgHandler, CanceledStatus cs) throws Throwable{ final String projectName = getProjectName(projectPath); @@ -167,7 +167,7 @@ class ServerState { try { final CompileScope compileScope = createCompilationScope(buildType, pd, modules, artifacts, paths); - final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), cs); + final IncProjectBuilder builder = new IncProjectBuilder(pd, BuilderRegistry.getInstance(), builderParams, cs); if (msgHandler != null) { builder.addMessageHandler(msgHandler); } diff --git a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java index 48ed13b9920e..549f4f5772ca 100644 --- a/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java +++ b/jps/jps-builders/testSrc/org/jetbrains/ether/IncrementalTestCase.java @@ -325,7 +325,7 @@ public abstract class IncrementalTestCase extends TestCase { try { new IncProjectBuilder( - projectDescriptor, BuilderRegistry.getInstance(), CanceledStatus.NULL + projectDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL ).build( new AllProjectScope(project, Collections.emptySet(), true), false, true ); @@ -337,7 +337,7 @@ public abstract class IncrementalTestCase extends TestCase { } new IncProjectBuilder( - projectDescriptor, BuilderRegistry.getInstance(), CanceledStatus.NULL + projectDescriptor, BuilderRegistry.getInstance(), Collections.emptyMap(), CanceledStatus.NULL ).build( new AllProjectScope(project, Collections.emptySet(), false), true, false ); diff --git a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java index cd03a44c613d..439465eb09f1 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java +++ b/platform/lang-impl/src/com/intellij/ide/util/FileStructurePopup.java @@ -111,6 +111,7 @@ public class FileStructurePopup implements Disposable { private PsiElement myInitialPsiElement; private Map myCheckBoxes = new HashMap(); private String myTestSearchFilter; + private final ActionCallback myTreeHasBuilt = new ActionCallback(); public FileStructurePopup(StructureViewModel structureViewModel, @Nullable Editor editor, @@ -119,6 +120,7 @@ public class FileStructurePopup implements Disposable { final boolean applySortAndFilter) { myProject = project; myEditor = editor; + IdeFocusManager.getInstance(myProject).typeAheadUntil(myTreeHasBuilt); myBaseTreeModel = structureViewModel; Disposer.register(this, auxDisposable); if (applySortAndFilter) { @@ -210,8 +212,6 @@ public class FileStructurePopup implements Disposable { public void show() { //final long time = System.currentTimeMillis(); - final ActionCallback treeHasBuilt = new ActionCallback(); - IdeFocusManager.getInstance(myProject).typeAheadUntil(treeHasBuilt); JComponent panel = createCenterPanel(); new MnemonicHelper().register(panel); boolean shouldSetWidth = DimensionService.getInstance().getSize(getDimensionServiceKey(), myProject) == null; @@ -250,8 +250,8 @@ public class FileStructurePopup implements Disposable { Disposer.register(myPopup, new Disposable() { @Override public void dispose() { - if (!treeHasBuilt.isDone()) { - treeHasBuilt.setRejected(); + if (!myTreeHasBuilt.isDone()) { + myTreeHasBuilt.setRejected(); } } }); @@ -275,7 +275,7 @@ public class FileStructurePopup implements Disposable { @Override public void run() { selectPsiElement(myInitialPsiElement); - treeHasBuilt.setDone(); + myTreeHasBuilt.setDone(); //long t = System.currentTimeMillis() - time; //System.out.println("Shown in " + t + "ms"); } @@ -434,13 +434,6 @@ public class FileStructurePopup implements Disposable { } }.registerCustomShortcutSet(shortcutSet, panel); - new AnAction() { - @Override - public void actionPerformed(AnActionEvent e) { - mySpeedSearch.setEnteredPrefix(""); - } - }.registerCustomShortcutSet(CustomShortcutSet.fromString(SystemInfo.isMac ? "meta BACK_SPACE" : "control BACK_SPACE"), myTree); - new AnAction() { public void actionPerformed(AnActionEvent e) { if (mySpeedSearch != null && mySpeedSearch.isPopupActive()) { diff --git a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java index 6b00860cd44c..12d00f611b57 100644 --- a/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java +++ b/platform/lang-impl/src/com/intellij/ide/util/gotoByName/GotoActionModel.java @@ -178,10 +178,11 @@ public class GotoActionModel implements ChooseByNameModel, CustomMatcherModel { } protected static Color defaultActionForeground(boolean isSelected, Presentation presentation) { - return isSelected ? UIUtil.getListSelectionForeground() - : presentation.isEnabled() && presentation.isVisible() - ? UIUtil.getListForeground() - : UIUtil.getInactiveTextColor(); + if (!presentation.isEnabled() || !presentation.isVisible()) { + return UIUtil.getInactiveTextColor(); + } + + return isSelected ? UIUtil.getListSelectionForeground() : UIUtil.getListForeground(); } public String[] getNames(boolean checkBoxState) { diff --git a/platform/platform-api/src/com/intellij/ui/MouseDragHelper.java b/platform/platform-api/src/com/intellij/ui/MouseDragHelper.java index bb0ccb0cb25a..de67b2b116b8 100644 --- a/platform/platform-api/src/com/intellij/ui/MouseDragHelper.java +++ b/platform/platform-api/src/com/intellij/ui/MouseDragHelper.java @@ -115,6 +115,7 @@ public abstract class MouseDragHelper implements MouseListener, MouseMotionListe myPressPointScreen = new RelativePoint(e).getScreenPoint(); myPressPointComponent = e.getPoint(); + processMousePressed(e); myDelta = new Dimension(); if (myDragComponent.isShowing()) { @@ -209,6 +210,9 @@ public abstract class MouseDragHelper implements MouseListener, MouseMotionListe return true; } + protected void processMousePressed(MouseEvent event) { + } + protected void processDragCancel() { } diff --git a/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java b/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java index 56e646ab8f4d..b851d9745126 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/TabInfo.java @@ -86,6 +86,12 @@ public final class TabInfo implements Queryable, PlaceProvider { private Queryable myQueryable; private DragOutDelegate myDragOutDelegate; + /** + * The tab which was selected before the mouse was pressed on this tab. Focus will be transferred to that tab if this tab is dragged + * out of its container. (IDEA-61536) + */ + private WeakReference myPreviousSelection = new WeakReference(null); + public TabInfo(final JComponent component) { myComponent = component; myPreferredFocusableComponent = component; @@ -371,6 +377,15 @@ public final class TabInfo implements Queryable, PlaceProvider { return myDragOutDelegate; } + public void setPreviousSelection(@Nullable TabInfo previousSelection) { + myPreviousSelection = new WeakReference(previousSelection); + } + + @Nullable + public TabInfo getPreviousSelection() { + return myPreviousSelection.get(); + } + public interface DragOutDelegate { void dragOutStarted(MouseEvent mouseEvent, TabInfo info); diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/DragHelper.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/DragHelper.java index c67151d77509..979f08e2fc22 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/DragHelper.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/DragHelper.java @@ -18,6 +18,7 @@ package com.intellij.ui.tabs.impl; import com.intellij.ui.InplaceButton; import com.intellij.ui.MouseDragHelper; import com.intellij.ui.ScreenUtil; +import com.intellij.ui.awt.RelativePoint; import com.intellij.ui.tabs.TabInfo; import org.jetbrains.annotations.Nullable; @@ -38,6 +39,7 @@ class DragHelper extends MouseDragHelper { Measurer myVertical = new Measurer.Height(); private TabInfo myDragOutSource; + private TabLabel myPressedTabLabel; public DragHelper(JBTabsImpl tabs) { super(tabs, tabs); @@ -81,19 +83,25 @@ class DragHelper extends MouseDragHelper { myDragOutSource.getDragOutDelegate().dragOutCancelled(myDragOutSource); } + @Override + protected void processMousePressed(MouseEvent event) { + // since selection change can cause tabs to be reordered, we need to remember the tab on which the mouse was pressed, otherwise + // we'll end up dragging the wrong tab (IDEA-65073) + myPressedTabLabel = findLabel(new RelativePoint(event).getPoint(myTabs)); + } + protected void processDrag(MouseEvent event, Point targetScreenPoint, Point startPointScreen) { if (!myTabs.isTabDraggingEnabled()) return; SwingUtilities.convertPointFromScreen(startPointScreen, myTabs); if (isDragJustStarted()) { - final TabLabel label = findLabel(startPointScreen); - if (label == null) return; + if (myPressedTabLabel == null) return; - final Rectangle labelBounds = label.getBounds(); + final Rectangle labelBounds = myPressedTabLabel.getBounds(); myHoldDelta = new Dimension(startPointScreen.x - labelBounds.x, startPointScreen.y - labelBounds.y); - myDragSource = label.getInfo(); + myDragSource = myPressedTabLabel.getInfo(); myDragRec = new Rectangle(startPointScreen, labelBounds.getSize()); myDragOriginalRec = (Rectangle)myDragRec.clone(); diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java index 67ad7b6694ec..f651f7fabcb0 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/JBTabsImpl.java @@ -147,7 +147,7 @@ public class JBTabsImpl extends JComponent private TimedDeadzone.Length myTabActionsMouseDeadzone = TimedDeadzone.DEFAULT; - private long myRemoveDefferredRequest; + private long myRemoveDeferredRequest; private boolean myTestMode; private JBTabsPosition myPosition = JBTabsPosition.top; @@ -156,8 +156,6 @@ public class JBTabsImpl extends JComponent private BaseNavigationAction myNextAction; private BaseNavigationAction myPrevAction; - private boolean myWasEverShown; - private boolean myTabDraggingEnabled; private DragHelper myDragHelper; private boolean myNavigationActionsEnabled = true; @@ -884,11 +882,11 @@ public class JBTabsImpl extends JComponent private ActionCallback removeDeferred() { final ActionCallback callback = new ActionCallback(); - final long executionRequest = ++myRemoveDefferredRequest; + final long executionRequest = ++myRemoveDeferredRequest; final Runnable onDone = new Runnable() { public void run() { - if (myRemoveDefferredRequest == executionRequest) { + if (myRemoveDeferredRequest == executionRequest) { removeDeferredNow(); } @@ -1468,11 +1466,6 @@ public class JBTabsImpl extends JComponent return insets; } - private int fixInset(int inset, int addin) { - return inset + addin; - } - - public int getToolbarInset() { return getArcSize() + 1; } @@ -2903,7 +2896,7 @@ public class JBTabsImpl extends JComponent return mySingleRowLayout; } - public JBTabsPresentation setUiDecorator(UiDecorator decorator) { + public JBTabsPresentation setUiDecorator(@Nullable UiDecorator decorator) { myUiDecorator = decorator == null ? ourDefaultDecorator : decorator; applyDecoration(); return this; @@ -2989,9 +2982,7 @@ public class JBTabsImpl extends JComponent ActionGroup group = selection.getGroup(); if (group != null) { AnAction[] children = group.getChildren(null); - for (int i = 0; i < children.length; i++) { - result.add(children[i]); - } + Collections.addAll(result, children); } } diff --git a/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java b/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java index 63237e5e51b8..a35f05d2f2c3 100644 --- a/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java +++ b/platform/platform-api/src/com/intellij/ui/tabs/impl/TabLabel.java @@ -34,6 +34,7 @@ import com.intellij.ui.tabs.UiDecorator; import com.intellij.ui.tabs.impl.table.TableLayout; import com.intellij.util.PairConsumer; import com.intellij.util.ui.Centerizer; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.EmptyBorder; @@ -87,6 +88,10 @@ public class TabLabel extends JPanel { addMouseListener(new MouseAdapter() { public void mousePressed(final MouseEvent e) { if (myTabs.isSelectionClick(e, false) && myInfo.isEnabled()) { + final TabInfo selectedInfo = myTabs.getSelectedInfo(); + if (selectedInfo != myInfo) { + myInfo.setPreviousSelection(selectedInfo); + } Component c = SwingUtilities.getDeepestComponentAt(e.getComponent(), e.getX(), e.getY()); if (c instanceof InplaceButton) return; myTabs.select(info, true); @@ -101,6 +106,7 @@ public class TabLabel extends JPanel { } public void mouseReleased(final MouseEvent e) { + myInfo.setPreviousSelection(null); handlePopup(e); } }); @@ -385,8 +391,8 @@ public class TabLabel extends JPanel { } } - private static int getValue(int curentValue, int newValue) { - return newValue != -1 ? newValue : curentValue; + private static int getValue(int currentValue, int newValue) { + return newValue != -1 ? newValue : currentValue; } public void setTabActions(ActionGroup group) { @@ -530,6 +536,7 @@ public class TabLabel extends JPanel { } + @Nullable public BufferedImage getInactiveStateImage(Rectangle effectiveBounds) { BufferedImage img = null; if (myLastPaintedInactiveImageBounds != null && myLastPaintedInactiveImageBounds.getSize().equals(effectiveBounds.getSize())) { @@ -541,7 +548,7 @@ public class TabLabel extends JPanel { return img; } - public void setInactiveStateImage(BufferedImage img) { + public void setInactiveStateImage(@Nullable BufferedImage img) { if (myInactiveStateImage != null && img != myInactiveStateImage) { myInactiveStateImage.flush(); } diff --git a/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeStructure.java b/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeStructure.java index 7a3fce1253bc..2f9403d92d55 100644 --- a/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeStructure.java +++ b/platform/platform-api/src/com/intellij/ui/treeStructure/filtered/FilteringTreeStructure.java @@ -100,6 +100,7 @@ public class FilteringTreeStructure extends AbstractTreeStructure { } private void setUnknown(FilteringNode node) { + if (node.state == State.UNKNOWN) return; node.state = State.UNKNOWN; List nodes = myNodesCache.get(node); if (nodes != null) { diff --git a/platform/platform-impl/src/com/intellij/notification/EventLog.java b/platform/platform-impl/src/com/intellij/notification/EventLog.java index bfd2dfc15bd9..d4b39dfdff33 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLog.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLog.java @@ -121,7 +121,7 @@ public class EventLog implements Notifications { return getLogModel(project).getStatusMessage(); } - public static LogEntry formatForLog(@NotNull final Notification notification) { + public static LogEntry formatForLog(@NotNull final Notification notification, String indent) { DocumentImpl logDoc = new DocumentImpl(true); AtomicBoolean showMore = new AtomicBoolean(false); Map links = new LinkedHashMap(); @@ -141,7 +141,7 @@ public class EventLog implements Notifications { String status = getStatusText(logDoc, showMore, lineSeparators, hasHtml); - indentNewLines(logDoc, lineSeparators, afterTitle, hasHtml); + indentNewLines(logDoc, lineSeparators, afterTitle, hasHtml, indent); ArrayList> list = new ArrayList>(); for (RangeMarker marker : links.keySet()) { @@ -165,7 +165,7 @@ public class EventLog implements Notifications { return new LogEntry(logDoc.getText(), status, list); } - private static void indentNewLines(DocumentImpl logDoc, List lineSeparators, RangeMarker afterTitle, boolean hasHtml) { + private static void indentNewLines(DocumentImpl logDoc, List lineSeparators, RangeMarker afterTitle, boolean hasHtml, String indent) { if (!hasHtml) { int i = -1; while (true) { @@ -187,8 +187,8 @@ public class EventLog implements Notifications { continue; } - logDoc.replaceString(start, separator.getEndOffset(), "\n\t"); - nextLineStart = start + 2; + logDoc.replaceString(start, separator.getEndOffset(), "\n" + indent); + nextLineStart = start + 1 + indent.length(); while (nextLineStart < logDoc.getTextLength() && Character.isWhitespace(logDoc.getCharsSequence().charAt(nextLineStart))) { logDoc.deleteString(nextLineStart, nextLineStart + 1); } @@ -234,8 +234,9 @@ public class EventLog implements Notifications { int linkEnd = content.indexOf(A_CLOSING, tagMatcher.end()); if (linkEnd > 0) { String linkText = content.substring(tagMatcher.end(), linkEnd).replaceAll(TAG_PATTERN.pattern(), ""); + int linkStart = document.getTextLength(); appendText(document, linkText); - links.put(document.createRangeMarker(new TextRange(document.getTextLength() - linkText.length(), document.getTextLength())), + links.put(document.createRangeMarker(new TextRange(linkStart, document.getTextLength())), new NotificationHyperlinkInfo(notification, href)); content = content.substring(linkEnd + A_CLOSING.length()); continue; diff --git a/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java b/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java index f298cad20cdb..f4b45cd6f86c 100644 --- a/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java +++ b/platform/platform-impl/src/com/intellij/notification/EventLogConsole.java @@ -38,6 +38,7 @@ import com.intellij.openapi.util.Disposer; import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.TextRange; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.awt.RelativePoint; import com.intellij.util.EditorPopupHandler; import com.intellij.util.text.DateFormatUtil; @@ -137,10 +138,11 @@ class EventLogConsole { if (notificationTime == null) { return; } - - append(document, DateFormatUtil.formatTimeWithSeconds(notificationTime) + " "); - EventLog.LogEntry pair = EventLog.formatForLog(notification); + String date = DateFormatUtil.formatTimeWithSeconds(notificationTime) + " "; + append(document, date); + + EventLog.LogEntry pair = EventLog.formatForLog(notification, StringUtil.repeatSymbol(' ', date.length())); final NotificationType type = notification.getType(); TextAttributesKey key = type == NotificationType.ERROR diff --git a/platform/platform-impl/src/com/intellij/notification/impl/actions/NotificationTestAction.java b/platform/platform-impl/src/com/intellij/notification/impl/actions/NotificationTestAction.java index 4e998c2833b0..a1e9e584c843 100644 --- a/platform/platform-impl/src/com/intellij/notification/impl/actions/NotificationTestAction.java +++ b/platform/platform-impl/src/com/intellij/notification/impl/actions/NotificationTestAction.java @@ -61,7 +61,7 @@ public class NotificationTestAction extends AnAction implements DumbAware { }; final Notification notification = new Notification(TEST_GROUP_ID, "This is a test notification", //"a", - "You can close this very very very very long notification by clicking this link. Long long long long. It should be long. Very long. Too long. And even longer.", + "You can
close this very

very very very long notification by clicking this link. Long long long long. It should be long. Very long. Too long. And even longer.", type, listener); messageBus.syncPublisher(Notifications.TOPIC).notify(notification); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java index 20a19762b1b8..b24815f3f014 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileEditor/impl/EditorTabbedContainer.java @@ -212,7 +212,12 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget public ActionCallback removeTabAt(final int componentIndex, int indexToSelect, boolean transferFocus) { TabInfo toSelect = indexToSelect >= 0 && indexToSelect < myTabs.getTabCount() ? myTabs.getTabAt(indexToSelect) : null; - final ActionCallback callback = myTabs.removeTab(myTabs.getTabAt(componentIndex), toSelect, transferFocus); + final TabInfo info = myTabs.getTabAt(componentIndex); + // removing hidden tab happens on end of drag-out, we've already selected the correct tab for this case in dragOutStarted + if (info.isHidden()) { + toSelect = null; + } + final ActionCallback callback = myTabs.removeTab(info, toSelect, transferFocus); return myProject.isOpen() ? callback : new ActionCallback.Done(); } @@ -554,8 +559,12 @@ final class EditorTabbedContainer implements Disposable, CloseAction.CloseTarget @Override public void dragOutStarted(MouseEvent mouseEvent, TabInfo info) { + final TabInfo previousSelection = info.getPreviousSelection(); final Image img = myTabs.getComponentImage(info); info.setHidden(true); + if (previousSelection != null) { + myTabs.select(previousSelection, true); + } myFile = (VirtualFile)info.getObject(); Presentation presentation = new Presentation(info.getText()); diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/StatusPanel.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/StatusPanel.java index 3f90f74fd95d..53f1f9e0ff04 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/StatusPanel.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/status/StatusPanel.java @@ -161,7 +161,7 @@ class StatusPanel extends JPanel { @Override public void run() { assert statusMessage != null; - String text = EventLog.formatForLog(statusMessage.first).status; + String text = EventLog.formatForLog(statusMessage.first, "").status; if (myDirty || System.currentTimeMillis() - statusMessage.second >= DateFormatUtil.MINUTE) { myTimeStart = text.length() + 1; text += " (" + StringUtil.decapitalize(DateFormatUtil.formatPrettyDateTime(statusMessage.second)) + ")"; diff --git a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java index 49615e70d6ed..797edb0b4f98 100644 --- a/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java +++ b/platform/platform-impl/src/com/intellij/ui/SpeedSearchBase.java @@ -17,16 +17,21 @@ package com.intellij.ui; import com.intellij.featureStatistics.FeatureUsageTracker; import com.intellij.ide.DataManager; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CustomShortcutSet; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; import com.intellij.openapi.wm.ex.ToolWindowManagerEx; import com.intellij.openapi.wm.ex.ToolWindowManagerListener; +import com.intellij.psi.codeStyle.NameUtil; import com.intellij.ui.speedSearch.SpeedSearchSupply; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NonNls; @@ -78,6 +83,23 @@ public abstract class SpeedSearchBase extends SpeedSear } }); + new AnAction() { + @Override + public void actionPerformed(AnActionEvent e) { + final String prefix = getEnteredPrefix(); + assert prefix != null; + final String[] strings = NameUtil.splitNameIntoWords(prefix); + final String last = strings[strings.length - 1]; + final int i = prefix.lastIndexOf(last); + mySearchPopup.mySearchField.setText(prefix.substring(0, i).trim()); + } + + @Override + public void update(AnActionEvent e) { + e.getPresentation().setEnabled(isPopupActive() && !StringUtil.isEmpty(getEnteredPrefix())); + } + }.registerCustomShortcutSet(CustomShortcutSet.fromString(SystemInfo.isMac ? "meta BACK_SPACE" : "control BACK_SPACE"), myComponent); + installSupplyTo(component); } @@ -276,13 +298,6 @@ public abstract class SpeedSearchBase extends SpeedSear return mySearchPopup != null ? mySearchPopup.mySearchField.getText() : null; } - public void setEnteredPrefix(@NotNull String text) { - if (mySearchPopup != null) { - mySearchPopup.mySearchField.setText(text); - mySearchPopup.refreshSelection(); - } - } - public void refreshSelection() { if ( mySearchPopup != null ) mySearchPopup.refreshSelection(); } diff --git a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties index 9f45496bbc7f..294fff60b400 100644 --- a/platform/platform-resources-en/src/messages/CodeInsightBundle.properties +++ b/platform/platform-resources-en/src/messages/CodeInsightBundle.properties @@ -269,7 +269,7 @@ templates.surround.no.defined=No surround templates defined in this context templates.no.defined.with.prefix=No templates starting with ''{0}'' defined in this context templates.settings.page.title=Live Templates templates.select.template.chooser.title=Select Template -templates.export.display.name=Code templates +templates.export.display.name=Live templates templates.dialog.edit.variables.title=Edit Template Variables templates.dialog.edit.variables.border.title=Variables templates.dialog.edit.variables.action.move.up=Move &Up diff --git a/platform/platform-resources-en/src/misc/registry.properties b/platform/platform-resources-en/src/misc/registry.properties index 20657e9847e7..25819ceda9e5 100644 --- a/platform/platform-resources-en/src/misc/registry.properties +++ b/platform/platform-resources-en/src/misc/registry.properties @@ -116,7 +116,7 @@ debugger.valueTooltipAutoShow=true debugger.valueTooltipAutoShow.description=Auto show tooltip on mouse over debugger.mayBringFrameToFrontOnBreakpoint=true debugger.breakpoint.message.full.trace=false -debugger.breakpoint.message.full.trace.description='Log message to console' breakpoint action will out full stacktrace for the trhread that hit the breakpoint +debugger.breakpoint.message.full.trace.description='Log message to console' breakpoint action will out full stacktrace for the thread that hit the breakpoint filesystem.useNative=true diff --git a/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy b/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy index a974d308537b..ffd1207a39cb 100644 --- a/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy +++ b/platform/platform-tests/testSrc/com/intellij/notification/EventLogTest.groovy @@ -30,17 +30,17 @@ class EventLogTest extends LightPlatformTestCase { } public void testHtmlEntities() { - def entry = EventLog.formatForLog(new Notification("xxx", "Title", "Hello world«»", NotificationType.ERROR)) + def entry = format("Title", "Hello world«»") assert entry.message == 'Title: Hello world<<>>' } public void testParseMultilineText() { - def entry = EventLog.formatForLog(new Notification("xxx", "Title", " " + + def entry = format("Title", " " + "first line
" + "second line
" + "third
" + "Action
" + - "", NotificationType.ERROR)) + "") assert entry.status == 'Title: first line second line third // Action' assert entry.message == '''Title \tfirst line @@ -52,13 +52,13 @@ class EventLogTest extends LightPlatformTestCase { } public void testInParagraph() { - def entry = EventLog.formatForLog(new Notification("xxx", "Title", "

message

", NotificationType.ERROR)) + def entry = format("Title", "

message

") assert entry.message == 'Title: message' assert entry.status == 'Title: message' } public void testJavaSeparators() { - def entry = EventLog.formatForLog(new Notification("xxx", "Title", "fst\nsnd", NotificationType.ERROR)) + def entry = format("Title", "fst\nsnd") assert entry.message == '''Title \tfst \tsnd''' @@ -71,7 +71,7 @@ class EventLogTest extends LightPlatformTestCase { } public void testMalformedLink() throws Exception { - def entry = EventLog.formatForLog(new Notification("xxx", 'link', "content", NotificationType.ERROR)) + def entry = format('link', "content") assert entry.message == 'link: content (show balloon)' } @@ -96,7 +96,7 @@ class EventLogTest extends LightPlatformTestCase { } EventLog.LogEntry format(String title, String content) { - EventLog.formatForLog(new Notification("xxx", title, content, NotificationType.ERROR)) + EventLog.formatForLog(new Notification("xxx", title, content, NotificationType.ERROR), '\t') } public void testManyNewlines() throws Exception { @@ -107,4 +107,14 @@ class EventLogTest extends LightPlatformTestCase { \tbar''' } + public void testTeamCityLink() { + def entry = format('title', '''

You are assigned for investigation of a test failure
FtlFixesTest.testToplevelVariableLocal (IDEA Trunk), assigned by Roman Shevchenko

+

Details »

''') + assert entry.message == '''title +\tYou are assigned for investigation of a test failure +\tFtlFixesTest.testToplevelVariableLocal (IDEA Trunk), assigned by Roman Shevchenko +\tDetails >>''' + assert entry.links.collect { it.first } == [new TextRange(144, 154)] + } + } diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/checkin/BeforeCheckinDialogHandler.java b/platform/vcs-api/src/com/intellij/openapi/vcs/checkin/BeforeCheckinDialogHandler.java index cbb51c59b205..1c9ec8dcd07e 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/checkin/BeforeCheckinDialogHandler.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/checkin/BeforeCheckinDialogHandler.java @@ -1,13 +1,17 @@ package com.intellij.openapi.vcs.checkin; +import com.intellij.openapi.vcs.changes.CommitExecutor; + /** * @author irengrig * Date: 5/24/11 * Time: 7:23 PM */ -public interface BeforeCheckinDialogHandler { +public abstract class BeforeCheckinDialogHandler { /** * @return false to cancel commit + * @param executors + * @param showVcsCommit */ - boolean beforeCommitDialogShownCallback(); + public abstract boolean beforeCommitDialogShownCallback(Iterable executors, boolean showVcsCommit); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java index c46617082086..67923aa96abb 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/ui/CommitChangeListDialog.java @@ -143,8 +143,8 @@ public class CommitChangeListDialog extends DialogWrapper implements CheckinProj CheckinHandlersManager.getInstance().getMatchingVcsFactories(Arrays.asList(allActiveVcss)); for (BaseCheckinHandlerFactory factory : factoryList) { final BeforeCheckinDialogHandler handler = factory.createSystemReadyHandler(project); - if (handler != null) { - if (! handler.beforeCommitDialogShownCallback()) return false; + if (handler != null && !handler.beforeCommitDialogShownCallback(Collections.unmodifiableList(executors), showVcsCommit)) { + return false; } } diff --git a/plugins/android-designer/src/com/intellij/android/designer/designSurface/TreeOperation.java b/plugins/android-designer/src/com/intellij/android/designer/designSurface/TreeOperation.java new file mode 100644 index 000000000000..ee6ae2a370bb --- /dev/null +++ b/plugins/android-designer/src/com/intellij/android/designer/designSurface/TreeOperation.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.android.designer.designSurface; + +import com.intellij.android.designer.model.RadViewComponent; +import com.intellij.designer.componentTree.TreeEditOperation; +import com.intellij.designer.designSurface.OperationContext; +import com.intellij.designer.model.RadComponent; + +/** + * @author Alexander Lobas + */ +public class TreeOperation extends TreeEditOperation { + public TreeOperation(RadComponent host, OperationContext context) { + super(host, context); + } + + @Override + protected boolean canExecute(RadComponent insertBefore) { + return !"TableRow".equals(((RadViewComponent)myHost).getTitle()); + } + + @Override + protected void execute(RadComponent insertBefore) throws Exception { + System.out.println("Execute(" + myHost + ") insert " + myComponents + " before " + insertBefore); + } +} \ No newline at end of file diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java index 17efca5c09ca..39b3694da575 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewComponent.java @@ -51,6 +51,11 @@ public class RadViewComponent extends RadComponent { return myTitle; } + @Override + public String toString() { + return super.toString() + " - " + myTitle; + } + @Override public Rectangle getBounds() { return myBounds; diff --git a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java index b827f8eaa590..fb3f861a6807 100644 --- a/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java +++ b/plugins/android-designer/src/com/intellij/android/designer/model/RadViewLayout.java @@ -17,6 +17,8 @@ package com.intellij.android.designer.model; import com.intellij.android.designer.designSurface.CreateOperation; import com.intellij.android.designer.designSurface.MoveOperation; +import com.intellij.android.designer.designSurface.TreeOperation; +import com.intellij.designer.componentTree.TreeEditOperation; import com.intellij.designer.designSurface.ComponentDecorator; import com.intellij.designer.designSurface.EditOperation; import com.intellij.designer.designSurface.OperationContext; @@ -43,6 +45,15 @@ public class RadViewLayout extends RadLayout { @Override public EditOperation processChildOperation(OperationContext context) { + if (context.getArea().isTree()) { + if (!myContainer.getChildren().isEmpty() && TreeEditOperation.isTarget(myContainer, context)) { + /*if ("TableRow".equals(myContainer.getTitle())) { + return null; + }*/ + return new TreeOperation(myContainer, context); + } + return null; + } if (context.isMove()) { return new MoveOperation(context); } diff --git a/plugins/gradle/resources/i18n/GradleBundle.properties b/plugins/gradle/resources/i18n/GradleBundle.properties index e85e37d53385..2f5a36196e9f 100644 --- a/plugins/gradle/resources/i18n/GradleBundle.properties +++ b/plugins/gradle/resources/i18n/GradleBundle.properties @@ -55,6 +55,7 @@ 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.module.dependency=module dependency 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 diff --git a/plugins/gradle/src/META-INF/plugin.xml b/plugins/gradle/src/META-INF/plugin.xml index 71c23dd96f02..50b6a4bbf64c 100644 --- a/plugins/gradle/src/META-INF/plugin.xml +++ b/plugins/gradle/src/META-INF/plugin.xml @@ -38,6 +38,7 @@ + diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java new file mode 100644 index 000000000000..e982b0022e79 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleAbstractDependencyStructureChangesCalculator.java @@ -0,0 +1,24 @@ +package org.jetbrains.plugins.gradle.diff; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.gradle.GradleEntity; + +/** + * Manages common dependency properties like 'scope', 'exported'. + *

+ * Thread-safe. + * + * @author Denis Zhdanov + * @since 2/20/12 11:17 AM + */ +public abstract class GradleAbstractDependencyStructureChangesCalculator + implements GradleStructureChangesCalculator +{ + @Override + public void calculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context) { + // TODO den process common dependency properties here. + doCalculate(gradleEntity, intellijEntity, context); + } + + protected abstract void doCalculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context); +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleChangesCalculationContext.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleChangesCalculationContext.java new file mode 100644 index 000000000000..7511561cb088 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleChangesCalculationContext.java @@ -0,0 +1,53 @@ +package org.jetbrains.plugins.gradle.diff; + +import org.jetbrains.annotations.NotNull; + +import java.util.HashSet; +import java.util.Set; + +/** + * 'Parameter object' to use during project structure changes calculations. + *

+ * Thread-safe. + */ +public class GradleChangesCalculationContext { + + @NotNull private final Set myKnownChanges = new HashSet(); + @NotNull private final Set myCurrentChanges = new HashSet(); + + @NotNull private final PlatformFacade myPlatformFacade; + + /** + * @param knownChanges changes between the gradle and intellij project structure that has been known up until now + * @param platformFacade platform facade to use during the calculations + */ + public GradleChangesCalculationContext(@NotNull Set knownChanges, + @NotNull PlatformFacade platformFacade) + { + myKnownChanges.addAll(knownChanges); + myPlatformFacade = platformFacade; + } + + @NotNull + public Set getKnownChanges() { + return myKnownChanges; + } + + @NotNull + public Set getCurrentChanges() { + return myCurrentChanges; + } + + public void register(@NotNull GradleProjectStructureChange change) { + myCurrentChanges.add(change); + } + + public boolean hasNewChanges() { + return !myKnownChanges.equals(myCurrentChanges); + } + + @NotNull + public PlatformFacade getPlatformFacade() { + return myPlatformFacade; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java index 243003b92ff7..16ee64b7690f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleDiffUtil.java @@ -1,11 +1,17 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.module.Module; +import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.ModuleOrderEntry; +import com.intellij.openapi.roots.OrderEntry; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.gradle.*; +import org.jetbrains.plugins.gradle.model.intellij.IntellijEntityVisitor; +import org.jetbrains.plugins.gradle.util.GradleUtil; -import java.util.*; +import java.util.HashMap; +import java.util.Map; /** * Contains various utility methods for building changes between the gradle and intellij project structures. @@ -25,10 +31,10 @@ public class GradleDiffUtil { * Example: particular module has been added at the gradle side. We want to mark that module, its content root(s), dependencies etc * as gradle-local changes. * - * @param entity target gradle-local entity - * @param currentChanges holder for the changes built during the current call + * @param entity target gradle-local entity + * @param context changes calculation context to use */ - public static void buildLocalChanges(@NotNull GradleEntity entity, @NotNull final Set currentChanges) { + public static void buildLocalChanges(@NotNull GradleEntity entity, @NotNull final GradleChangesCalculationContext context) { entity.invite(new GradleEntityVisitor() { @Override public void visit(@NotNull GradleProject project) { @@ -37,7 +43,7 @@ public class GradleDiffUtil { @Override public void visit(@NotNull GradleModule module) { - currentChanges.add(new GradleModulePresenceChange(module, null)); + context.register(new GradleModulePresenceChange(module, null)); for (GradleDependency dependency : module.getDependencies()) { dependency.invite(this); } @@ -55,59 +61,56 @@ public class GradleDiffUtil { @Override public void visit(@NotNull GradleModuleDependency dependency) { - // TODO den implement + context.register(new GradleModuleDependencyPresenceChange(dependency, null)); } @Override public void visit(@NotNull GradleLibraryDependency dependency) { - currentChanges.add(new GradleLibraryDependencyPresenceChange(dependency, null)); + context.register(new GradleLibraryDependencyPresenceChange(dependency, null)); } }); } - /** - * Analogues to {@link #buildLocalChanges} but targets intellij entity. - * - * @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 currentChanges) - { - currentChanges.add(new GradleModulePresenceChange(null, module)); - // TODO den process module sub-entities here (content roots and dependencies). - } - - /** - * Analogues to {@link #buildLocalChanges} but targets intellij entity. - * - * @param libraryDependency target intellij-local library dependency that doesn't present at the gradle side - * @param currentChanges holder for the changes built during the current call - */ - public static void buildLocalChanges(@NotNull LibraryOrderEntry libraryDependency, - @NotNull Set currentChanges) - { - 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 'buildLocalChanges()' methods. * - * @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 + * @param entity target intellij-local entity that doesn't present at the gradle side + * @param context changes calculation context to use */ - public static void buildLocalChanges(@NotNull Object entity, @NotNull Set currentChanges) { + public static void buildLocalChanges(@NotNull Object entity, @NotNull final GradleChangesCalculationContext context) { if (entity instanceof GradleEntity) { - buildLocalChanges((GradleEntity)entity, currentChanges); + buildLocalChanges((GradleEntity)entity, context); } - else if (entity instanceof Module) { - buildLocalChanges((Module)entity, currentChanges); - } - else if (entity instanceof LibraryOrderEntry) { - buildLocalChanges((LibraryOrderEntry)entity, currentChanges); + else { + GradleUtil.dispatch(entity, new IntellijEntityVisitor() { + @Override + public void visit(@NotNull Project project) { + } + + @Override + public void visit(@NotNull Module module) { + context.register(new GradleModulePresenceChange(null, module)); + for (OrderEntry entry : context.getPlatformFacade().getOrderEntries(module)) { + GradleUtil.dispatch(entry, this); + } + } + + @Override + public void visit(@NotNull LibraryOrderEntry libraryDependency) { + final String libraryName = libraryDependency.getLibraryName(); + if (libraryName != null) { + context.register(new GradleLibraryDependencyPresenceChange(null, libraryDependency)); + } + } + + @Override + public void visit(@NotNull ModuleOrderEntry moduleDependency) { + final Module module = moduleDependency.getModule(); + if (module != null) { + context.register(new GradleModuleDependencyPresenceChange(null, moduleDependency)); + } + } + }); } } @@ -120,8 +123,7 @@ public class GradleDiffUtil { * @param calculator comparison strategy that works with the single entities (not collection of entities) * @param gradleEntities entities available at the gradle side * @param intellijEntities entities available at the intellij side - * @param knownChanges collection that contains known changes about the entities - * @param currentChanges holder for the changes discovered during the current call + * @param context changes calculation context * @param target intellij entity type * @param target gradle entity type */ @@ -129,8 +131,7 @@ public class GradleDiffUtil { @NotNull GradleStructureChangesCalculator calculator, @NotNull Iterable gradleEntities, @NotNull Iterable intellijEntities, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { Map intellijEntitiesByKeys = new HashMap(); for (I entity : intellijEntities) { @@ -138,17 +139,17 @@ public class GradleDiffUtil { assert previous == null; } for (G gradleEntity: gradleEntities) { - I intellijEntity = intellijEntitiesByKeys.remove(calculator.getGradleKey(gradleEntity, knownChanges)); + I intellijEntity = intellijEntitiesByKeys.remove(calculator.getGradleKey(gradleEntity, context)); if (intellijEntity == null) { - buildLocalChanges(gradleEntity, currentChanges); + buildLocalChanges(gradleEntity, context); } else { - calculator.calculate(gradleEntity, intellijEntity, knownChanges, currentChanges); + calculator.calculate(gradleEntity, intellijEntity, context); } } for (I entity : intellijEntitiesByKeys.values()) { - buildLocalChanges(entity, currentChanges); + buildLocalChanges(entity, context); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java index 68d2fe30c243..68e360327790 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryDependencyStructureChangesCalculator.java @@ -5,14 +5,12 @@ import com.intellij.openapi.roots.libraries.Library; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.gradle.GradleLibraryDependency; -import java.util.Set; - /** * @author Denis Zhdanov * @since 1/24/12 1:37 PM */ public class GradleLibraryDependencyStructureChangesCalculator - implements GradleStructureChangesCalculator + extends GradleAbstractDependencyStructureChangesCalculator { private final GradleLibraryStructureChangesCalculator myLibraryCalculator; @@ -22,28 +20,30 @@ public class GradleLibraryDependencyStructureChangesCalculator } @Override - public void calculate(@NotNull GradleLibraryDependency gradleEntity, - @NotNull LibraryOrderEntry intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + public void doCalculate(@NotNull GradleLibraryDependency gradleEntity, + @NotNull LibraryOrderEntry intellijEntity, + @NotNull GradleChangesCalculationContext context) { final Library library = intellijEntity.getLibrary(); if (library == null) { return; } - myLibraryCalculator.calculate(gradleEntity.getTarget(), library, knownChanges, currentChanges); + myLibraryCalculator.calculate(gradleEntity.getTarget(), library, context); } @NotNull @Override public Object getIntellijKey(@NotNull LibraryOrderEntry entity) { - final String result = entity.getLibraryName(); - return result == null ? "" : result; + final Library library = entity.getLibrary(); + if (library == null) { + return ""; + } + return myLibraryCalculator.getIntellijKey(library); } @NotNull @Override - public Object getGradleKey(@NotNull GradleLibraryDependency entity, @NotNull Set knownChanges) { - return myLibraryCalculator.getGradleKey(entity.getTarget(), knownChanges); + public Object getGradleKey(@NotNull GradleLibraryDependency entity, @NotNull GradleChangesCalculationContext context) { + return myLibraryCalculator.getGradleKey(entity.getTarget(), context); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java index f746329331bb..b1cf497ff872 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleLibraryStructureChangesCalculator.java @@ -25,20 +25,20 @@ public class GradleLibraryStructureChangesCalculator implements GradleStructureC @Override public void calculate(@NotNull GradleLibrary gradleEntity, @NotNull Library intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { final Set gradleBinaryPaths = new HashSet(gradleEntity.getPaths(LibraryPathType.BINARY)); + final Set intellijBinaryPaths = new HashSet(); for (VirtualFile file : intellijEntity.getFiles(OrderRootType.CLASSES)) { final String path = myPlatformFacade.getLocalFileSystemPath(file); if (!gradleBinaryPaths.remove(path)) { - currentChanges.add(new GradleMismatchedLibraryPathChange(intellijEntity, null, path)); + intellijBinaryPaths.add(path); } } - for (String binaryPath : gradleBinaryPaths) { - currentChanges.add(new GradleMismatchedLibraryPathChange(intellijEntity, binaryPath, null)); - } + if (!gradleBinaryPaths.equals(intellijBinaryPaths)) { + context.register(new GradleMismatchedLibraryPathChange(intellijEntity, gradleBinaryPaths, intellijBinaryPaths)); + } } @NotNull @@ -49,7 +49,7 @@ public class GradleLibraryStructureChangesCalculator implements GradleStructureC @NotNull @Override - public Object getGradleKey(@NotNull GradleLibrary entity, @NotNull Set knownChanges) { + public Object getGradleKey(@NotNull GradleLibrary entity, @NotNull GradleChangesCalculationContext context) { // TODO den consider the known changes return entity.getName(); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleMismatchedLibraryPathChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleMismatchedLibraryPathChange.java index c6dbdbcf2d9b..9853e006c3a6 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleMismatchedLibraryPathChange.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleMismatchedLibraryPathChange.java @@ -5,17 +5,19 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.util.GradleBundle; +import java.util.Set; + /** * @author Denis Zhdanov * @since 2/2/12 1:32 PM */ -public class GradleMismatchedLibraryPathChange extends GradleAbstractConflictingPropertyChange { +public class GradleMismatchedLibraryPathChange extends GradleAbstractConflictingPropertyChange> { private final String myLibraryName; public GradleMismatchedLibraryPathChange(@NotNull Library entity, - @Nullable String gradleValue, - @Nullable String intellijValue) + @Nullable Set gradleValue, + @Nullable Set intellijValue) throws IllegalArgumentException { super(GradleBundle.message("gradle.sync.change.library.path", entity.getName()), gradleValue, intellijValue); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyPresenceChange.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyPresenceChange.java new file mode 100644 index 000000000000..54a352245e51 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyPresenceChange.java @@ -0,0 +1,43 @@ +package org.jetbrains.plugins.gradle.diff; + +import com.intellij.openapi.roots.ModuleOrderEntry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.gradle.model.gradle.GradleModuleDependency; +import org.jetbrains.plugins.gradle.model.id.GradleEntityIdMapper; +import org.jetbrains.plugins.gradle.model.id.GradleModuleDependencyId; +import org.jetbrains.plugins.gradle.util.GradleBundle; + +/** + * @author Denis Zhdanov + * @since 2/17/12 3:14 PM + */ +public class GradleModuleDependencyPresenceChange extends GradleEntityPresenceChange { + + public GradleModuleDependencyPresenceChange(@Nullable GradleModuleDependency gradle, + @Nullable ModuleOrderEntry intellij) + { + super(GradleBundle.message("gradle.sync.change.entity.type.module.dependency"), of(gradle), of(intellij)); + } + + @Override + public void invite(@NotNull GradleProjectStructureChangeVisitor visitor) { + visitor.visit(this); + } + + @Nullable + private static GradleModuleDependencyId of(@Nullable GradleModuleDependency dependency) { + if (dependency == null) { + return null; + } + return GradleEntityIdMapper.mapEntityToId(dependency); + } + + @Nullable + private static GradleModuleDependencyId of(@Nullable ModuleOrderEntry dependency) { + if (dependency == null) { + return null; + } + return GradleEntityIdMapper.mapEntityToId(dependency); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyStructureChangesCalculator.java new file mode 100644 index 000000000000..9374b83dab87 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleDependencyStructureChangesCalculator.java @@ -0,0 +1,39 @@ +package org.jetbrains.plugins.gradle.diff; + +import com.intellij.openapi.roots.ModuleOrderEntry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.gradle.GradleModuleDependency; + +/** + * @author Denis Zhdanov + * @since 2/20/12 11:10 AM + */ +public class GradleModuleDependencyStructureChangesCalculator + extends GradleAbstractDependencyStructureChangesCalculator +{ + + @Override + public void doCalculate(@NotNull GradleModuleDependency gradleEntity, + @NotNull ModuleOrderEntry intellijEntity, + @NotNull GradleChangesCalculationContext context) + { + // Assuming that the modules referenced by the given dependencies are compared independently. + } + + @NotNull + @Override + public Object getIntellijKey(@NotNull ModuleOrderEntry entity) { + final String intellijModuleName = entity.getModuleName(); + if (intellijModuleName == null) { + return ""; + } + return intellijModuleName; + } + + @NotNull + @Override + public Object getGradleKey(@NotNull GradleModuleDependency entity, @NotNull GradleChangesCalculationContext context) { + // TODO den consider known changes here. + return entity.getTarget().getName(); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java index 5638b9df1541..1fe1c70a5f79 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleModuleStructureChangesCalculator.java @@ -16,13 +16,15 @@ package org.jetbrains.plugins.gradle.diff; import com.intellij.openapi.module.Module; -import com.intellij.openapi.roots.*; +import com.intellij.openapi.roots.LibraryOrderEntry; +import com.intellij.openapi.roots.ModuleOrderEntry; +import com.intellij.openapi.roots.OrderEntry; +import com.intellij.openapi.roots.RootPolicy; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.gradle.*; import java.util.ArrayList; import java.util.List; -import java.util.Set; /** * Encapsulates functionality of calculating changes between Gradle and IntelliJ IDEA module hierarchies. @@ -34,25 +36,24 @@ import java.util.Set; */ public class GradleModuleStructureChangesCalculator implements GradleStructureChangesCalculator { - private final GradleLibraryDependencyStructureChangesCalculator myLibraryDependencyCalculator; - private final PlatformFacade myStructureHelper; + @NotNull private final GradleLibraryDependencyStructureChangesCalculator myLibraryDependencyCalculator; + @NotNull private final GradleModuleDependencyStructureChangesCalculator myModuleDependencyCalculator; public GradleModuleStructureChangesCalculator(@NotNull GradleLibraryDependencyStructureChangesCalculator libraryDependencyCalculator, - @NotNull PlatformFacade structureHelper) + @NotNull GradleModuleDependencyStructureChangesCalculator moduleDependencyCalculator) { myLibraryDependencyCalculator = libraryDependencyCalculator; - myStructureHelper = structureHelper; + myModuleDependencyCalculator = moduleDependencyCalculator; } @Override public void calculate(@NotNull GradleModule gradleEntity, @NotNull Module intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { //TODO den process module-local settings //TODO den process content roots - checkDependencies(gradleEntity, intellijEntity, knownChanges, currentChanges); + checkDependencies(gradleEntity, intellijEntity, context); } @NotNull @@ -63,15 +64,14 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh @NotNull @Override - public Object getGradleKey(@NotNull GradleModule entity, @NotNull Set knownChanges) { + public Object getGradleKey(@NotNull GradleModule entity, @NotNull GradleChangesCalculationContext context) { // TODO den consider the known changes return entity.getName(); } private void checkDependencies(@NotNull GradleModule gradleModule, @NotNull Module intellijModule, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { // Prepare intellij part. final List intellijModuleDependencies = new ArrayList(); @@ -89,7 +89,7 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh return libraryOrderEntry; } }; - for (OrderEntry orderEntry : myStructureHelper.getOrderEntries(intellijModule)) { + for (OrderEntry orderEntry : context.getPlatformFacade().getOrderEntries(intellijModule)) { orderEntry.accept(policy, null); } @@ -112,8 +112,7 @@ public class GradleModuleStructureChangesCalculator implements GradleStructureCh } // Calculate changes. - // TODO den process module dependencies here as well. - GradleDiffUtil.calculate(myLibraryDependencyCalculator, gradleLibraryDependencies, intellijLibraryDependencies, - knownChanges, currentChanges); + GradleDiffUtil.calculate(myLibraryDependencyCalculator, gradleLibraryDependencies, intellijLibraryDependencies, context); + GradleDiffUtil.calculate(myModuleDependencyCalculator, gradleModuleDependencies, intellijModuleDependencies, context); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java index 0a41c198a88b..5b8fc2e6f680 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitor.java @@ -28,5 +28,6 @@ public interface GradleProjectStructureChangeVisitor { void visit(@NotNull GradleLanguageLevelChange change); void visit(@NotNull GradleModulePresenceChange change); void visit(@NotNull GradleLibraryDependencyPresenceChange change); + void visit(@NotNull GradleModuleDependencyPresenceChange change); void visit(@NotNull GradleMismatchedLibraryPathChange change); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java deleted file mode 100644 index 6e963b8ea895..000000000000 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangeVisitorAdapter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2000-2011 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.jetbrains.plugins.gradle.diff; - -import org.jetbrains.annotations.NotNull; - -/** - * @author Denis Zhdanov - * @since 11/16/11 8:49 PM - */ -public class GradleProjectStructureChangeVisitorAdapter implements GradleProjectStructureChangeVisitor { - - @Override - public void visit(@NotNull GradleProjectRenameChange change) { - } - - @Override - public void visit(@NotNull GradleLanguageLevelChange change) { - } - - @Override - public void visit(@NotNull GradleModulePresenceChange change) { - } - - @Override - public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { - } - - @Override - public void visit(@NotNull GradleMismatchedLibraryPathChange change) { - } -} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java index 7b64e2613f13..1c512480105e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleProjectStructureChangesCalculator.java @@ -21,25 +21,24 @@ import java.util.Set; public class GradleProjectStructureChangesCalculator implements GradleStructureChangesCalculator { private final GradleModuleStructureChangesCalculator myModuleChangesCalculator; - private final PlatformFacade myStructureHelper; + private final PlatformFacade myPlatformFacade; public GradleProjectStructureChangesCalculator(@NotNull GradleModuleStructureChangesCalculator moduleCalculator, - @NotNull PlatformFacade structureHelper) { + @NotNull PlatformFacade platformFacade) { myModuleChangesCalculator = moduleCalculator; - myStructureHelper = structureHelper; + myPlatformFacade = platformFacade; } @Override public void calculate(@NotNull GradleProject gradleEntity, @NotNull Project intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges) + @NotNull GradleChangesCalculationContext context) { - calculateProjectChanges(gradleEntity, intellijEntity, currentChanges); + calculateProjectChanges(gradleEntity, intellijEntity, context.getCurrentChanges()); final Set gradleSubEntities = gradleEntity.getModules(); - final Collection intellijSubEntities = myStructureHelper.getModules(intellijEntity); - GradleDiffUtil.calculate(myModuleChangesCalculator, gradleSubEntities, intellijSubEntities, knownChanges, currentChanges); + final Collection intellijSubEntities = myPlatformFacade.getModules(intellijEntity); + GradleDiffUtil.calculate(myModuleChangesCalculator, gradleSubEntities, intellijSubEntities, context); } @NotNull @@ -50,7 +49,7 @@ public class GradleProjectStructureChangesCalculator implements GradleStructureC @NotNull @Override - public Object getGradleKey(@NotNull GradleProject entity, @NotNull Set knownChanges) { + public Object getGradleKey(@NotNull GradleProject entity, @NotNull GradleChangesCalculationContext context) { // TODO den consider the known changes return entity.getName(); } @@ -79,7 +78,7 @@ public class GradleProjectStructureChangesCalculator implements GradleStructureC @NotNull Set currentChanges) { LanguageLevel gradleLevel = gradleProject.getLanguageLevel(); - LanguageLevel intellijLevel = myStructureHelper.getLanguageLevel(intellijProject); + LanguageLevel intellijLevel = myPlatformFacade.getLanguageLevel(intellijProject); if (gradleLevel != intellijLevel) { currentChanges.add(new GradleLanguageLevelChange(gradleLevel, intellijLevel)); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java index 53db9679b2ae..04feeaa63b4d 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/diff/GradleStructureChangesCalculator.java @@ -3,8 +3,6 @@ package org.jetbrains.plugins.gradle.diff; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.model.gradle.GradleEntity; -import java.util.Set; - /** * Defines common interface to the strategy that calculates difference between the corresponding gradle and intellij entities * (e.g. between the gradle and intellij module). @@ -20,18 +18,12 @@ public interface GradleStructureChangesCalculator { /** * Calculates changes between the given entities. - * + * * @param gradleEntity target gradle entity * @param intellijEntity target intellij entity - * @param knownChanges changes between the gradle and intellij project structure that has been known up until now - * @param currentChanges holder for the changes between the given entities discovered by the current call. Note that - * it must contain the change objects that have been known (contained at the 'knownChanges') - * but are still in place + * @param context target diff calculation context */ - void calculate(@NotNull G gradleEntity, - @NotNull I intellijEntity, - @NotNull Set knownChanges, - @NotNull Set currentChanges); + void calculate(@NotNull G gradleEntity, @NotNull I intellijEntity, @NotNull GradleChangesCalculationContext context); /** * There are three possible situations when we compare a set of gradle entities with a set of intellij entities: @@ -43,16 +35,16 @@ public interface GradleStructureChangesCalculator { * * *

- * The general idea is to map evey item at the given sets of gradle and intellij entities to particular key (both gradle and + * The general idea is to map every item at the given sets of gradle and intellij entities to particular key (both gradle and * intellij keys are expected to belong to the same class) and then compare them. Matched keys shows that corresponding - * entities should be {@link #calculate(GradleEntity, Object, Set, Set)} compared to each other}; non-matched indicate that corresponding - * entities are gradle- or intellij-local. + * entities should be {@link #calculate(GradleEntity, Object, GradleChangesCalculationContext) compared to each other}; + * non-matched indicate that corresponding entities are gradle- or intellij-local. *

* This method allows to match intellij entity to the target key. * * @param entity intellij entity to match * @return key for the given entity - * @see #getGradleKey(GradleEntity, Set) + * @see #getGradleKey(GradleEntity, GradleChangesCalculationContext) */ @NotNull Object getIntellijKey(@NotNull I entity); @@ -68,10 +60,10 @@ public interface GradleStructureChangesCalculator { * So, we take into consideration the known changes only during {@code gradle-entity -> key} processing. * * @param entity target gradle entity that should be mapped to a key - * @param knownChanges known changes between the gradle and intellij structures + * @param context changes calculation context * @return key for the given entity * @see #getIntellijKey(Object) */ @NotNull - Object getGradleKey(@NotNull G entity, @NotNull Set knownChanges); + Object getGradleKey(@NotNull G entity, @NotNull GradleChangesCalculationContext context); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java index 4f43cc086056..59550283de6e 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/GradleEntityType.java @@ -11,7 +11,7 @@ import javax.swing.*; */ public enum GradleEntityType { PROJECT(GradleIcons.PROJECT_ICON), MODULE(GradleIcons.MODULE_ICON), MODULE_DEPENDENCY(GradleIcons.MODULE_ICON), - LIBRARY_DEPENDENCY(GradleIcons.LIB_ICON), CONTENT_ROOT(GradleIcons.CONTENT_ROOT_ICON), SYNTHETIC(null); + LIBRARY(GradleIcons.LIB_ICON), LIBRARY_DEPENDENCY(GradleIcons.LIB_ICON), CONTENT_ROOT(GradleIcons.CONTENT_ROOT_ICON), SYNTHETIC(null); @Nullable private final Icon myIcon; diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/gradle/GradleModule.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/gradle/GradleModule.java index dcfeff87a3af..9a0622dd7083 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/gradle/GradleModule.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/gradle/GradleModule.java @@ -89,6 +89,10 @@ public class GradleModule extends AbstractNamedGradleEntity implements Named { myDependencies.add(dependency); } + public void clearDependencies() { + myDependencies.clear(); + } + @Override public void invite(@NotNull GradleEntityVisitor visitor) { visitor.visit(this); diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleAbstractDependencyId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleAbstractDependencyId.java new file mode 100644 index 000000000000..413b9017e6d5 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleAbstractDependencyId.java @@ -0,0 +1,55 @@ +package org.jetbrains.plugins.gradle.model.id; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleEntityOwner; +import org.jetbrains.plugins.gradle.model.GradleEntityType; + +/** + * @author Denis Zhdanov + * @since 2/20/12 12:01 PM + */ +public abstract class GradleAbstractDependencyId extends GradleAbstractEntityId { + + @NotNull private final String myOwnerModuleName; + @NotNull private final String myDependencyName; + + public GradleAbstractDependencyId(@NotNull GradleEntityType type, + @NotNull GradleEntityOwner owner, + @NotNull String ownerModuleName, + @NotNull String dependencyName) + { + super(type, owner); + myOwnerModuleName = ownerModuleName; + myDependencyName = dependencyName; + } + + @NotNull + public String getOwnerModuleName() { + return myOwnerModuleName; + } + + @NotNull + public String getDependencyName() { + return myDependencyName; + } + + @NotNull + public GradleModuleId getOwnerModuleId() { + return new GradleModuleId(getOwner(), myOwnerModuleName); + } + + @Override + public int hashCode() { + int result = 31 * super.hashCode() + myOwnerModuleName.hashCode(); + return 31 * result + myDependencyName.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!super.equals(o)) { + return false; + } + GradleAbstractDependencyId that = (GradleAbstractDependencyId)o; + return myOwnerModuleName.equals(that.myOwnerModuleName) && myDependencyName.equals(that.myDependencyName); + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleEntityIdMapper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleEntityIdMapper.java index 4d5f08219d8f..7e5c93141ff4 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleEntityIdMapper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleEntityIdMapper.java @@ -59,7 +59,7 @@ public class GradleEntityIdMapper { @Override public void visit(@NotNull GradleModuleDependency dependency) { - result.set(new GradleLibraryDependencyId(GradleEntityOwner.GRADLE, dependency.getOwnerModule().getName(), dependency.getName())); + result.set(new GradleModuleDependencyId(GradleEntityOwner.GRADLE, dependency.getOwnerModule().getName(), dependency.getName())); } @Override @@ -74,7 +74,7 @@ public class GradleEntityIdMapper { @Override public void visit(@NotNull GradleLibrary library) { - // TODO den implement + result.set(new GradleLibraryId(GradleEntityOwner.GRADLE, library.getName())); } }); } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryDependencyId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryDependencyId.java index b0584a9dc072..6ad1b6187bdc 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryDependencyId.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryDependencyId.java @@ -8,60 +8,26 @@ import org.jetbrains.plugins.gradle.model.GradleEntityType; * @author Denis Zhdanov * @since 2/14/12 1:59 PM */ -public class GradleLibraryDependencyId extends GradleAbstractEntityId { +public class GradleLibraryDependencyId extends GradleAbstractDependencyId { - @NotNull private final String myModuleName; - @NotNull private final String myLibraryName; - public GradleLibraryDependencyId(@NotNull GradleEntityOwner owner, @NotNull String moduleName, @NotNull String libraryName) { - super(GradleEntityType.LIBRARY_DEPENDENCY, owner); - myModuleName = moduleName; - myLibraryName = libraryName; + super(GradleEntityType.LIBRARY_DEPENDENCY, owner, moduleName, libraryName); } - @NotNull - public String getModuleName() { - return myModuleName; - } - - @NotNull - public String getLibraryName() { - return myLibraryName; - } - - @NotNull - public GradleModuleId getModuleId() { - return new GradleModuleId(getOwner(), myModuleName); - } - @Override public Object mapToEntity(@NotNull GradleEntityMappingContext context) { switch (getOwner()) { - case GRADLE: return context.getProjectStructureHelper().findGradleLibraryDependency(myModuleName, myLibraryName); - case INTELLIJ: return context.getProjectStructureHelper().findIntellijLibraryDependency(myModuleName, myLibraryName); + case GRADLE: return context.getProjectStructureHelper().findGradleLibraryDependency(getOwnerModuleName(), getDependencyName()); + case INTELLIJ: return context.getProjectStructureHelper().findIntellijLibraryDependency(getOwnerModuleName(), getDependencyName()); } throw new IllegalStateException(String.format( - "Can't map id to the target library dependency. Owner: %s, module: '%s', library: '%s'", getOwner(), myModuleName, myLibraryName + "Can't map id to the target library dependency. Owner: %s, module: '%s', library: '%s'", + getOwner(), getOwnerModuleName(), getDependencyName() )); } - @Override - public int hashCode() { - int result = 31 * super.hashCode() + myModuleName.hashCode(); - return 31 * result + myLibraryName.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (!super.equals(o)) { - return false; - } - GradleLibraryDependencyId that = (GradleLibraryDependencyId)o; - return myModuleName.equals(that.myModuleName) && myLibraryName.equals(that.myLibraryName); - } - @Override public String toString() { - return String.format("library dependency:owner module='%s'|library='%s'", myModuleName, myLibraryName); + return String.format("library dependency:owner module='%s'|library='%s'", getOwnerModuleName(), getDependencyName()); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryId.java new file mode 100644 index 000000000000..803262104548 --- /dev/null +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleLibraryId.java @@ -0,0 +1,49 @@ +package org.jetbrains.plugins.gradle.model.id; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.gradle.model.GradleEntityOwner; +import org.jetbrains.plugins.gradle.model.GradleEntityType; + +/** + * @author Denis Zhdanov + * @since 2/20/12 7:12 PM + */ +public class GradleLibraryId extends GradleAbstractEntityId { + + @NotNull private final String myLibraryName; + + public GradleLibraryId(@NotNull GradleEntityOwner owner, @NotNull String libraryName) { + super(GradleEntityType.LIBRARY, owner); + myLibraryName = libraryName; + } + + @Override + public Object mapToEntity(@NotNull GradleEntityMappingContext context) { + switch (getOwner()) { + case GRADLE: return context.getProjectStructureHelper().findGradleLibrary(myLibraryName); + case INTELLIJ: return context.getProjectStructureHelper().findIntellijLibrary(myLibraryName); + } + throw new IllegalStateException(String.format( + "Can't map library id to the target library. Id owner: %s, name: '%s'", getOwner(), myLibraryName + )); + } + + @Override + public int hashCode() { + return 31 * super.hashCode() + myLibraryName.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (!super.equals(o)) { + return false; + } + GradleLibraryId that = (GradleLibraryId)o; + return myLibraryName.equals(that.myLibraryName); + } + + @Override + public String toString() { + return "library '" + myLibraryName + "'"; + } +} diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleDependencyId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleDependencyId.java index 285626fdb950..342962b324a5 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleDependencyId.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleDependencyId.java @@ -8,46 +8,26 @@ import org.jetbrains.plugins.gradle.model.GradleEntityType; * @author Denis Zhdanov * @since 2/14/12 2:06 PM */ -public class GradleModuleDependencyId extends GradleAbstractEntityId { +public class GradleModuleDependencyId extends GradleAbstractDependencyId { - @NotNull private final String myOwnerModuleName; - @NotNull private final String myDependencyModuleName; - public GradleModuleDependencyId(@NotNull GradleEntityOwner owner, @NotNull String ownerModuleName, @NotNull String dependencyModuleName) { - super(GradleEntityType.MODULE, owner); - myOwnerModuleName = ownerModuleName; - myDependencyModuleName = dependencyModuleName; + super(GradleEntityType.MODULE_DEPENDENCY, owner, ownerModuleName, dependencyModuleName); } @Override public Object mapToEntity(@NotNull GradleEntityMappingContext context) { switch (getOwner()) { - case GRADLE: return context.getProjectStructureHelper().findGradleModuleDependency(myOwnerModuleName, myDependencyModuleName); - case INTELLIJ: return context.getProjectStructureHelper().findIntellijModuleDependency(myOwnerModuleName, myDependencyModuleName); + case GRADLE: return context.getProjectStructureHelper().findGradleModuleDependency(getOwnerModuleName(), getDependencyName()); + case INTELLIJ: return context.getProjectStructureHelper().findIntellijModuleDependency(getOwnerModuleName(), getDependencyName()); } throw new IllegalStateException(String.format( "Can't map id to the target module dependency. Owner: %s, owner module: '%s', dependency module: '%s'", - getOwner(), myOwnerModuleName, myDependencyModuleName + getOwner(), getOwnerModuleName(), getDependencyName() )); } - @Override - public int hashCode() { - int result = 31 * super.hashCode() + myOwnerModuleName.hashCode(); - return 31 * result + myDependencyModuleName.hashCode(); - } - - @Override - public boolean equals(Object o) { - if (!super.equals(o)) { - return false; - } - GradleModuleDependencyId that = (GradleModuleDependencyId)o; - return myOwnerModuleName.equals(that.myOwnerModuleName) && myDependencyModuleName.equals(that.myDependencyModuleName); - } - @Override public String toString() { - return String.format("module dependency:owner module='%s'|dependency module='%s'", myOwnerModuleName, myDependencyModuleName); + return String.format("module dependency:owner module='%s'|dependency module='%s'", getOwnerModuleName(), getDependencyName()); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleId.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleId.java index e447f2189540..275887045ed8 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleId.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/model/id/GradleModuleId.java @@ -46,4 +46,9 @@ public class GradleModuleId extends GradleAbstractEntityId { GradleModuleId that = (GradleModuleId)o; return myModuleName.equals(that.myModuleName); } + + @Override + public String toString() { + return "module '" + myModuleName + "'"; + } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesDetector.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesDetector.java index e46258ad1597..11baf98bbe71 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesDetector.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesDetector.java @@ -1,11 +1,13 @@ package org.jetbrains.plugins.gradle.sync; import com.intellij.ProjectTopics; +import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.AbstractProjectComponent; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootEvent; import com.intellij.openapi.roots.ModuleRootListener; import com.intellij.util.Alarm; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.plugins.gradle.util.GradleUtil; @@ -59,10 +61,25 @@ public class GradleProjectStructureChangesDetector extends AbstractProjectCompon myAlarm.cancelAllRequests(); final long diff = System.currentTimeMillis() - myStartRefreshTime.get(); if (diff < 0) { + myAlarm.cancelAllRequests(); myAlarm.addRequest(this, (int)-diff); return; } - GradleUtil.refreshProject(myProject); + + UIUtil.invokeAndWaitIfNeeded(new Runnable() { + @Override + public void run() { + if (ModalityState.current() != ModalityState.NON_MODAL) { + // There is a possible case that user performs intellij project structure modification and 'project settings' dialog + // is open. We want to perform the refresh when the editing is completely finished then. + myAlarm.cancelAllRequests(); + myAlarm.addRequest(RefreshRequest.this, REFRESH_DELAY_MILLIS); + return; + } + + GradleUtil.refreshProject(myProject); + } + }); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java index f91b30f579dd..a05831228288 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModel.java @@ -4,8 +4,10 @@ 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.GradleChangesCalculationContext; import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChange; import org.jetbrains.plugins.gradle.diff.GradleStructureChangesCalculator; +import org.jetbrains.plugins.gradle.diff.PlatformFacade; import org.jetbrains.plugins.gradle.model.gradle.GradleProject; import java.util.HashSet; @@ -28,14 +30,17 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent = new AtomicReference>(new HashSet()); private final AtomicReference myGradleProject = new AtomicReference(); - - private final GradleStructureChangesCalculator myChangesCalculator; + + @NotNull private final GradleStructureChangesCalculator myChangesCalculator; + @NotNull private final PlatformFacade myPlatformFacade; public GradleProjectStructureChangesModel(@NotNull Project project, - @NotNull GradleStructureChangesCalculator changesCalculator) + @NotNull GradleStructureChangesCalculator changesCalculator, + @NotNull PlatformFacade platformFacade) { super(project); myChangesCalculator = changesCalculator; + myPlatformFacade = platformFacade; } /** @@ -58,15 +63,14 @@ public class GradleProjectStructureChangesModel extends AbstractProjectComponent */ public void update(@NotNull GradleProject gradleProject) { myGradleProject.set(gradleProject); - Set knownChanges = new HashSet(myChanges.get()); - Set currentChanges = new HashSet(); - myChangesCalculator.calculate(gradleProject, myProject, knownChanges, currentChanges); - if (currentChanges.equals(knownChanges)) { + GradleChangesCalculationContext context = new GradleChangesCalculationContext(myChanges.get(), myPlatformFacade); + myChangesCalculator.calculate(gradleProject, myProject, context); + if (!context.hasNewChanges()) { return; } - myChanges.set(currentChanges); + myChanges.set(context.getCurrentChanges()); for (GradleProjectStructureChangeListener listener : myListeners) { - listener.onChanges(knownChanges, currentChanges); + listener.onChanges(context.getKnownChanges(), context.getCurrentChanges()); } } 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/GradleProjectStructureHelper.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java index 268fe0d2d1be..63f41e11b0b2 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureHelper.java @@ -15,6 +15,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.gradle.diff.PlatformFacade; import org.jetbrains.plugins.gradle.model.gradle.*; import org.jetbrains.plugins.gradle.model.id.GradleLibraryDependencyId; +import org.jetbrains.plugins.gradle.model.id.GradleModuleDependencyId; /** * Thread-safe. @@ -49,23 +50,7 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { * false otherwise */ public boolean isIntellijLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) { - final Module module = findIntellijModule(id.getModuleName()); - if (module == null) { - return false; - } - - RootPolicy visitor = new RootPolicy() { - @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; + return findIntellijLibraryDependency(id.getOwnerModuleName(), id.getDependencyName()) != null; } /** @@ -76,7 +61,15 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { * false otherwise */ public boolean isGradleLibraryDependencyExist(@NotNull final GradleLibraryDependencyId id) { - return findGradleLibraryDependency(id.getModuleName(), id.getLibraryName()) != null; + return findGradleLibraryDependency(id.getOwnerModuleName(), id.getDependencyName()) != null; + } + + public boolean isIntellijModuleDependencyExist(@NotNull final GradleModuleDependencyId id) { + return findIntellijModuleDependency(id.getOwnerModuleName(), id.getDependencyName()) != null; + } + + public boolean isGradleModuleDependencyExist(@NotNull final GradleModuleDependencyId id) { + return findIntellijModuleDependency(id.getOwnerModuleName(), id.getDependencyName()) != null; } @Nullable @@ -111,10 +104,15 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { @Nullable public Library findIntellijLibrary(@NotNull final GradleLibrary library) { + return findIntellijLibrary(library.getName()); + } + + @Nullable + public Library findIntellijLibrary(@NotNull String libraryName) { final LibraryTable libraryTable = myFacade.getProjectLibraryTable(myProject); for (Library intellijLibrary : libraryTable.getLibraries()) { // TODO den consider 'merged libraries' at the registered project structure changes here. - if (library.getName().equals(intellijLibrary.getName())) { + if (libraryName.equals(intellijLibrary.getName())) { return intellijLibrary; } } @@ -145,6 +143,20 @@ public class GradleProjectStructureHelper extends AbstractProjectComponent { } return null; } + + @Nullable + public GradleLibrary findGradleLibrary(@NotNull final String libraryName) { + final GradleProject project = myModel.getGradleProject(); + if (project == null) { + return null; + } + for (GradleLibrary library : project.getLibraries()) { + if (libraryName.equals(library.getName())) { + return library; + } + } + return null; + } @Nullable public GradleLibraryDependency findGradleLibraryDependency(@NotNull final String moduleName, @NotNull final String libraryName) { 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 f0dc67d9692d..7deb8d5e3f8f 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/sync/GradleProjectStructureTreeModel.java @@ -92,7 +92,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { return value; } GradleLibraryDependencyId id = GradleEntityIdMapper.mapEntityToId(libraryOrderEntry); - dependencies.add(buildNode(id, id.getLibraryName())); + dependencies.add(buildNode(id, id.getDependencyName())); return value; } }; @@ -137,6 +137,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { GradleProjectStructureNode moduleNode = getModuleNode(id); GradleProjectStructureNode result = new GradleProjectStructureNode(GradleConstants.DEPENDENCIES_NODE_DESCRIPTOR); + result.addListener(myNodeListener); moduleNode.add(result); myModuleDependencies.put(id.getModuleName(), result); @@ -159,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); } @@ -196,7 +197,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { for (GradleProjectStructureNode holder : myModuleDependencies.values()) { for (GradleProjectStructureNode dependencyNode : holder.getChildren(GradleLibraryDependencyId.class)) { final GradleLibraryDependencyId id = dependencyNode.getDescriptor().getElement(); - if (change.getLibraryName().equals(id.getLibraryName())) { + if (change.getLibraryName().equals(id.getDependencyName())) { dependencyNode.addConflictChange(change); break; } @@ -205,26 +206,31 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } private void processNewLibraryDependencyPresenceChange(@NotNull GradleLibraryDependencyPresenceChange change) { - GradleLibraryDependencyId id = change.getGradleEntity(); + processNewDependencyPresenceChange(change); + } + + private void processNewModuleDependencyPresenceChange(@NotNull GradleModuleDependencyPresenceChange change) { + processNewDependencyPresenceChange(change); + } + + private void processNewDependencyPresenceChange(@NotNull GradleEntityPresenceChange change) { + I id = change.getGradleEntity(); TextAttributesKey attributes = GradleTextAttributes.GRADLE_LOCAL_CHANGE; if (id == null) { id = change.getIntellijEntity(); attributes = GradleTextAttributes.INTELLIJ_LOCAL_CHANGE; } assert id != null; - final GradleProjectStructureNode dependenciesNode = getDependenciesNode(id.getModuleId()); - for (GradleProjectStructureNode node : dependenciesNode.getChildren(GradleLibraryDependencyId.class)) { - GradleProjectStructureNodeDescriptor d = node.getDescriptor(); - if (id.equals(d.getElement())) { - d.setAttributes(attributes); - nodeStructureChanged(node); + final GradleProjectStructureNode dependenciesNode = getDependenciesNode(id.getOwnerModuleId()); + for (GradleProjectStructureNode node : dependenciesNode.getChildren(id.getClass())) { + if (id.equals(node.getDescriptor().getElement())) { + node.setAttributes(attributes); return; } } - GradleProjectStructureNode newNode = buildNode(id, id.getLibraryName()); - newNode.getDescriptor().setAttributes(attributes); + GradleProjectStructureNode newNode = buildNode(id, id.getDependencyName()); dependenciesNode.add(newNode); - nodeStructureChanged(dependenciesNode); + newNode.setAttributes(attributes); } private void processNewModulePresenceChange(@NotNull GradleModulePresenceChange change) { @@ -255,7 +261,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { for (GradleProjectStructureNode holder : myModuleDependencies.values()) { for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { final GradleLibraryDependencyId id = node.getDescriptor().getElement(); - if (id.getLibraryName().equals(change.getLibraryName())) { + if (id.getDependencyName().equals(change.getLibraryName())) { node.removeConflictChange(change); break; } @@ -275,7 +281,25 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { else { removeNode = !myProjectStructureHelper.isGradleLibraryDependencyExist(id); } - final GradleProjectStructureNode holder = myModuleDependencies.get(id.getModuleName()); + processObsoleteDependencyPresenceChange(id, removeNode); + } + + private void processObsoleteModuleDependencyPresenceChange(@NotNull GradleModuleDependencyPresenceChange change) { + GradleModuleDependencyId id = change.getGradleEntity(); + boolean removeNode; + if (id == null) { + id = change.getIntellijEntity(); + assert id != null; + removeNode = !myProjectStructureHelper.isIntellijModuleDependencyExist(id); + } + else { + removeNode = !myProjectStructureHelper.isGradleModuleDependencyExist(id); + } + processObsoleteDependencyPresenceChange(id, removeNode); + } + + private void processObsoleteDependencyPresenceChange(@NotNull GradleAbstractDependencyId id, boolean removeNode) { + final GradleProjectStructureNode holder = myModuleDependencies.get(id.getOwnerModuleName()); if (holder == null) { return; } @@ -286,8 +310,8 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { // We should distinguish between those situations because we need to mark the node as 'synced' at one case and // completely removed at another one. - for (GradleProjectStructureNode node : holder.getChildren(GradleLibraryDependencyId.class)) { - GradleProjectStructureNodeDescriptor descriptor = node.getDescriptor(); + for (GradleProjectStructureNode node : holder.getChildren(id.getClass())) { + GradleProjectStructureNodeDescriptor descriptor = node.getDescriptor(); if (!id.equals(descriptor.getElement())) { continue; } @@ -304,13 +328,32 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { private void processObsoleteModulePresenceChange(@NotNull GradleModulePresenceChange change) { GradleModuleId id = change.getGradleEntity(); + boolean removeNode; if (id == null) { id = change.getIntellijEntity(); + assert id != null; + removeNode = myProjectStructureHelper.findIntellijModule(id.getModuleName()) == null; } - assert id != null; + else { + removeNode = myProjectStructureHelper.findGradleModule(id.getModuleName()) == null; + } + + + // There are two possible cases why 'module presence' change is obsolete: + // 1. Corresponding module has been added at the counterparty; + // 2. The 'local module' 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. + final GradleProjectStructureNode moduleNode = myModules.get(id.getModuleName()); - if (moduleNode != null) { - moduleNode.getDescriptor().setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); + if (moduleNode == null) { + return; + } + if (removeNode) { + moduleNode.removeFromParent(); + } + else { + moduleNode.setAttributes(GradleTextAttributes.GRADLE_NO_CHANGE); } } @@ -323,10 +366,13 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { } @Override - public void onNodeRemoved(@NotNull GradleProjectStructureNode node, int index) { - myIndexHolder[0] = index; - myNodeHolder[0] = node; - nodesWereRemoved(node.getParent(), myIndexHolder, myNodeHolder); + public void onNodeRemoved(@NotNull GradleProjectStructureNode parent, + @NotNull GradleProjectStructureNode removedChild, + int removedChildIndex) + { + myIndexHolder[0] = removedChildIndex; + myNodeHolder[0] = removedChild; + nodesWereRemoved(parent, myIndexHolder, myNodeHolder); } @Override @@ -340,6 +386,7 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { @Override public void visit(@NotNull GradleLanguageLevelChange change) { processNewLanguageLevelChange(change); } @Override public void visit(@NotNull GradleModulePresenceChange change) { processNewModulePresenceChange(change); } @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { processNewLibraryDependencyPresenceChange(change); } + @Override public void visit(@NotNull GradleModuleDependencyPresenceChange change) { processNewModuleDependencyPresenceChange(change); } @Override public void visit(@NotNull GradleMismatchedLibraryPathChange change) { processNewMismatchedLibraryPathChange(change); } } @@ -350,6 +397,9 @@ public class GradleProjectStructureTreeModel extends DefaultTreeModel { @Override public void visit(@NotNull GradleLibraryDependencyPresenceChange change) { processObsoleteLibraryDependencyPresenceChange(change); } + @Override public void visit(@NotNull GradleModuleDependencyPresenceChange change) { + processObsoleteModuleDependencyPresenceChange(change); + } @Override public void visit(@NotNull GradleMismatchedLibraryPathChange change) { processObsoleteMismatchedLibraryPathChange(change); } } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java index 2fbce6411fea..0ad2b87a27a6 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/task/GradleResolveProjectTask.java @@ -39,7 +39,7 @@ public class GradleResolveProjectTask extends AbstractGradleTask { final GradleProject project = resolver.resolveProjectInfo(getId(), myProjectPath, myResolveLibraries); myGradleProject.set(project); setState(GradleTaskState.FINISHED); - if (myIntellijProject == null) { + if (myIntellijProject == null || myIntellijProject.isDisposed()) { return; } final GradleProjectStructureChangesModel model = myIntellijProject.getComponent(GradleProjectStructureChangesModel.class); 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 37dcd05b960c..c1068610d2b4 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/ui/GradleProjectStructureNode.java @@ -70,13 +70,11 @@ public class GradleProjectStructureNode extends Defaul for (int i = 0; i < getChildCount(); i++) { GradleProjectStructureNode node = getChildAt(i); if (NODE_COMPARATOR.compare((GradleProjectStructureNode)newChild, node) <= 0) { - insert(newChild, i); - onNodeAdded((GradleProjectStructureNode)newChild, i); + insert(newChild, i); // Assuming that the node listeners are notified during the nested call. return; } } - super.add(newChild); - onNodeAdded((GradleProjectStructureNode)newChild, getChildCount() - 1); + super.add(newChild); // Assuming that the node listeners are notified during the nested call to 'insert()'. } @Override @@ -105,26 +103,40 @@ 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() - 1; + 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; + } } } 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 false; } remove(currentPosition); insert(child, desiredPosition); + return true; } /** @@ -145,7 +157,12 @@ public class GradleProjectStructureNode extends Defaul */ public void addConflictChange(@NotNull GradleProjectStructureChange change) { myConflictChanges.add(change); - if (myConflictChanges.size() == 1) { + if (myConflictChanges.size() != 1) { + return; + } + final TextAttributesKey key = myDescriptor.getAttributes(); + boolean localNode = key == GradleTextAttributes.GRADLE_LOCAL_CHANGE || key == GradleTextAttributes.INTELLIJ_LOCAL_CHANGE; + if (!localNode) { myDescriptor.setAttributes(GradleTextAttributes.GRADLE_CHANGE_CONFLICT); onNodeChanged(this); } @@ -219,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) { @@ -232,9 +257,9 @@ public class GradleProjectStructureNode extends Defaul } } - private void onNodeRemoved(@NotNull GradleProjectStructureNode node, int index) { + private void onNodeRemoved(@NotNull GradleProjectStructureNode node, int removedChildIndex) { for (Listener listener : myListeners) { - listener.onNodeRemoved(node, index); + listener.onNodeRemoved(this, node, removedChildIndex); } } @@ -246,7 +271,9 @@ public class GradleProjectStructureNode extends Defaul public interface Listener { void onNodeAdded(@NotNull GradleProjectStructureNode node, int index); - void onNodeRemoved(@NotNull GradleProjectStructureNode node, int index); + void onNodeRemoved(@NotNull GradleProjectStructureNode parent, + @NotNull GradleProjectStructureNode removedChild, + int removedChildIndex); void onNodeChanged(@NotNull GradleProjectStructureNode node); } } diff --git a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java index b2327cf987f0..3977afeb7df3 100644 --- a/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java +++ b/plugins/gradle/src/org/jetbrains/plugins/gradle/util/GradleUtil.java @@ -157,10 +157,10 @@ public class GradleUtil { */ @Nullable public static GradleProject refreshProject(@NotNull final Project project, - @NotNull final String gradleProjectPath, - @NotNull final Ref errorHolder, - final boolean resolveLibraries, - final boolean modal) + @NotNull final String gradleProjectPath, + @NotNull final Ref errorHolder, + final boolean resolveLibraries, + final boolean modal) { final Ref gradleProject = new Ref(); final TaskUnderProgress task = new TaskUnderProgress() { @@ -196,7 +196,7 @@ public class GradleUtil { task.execute(indicator); } }); - } + } } }); return gradleProject.get(); 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 897969814943..4f94296362ef 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/sync/GradleProjectStructureChangesModelTest.groovy @@ -6,6 +6,8 @@ import org.jetbrains.plugins.gradle.testutil.AbstractGradleTest import org.junit.Test import static org.junit.Assert.assertEquals +import org.jetbrains.plugins.gradle.diff.GradleMismatchedLibraryPathChange +import org.jetbrains.plugins.gradle.diff.GradleLibraryDependencyPresenceChange /** * @author Denis Zhdanov @@ -15,7 +17,7 @@ import static org.junit.Assert.assertEquals public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { @Test - public void processObsoleteGradleLocalChange() { + public void "obsolete gradle-local modules"() { // Configure initial projects state. init( gradle: { @@ -32,14 +34,17 @@ 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. checkChanges { presence { - library(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib2" }) - library(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib3" }) + library(gradle: gradle.libraryDependencies.values().flatten().findAll { it.name == "lib2" }) + library(gradle: gradle.libraryDependencies.values().flatten().findAll { it.name == "lib3" }) } } checkTree { project { @@ -61,7 +66,7 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { checkChanges { presence { - library(gradle: gradle.modules.dependencies.flatten().findAll { it.name == "lib3" }) + library(gradle: gradle.libraryDependencies.values().flatten().findAll { it.name == "lib3" }) } } checkTree { project { @@ -93,7 +98,7 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } @Test - public void libraryDependenciesWithDifferentPaths() { + public void "library dependencies on binary paths"() { // Let the model has two differences in a library setup initially. init( gradle: { @@ -114,8 +119,7 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { checkChanges { libraryConflict(entity: intellij.libraries['lib2']) { - binaryPath(gradle: '1', intellij: null) - binaryPath(gradle: null, intellij: '3') + binaryPath(gradle: '1', intellij: ['3']) } } checkTree { project { @@ -143,7 +147,7 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } } } } ) checkChanges { - libraryConflict(entity: intellij.dependencies.values().flatten().find {it.library.name == 'lib2' }.library) { + libraryConflict(entity: intellij.libraryDependencies.values().flatten().find {it.library.name == 'lib2' }.library) { binaryPath(gradle: null, intellij: '3') } } checkTree { @@ -182,7 +186,7 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } @Test - public void intellijModuleRemoval() { + public void "intellij module removal"() { Closure initialClosure = { project { module('module1') @@ -208,21 +212,22 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { } } ) checkChanges { presence { - module(gradle: gradle.modules.find { it.name == 'module2'}) - libraryDependency(gradle: gradle.modules.dependencies.flatten()) + module(gradle: gradle.modules['module2']) + libraryDependency(gradle: gradle.modules['module2'].dependencies) } } checkTree { project { - module1() module2('gradle') { dependencies { lib1('gradle') lib2('gradle') - } } } } + } } + module1() + } } } @Test - public void gradleModuleIsImported() { + public void "gradle-local module is not treated as 'local' after import"() { init( gradle: { project { @@ -236,12 +241,12 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { ) checkChanges { presence { - module(gradle: gradle.modules.find { it.name == 'module2' }) + module(gradle: gradle.modules['module2']) } } checkTree { project { - module1() module2('gradle') + module1() } } // Emulate import gradle module to intellij. @@ -257,4 +262,293 @@ public class GradleProjectStructureChangesModelTest extends AbstractGradleTest { module2() // Imported module node is not highlighted anymore. } } } + + @Test + public void "gradle local library dependency outweighs library path conflict"() { + init( + gradle: { + project { + module('module1') { + dependencies { + library('lib1', bin: ['1']) + } } + module('module2') { + dependencies { + library('lib1') + } } } }, + intellij: { + project { + module('module1') { + dependencies { + library('lib1', bin: ['2']) + } } } }, + changesSorter: changeByClassSorter([ + (GradleMismatchedLibraryPathChange) : 2, + (GradleLibraryDependencyPresenceChange) : 1 + ]) + ) + + checkChanges { + presence { + module(gradle: gradle.modules['module2']) + libraryDependency(gradle: gradle.libraryDependencies[gradle.modules['module2']].first()) + } + libraryConflict(entity: intellij.libraries['lib1']) { + binaryPath(gradle: ['1'], intellij: ['2']) + } } + checkTree { + project { + module2('gradle') { + dependencies { + lib1('gradle') // This is the point of the test. We don't expect to see 'conflict' here. + } } + module1() { + dependencies { + lib1('conflict') + } } } } + } + + @Test + public void "mismatched module dependency import"() { + init( + gradle: { + project { + module('module1') + module('module2') + module('module3') { + dependencies { + module('module1') + module('module2') + } } } }, + intellij: { + project { + module('module2') + module('module4') + module('module3') { + dependencies { + module('module2') + module('module4') + } } } } + ) + checkChanges { + presence { + module(gradle: gradle.modules['module1']) + module(intellij: intellij.modules['module4']) + moduleDependency(gradle: gradle.moduleDependencies[gradle.modules['module3']].find { it.target == gradle.modules['module1']}) + moduleDependency(intellij: intellij.moduleDependencies[intellij.modules['module3']].find { it.moduleName == 'module4'}) + } } + checkTree { + project { + module1('gradle') + module2() + module3() { + dependencies { + module1('gradle') + module2() + module4('intellij') + } } + module4('intellij') + } } + + Closure newProjectState = { + project { + module('module1') + module('module2') + module('module4') + module('module3') { + dependencies { + module('module1') + module('module2') + module('module4') + } } } } + setState(gradle: newProjectState, intellij: newProjectState) + checkChanges { } // No changes + checkTree { + project { + module1() + module2() + module3 { + dependencies { + module1() + module2() + module4() + } } + module4() + } } + } + + @Test + public void "mismatched module dependency removal"() { + init( + gradle: { + project { + module('module1') + module('module2') + module('module3') { + dependencies { + module('module1') + module('module2') + } } } }, + intellij: { + project { + module('module2') + module('module4') + module('module3') { + dependencies { + module('module2') + module('module4') + } } } } + ) + checkChanges { + presence { + module(gradle: gradle.modules['module1']) + module(intellij: intellij.modules['module4']) + moduleDependency(gradle: gradle.moduleDependencies[gradle.modules['module3']].find { it.target == gradle.modules['module1']}) + moduleDependency(intellij: intellij.moduleDependencies[intellij.modules['module3']].find { it.moduleName == 'module4'}) + } } + checkTree { + project { + module1('gradle') + module2() + module3() { + dependencies { + module1('gradle') + module2() + module4('intellij') + } } + module4('intellij') + } } + + Closure newProjectState = { + project { + module('module2') + module('module3') { + dependencies { + module('module2') + } } } } + setState(gradle: newProjectState, intellij: newProjectState) + checkChanges { } // No changes + checkTree { + project { + module2() + module3 { + dependencies { + module2() + } } } } + } + + @Test + public void "cycled module dependencies"() { + init( + gradle: { + project { + module('module1') { + dependencies { + module('module2') + } } + module('module2') { + dependencies { + module('module1') + } } } }, + intellij: { + project { + module('module2') { + dependencies { + module('module3') + } } + module('module3') { + dependencies { + module('module2') + } } } } + ) + checkChanges { + presence { + module(gradle: gradle.modules['module1']) + module(intellij: intellij.modules['module3']) + moduleDependency(gradle: gradle.moduleDependencies.values().flatten()) + moduleDependency(intellij: intellij.moduleDependencies.values().flatten()) + } } + checkTree { + project { + module1('gradle') { + dependencies { + module2('gradle') + } } + module2() { + dependencies { + module1('gradle') + module3('intellij') + } } + module3('intellij') { + dependencies { + 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 99f9fc4f7076..d97f7288a24e 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractGradleTest.groovy @@ -1,23 +1,18 @@ package org.jetbrains.plugins.gradle.testutil +import com.intellij.openapi.project.Project +import com.intellij.util.containers.ContainerUtil +import org.jetbrains.plugins.gradle.model.id.GradleEntityIdMapper +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangeListener import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangesModel +import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper import org.jetbrains.plugins.gradle.sync.GradleProjectStructureTreeModel import org.junit.Before -import org.picocontainer.defaults.DefaultPicoContainer -import com.intellij.openapi.project.Project -import org.jetbrains.plugins.gradle.diff.PlatformFacade -import org.jetbrains.plugins.gradle.diff.GradleStructureChangesCalculator -import org.jetbrains.plugins.gradle.diff.GradleProjectStructureChangesCalculator -import org.jetbrains.plugins.gradle.diff.GradleModuleStructureChangesCalculator -import org.jetbrains.plugins.gradle.diff.GradleLibraryDependencyStructureChangesCalculator -import org.jetbrains.plugins.gradle.diff.GradleLibraryStructureChangesCalculator -import org.jetbrains.plugins.gradle.sync.GradleProjectStructureHelper -import com.intellij.util.containers.ContainerUtil -import org.jetbrains.plugins.gradle.sync.GradleProjectStructureChangeListener - -import static org.junit.Assert.assertEquals import org.picocontainer.MutablePicoContainer -import org.jetbrains.plugins.gradle.model.id.GradleEntityIdMapper; +import org.picocontainer.defaults.DefaultPicoContainer +import org.jetbrains.plugins.gradle.diff.* + +import static org.junit.Assert.fail /** * @author Denis Zhdanov @@ -29,15 +24,16 @@ public abstract class AbstractGradleTest { GradleProjectStructureTreeModel treeModel def gradle def intellij - def changes + def changesBuilder def treeChecker def container + private Closure changesComparator @Before public void setUp() { gradle = new GradleProjectBuilder() intellij = new IntellijProjectBuilder() - changes = new ChangeBuilder() + changesBuilder = new ChangeBuilder() treeChecker = new ProjectStructureChecker() container = new DefaultPicoContainer() container.registerComponentInstance(Project, intellij.project) @@ -47,6 +43,7 @@ public abstract class AbstractGradleTest { container.registerComponentImplementation(GradleProjectStructureHelper) container.registerComponentImplementation(GradleStructureChangesCalculator, GradleProjectStructureChangesCalculator) container.registerComponentImplementation(GradleModuleStructureChangesCalculator) + container.registerComponentImplementation(GradleModuleDependencyStructureChangesCalculator) container.registerComponentImplementation(GradleLibraryDependencyStructureChangesCalculator) container.registerComponentImplementation(GradleLibraryStructureChangesCalculator) container.registerComponentImplementation(GradleEntityIdMapper) @@ -62,31 +59,55 @@ public abstract class AbstractGradleTest { protected def init(map = [:]) { treeModel = container.getComponentInstance(GradleProjectStructureTreeModel) as GradleProjectStructureTreeModel changesModel.addListener({ old, current -> - treeModel.update(current) - treeModel.processObsoleteChanges(ContainerUtil.subtract(old, current)); + treeModel.processObsoleteChanges(sortChanges(ContainerUtil.subtract(old, current))); + treeModel.processCurrentChanges(sortChanges(current)) } as GradleProjectStructureChangeListener) setState(map, false) treeModel.rebuild() changesModel.update(gradle.project) } + def sortChanges(changes) { + if (changesComparator) { + return changes.toList().sort(changesComparator) + } + return changes + } + protected def setState(map, update = true) { map.intellij?.delegate = intellij map.intellij?.call() map.gradle?.delegate = gradle map.gradle?.call() + changesComparator = map.changesSorter if (update) { changesModel.update(gradle.project) } } protected def checkChanges(Closure c) { - c.delegate = changes + changesBuilder.changes.clear() + c.delegate = changesBuilder def expected = c() if (!expected) { expected = [].toSet() } - assertEquals(expected, changesModel.changes) + def actual = new HashSet(changesModel.changes) + if (expected == actual) { + return + } + actual.removeAll(expected) + expected.removeAll(changesModel.changes) + def message = "Project structure changes are mismatched." + if (expected) { + message += "\n Expected but not matched:" + expected.each { message += "\n * $it"} + } + if (actual) { + message += "\n Unexpected:" + actual.each { message += "\n * $it"} + } + fail(message) } protected def checkTree(c) { @@ -95,4 +116,17 @@ public abstract class AbstractGradleTest { def expected = c() treeChecker.check(expected, treeModel.root) } + + protected Closure changeByClassSorter(Map, Integer> rules) { + { a, b -> + def weightA = rules[a.class] ?: Integer.MAX_VALUE + def weightB = rules[b.class] ?: Integer.MAX_VALUE + if (weightA == weightB) { + return a.hashCode() - b.hashCode() + } + else { + return weightA - weightB + } + } + } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy index 4b031f380a76..4b6ad6712fb7 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/AbstractProjectBuilder.groovy @@ -1,6 +1,7 @@ package org.jetbrains.plugins.gradle.testutil import com.intellij.pom.java.LanguageLevel +import com.intellij.openapi.util.text.StringUtil /** * @author Denis Zhdanov @@ -12,16 +13,28 @@ public abstract class AbstractProjectBuilder extends BuilderSupport { private static int COUNTER def project - def modules = [] + + /** [module name; module] */ + def modules = [:] + /** Holds (library name; library) pairs for the active configuration. */ def libraries = [:] + + /** [module; dependency list] */ + def libraryDependencies = [:].withDefault {[]} + + /** [module; dependency list] */ + def moduleDependencies = [:].withDefault {[]} + /** * 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 {[]} + + /** [module name; module] */ + def modulesCache = [:] @Override protected void setParent(Object parent, Object child) { @@ -43,37 +56,54 @@ public abstract class AbstractProjectBuilder extends BuilderSupport { } @Override - protected Object createNode(Object name, Map attributes) { + protected Object createNode(name, Map attributes) { switch (name) { case "dependencies": return current // Assuming that 'current' is a module object case "project": - reset() + clear() return project = createProject(attributes.name?: same, attributes.langLevel?: LanguageLevel.JDK_1_6) - case "module": def module = createModule(attributes.name?: same); modules << module; return module + case "module": case "library": + def n = StringUtil.capitalize(name) if (current == project) { - // Library. - return getLibrary(attributes) - } - else { - // Library dependency. - def module = current - def dep = createLibraryDependency(module, getLibrary(attributes)) - dependencies[module] << dep - return dep + // Not a dependency. + return "get$n"(attributes) } + def ownerModule = current + def dep = "create${n}Dependency"(ownerModule, "get$n"(attributes)) + "get${n}Dependencies"()[ownerModule] << dep + return dep } } protected abstract def createProject(String name, LanguageLevel languageLevel) protected abstract def createModule(String name) + protected abstract def registerModule(module) protected abstract def createLibrary(String name, Map paths) protected abstract def applyLibraryPaths(library, Map paths) protected abstract def createLibraryDependency(module, library) + protected abstract def createModuleDependency(ownerModule, targetModule) + protected abstract def reset(); protected String getUnique() { "./${COUNTER++}" } protected String getSame() { SAME_TOKEN } + private def getModule(Map attributes) { + def name = attributes.name?: same + def result = modules[name] + if (result) return result + result = modulesCache[name] + if (result) { + registerModule(result) + } + else { + result = createModule(name) + modulesCache[name] = result + } + modules[name] = result + result + } + private def getLibrary(Map attributes) { def name = attributes.name?: same def result = libraries[name] @@ -89,8 +119,9 @@ public abstract class AbstractProjectBuilder extends BuilderSupport { libraries[name] = result result } - - private def reset() { - [modules, dependencies, libraries]*.clear() + + private def clear() { + reset() + [modules, libraryDependencies, libraries, moduleDependencies]*.clear() } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy index 0a840bdb4674..07a7219421ae 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/ChangeBuilder.groovy @@ -6,6 +6,7 @@ import org.jetbrains.plugins.gradle.diff.GradleMismatchedLibraryPathChange import com.intellij.openapi.roots.libraries.Library import org.jetbrains.plugins.gradle.util.GradleUtil import org.jetbrains.plugins.gradle.diff.GradleModulePresenceChange +import org.jetbrains.plugins.gradle.diff.GradleModuleDependencyPresenceChange /** * @author Denis Zhdanov @@ -29,14 +30,15 @@ public class ChangeBuilder extends BuilderSupport { @Override protected Object createNode(Object name, Map attributes) { - if (current == null) { - changes = [] - } switch (name) { case "module": changes.addAll attributes.gradle.collect { new GradleModulePresenceChange(it, null)} changes.addAll attributes.intellij.collect { new GradleModulePresenceChange(null, it)} return changes + case "moduleDependency": + changes.addAll attributes.gradle.collect { new GradleModuleDependencyPresenceChange(it, null) } + changes.addAll attributes.intellij.collect { new GradleModuleDependencyPresenceChange(null, it) } + return changes case "library": changes.addAll attributes.gradle.collect { new GradleLibraryDependencyPresenceChange(it, null)} changes.addAll attributes.intellij.collect { new GradleLibraryDependencyPresenceChange(null, it)} @@ -50,15 +52,12 @@ public class ChangeBuilder extends BuilderSupport { 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) - )) + current as Library, collectPaths(attributes.gradle), collectPaths(attributes.intellij) + )) } changes } @@ -73,9 +72,16 @@ public class ChangeBuilder extends BuilderSupport { protected def register(change) { changes << change - change + changes } + private def collectPaths(paths) { + if (!paths) { + return [].toSet() + } + paths.collect { toCanonicalPath(it) }.toSet() + } + private def toCanonicalPath(String path) { path ? GradleUtil.toCanonicalPath(path) : path } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy index 9926a3f7f3b8..be6902acd9dc 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/GradleProjectBuilder.groovy @@ -6,6 +6,7 @@ import org.jetbrains.plugins.gradle.model.gradle.GradleLibraryDependency import org.jetbrains.plugins.gradle.model.gradle.GradleLibrary import org.jetbrains.plugins.gradle.model.gradle.LibraryPathType import com.intellij.pom.java.LanguageLevel +import org.jetbrains.plugins.gradle.model.gradle.GradleModuleDependency /** * @author Denis Zhdanov @@ -23,8 +24,19 @@ class GradleProjectBuilder extends AbstractProjectBuilder { @Override protected createModule(String name) { - def result = new GradleModule(name, unique) - project.addModule(result) + registerModule(new GradleModule(name, unique)) + } + + @Override + protected registerModule(module) { + project.addModule(module) + module + } + + @Override + protected createModuleDependency(ownerModule, targetModule) { + def result = new GradleModuleDependency(ownerModule, targetModule) + ownerModule.addDependency(result) result } @@ -49,4 +61,9 @@ class GradleProjectBuilder extends AbstractProjectBuilder { key, type -> paths[key]?.each { library.addPath(type, it) } } } + + @Override + protected reset() { + modulesCache.values().each { it.clearDependencies() } + } } diff --git a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy index c2530ad59f2e..9a694bef6d3e 100644 --- a/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy +++ b/plugins/gradle/testSources/org/jetbrains/plugins/gradle/testutil/IntellijProjectBuilder.groovy @@ -13,6 +13,7 @@ import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.roots.OrderRootType import org.jetbrains.plugins.gradle.util.GradleUtil import com.intellij.openapi.roots.libraries.LibraryTable +import com.intellij.openapi.roots.ModuleOrderEntry /** * @author Denis Zhdanov @@ -30,8 +31,8 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { def projectLibraryTable = projectLibraryTableStub as LibraryTable def platformFacade = [ - getModules: { modules }, - getOrderEntries: { dependencies[it] }, + getModules: { modules.values() }, + getOrderEntries: { libraryDependencies[it] + moduleDependencies[it] }, getProjectIcon: { IconLoader.getIcon("/nodes/ideaProject.png") }, getLocalFileSystemPath: { it.path }, getProjectLibraryTable: { projectLibraryTable } @@ -42,7 +43,7 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { @Override protected createProject(String name, LanguageLevel languageLevel) { projectStub.getName = { name } - platformFacade.getLanguageLevel = { languageLevel } + platformFacade.getLanguageLevel = { languageLevel } as Closure project } @@ -51,6 +52,20 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { [ getName: { name } ] as Module } + @Override + protected registerModule(Object module) { } + + @Override + protected createModuleDependency(ownerModule, targetModule) { + def stub = [:] + def result = stub as ModuleOrderEntry + stub.accept = { policy, defaultValue -> policy.visitModuleOrderEntry(result, defaultValue) } + stub.getModule = { targetModule } + stub.getOwnerModule = { ownerModule } + stub.getModuleName = { targetModule.name } + result + } + @Override protected createLibrary(String name, Map paths) { libraryPaths[name] = paths @@ -81,4 +96,7 @@ class IntellijProjectBuilder extends AbstractProjectBuilder { protected applyLibraryPaths(library, Map paths) { libraryPaths[library.name] = paths } + + @Override + protected reset() { } } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java index 133d687a7e1d..67c81ff24225 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/runner/GroovyScriptRunConfigurationProducer.java @@ -56,7 +56,7 @@ public class GroovyScriptRunConfigurationProducer extends RuntimeConfigurationPr GroovyFile groovyFile = (GroovyFile)file; final PsiClass aClass = GroovyRunnerUtil.getRunningClass(location.getPsiElement()); - if (aClass != null) { + if (aClass != null && GroovyRunnerUtil.canBeRunByGroovy(aClass)) { final RunnerAndConfigurationSettings settings = createConfiguration(aClass); if (settings != null) { mySourceElement = element; diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java index 742dc769f312..8c8f0d4d24be 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTree.java @@ -15,27 +15,35 @@ */ package com.intellij.designer.componentTree; -import com.intellij.designer.designSurface.DesignerEditorPanel; +import com.intellij.designer.designSurface.FeedbackTreeLayer; import com.intellij.designer.model.RadComponent; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.ui.ColoredTreeCellRenderer; +import com.intellij.ui.IdeBorderFactory; +import com.intellij.ui.SideBorder; import com.intellij.ui.treeStructure.Tree; import com.intellij.util.ui.tree.TreeUtil; import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.Nullable; import javax.swing.*; +import javax.swing.border.LineBorder; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; +import java.awt.*; /** * @author Alexander Lobas */ public final class ComponentTree extends Tree implements DataProvider { private TreeComponentDecorator myDecorator; + private RadComponent myMarkComponent; + private int myMarkFeedback; public ComponentTree() { newModel(); + setScrollsOnExpand(true); installCellRenderer(); setRootVisible(false); @@ -50,8 +58,6 @@ public final class ComponentTree extends Tree implements DataProvider { // TODO: Popup menu // TODO: F2 should start inplace editing - - // TODO: DND } public void newModel() { @@ -60,6 +66,13 @@ public final class ComponentTree extends Tree implements DataProvider { public void setDecorator(TreeComponentDecorator decorator) { myDecorator = decorator; + myMarkComponent = null; + } + + public void mark(RadComponent component, int feedback) { + myMarkComponent = component; + myMarkFeedback = feedback; + repaint(); } @Override @@ -67,6 +80,23 @@ public final class ComponentTree extends Tree implements DataProvider { return null; //TODO } + @Nullable + public RadComponent extractComponent(Object value) { + DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; + Object userObject = node.getUserObject(); + + if (myDecorator != null && userObject instanceof TreeNodeDescriptor) { + TreeNodeDescriptor descriptor = (TreeNodeDescriptor)userObject; + Object element = descriptor.getElement(); + + if (element instanceof RadComponent) { + return (RadComponent)element; + } + } + return null; + } + + private void installCellRenderer() { setCellRenderer(new ColoredTreeCellRenderer() { @Override @@ -77,16 +107,64 @@ public final class ComponentTree extends Tree implements DataProvider { boolean leaf, int row, boolean hasFocus) { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)value; - if (myDecorator != null && node.getUserObject() instanceof TreeNodeDescriptor) { - TreeNodeDescriptor descriptor = (TreeNodeDescriptor)node.getUserObject(); - if (descriptor.getElement() instanceof RadComponent) { - RadComponent component = (RadComponent)descriptor.getElement(); - // TODO: support more parameters and attributes - myDecorator.decorate(component, this); + RadComponent component = extractComponent(value); + if (component != null) { + // TODO: support more parameters and attributes + myDecorator.decorate(component, this); + + if (myMarkComponent == component) { + if (myMarkFeedback == FeedbackTreeLayer.INSERT_SELECTION) { + setBorder(BorderFactory.createLineBorder(Color.RED, 1)); + } + else { + setBorder(new InsertBorder(myMarkFeedback)); + } + } + else { + setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); } } } }); } + + private static class InsertBorder extends LineBorder { + private final int myMode; + + public InsertBorder(int mode) { + super(Color.BLACK, 2); + myMode = mode; + } + + @Override + public Insets getBorderInsets(Component component) { + return getBorderInsets(component, new Insets(0, 0, 0, 0)); + } + + @Override + public Insets getBorderInsets(Component component, Insets insets) { + insets.top = myMode == FeedbackTreeLayer.INSERT_BEFORE ? thickness : 0; + insets.left = insets.right = thickness; + insets.bottom = myMode == FeedbackTreeLayer.INSERT_AFTER ? thickness : 0; + return insets; + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + Color oldColor = g.getColor(); + + g.setColor(getLineColor()); + if (myMode == FeedbackTreeLayer.INSERT_BEFORE) { + g.fillRect(x, y, width, thickness); + g.fillRect(x, y, thickness, 2 * thickness); + g.fillRect(x + width - thickness, y, thickness, 2 * thickness); + } + else { + g.fillRect(x, y + height - thickness, width, thickness); + g.fillRect(x, y + height - 2 * thickness, thickness, 2 * thickness); + g.fillRect(x + width - thickness, y + height - 2 * thickness, thickness, 2 * thickness); + } + g.setColor(oldColor); + } + } } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java index c2f2c0b0bea2..6b7941ac545b 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/ComponentTreeBuilder.java @@ -18,7 +18,6 @@ package com.intellij.designer.componentTree; import com.intellij.designer.designSurface.ComponentSelectionListener; import com.intellij.designer.designSurface.DesignerEditorPanel; import com.intellij.designer.designSurface.EditableArea; -import com.intellij.designer.model.RadComponent; import com.intellij.ide.util.treeView.AbstractTreeBuilder; import javax.swing.event.TreeSelectionEvent; @@ -30,22 +29,27 @@ import javax.swing.tree.TreeSelectionModel; * @author Alexander Lobas */ public final class ComponentTreeBuilder extends AbstractTreeBuilder implements ComponentSelectionListener, TreeSelectionListener { - private final EditableArea mySurfaceArea; private final TreeSelectionModel myTreeSelectionModel; + private final EditableArea mySurfaceArea; + private final TreeEditableArea myTreeArea; + private final TreeGlassLayer myGlassLayer; public ComponentTreeBuilder(ComponentTree tree, DesignerEditorPanel designer) { - super(tree, (DefaultTreeModel)tree.getModel(), new TreeContentProvider(designer), null); // TODO: comparator? + super(tree, (DefaultTreeModel)tree.getModel(), new TreeContentProvider(designer), null); initRootNode(); - mySurfaceArea = designer.getSurfaceArea(); myTreeSelectionModel = getTree().getSelectionModel(); + mySurfaceArea = designer.getSurfaceArea(); + myTreeArea = new TreeEditableArea(tree, this); + myGlassLayer = new TreeGlassLayer(tree, designer.getToolProvider(), myTreeArea); // TODO: restore expanded state - setTreeSelection(); + select(mySurfaceArea.getSelection().toArray(), null); addListeners(); } @Override public void dispose() { removeListeners(); + myGlassLayer.dispose(); super.dispose(); } @@ -74,22 +78,17 @@ public final class ComponentTreeBuilder extends AbstractTreeBuilder implements C handleSelection(new Runnable() { @Override public void run() { - queueUpdate(); - setTreeSelection(); + myTreeArea.setSelection(mySurfaceArea.getSelection()); } }); } - private void setTreeSelection() { - select(mySurfaceArea.getSelection().toArray(), null); - } - @Override public void valueChanged(TreeSelectionEvent e) { handleSelection(new Runnable() { @Override public void run() { - mySurfaceArea.setSelection(getSelectedElements(RadComponent.class)); + mySurfaceArea.setSelection(myTreeArea.getSelection()); } }); } diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeEditOperation.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeEditOperation.java new file mode 100644 index 000000000000..ecda60e3cbf6 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeEditOperation.java @@ -0,0 +1,146 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.designer.componentTree; + +import com.intellij.designer.designSurface.EditOperation; +import com.intellij.designer.designSurface.FeedbackTreeLayer; +import com.intellij.designer.designSurface.OperationContext; +import com.intellij.designer.model.RadComponent; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; +import java.util.Collections; +import java.util.List; + +/** + * @author Alexander Lobas + */ +public abstract class TreeEditOperation implements EditOperation { + protected final RadComponent myHost; + protected final OperationContext myContext; + protected List myComponents; + + public static boolean isTarget(RadComponent host, OperationContext context) { + Point location = context.getLocation(); + RadComponent target = context.getArea().findTarget(location.x, location.y, null); + if (target == host) { + FeedbackTreeLayer layer = context.getArea().getFeedbackTreeLayer(); + return !layer.isBeforeLocation(target, location.x, location.y) && + !layer.isAfterLocation(target, location.x, location.y); + } + return true; + } + + public TreeEditOperation(RadComponent host, OperationContext context) { + myHost = host; + myContext = context; + } + + @Override + public void setComponent(RadComponent component) { + myComponents = Collections.singletonList(component); + } + + @Override + public void setComponents(List components) { + myComponents = components; + } + + @Override + public void showFeedback() { + Point location = myContext.getLocation(); + RadComponent target = myContext.getArea().findTarget(location.x, location.y, null); + FeedbackTreeLayer layer = myContext.getArea().getFeedbackTreeLayer(); + + if (myHost == target) { + layer.mark(target, FeedbackTreeLayer.INSERT_SELECTION); + } + else if (target != null && isChildren(target)) { + layer.mark(target, + layer.isBeforeLocation(target, location.x, location.y) ? + FeedbackTreeLayer.INSERT_BEFORE : FeedbackTreeLayer.INSERT_AFTER); + } else { + eraseFeedback(); + } + } + + private boolean isChildren(RadComponent component) { + for (Object child : myHost.getTreeChildren()) { + if (child == component) { + return true; + } + } + return false; + } + + @Override + public void eraseFeedback() { + myContext.getArea().getFeedbackTreeLayer().mark(null, FeedbackTreeLayer.INSERT_AFTER); + } + + @Override + public boolean canExecute() { + RadComponent reference = getReference(); + if (reference == null) { + return false; + } + return canExecute(myHost == reference ? null : reference); + } + + protected boolean canExecute(RadComponent insertBefore) { + return true; + } + + @Override + public void execute() throws Exception { + RadComponent reference = getReference(); + execute(myHost == reference ? null : reference); + } + + protected abstract void execute(RadComponent insertBefore) throws Exception; + + @Nullable + private RadComponent getReference() { + Point location = myContext.getLocation(); + RadComponent target = myContext.getArea().findTarget(location.x, location.y, null); + + if (myHost == target) { + return myHost; + } + if (target != null) { + Object[] children = myHost.getTreeChildren(); + int index = -1; + + for (int i = 0; i < children.length; i++) { + if (children[i] == target) { + index = i + 1; + break; + } + } + if (index == -1) { + return null; + } + if (myContext.getArea().getFeedbackTreeLayer().isBeforeLocation(target, location.x, location.y)) { + return target; + } + if (index < children.length) { + return (RadComponent)children[index]; + } + return myHost; + } + return null; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeEditableArea.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeEditableArea.java new file mode 100644 index 000000000000..75a720757550 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeEditableArea.java @@ -0,0 +1,211 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.designer.componentTree; + +import com.intellij.designer.designSurface.*; +import com.intellij.designer.designSurface.tools.InputTool; +import com.intellij.designer.model.RadComponent; +import com.intellij.ide.util.treeView.AbstractTreeBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.tree.DefaultMutableTreeNode; +import javax.swing.tree.TreePath; +import java.awt.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @author Alexander Lobas + */ +public final class TreeEditableArea implements EditableArea, FeedbackTreeLayer { + private final ComponentTree myTree; + private final AbstractTreeBuilder myTreeBuilder; + + public TreeEditableArea(ComponentTree tree, AbstractTreeBuilder treeBuilder) { + myTree = tree; + myTreeBuilder = treeBuilder; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // Selection + // + ////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void addSelectionListener(ComponentSelectionListener listener) { + } + + @Override + public void removeSelectionListener(ComponentSelectionListener listener) { + } + + @NotNull + @Override + public List getSelection() { + return new ArrayList(getRawSelection()); + } + + @Override + public boolean isSelected(@NotNull RadComponent component) { + return getRawSelection().contains(component); + } + + @Override + public void select(@NotNull RadComponent component) { + myTreeBuilder.queueUpdate(); + myTreeBuilder.select(component); + } + + @Override + public void deselect(@NotNull RadComponent component) { + Collection selection = getRawSelection(); + selection.remove(component); + setRawSelection(selection); + } + + @Override + public void appendSelection(@NotNull RadComponent component) { + Collection selection = getRawSelection(); + selection.add(component); + setRawSelection(selection); + } + + @Override + public void setSelection(@NotNull List components) { + setRawSelection(components); + } + + private void setRawSelection(Collection components) { + myTreeBuilder.queueUpdate(); + myTreeBuilder.select(components.toArray(), null); + } + + private Collection getRawSelection() { + return myTreeBuilder.getSelectedElements(RadComponent.class); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // Visual + // + ////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void setCursor(@Nullable Cursor cursor) { + myTree.setCursor(cursor); + } + + @NotNull + @Override + public JComponent getNativeComponent() { + return myTree; + } + + @Override + public RadComponent findTarget(int x, int y, @Nullable ComponentTargetFilter filter) { + TreePath path = myTree.getPathForLocation(x, y); + if (path != null) { + RadComponent component = myTree.extractComponent(path.getLastPathComponent()); + if (filter != null) { + while (component != null) { + if (filter.preFilter(component) && filter.resultFilter(component)) { + break; + } + component = component.getParent(); + } + } + return component; + } + return null; + } + + @Override + public InputTool findTargetTool(int x, int y) { + return null; + } + + @Override + public ComponentDecorator getRootSelectionDecorator() { + return null; + } + + @Override + public EditOperation processRootOperation(OperationContext context) { + return null; + } + + @Override + public FeedbackLayer getFeedbackLayer() { + return null; + } + + @Override + public RadComponent getRootComponent() { + return null; + } + + @Override + public boolean isTree() { + return true; + } + + @Override + public FeedbackTreeLayer getFeedbackTreeLayer() { + return this; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // FeedbackTreeLayer + // + ////////////////////////////////////////////////////////////////////////////////////////// + + private TreePath getPath(RadComponent component) { + // TODO: I don't know better way gets tree path for element + return new TreePath(myTreeBuilder.getNodeForElement(component).getPath()); + } + + @Override + public void mark(RadComponent component, int feedback) { + // TODO: INSERT_BEFORE - ensure visible up component + // TODO: INSERT_AFTER - ensure visible down component + + if (component != null && feedback == INSERT_SELECTION) { + TreePath path = getPath(component); + myTree.scrollPathToVisible(path); + if (!myTree.isExpanded(path)) { + myTreeBuilder.expand(component, null); + } + } + myTree.mark(component, feedback); + } + + @Override + public boolean isBeforeLocation(RadComponent component, int x, int y) { + Rectangle bounds = myTree.getPathBounds(getPath(component)); + return bounds != null && y - bounds.y < 15; + } + + @Override + public boolean isAfterLocation(RadComponent component, int x, int y) { + Rectangle bounds = myTree.getPathBounds(getPath(component)); + return bounds != null && bounds.getMaxY() - y < 15; + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeGlassLayer.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeGlassLayer.java new file mode 100644 index 000000000000..9051d05e3fa6 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/componentTree/TreeGlassLayer.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.designer.componentTree; + +import com.intellij.designer.designSurface.EditableArea; +import com.intellij.designer.designSurface.tools.ToolProvider; + +import java.awt.event.*; + +/** + * @author Alexander Lobas + */ +public final class TreeGlassLayer implements KeyListener, MouseListener, MouseMotionListener { + private final ComponentTree myTree; + private final ToolProvider myToolProvider; + private final EditableArea myArea; + + public TreeGlassLayer(ComponentTree tree, ToolProvider provider, EditableArea area) { + myTree = tree; + myToolProvider = provider; + myArea = area; + + myTree.addKeyListener(this); + myTree.addMouseListener(this); + myTree.addMouseMotionListener(this); + } + + public void dispose() { + myTree.removeKeyListener(this); + myTree.removeMouseListener(this); + myTree.removeMouseMotionListener(this); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // Keyboard + // + ////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void keyTyped(KeyEvent event) { + myToolProvider.processKeyEvent(event, myArea); + } + + @Override + public void keyPressed(KeyEvent event) { + myToolProvider.processKeyEvent(event, myArea); + } + + @Override + public void keyReleased(KeyEvent event) { + myToolProvider.processKeyEvent(event, myArea); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // Mouse + // + ////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void mouseClicked(MouseEvent event) { + myToolProvider.processMouseEvent(event, myArea); + } + + @Override + public void mousePressed(MouseEvent event) { + myToolProvider.processMouseEvent(event, myArea); + } + + @Override + public void mouseReleased(MouseEvent event) { + myToolProvider.processMouseEvent(event, myArea); + } + + @Override + public void mouseEntered(MouseEvent event) { + myToolProvider.processMouseEvent(event, myArea); + } + + @Override + public void mouseExited(MouseEvent event) { + myToolProvider.processMouseEvent(event, myArea); + } + + @Override + public void mouseDragged(MouseEvent event) { + myToolProvider.processMouseEvent(event, myArea); + } + + @Override + public void mouseMoved(MouseEvent event) { + myToolProvider.processMouseEvent(event, myArea); + } +} \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/ComponentEditableArea.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/ComponentEditableArea.java new file mode 100644 index 000000000000..b8a119174608 --- /dev/null +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/ComponentEditableArea.java @@ -0,0 +1,122 @@ +/* + * Copyright 2000-2012 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.designer.designSurface; + +import com.intellij.designer.model.RadComponent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import javax.swing.event.EventListenerList; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +/** + * @author Alexander Lobas + */ +public abstract class ComponentEditableArea implements EditableArea { + private final JComponent myComponent; + private final EventListenerList myListenerList = new EventListenerList(); + private List mySelection = new ArrayList(); + + public ComponentEditableArea(JComponent component) { + myComponent = component; + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // Selection + // + ////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public void addSelectionListener(ComponentSelectionListener listener) { + myListenerList.add(ComponentSelectionListener.class, listener); + } + + @Override + public void removeSelectionListener(ComponentSelectionListener listener) { + myListenerList.remove(ComponentSelectionListener.class, listener); + } + + protected void fireSelectionChanged() { + for (ComponentSelectionListener listener : myListenerList.getListeners(ComponentSelectionListener.class)) { + listener.selectionChanged(this); + } + } + + @Override + @NotNull + public List getSelection() { + return mySelection; + } + + @Override + public boolean isSelected(@NotNull RadComponent component) { + return mySelection.contains(component); + } + + @Override + public void select(@NotNull RadComponent component) { + mySelection = new ArrayList(); + mySelection.add(component); + fireSelectionChanged(); + } + + @Override + public void deselect(@NotNull RadComponent component) { + mySelection.remove(component); + fireSelectionChanged(); + } + + @Override + public void appendSelection(@NotNull RadComponent component) { + mySelection.remove(component); + mySelection.add(component); + fireSelectionChanged(); + } + + @Override + public void setSelection(@NotNull List components) { + mySelection = new ArrayList(components); + fireSelectionChanged(); + } + + ////////////////////////////////////////////////////////////////////////////////////////// + // + // Visual + // + ////////////////////////////////////////////////////////////////////////////////////////// + + public void setCursor(@Nullable Cursor cursor) { + myComponent.setCursor(cursor); + } + + @NotNull + public JComponent getNativeComponent() { + return myComponent; + } + + public boolean isTree() { + return false; + } + + @Nullable + public FeedbackTreeLayer getFeedbackTreeLayer() { + return null; + } +} diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java index de715ad37985..8c9957c9fe1f 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/DesignerEditorPanel.java @@ -93,17 +93,7 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider myLayeredPane = new MyLayeredPane(); - mySurfaceArea = new EditableArea() { - @Override - public void setCursor(Cursor cursor) { - myLayeredPane.setCursor(cursor); - } - - @Override - public JComponent getNativeComponent() { - return myLayeredPane; - } - + mySurfaceArea = new ComponentEditableArea(myLayeredPane) { @Override protected void fireSelectionChanged() { super.fireSelectionChanged(); @@ -191,6 +181,10 @@ public abstract class DesignerEditorPanel extends JPanel implements DataProvider return mySurfaceArea; } + public ToolProvider getToolProvider() { + return myToolProvider; + } + protected abstract ComponentDecorator getRootSelectionDecorator(); @Nullable diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/EditableArea.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/EditableArea.java index 9515b07f82c6..3028c4761867 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/EditableArea.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/EditableArea.java @@ -21,104 +21,64 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.event.EventListenerList; import java.awt.*; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; /** * @author Alexander Lobas */ -public abstract class EditableArea { +public interface EditableArea { ////////////////////////////////////////////////////////////////////////////////////////// // // Selection // ////////////////////////////////////////////////////////////////////////////////////////// - private final EventListenerList myListenerList = new EventListenerList(); - private List mySelection = new ArrayList(); + void addSelectionListener(ComponentSelectionListener listener); - public void addSelectionListener(ComponentSelectionListener listener) { - myListenerList.add(ComponentSelectionListener.class, listener); - } - - public void removeSelectionListener(ComponentSelectionListener listener) { - myListenerList.remove(ComponentSelectionListener.class, listener); - } - - protected void fireSelectionChanged() { - for (ComponentSelectionListener listener : myListenerList.getListeners(ComponentSelectionListener.class)) { - listener.selectionChanged(this); - } - } + void removeSelectionListener(ComponentSelectionListener listener); @NotNull - public List getSelection() { - return mySelection; - } + List getSelection(); - public boolean isSelected(@NotNull RadComponent component) { - return mySelection.contains(component); - } + boolean isSelected(@NotNull RadComponent component); - public void select(@NotNull RadComponent component) { - mySelection = new ArrayList(); - mySelection.add(component); - fireSelectionChanged(); - } + void select(@NotNull RadComponent component); - public void deselect(@NotNull RadComponent component) { - mySelection.remove(component); - fireSelectionChanged(); - } + void deselect(@NotNull RadComponent component); - public void appendSelection(@NotNull RadComponent component) { - mySelection.remove(component); - mySelection.add(component); - fireSelectionChanged(); - } + void appendSelection(@NotNull RadComponent component); - public void setSelection(@NotNull Collection components) { - mySelection = new ArrayList(components); - fireSelectionChanged(); - } + void setSelection(@NotNull List components); ////////////////////////////////////////////////////////////////////////////////////////// // - // + // Visual // ////////////////////////////////////////////////////////////////////////////////////////// - public abstract void setCursor(@Nullable Cursor cursor); + void setCursor(@Nullable Cursor cursor); @NotNull - public abstract JComponent getNativeComponent(); + JComponent getNativeComponent(); @Nullable - public abstract RadComponent findTarget(int x, int y, @Nullable ComponentTargetFilter filter); + RadComponent findTarget(int x, int y, @Nullable ComponentTargetFilter filter); @Nullable - public abstract InputTool findTargetTool(int x, int y); + InputTool findTargetTool(int x, int y); - public abstract ComponentDecorator getRootSelectionDecorator(); + ComponentDecorator getRootSelectionDecorator(); @Nullable - public EditOperation processRootOperation(OperationContext context) { - return null; - } + EditOperation processRootOperation(OperationContext context); - public abstract FeedbackLayer getFeedbackLayer(); + FeedbackLayer getFeedbackLayer(); - public abstract RadComponent getRootComponent(); + RadComponent getRootComponent(); - public boolean isTree() { - return false; - } + boolean isTree(); @Nullable - public FeedbackTreeLayer getFeedbackTreeLayer() { - return null; - } + FeedbackTreeLayer getFeedbackTreeLayer(); } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/FeedbackTreeLayer.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/FeedbackTreeLayer.java index 2c3bf8b39dd3..14e63a55d890 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/FeedbackTreeLayer.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/FeedbackTreeLayer.java @@ -15,8 +15,20 @@ */ package com.intellij.designer.designSurface; +import com.intellij.designer.model.RadComponent; +import org.jetbrains.annotations.Nullable; + /** * @author Alexander Lobas */ public interface FeedbackTreeLayer { + int INSERT_BEFORE = 0; + int INSERT_AFTER = 1; + int INSERT_SELECTION = 2; + + void mark(RadComponent component, int feedback); + + boolean isBeforeLocation(RadComponent component, int x, int y); + + boolean isAfterLocation(RadComponent component, int x, int y); } \ No newline at end of file diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/GlassLayer.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/GlassLayer.java index 7ecae96e4059..e2263af6d68e 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/GlassLayer.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/GlassLayer.java @@ -15,7 +15,6 @@ */ package com.intellij.designer.designSurface; -import com.intellij.designer.designSurface.tools.InputTool; import com.intellij.designer.designSurface.tools.ToolProvider; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.ui.popup.PopupOwner; @@ -37,31 +36,12 @@ public final class GlassLayer extends JComponent implements PopupOwner, DataProv myToolProvider = provider; myArea = area; enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK); - // TODO: DND } @Override protected void processKeyEvent(KeyEvent event) { - try { - InputTool tool = myToolProvider.getActiveTool(); + myToolProvider.processKeyEvent(event, myArea); - if (tool != null) { - switch (event.getID()) { - case KeyEvent.KEY_PRESSED: - tool.keyPressed(event, myArea); - break; - case KeyEvent.KEY_TYPED: - tool.keyTyped(event, myArea); - break; - case KeyEvent.KEY_RELEASED: - tool.keyReleased(event, myArea); - break; - } - } - } - catch (Throwable e) { - handleException(e); - } if (!event.isConsumed()) { super.processKeyEvent(event); } @@ -72,59 +52,13 @@ public final class GlassLayer extends JComponent implements PopupOwner, DataProv if (event.getID() == MouseEvent.MOUSE_PRESSED) { requestFocusInWindow(); } - try { - InputTool tool = myToolProvider.getActiveTool(); - if (tool != null) { - switch (event.getID()) { - case MouseEvent.MOUSE_PRESSED: - tool.mouseDown(event, myArea); - break; - case MouseEvent.MOUSE_RELEASED: - tool.mouseUp(event, myArea); - break; - case MouseEvent.MOUSE_ENTERED: - tool.mouseEntered(event, myArea); - break; - case MouseEvent.MOUSE_EXITED: - tool.mouseExited(event, myArea); - break; - case MouseEvent.MOUSE_CLICKED: - if (event.getClickCount() == 2) { - tool.mouseDoubleClick(event, myArea); - } - break; - } - } - } - catch (Throwable e) { - handleException(e); - } + myToolProvider.processMouseEvent(event, myArea); } @Override protected void processMouseMotionEvent(MouseEvent event) { - try { - InputTool tool = myToolProvider.getActiveTool(); - - if (tool != null) { - switch (event.getID()) { - case MouseEvent.MOUSE_MOVED: - tool.mouseMove(event, myArea); - break; - case MouseEvent.MOUSE_DRAGGED: - tool.mouseDrag(event, myArea); - break; - } - } - } - catch (Throwable e) { - handleException(e); - } - } - - private void handleException(Throwable e) { - myToolProvider.showError("Edit error: ", e); + myToolProvider.processMouseEvent(event, myArea); } @Override diff --git a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/tools/ToolProvider.java b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/tools/ToolProvider.java index cb2c190224a6..d8a5012ae174 100644 --- a/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/tools/ToolProvider.java +++ b/plugins/ui-designer/ui-designer-new/src/com/intellij/designer/designSurface/tools/ToolProvider.java @@ -19,6 +19,7 @@ import com.intellij.designer.designSurface.EditableArea; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.Nullable; +import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; /** @@ -29,6 +30,72 @@ public abstract class ToolProvider { private EditableArea myArea; private MouseEvent myEvent; + public void processKeyEvent(KeyEvent event, EditableArea area) { + if (myTool != null) { + try { + switch (event.getID()) { + case KeyEvent.KEY_PRESSED: + myTool.keyPressed(event, area); + break; + case KeyEvent.KEY_TYPED: + myTool.keyTyped(event, area); + break; + case KeyEvent.KEY_RELEASED: + myTool.keyReleased(event, area); + break; + } + } + catch (Throwable e) { + showError("Edit error: ", e); + } + } + } + + public void processMouseEvent(MouseEvent event, EditableArea area) { + if (myTool != null) { + try { + switch (event.getID()) { + case MouseEvent.MOUSE_PRESSED: + myTool.mouseDown(event, area); + break; + case MouseEvent.MOUSE_RELEASED: + myTool.mouseUp(event, area); + break; + case MouseEvent.MOUSE_ENTERED: + myTool.mouseEntered(event, area); + break; + case MouseEvent.MOUSE_EXITED: + myTool.mouseExited(event, area); + break; + case MouseEvent.MOUSE_CLICKED: + if (event.getClickCount() == 2) { + myTool.mouseDoubleClick(event, area); + } + break; + case MouseEvent.MOUSE_MOVED: + myTool.mouseMove(event, area); + break; + case MouseEvent.MOUSE_DRAGGED: + myTool.mouseDrag(event, area); + break; + } + } + catch (Throwable e) { + showError("Edit error: ", e); + } + } + } + + public void setEvent(MouseEvent event) { + myEvent = event; + } + + public void setArea(@Nullable EditableArea area) { + myArea = area; + } + + public abstract void showError(@NonNls String message, Throwable e); + public InputTool getActiveTool() { return myTool; } @@ -59,14 +126,4 @@ public abstract class ToolProvider { } public abstract void loadDefaultTool(); - - public void setArea(@Nullable EditableArea area) { - myArea = area; - } - - public void setEvent(MouseEvent event) { - myEvent = event; - } - - public abstract void showError(@NonNls String message, Throwable e); } \ No newline at end of file