diff --git a/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java b/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java
index bd41446c1c1f..8dd004c11532 100644
--- a/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java
+++ b/platform/diff-api/src/com/intellij/diff/DiffContentFactory.java
@@ -50,6 +50,9 @@ public abstract class DiffContentFactory {
@NotNull
public abstract DocumentContent create(@NotNull String text, @Nullable FileType type, boolean respectLineSeparators);
+ @NotNull
+ public abstract DocumentContent create(@NotNull String text, @Nullable VirtualFile highlightFile);
+
@NotNull
public abstract DocumentContent create(@Nullable Project project, @NotNull Document document);
diff --git a/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java b/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java
index 653017dcf568..d6f207e2ad93 100644
--- a/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java
+++ b/platform/diff-impl/src/com/intellij/diff/DiffContentFactoryImpl.java
@@ -58,7 +58,7 @@ public class DiffContentFactoryImpl extends DiffContentFactory {
@Override
@NotNull
public DocumentContent create(@NotNull String text) {
- return create(text, null);
+ return create(text, (FileType)null);
}
@Override
@@ -73,6 +73,11 @@ public class DiffContentFactoryImpl extends DiffContentFactory {
return createImpl(text, type, null, null, respectLineSeparators, true);
}
+ @NotNull
+ public DocumentContent create(@NotNull String text, @Nullable VirtualFile highlightFile) {
+ return createImpl(text, highlightFile != null ? highlightFile.getFileType() : null, highlightFile, null, true, true);
+ }
+
@Override
@NotNull
public DocumentContent create(@Nullable Project project, @NotNull Document document) {
diff --git a/platform/platform-resources/src/META-INF/VcsExtensions.xml b/platform/platform-resources/src/META-INF/VcsExtensions.xml
index a76f7f43f371..d07e6da2c252 100644
--- a/platform/platform-resources/src/META-INF/VcsExtensions.xml
+++ b/platform/platform-resources/src/META-INF/VcsExtensions.xml
@@ -26,6 +26,8 @@
+
+
diff --git a/platform/testRunner/src/com/intellij/execution/testframework/actions/TestDiffRequestProcessor.java b/platform/testRunner/src/com/intellij/execution/testframework/actions/TestDiffRequestProcessor.java
index aff16950c712..9e8aeb14e34e 100644
--- a/platform/testRunner/src/com/intellij/execution/testframework/actions/TestDiffRequestProcessor.java
+++ b/platform/testRunner/src/com/intellij/execution/testframework/actions/TestDiffRequestProcessor.java
@@ -86,7 +86,7 @@ public class TestDiffRequestProcessor extends DiffRequestProcessor {
}
else {
title = ExecutionBundle.message(titleKey);
- content = DiffContentFactory.getInstance().create(contentString, null);
+ content = DiffContentFactory.getInstance().create(contentString);
}
return Pair.create(title, content);
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java
index 3a2a8ad5aefb..8c77f259577e 100644
--- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchAction.java
@@ -22,7 +22,10 @@
*/
package com.intellij.openapi.vcs.changes.patch;
-import com.intellij.diff.*;
+import com.intellij.diff.DiffContentFactory;
+import com.intellij.diff.DiffManager;
+import com.intellij.diff.DiffRequestFactory;
+import com.intellij.diff.InvalidDiffRequestException;
import com.intellij.diff.chains.DiffRequestProducerException;
import com.intellij.diff.contents.DiffContent;
import com.intellij.diff.contents.DocumentContent;
@@ -47,8 +50,6 @@ import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.WindowWrapper;
-import com.intellij.openapi.util.BooleanGetter;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Ref;
@@ -59,7 +60,6 @@ import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vcs.changes.CommitContext;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.ui.EditorNotificationPanel;
import com.intellij.util.Consumer;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
@@ -254,52 +254,24 @@ public class ApplyPatchAction extends DumbAwareAction {
final Document document = FileDocumentManager.getInstance().getDocument(file);
if (texts.getLocal() == null || document == null) return ApplyPatchStatus.FAILURE;
- final CharSequence oldContent = document.getImmutableCharSequence();
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- document.setText(texts.getPatched());
- }
- });
-
final String fullPath = file.getParent() == null ? file.getPath() : file.getParent().getPath();
final String windowTitle = "Result Of Patch Apply To " + file.getName() + " (" + fullPath + ")";
- final List titles = ContainerUtil.list(VcsBundle.message("diff.title.local"), "Patched (with problems)");
- final DiffContentFactory contentFactory = DiffContentFactory.getInstance();
- final DocumentContent originalContent = contentFactory.create(texts.getLocal().toString(), file.getFileType());
- final DiffContent mergedContent = contentFactory.create(project, document);
-
- final List contents = ContainerUtil.list(originalContent, mergedContent);
-
- final DiffRequest request = new SimpleDiffRequest(windowTitle, contents, titles);
- DiffUtil.addNotification(new DiffIsApproximateNotification(), request);
-
- final DiffDialogHints dialogHints = new DiffDialogHints(WindowWrapper.Mode.MODAL);
- dialogHints.setCancelAction(new BooleanGetter() {
+ final Ref successRef = new Ref();
+ Consumer callback = new Consumer() {
@Override
- public boolean get() {
- ApplicationManager.getApplication().runWriteAction(new Runnable() {
- @Override
- public void run() {
- document.setText(oldContent);
- FileDocumentManager.getInstance().saveDocument(document);
- }
- });
- return true;
- }
- });
- dialogHints.setOkAction(new BooleanGetter() {
- @Override
- public boolean get() {
+ public void consume(MergeResult result) {
FileDocumentManager.getInstance().saveDocument(document);
- return true;
+ successRef.set(true);
}
- });
+ };
- DiffManager.getInstance().showDiff(project, request, dialogHints);
+ MergeRequest request = new ApplyPatchMergeRequest(project, document, file, texts.getLocal().toString(), texts.getPatched(), windowTitle,
+ VcsBundle.message("diff.title.local"), "Patched (with problems)", callback);
- return ApplyPatchStatus.SUCCESS;
+ DiffManager.getInstance().showMerge(project, request);
+
+ return successRef.get() == Boolean.TRUE ? ApplyPatchStatus.SUCCESS : ApplyPatchStatus.FAILURE;
}
@NotNull
@@ -322,14 +294,8 @@ public class ApplyPatchAction extends DumbAwareAction {
final List contents = ContainerUtil.list(localContent, mergedContent);
final DiffRequest request = new SimpleDiffRequest(windowTitle, contents, titles);
- DiffUtil.addNotification(new DiffIsApproximateNotification(), request);
+ DiffUtil.addNotification(new ApplyPatchMergeTool.DiffIsApproximateNotification(), request);
return request;
}
-
- private static class DiffIsApproximateNotification extends EditorNotificationPanel {
- public DiffIsApproximateNotification() {
- myLabel.setText("Couldn't find context for patch. Some fragments were applied at the best possible place. Please check carefully.");
- }
- }
}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchMergeRequest.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchMergeRequest.java
new file mode 100644
index 000000000000..63cb798a746f
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchMergeRequest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2000-2015 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.openapi.vcs.changes.patch;
+
+import com.intellij.diff.merge.MergeRequest;
+import com.intellij.diff.merge.MergeResult;
+import com.intellij.openapi.application.ApplicationManager;
+import com.intellij.openapi.command.WriteCommandAction;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Computable;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.util.Consumer;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class ApplyPatchMergeRequest extends MergeRequest {
+ @Nullable private final Project myProject;
+ @NotNull private final Document myDocument;
+
+ @NotNull private final CharSequence myOriginalContent;
+ @NotNull private final String myLocalContent;
+ @NotNull private final String myPatchedContent;
+
+ @NotNull private final String myWindowTitle;
+ @NotNull private final String myLocalTitle;
+ @NotNull private final String myPatchedTitle;
+
+ @Nullable private final Consumer myCallback;
+
+ public ApplyPatchMergeRequest(@Nullable Project project,
+ @NotNull Document document,
+ @NotNull String localContent,
+ @NotNull String patchedContent,
+ @NotNull String windowTitle,
+ @NotNull String localTitle,
+ @NotNull String patchedTitle,
+ @Nullable Consumer callback) {
+ myProject = project;
+ myDocument = document;
+
+ myOriginalContent = ApplicationManager.getApplication().runReadAction(new Computable() {
+ @Override
+ public CharSequence compute() {
+ return myDocument.getImmutableCharSequence();
+ }
+ });
+ myLocalContent = localContent;
+ myPatchedContent = patchedContent;
+
+ myWindowTitle = windowTitle;
+ myLocalTitle = localTitle;
+ myPatchedTitle = patchedTitle;
+
+ myCallback = callback;
+ }
+
+ @Nullable
+ public Project getProject() {
+ return myProject;
+ }
+
+ @NotNull
+ public Document getDocument() {
+ return myDocument;
+ }
+
+ @NotNull
+ public String getLocalContent() {
+ return myLocalContent;
+ }
+
+ @NotNull
+ public String getPatchedContent() {
+ return myPatchedContent;
+ }
+
+ @Nullable
+ @Override
+ public String getTitle() {
+ return myWindowTitle;
+ }
+
+ @NotNull
+ public String getLocalTitle() {
+ return myLocalTitle;
+ }
+
+ @NotNull
+ public String getPatchedTitle() {
+ return myPatchedTitle;
+ }
+
+ @Override
+ public void applyResult(@NotNull MergeResult result) {
+ final CharSequence applyContent;
+ switch (result) {
+ case CANCEL:
+ applyContent = myOriginalContent;
+ break;
+ case LEFT:
+ applyContent = myLocalContent;
+ break;
+ case RIGHT:
+ applyContent = myPatchedContent;
+ break;
+ case RESOLVED:
+ applyContent = null;
+ break;
+ default:
+ throw new IllegalArgumentException(result.name());
+ }
+
+ if (applyContent != null) {
+ new WriteCommandAction.Simple(myProject) {
+ @Override
+ protected void run() throws Throwable {
+ myDocument.setText(applyContent);
+ }
+ }.execute();
+ }
+
+ if (myCallback != null) myCallback.consume(result);
+ }
+}
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchMergeTool.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchMergeTool.java
new file mode 100644
index 000000000000..2e4e0ce44d1b
--- /dev/null
+++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchMergeTool.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2000-2015 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.openapi.vcs.changes.patch;
+
+import com.intellij.diff.DiffContentFactory;
+import com.intellij.diff.FrameDiffTool;
+import com.intellij.diff.contents.DocumentContent;
+import com.intellij.diff.merge.*;
+import com.intellij.diff.requests.SimpleDiffRequest;
+import com.intellij.diff.tools.simple.SimpleDiffViewer;
+import com.intellij.diff.util.DiffUtil;
+import com.intellij.openapi.command.undo.DocumentReference;
+import com.intellij.openapi.command.undo.DocumentReferenceManager;
+import com.intellij.openapi.command.undo.UndoManager;
+import com.intellij.openapi.diff.DiffBundle;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import com.intellij.openapi.util.BooleanGetter;
+import com.intellij.openapi.util.Disposer;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.ui.EditorNotificationPanel;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+public class ApplyPatchMergeTool implements MergeTool {
+ @NotNull
+ @Override
+ public MergeViewer createComponent(@NotNull MergeContext context, @NotNull MergeRequest request) {
+ return new MyViewer(context, (ApplyPatchMergeRequest)request);
+ }
+
+ @Override
+ public boolean canShow(@NotNull MergeContext context, @NotNull MergeRequest request) {
+ return request instanceof ApplyPatchMergeRequest;
+ }
+
+ private static class MyViewer implements MergeViewer {
+ @NotNull private final MergeContext myMergeContext;
+ @NotNull private final ApplyPatchMergeRequest myMergeRequest;
+
+ @NotNull private final SimpleDiffViewer myViewer;
+
+ public MyViewer(@NotNull MergeContext context, @NotNull ApplyPatchMergeRequest request) {
+ myMergeContext = context;
+ myMergeRequest = request;
+
+ MergeUtil.ProxyDiffContext diffContext = new MergeUtil.ProxyDiffContext(myMergeContext);
+
+ VirtualFile file = FileDocumentManager.getInstance().getFile(myMergeRequest.getDocument());
+ final DiffContentFactory contentFactory = DiffContentFactory.getInstance();
+ final DocumentContent localContent = contentFactory.create(myMergeRequest.getLocalContent(), file);
+ final DocumentContent mergedContent = contentFactory.create(myMergeRequest.getProject(), myMergeRequest.getDocument());
+
+ SimpleDiffRequest diffRequest = new SimpleDiffRequest(myMergeRequest.getTitle(), localContent, mergedContent,
+ myMergeRequest.getLocalTitle(), myMergeRequest.getPatchedTitle());
+ DiffUtil.addNotification(new DiffIsApproximateNotification(), diffRequest);
+
+ myViewer = new SimpleDiffViewer(diffContext, diffRequest);
+ }
+
+ @NotNull
+ @Override
+ public JComponent getComponent() {
+ return myViewer.getComponent();
+ }
+
+ @Nullable
+ @Override
+ public JComponent getPreferredFocusedComponent() {
+ return myViewer.getPreferredFocusedComponent();
+ }
+
+ @Override
+ public ToolbarComponents init() {
+ final Project project = myMergeContext.getProject();
+ final Document document = myMergeRequest.getDocument();
+
+ DiffUtil.executeWriteCommand(document, project, "Init merge content", new Runnable() {
+ @Override
+ public void run() {
+ document.setText(myMergeRequest.getPatchedContent());
+
+ UndoManager undoManager = project != null ? UndoManager.getInstance(project) : UndoManager.getGlobalInstance();
+ if (undoManager != null) {
+ DocumentReference ref = DocumentReferenceManager.getInstance().create(document);
+ undoManager.nonundoableActionPerformed(ref, false);
+ }
+ }
+ });
+
+ ToolbarComponents components = new ToolbarComponents();
+
+ FrameDiffTool.ToolbarComponents init = myViewer.init();
+ components.statusPanel = init.statusPanel;
+ components.toolbarActions = init.toolbarActions;
+
+ components.closeHandler = new BooleanGetter() {
+ @Override
+ public boolean get() {
+ return Messages.showYesNoDialog(getComponent().getRootPane(),
+ DiffBundle.message("merge.dialog.exit.without.applying.changes.confirmation.message"),
+ DiffBundle.message("cancel.visual.merge.dialog.title"), Messages.getQuestionIcon()) ==
+ Messages.YES;
+ }
+ };
+ return components;
+ }
+
+ @Nullable
+ @Override
+ public Action getResolveAction(@NotNull final MergeResult result) {
+ if (result == MergeResult.LEFT || result == MergeResult.RIGHT) return null;
+
+ String caption = MergeUtil.getResolveActionTitle(result, myMergeRequest, myMergeContext);
+ return new AbstractAction(caption) {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (result == MergeResult.CANCEL) {
+ if (Messages.showYesNoDialog(getComponent().getRootPane(),
+ DiffBundle.message("merge.dialog.exit.without.applying.changes.confirmation.message"),
+ DiffBundle.message("cancel.visual.merge.dialog.title"), Messages.getQuestionIcon()) !=
+ Messages.YES) {
+ return;
+ }
+ }
+ myMergeContext.finishMerge(result);
+ }
+ };
+ }
+
+ @Override
+ public void dispose() {
+ Disposer.dispose(myViewer);
+ }
+ }
+
+ public static class DiffIsApproximateNotification extends EditorNotificationPanel {
+ public DiffIsApproximateNotification() {
+ myLabel.setText("Couldn't find context for patch. Some fragments were applied at the best possible place. " +
+ "Please check carefully.");
+ }
+ }
+}