IDEA-64887 Mercurial: change dialog that appears on deleted-modified conflict

This commit is contained in:
Nadya.Zabrodina
2012-10-15 13:17:48 +04:00
parent 912cf5ec65
commit 4f725efed9
5 changed files with 240 additions and 54 deletions
@@ -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;
}
@@ -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;
* </p>
*/
public final class HgCommandExecutor {
private static final Logger LOG = Logger.getInstance(HgCommandExecutor.class.getName());
private static final List<String> 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<String> arguments) {
return executeInCurrentThread(repo, operation, arguments, null);
}
@Nullable
public HgCommandResult executeInCurrentThread(@Nullable final VirtualFile repo, @NotNull final String operation,
@Nullable final List<String> 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;
@@ -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;
}
}
@@ -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();
}
}
@@ -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);
}