From 4f725efed9cd65991de607fd2a2f2535ffdb45d4 Mon Sep 17 00:00:00 2001
From: "Nadya.Zabrodina"
Date: Mon, 15 Oct 2012 13:14:51 +0400
Subject: [PATCH] IDEA-64887 Mercurial: change dialog that appears on
deleted-modified conflict
---
.../zmlx/hg4idea/command/HgUpdateCommand.java | 3 +-
.../hg4idea/execution/HgCommandExecutor.java | 93 ++++++++-----------
.../HgDeleteModifyPromptHandler.java | 90 ++++++++++++++++++
.../hg4idea/execution/HgPromptChoice.java | 61 ++++++++++++
.../hg4idea/execution/HgPromptHandler.java | 47 ++++++++++
5 files changed, 240 insertions(+), 54 deletions(-)
create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgDeleteModifyPromptHandler.java
create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgPromptChoice.java
create mode 100644 plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgPromptHandler.java
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgUpdateCommand.java b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgUpdateCommand.java
index 6194efa48996..f389393ac909 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgUpdateCommand.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/command/HgUpdateCommand.java
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.Nullable;
import org.zmlx.hg4idea.HgVcs;
import org.zmlx.hg4idea.execution.HgCommandExecutor;
import org.zmlx.hg4idea.execution.HgCommandResult;
+import org.zmlx.hg4idea.execution.HgDeleteModifyPromptHandler;
import java.util.LinkedList;
import java.util.List;
@@ -66,7 +67,7 @@ public class HgUpdateCommand {
final HgCommandExecutor executor = new HgCommandExecutor(project);
executor.setShowOutput(true);
- final HgCommandResult result = executor.executeInCurrentThread(repo, "update", arguments);
+ final HgCommandResult result = executor.executeInCurrentThread(repo, "update", arguments,new HgDeleteModifyPromptHandler());
project.getMessageBus().syncPublisher(HgVcs.BRANCH_TOPIC).update(project);
return result;
}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java
index 5204f2ded5cb..575cb123fcb8 100644
--- a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgCommandExecutor.java
@@ -13,9 +13,9 @@
package org.zmlx.hg4idea.execution;
import com.intellij.execution.ui.ConsoleViewContentType;
-import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.vcsUtil.VcsImplUtil;
@@ -28,7 +28,6 @@ import org.zmlx.hg4idea.util.HgEncodingUtil;
import org.zmlx.hg4idea.util.HgErrorUtil;
import org.zmlx.hg4idea.util.HgUtil;
-import javax.swing.*;
import java.awt.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -52,7 +51,7 @@ import java.util.List;
*
*/
public final class HgCommandExecutor {
-
+
private static final Logger LOG = Logger.getInstance(HgCommandExecutor.class.getName());
private static final List DEFAULT_OPTIONS = Arrays.asList("--config", "ui.merge=internal:merge");
@@ -100,6 +99,12 @@ public final class HgCommandExecutor {
@Nullable
public HgCommandResult executeInCurrentThread(@Nullable final VirtualFile repo, @NotNull final String operation,
@Nullable final List arguments) {
+ return executeInCurrentThread(repo, operation, arguments, null);
+ }
+
+ @Nullable
+ public HgCommandResult executeInCurrentThread(@Nullable final VirtualFile repo, @NotNull final String operation,
+ @Nullable final List arguments, @Nullable HgPromptHandler handler) {
//LOG.assertTrue(!ApplicationManager.getApplication().isDispatchThread()); disabled for release
if (myProject == null || myProject.isDisposed() || myVcs == null) {
return null;
@@ -114,11 +119,11 @@ public final class HgCommandExecutor {
WarningReceiver warningReceiver = new WarningReceiver();
PassReceiver passReceiver = new PassReceiver(myProject);
-
- SocketServer promptServer = new SocketServer(new PromptReceiver());
+
+ SocketServer promptServer = new SocketServer(new PromptReceiver(handler));
SocketServer warningServer = new SocketServer(warningReceiver);
SocketServer passServer = new SocketServer(passReceiver);
-
+
try {
int promptPort = promptServer.start();
int warningPort = warningServer.start();
@@ -258,37 +263,46 @@ public final class HgCommandExecutor {
}
private static class PromptReceiver extends SocketServer.Protocol {
+ @Nullable HgPromptHandler myHandler;
+
+ public PromptReceiver(@Nullable HgPromptHandler handler) {
+ myHandler = handler;
+ }
public boolean handleConnection(Socket socket) throws IOException {
DataInputStream dataInput = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
final String message = new String(readDataBlock(dataInput));
int numOfChoices = dataInput.readInt();
- final Choice[] choices = new Choice[numOfChoices];
+ final HgPromptChoice[] choices = new HgPromptChoice[numOfChoices];
for (int i = 0; i < numOfChoices; i++) {
String choice = new String(readDataBlock(dataInput));
- choices[i] = new Choice(choice);
+ choices[i] = new HgPromptChoice(i, choice);
}
int defaultChoiceInt = dataInput.readInt();
- final Choice defaultChoice = choices[defaultChoiceInt];
-
+ final HgPromptChoice defaultChoice = choices[defaultChoiceInt];
+ if (myHandler != null && myHandler.shouldHandle(message)) {
+ int chosen = myHandler.promptUser(message, choices, defaultChoice).getChosenIndex();
+ sendChoiceToHg(out, chosen);
+ return true;
+ }
final int[] index = new int[]{-1};
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
- Window parent = ApplicationManager.getApplication().getComponent(Window.class);
- index[0] = JOptionPane
- .showOptionDialog(parent, message, "hg4idea", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, choices,
- defaultChoice);
+ String[] choicePresentationArray = new String[choices.length];
+ for (int i = 0; i < choices.length; ++i) {
+ choicePresentationArray[i] = choices[i].toString();
+ }
+ index[0] = Messages
+ .showChooseDialog(message, "hg4idea",
+ choicePresentationArray,
+ defaultChoice.toString(), Messages.getQuestionIcon());
}
});
-
+
int chosen = index[0];
- if (chosen == JOptionPane.CLOSED_OPTION) {
- out.writeInt(-1);
- } else {
- out.writeInt(chosen);
- }
+ sendChoiceToHg(out, chosen);
return true;
}
catch (InterruptedException e) {
@@ -301,43 +315,16 @@ public final class HgCommandExecutor {
}
}
- private static class Choice{
- private final String fullString;
- private final String representation;
- private final String choiceChar;
-
- private Choice(String fullString) {
- this.fullString = fullString;
- this.representation = fullString.replaceAll("&", "");
- int index = fullString.indexOf("&");
- this.choiceChar = "" + fullString.charAt(index + 1);
-
+ private static void sendChoiceToHg(@NotNull DataOutputStream outStream, int choice) throws IOException {
+ if (choice == HgPromptChoice.CLOSED_OPTION) {
+ outStream.writeInt(-1);
}
-
- @Override
- public String toString() {
- return representation;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Choice choice = (Choice) o;
-
- if (!fullString.equals(choice.fullString)) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- return fullString.hashCode();
+ else {
+ outStream.writeInt(choice);
}
}
}
-
+
private static class PassReceiver extends SocketServer.Protocol{
private final Project myProject;
private HgCommandAuthenticator myAuthenticator;
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgDeleteModifyPromptHandler.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgDeleteModifyPromptHandler.java
new file mode 100644
index 000000000000..ce545ca8f69a
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgDeleteModifyPromptHandler.java
@@ -0,0 +1,90 @@
+/*
+ * 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 org.zmlx.hg4idea.execution;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.ui.Messages;
+import org.jetbrains.annotations.NotNull;
+
+import java.awt.*;
+import java.lang.reflect.InvocationTargetException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Nadya Zabrodina
+ */
+public class HgDeleteModifyPromptHandler implements HgPromptHandler {
+
+ private static final Logger LOG = Logger.getInstance("#org.zmlx.hg4idea.execution.HgDeleteModifyPromptHandler");
+
+ private static final Pattern LOCAL_DELETE_REMOTE_MODIFIED_CONFLICT_MESSAGE_PATTERN = Pattern.compile(
+ "remote\\schanged(.+)which\\slocal\\sdeleted\\s.+");
+ private static final Pattern REMOTE_DELETE_LOCAL_MODIFIED_CONFLICT_MESSAGE_PATTERN = Pattern.compile(
+ "\\slocal\\schanged(.+)which\\sremote\\sdeleted\\s.+");
+
+ private String myMessage = "";
+
+ public HgPromptChoice promptUser(final String message,
+ @NotNull final HgPromptChoice[] choices,
+ @NotNull final HgPromptChoice defaultChoice) {
+
+ final int[] chosen = new int[]{-1};
+ try {
+ EventQueue.invokeAndWait
+ (new Runnable() {
+ public void run() {
+ String[] choicePresentationArray = new String[choices.length];
+ for (int i = 0; i < choices.length; ++i) {
+ choicePresentationArray[i] = choices[i].toString();
+ }
+ chosen[0] = Messages
+ .showChooseDialog(myMessage, "Delete-Modify Conflict",
+ choicePresentationArray,
+ defaultChoice.toString(), Messages.getQuestionIcon());
+ }
+ });
+ }
+ catch (InterruptedException e) {
+ LOG.error(e);
+ return defaultChoice;
+ }
+ catch (InvocationTargetException e) {
+ LOG.error(e);
+ return defaultChoice;
+ }
+ return chosen[0] >= 0 ? choices[chosen[0]] : HgPromptChoice.ABORT;
+ }
+
+ public boolean shouldHandle(String message) {
+ Matcher localDelMatcher = LOCAL_DELETE_REMOTE_MODIFIED_CONFLICT_MESSAGE_PATTERN.matcher(message);
+ Matcher locaModifMatcher = REMOTE_DELETE_LOCAL_MODIFIED_CONFLICT_MESSAGE_PATTERN.matcher(message);
+ String filename;
+ if (localDelMatcher.matches()) {
+ filename = localDelMatcher.group(1);
+ myMessage =
+ "File " + filename + " is deleted locally, but modified remotely. Do you want to keep the modified version or remove the file?";
+ return true;
+ }
+ else if (locaModifMatcher.matches()) {
+ filename = locaModifMatcher.group(1);
+ myMessage =
+ "File " + filename + " is deleted remotely, but modified locally. Do you want to keep the modified version or remove the file?";
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgPromptChoice.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgPromptChoice.java
new file mode 100644
index 000000000000..2880bc983dba
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgPromptChoice.java
@@ -0,0 +1,61 @@
+/*
+ * 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 org.zmlx.hg4idea.execution;
+
+
+public class HgPromptChoice {
+ private final String fullString;
+ private final String representation;
+ private final String choiceChar;
+ private final int chosenIndex;
+ public static final int CLOSED_OPTION = -1;
+ public static final HgPromptChoice ABORT = new HgPromptChoice(-1, "AbortChoice");
+
+ public int getChosenIndex() {
+ return chosenIndex;
+ }
+
+
+ HgPromptChoice(int chosenIndex, String fullString) {
+ this.fullString = fullString;
+ this.representation = fullString.replaceAll("&", "");
+ int index = fullString.indexOf("&");
+ this.choiceChar = String.valueOf(fullString.charAt(index + 1));
+ this.chosenIndex = chosenIndex;
+ }
+
+ @Override
+ public String toString() {
+ return representation;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (null == o) return true;
+ if (getClass() != o.getClass()) return false;
+
+ HgPromptChoice choice = (HgPromptChoice)o;
+
+ if (!fullString.equals(choice.fullString)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return fullString.hashCode();
+ }
+}
\ No newline at end of file
diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgPromptHandler.java b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgPromptHandler.java
new file mode 100644
index 000000000000..66e75abca9b6
--- /dev/null
+++ b/plugins/hg4idea/src/org/zmlx/hg4idea/execution/HgPromptHandler.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.zmlx.hg4idea.execution;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * HgPromptHandler is used by {@link HgCommandExecutor}, when you want to change the behavior of standart commands execution in the Mercurial.
+ *
+ * @author Nadya Zabrodina
+ */
+public interface HgPromptHandler {
+
+ /**
+ * Checks you need to change the default behavior.
+ *
+ * @param message standart output message from Mercurial
+ * @return
+ */
+ boolean shouldHandle(String message);
+
+ /**
+ * Change default behavior in commands execution.
+ *
+ *
+ * @param message standard output message from Mercurial
+ * @param choices possible choices
+ * @param defaultChoice
+ * @return
+ */
+ HgPromptChoice promptUser(final String message,
+ @NotNull final HgPromptChoice[] choices,
+ @NotNull final HgPromptChoice defaultChoice);
+}