From be7e174a8d843d0510faf7b19aa168b0a95019c2 Mon Sep 17 00:00:00 2001 From: irengrig Date: Fri, 6 Nov 2009 15:36:43 +0300 Subject: [PATCH] apply patch: show diff with conflicts --- .../intellij/openapi/diff/DiffRequest.java | 33 ++- .../com/intellij/openapi/diff/DiffViewer.java | 2 + .../openapi/diff/SimpleDiffRequest.java | 31 --- .../openapi/diff/impl/DiffPanelImpl.java | 39 ++-- .../diff/impl/GenericDataProvider.java | 40 ++++ .../impl/incrementalMerge/ui/MergePanel2.java | 14 +- .../vcs/changes/ChangeRequestChain.java | 5 +- .../changes/actions/ChangeDiffRequest.java | 206 ++++-------------- .../actions/ChangeDiffRequestPresentable.java | 196 +++++++++++++++++ .../actions/DiffPresentationReturnValue.java | 22 ++ .../actions/DiffRequestPresentable.java | 45 ++++ .../vcs/changes/actions/ShowDiffAction.java | 40 ++-- .../changes/actions/ShowNextChangeAction.java | 15 +- .../changes/actions/ShowPrevChangeAction.java | 15 +- .../vcs/changes/patch/ApplyPatchAction.java | 55 ++--- .../patch/ApplyPatchDifferentiatedDialog.java | 40 +++- .../patch/ApplyPatchForBaseRevisionTexts.java | 99 +++++++++ .../changes/patch/FilePatchInProgress.java | 83 ++++++- .../patch/LazyPatchContentRevision.java | 2 +- 19 files changed, 682 insertions(+), 300 deletions(-) create mode 100644 platform/platform-impl/src/com/intellij/openapi/diff/impl/GenericDataProvider.java create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeDiffRequestPresentable.java create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffPresentationReturnValue.java create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestPresentable.java create mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchForBaseRevisionTexts.java diff --git a/platform/platform-api/src/com/intellij/openapi/diff/DiffRequest.java b/platform/platform-api/src/com/intellij/openapi/diff/DiffRequest.java index b325e87db0c4..34041fa45cb6 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/DiffRequest.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/DiffRequest.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.diff; +import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.actionSystem.IdeActions; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Factory; @@ -23,8 +24,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.util.Collection; -import java.util.Collections; +import java.util.*; /** * A request for a diff or merge operation. @@ -35,9 +35,12 @@ public abstract class DiffRequest { private ToolbarAddons myToolbarAddons = ToolbarAddons.NOTHING; @NonNls private static final String COMMON_DIFF_GROUP_KEY = "DiffWindow"; private Factory myBottomComponentFactory = null; + private final HashSet myHints = new HashSet(); + private final Map myGenericData; protected DiffRequest(Project project) { myProject = project; + myGenericData = new HashMap(2); } public void setToolbarAddons(@NotNull ToolbarAddons toolbarAddons) { @@ -75,7 +78,31 @@ public abstract class DiffRequest { * @return not null (possibly empty) collection of hints for diff tool. */ public Collection getHints() { - return Collections.emptySet(); + return Collections.unmodifiableCollection(myHints); + } + + public void passForDataContext(final DataKey key, final Object value) { + myGenericData.put(key.getName(), value); + } + + public Map getGenericData() { + return myGenericData; + } + + /** + * @param hint + * @see DiffRequest#getHints() + */ + public void addHint(Object hint) { + myHints.add(hint); + } + + /** + * @param hint + * @see DiffRequest#getHints() + */ + public void removeHint(Object hint) { + myHints.remove(hint); } /** diff --git a/platform/platform-api/src/com/intellij/openapi/diff/DiffViewer.java b/platform/platform-api/src/com/intellij/openapi/diff/DiffViewer.java index 25cb19b83384..89c7afa4a373 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/DiffViewer.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/DiffViewer.java @@ -26,4 +26,6 @@ public interface DiffViewer { JComponent getComponent(); JComponent getPreferredFocusedComponent(); + + int getContentsNumber(); } diff --git a/platform/platform-api/src/com/intellij/openapi/diff/SimpleDiffRequest.java b/platform/platform-api/src/com/intellij/openapi/diff/SimpleDiffRequest.java index 1619723aab85..32874a74e99a 100644 --- a/platform/platform-api/src/com/intellij/openapi/diff/SimpleDiffRequest.java +++ b/platform/platform-api/src/com/intellij/openapi/diff/SimpleDiffRequest.java @@ -31,47 +31,16 @@ public class SimpleDiffRequest extends DiffRequest { private final DiffContent[] myContents = new DiffContent[2]; private final String[] myContentTitles = new String[2]; private String myWindowTitle; - private final HashSet myHints = new HashSet(); - private final Map myGenericData; public SimpleDiffRequest(Project project, String windowtitle) { super(project); myWindowTitle = windowtitle; - myGenericData = new HashMap(2); } public DiffContent[] getContents() { return myContents; } public String[] getContentTitles() { return myContentTitles; } public String getWindowTitle() { return myWindowTitle; } - public Collection getHints() { - return Collections.unmodifiableCollection(myHints); - } - - public void passForDataContext(final DataKey key, final Object value) { - myGenericData.put(key.getName(), value); - } - - public Map getGenericData() { - return myGenericData; - } - - /** - * @param hint - * @see DiffRequest#getHints() - */ - public void addHint(Object hint) { - myHints.add(hint); - } - - /** - * @param hint - * @see DiffRequest#getHints() - */ - public void removeHint(Object hint) { - myHints.remove(hint); - } - public void setContents(@NotNull DiffContent content1, @NotNull DiffContent content2) { myContents[0] = content1; myContents[1] = content2; diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java index 7cbc297d3cd5..68042341ac6f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/DiffPanelImpl.java @@ -19,7 +19,6 @@ import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.DataConstants; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diff.*; import com.intellij.openapi.diff.actions.MergeActionGroup; @@ -49,8 +48,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.security.InvalidParameterException; -import java.util.HashMap; -import java.util.Map; public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSidesContainer { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.diff.impl.DiffPanelImpl"); @@ -79,7 +76,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid } }; private boolean myDisposed = false; - private final DiffPanelImpl.MyDataProvider myDataProvider; + private final GenericDataProvider myDataProvider; public DiffPanelImpl(final Window owner, Project project, boolean enableToolbar) { myOptions = new DiffPanelOptions(this); @@ -96,7 +93,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid mySplitter = new DiffSplitter(myLeftSide.getComponent(), myRightSide.getComponent(), new DiffDividerPaint(this, FragmentSide.SIDE1)); myPanel.insertDiffComponent(mySplitter, new MyScrollingPanel()); - myDataProvider = new MyDataProvider(); + myDataProvider = new MyGenericDataProvider(this); myPanel.setDataProvider(myDataProvider); final ComparisonPolicy comparisonPolicy = getComparisonPolicy(); @@ -202,6 +199,10 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid return myCurrentSide.getFocusableComponent(); } + public int getContentsNumber() { + return 2; + } + public ComparisonPolicy getComparisonPolicy() { return myData.getComparisonPolicy(); } @@ -306,9 +307,7 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid if (data.getHints().contains(DiffTool.HINT_DO_NOT_IGNORE_WHITESPACES)) { setComparisonPolicy(ComparisonPolicy.DEFAULT, false); } - if (myDiffRequest instanceof SimpleDiffRequest) { - myDataProvider.putData(((SimpleDiffRequest) myDiffRequest).getGenericData()); - } + myDataProvider.putData(myDiffRequest.getGenericData()); setContents(data.getContents()[0], data.getContents()[1]); setTitle1(data.getContentTitles()[0]); @@ -360,32 +359,28 @@ public class DiffPanelImpl implements DiffPanelEx, ContentChangeListener, TwoSid } } - private class MyDataProvider implements DataProvider { - private final Map myGenericData; + private class MyGenericDataProvider extends GenericDataProvider { + private DiffPanelImpl myDiffPanel; - private MyDataProvider() { - myGenericData = new HashMap(); + private MyGenericDataProvider(DiffPanelImpl diffPanel) { + myDiffPanel = diffPanel; } private final FocusDiffSide myFocusDiffSide = new FocusDiffSide() { public Editor getEditor() { - return getCurrentSide().getEditor(); + return myDiffPanel.getCurrentSide().getEditor(); } public int[] getFragmentStartingLines() { - return getFragmentBeginnings(); + return myDiffPanel.getFragmentBeginnings(); } }; - void putData(final Map map) { - myGenericData.putAll(map); - } - + @Override public Object getData(String dataId) { - if (DataConstants.DIFF_VIEWER.equals(dataId)) return DiffPanelImpl.this; - if (FocusDiffSide.FOCUSED_DIFF_SIDE.equals(dataId)) return myCurrentSide == null ? null : myFocusDiffSide; - return myGenericData.get(dataId); + if (DataConstants.DIFF_VIEWER.equals(dataId)) return myDiffPanel; + if (FocusDiffSide.FOCUSED_DIFF_SIDE.equals(dataId)) return myDiffPanel.myCurrentSide == null ? null : myFocusDiffSide; + return super.getData(dataId); } } - } diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/GenericDataProvider.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/GenericDataProvider.java new file mode 100644 index 000000000000..250ebf320e75 --- /dev/null +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/GenericDataProvider.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2009 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.diff.impl; + +import com.intellij.openapi.actionSystem.DataConstants; +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.diff.impl.util.FocusDiffSide; +import com.intellij.openapi.editor.Editor; + +import java.util.HashMap; +import java.util.Map; + +public class GenericDataProvider implements DataProvider { + private final Map myGenericData; + + public GenericDataProvider() { + myGenericData = new HashMap(); + } + + public void putData(final Map map) { + myGenericData.putAll(map); + } + + public Object getData(String dataId) { + return myGenericData.get(dataId); + } +} diff --git a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java index 2425300d28fe..7374181b6101 100644 --- a/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java +++ b/platform/platform-impl/src/com/intellij/openapi/diff/impl/incrementalMerge/ui/MergePanel2.java @@ -23,6 +23,7 @@ import com.intellij.openapi.diff.actions.NextDiffAction; import com.intellij.openapi.diff.actions.PreviousDiffAction; import com.intellij.openapi.diff.impl.DiffUtil; import com.intellij.openapi.diff.impl.EditingSides; +import com.intellij.openapi.diff.impl.GenericDataProvider; import com.intellij.openapi.diff.impl.highlighting.FragmentSide; import com.intellij.openapi.diff.impl.incrementalMerge.ChangeCounter; import com.intellij.openapi.diff.impl.incrementalMerge.ChangeList; @@ -72,6 +73,7 @@ public class MergePanel2 implements DiffViewer { private final DividersRepainter myDividersRepainter = new DividersRepainter(); private StatusUpdater myStatusUpdater; private final DialogBuilder myBuilder; + private MergePanel2.MyDataProvider myProvider; public MergePanel2(DialogBuilder builder, Disposable parent) { ArrayList editorPlaces = new ArrayList(); @@ -105,7 +107,8 @@ public class MergePanel2 implements DiffViewer { FontSizeSynchronizer.attachTo(editorPlaces); myPanel = new DiffPanelOutterComponent(TextDiffType.MERGE_TYPES, TOOLBAR); myPanel.insertDiffComponent(new ThreePanels(myEditorsPanels, myDividers), new MyScrollingPanel()); - myPanel.setDataProvider(new MyDataProvider()); + myProvider = new MyDataProvider(); + myPanel.setDataProvider(myProvider); myBuilder = builder; } @@ -233,6 +236,7 @@ public class MergePanel2 implements DiffViewer { } LOG.assertTrue(!myDuringCreation); myDuringCreation = true; + myProvider.putData(data.getGenericData()); try { myData = data; String[] titles = myData.getContentTitles(); @@ -275,6 +279,10 @@ public class MergePanel2 implements DiffViewer { return getEditorPlace(1).getContentComponent(); } + public int getContentsNumber() { + return 3; + } + private boolean hasAllEditors() { for (int i = 0; i < EDITORS_COUNT; i++) { if (getEditor(i) == null) return false; @@ -390,7 +398,7 @@ public class MergePanel2 implements DiffViewer { return contentType; } - private class MyDataProvider implements DataProvider { + private class MyDataProvider extends GenericDataProvider { public Object getData(String dataId) { if (FocusDiffSide.FOCUSED_DIFF_SIDE.equals(dataId)) { int index = getFocusedEditorIndex(); @@ -405,7 +413,7 @@ public class MergePanel2 implements DiffViewer { } } else if (DataConstants.DIFF_VIEWER.equals(dataId)) return MergePanel2.this; - return null; + return super.getData(dataId); } private int getFocusedEditorIndex() { diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeRequestChain.java b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeRequestChain.java index 617effa9de4e..9bca839d68e6 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeRequestChain.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangeRequestChain.java @@ -15,6 +15,7 @@ */ package com.intellij.openapi.vcs.changes; +import com.intellij.openapi.diff.DiffRequest; import org.jetbrains.annotations.Nullable; import com.intellij.openapi.diff.SimpleDiffRequest; @@ -24,8 +25,8 @@ public interface ChangeRequestChain { boolean canMoveBack(); @Nullable - SimpleDiffRequest moveForward(); + DiffRequest moveForward(); @Nullable - SimpleDiffRequest moveBack(); + DiffRequest moveBack(); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeDiffRequest.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeDiffRequest.java index cc806ccf68cf..628a0d7e4755 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeDiffRequest.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeDiffRequest.java @@ -28,6 +28,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.NullableFactory; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.VcsBundle; +import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeRequestChain; @@ -44,7 +45,8 @@ import java.util.List; * @author yole */ public class ChangeDiffRequest implements ChangeRequestChain { - private final List myChanges; + private final List mySteps; + private final boolean myShowFrame; private int myIndex; private final ShowDiffAction.DiffExtendUIFactory myActionsFactory; @@ -53,9 +55,11 @@ public class ChangeDiffRequest implements ChangeRequestChain { private final AnAction myNextChangeAction; private final Project myProject; - public ChangeDiffRequest(final Project project, final List changes, final ShowDiffAction.DiffExtendUIFactory actionsFactory) { + public ChangeDiffRequest(final Project project, final List steps, final ShowDiffAction.DiffExtendUIFactory actionsFactory, + final boolean showFrame) { myProject = project; - myChanges = changes; + mySteps = steps; + myShowFrame = showFrame; myIndex = 0; myActionsFactory = actionsFactory; @@ -64,24 +68,36 @@ public class ChangeDiffRequest implements ChangeRequestChain { myNextChangeAction = ActionManager.getInstance().getAction("Diff.NextChange"); } + private void onEveryMove(final DiffRequest simpleRequest, final boolean showFrame) { + simpleRequest.passForDataContext(VcsDataKeys.DIFF_REQUEST_CHAIN, this); + if (showFrame) { + simpleRequest.addHint(DiffTool.HINT_SHOW_FRAME); + } + else { + simpleRequest.addHint(DiffTool.HINT_SHOW_MODAL_DIALOG); + } + if (mySteps.size() > 1) { + simpleRequest.addHint(DiffTool.HINT_ALLOW_NO_DIFFERENCES); + } + } + public boolean quickCheckHaveStuff() { - if (myChanges.isEmpty()) return false; - if (myChanges.size() == 1) { - final Change change = myChanges.get(0); - return checkContentsAvailable(change.getBeforeRevision(), change.getAfterRevision()); + if (mySteps.isEmpty()) return false; + if (mySteps.size() == 1) { + return mySteps.get(0).haveStuff(); } return true; } @Nullable - public SimpleDiffRequest init(final int idx) { - if (idx < 0 || idx > (myChanges.size() - 1)) return null; + public DiffRequest init(final int idx) { + if (idx < 0 || idx > (mySteps.size() - 1)) return null; myIndex = idx - 1; return moveForward(); } public boolean canMoveForward() { - return myIndex < (myChanges.size() - 1); + return myIndex < (mySteps.size() - 1); } public boolean canMoveBack() { @@ -89,7 +105,7 @@ public class ChangeDiffRequest implements ChangeRequestChain { } @Nullable - public SimpleDiffRequest moveForward() { + public DiffRequest moveForward() { return moveImpl(new MoveDirection() { public boolean canMove() { return canMoveForward(); @@ -101,20 +117,24 @@ public class ChangeDiffRequest implements ChangeRequestChain { } @Nullable - private SimpleDiffRequest moveImpl(final MoveDirection moveDirection) { + private DiffRequest moveImpl(final MoveDirection moveDirection) { while (moveDirection.canMove()) { final int nextIdx = myIndex + moveDirection.direction(); - final Change change = myChanges.get(nextIdx); - final SimpleDiffRequest request = new SimpleDiffRequest(myProject, null); - final MyReturnValue returnValue = getRequestForChange(request, change); - if (MyReturnValue.quit.equals(returnValue)) { + + final DiffRequestPresentable diffRequestPresentable = mySteps.get(nextIdx); + final DiffRequestPresentable.MyResult result = diffRequestPresentable.step(); + final DiffPresentationReturnValue returnValue = result.getReturnValue(); + if (DiffPresentationReturnValue.quit.equals(returnValue)) { return null; } - if (MyReturnValue.removeFromList.equals(returnValue)) { - myChanges.remove(nextIdx); + if (DiffPresentationReturnValue.removeFromList.equals(returnValue)) { + mySteps.remove(nextIdx); continue; } + final DiffRequest request = result.getRequest(); + takeStuffFromFactory(request, diffRequestPresentable.createActions(myActionsFactory)); myIndex = nextIdx; + onEveryMove(request, myShowFrame); return request; } return null; @@ -126,7 +146,7 @@ public class ChangeDiffRequest implements ChangeRequestChain { } @Nullable - public SimpleDiffRequest moveBack() { + public DiffRequest moveBack() { return moveImpl(new MoveDirection() { public boolean canMove() { return canMoveBack(); @@ -137,32 +157,18 @@ public class ChangeDiffRequest implements ChangeRequestChain { }); } - private static enum MyReturnValue { - removeFromList, - useRequest, - quit; - } - - @Nullable - private MyReturnValue getRequestForChange(final SimpleDiffRequest request, final Change change) { - if (! canShowChange(change)) return MyReturnValue.removeFromList; - if (! loadCurrentContents(request, change)) return MyReturnValue.quit; - takeStuffFromFactory(request, change); - return MyReturnValue.useRequest; - } - - private void takeStuffFromFactory(final SimpleDiffRequest request, final Change change) { - if (myChanges.size() > 1 || (myActionsFactory != null)) { + private void takeStuffFromFactory(final DiffRequest request, final List actions) { + if (mySteps.size() > 1 || (myActionsFactory != null)) { request.setToolbarAddons(new DiffRequest.ToolbarAddons() { public void customize(DiffToolbar toolbar) { - if (myChanges.size() > 1) + if (mySteps.size() > 1) toolbar.addSeparator(); toolbar.addAction(myPrevChangeAction); toolbar.addAction(myNextChangeAction); if (myActionsFactory != null) { toolbar.addSeparator(); - for (AnAction action : myActionsFactory.createActions(change)) { + for (AnAction action : actions) { toolbar.addAction(action); } } @@ -178,130 +184,4 @@ public class ChangeDiffRequest implements ChangeRequestChain { }); } } - - private boolean loadCurrentContents(final SimpleDiffRequest request, final Change change) { - final ContentRevision bRev = change.getBeforeRevision(); - final ContentRevision aRev = change.getAfterRevision(); - - String beforePath = bRev != null ? bRev.getFile().getPath() : null; - String afterPath = aRev != null ? aRev.getFile().getPath() : null; - String title; - if (beforePath != null && afterPath != null && !beforePath.equals(afterPath)) { - title = beforePath + " -> " + afterPath; - } - else if (beforePath != null) { - title = beforePath; - } - else if (afterPath != null) { - title = afterPath; - } - else { - title = VcsBundle.message("diff.unknown.path.title"); - } - request.setWindowTitle(title); - - boolean result = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { - public void run() { - request.setContents(createContent(bRev), createContent(aRev)); - } - }, VcsBundle.message("progress.loading.diff.revisions"), true, myProject); - if (! result) return false; - - String beforeRevisionTitle = (bRev != null) ? bRev.getRevisionNumber().asString() : ""; - String afterRevisionTitle = (aRev != null) ? aRev.getRevisionNumber().asString() : ""; - if (beforeRevisionTitle.length() == 0) { - beforeRevisionTitle = "Base version"; - } - if (afterRevisionTitle.length() == 0) { - afterRevisionTitle = "Your version"; - } - request.setContentTitles(beforeRevisionTitle, afterRevisionTitle); - return true; - } - - @NotNull - private DiffContent createContent(final ContentRevision revision) { - ProgressManager.checkCanceled(); - if (revision == null) return new SimpleContent(""); - if (revision instanceof CurrentContentRevision) { - final CurrentContentRevision current = (CurrentContentRevision)revision; - final VirtualFile vFile = current.getVirtualFile(); - return vFile != null ? new FileContent(myProject, vFile) : new SimpleContent(""); - } - - String revisionContent; - try { - revisionContent = revision.getContent(); - } - catch(VcsException ex) { - // TODO: correct exception handling - revisionContent = null; - } - SimpleContent content = revisionContent == null - ? new SimpleContent("") - : new SimpleContent(revisionContent, revision.getFile().getFileType()); - VirtualFile vFile = revision.getFile().getVirtualFile(); - if (vFile != null) { - content.setCharset(vFile.getCharset()); - content.setBOM(vFile.getBOM()); - } - content.setReadOnly(true); - return content; - } - - private boolean canShowChange(final Change change) { - final ContentRevision bRev = change.getBeforeRevision(); - final ContentRevision aRev = change.getAfterRevision(); - - if ((bRev != null && (bRev.getFile().getFileType().isBinary() || bRev.getFile().isDirectory())) || - (aRev != null && (aRev.getFile().getFileType().isBinary() || aRev.getFile().isDirectory()))) { - if (bRev != null && bRev.getFile().getFileType() == FileTypes.UNKNOWN && !bRev.getFile().isDirectory()) { - if (! checkContentsAvailable(bRev, aRev)) return false; - if (!checkAssociate(myProject, bRev.getFile())) return false; - } - else if (aRev != null && aRev.getFile().getFileType() == FileTypes.UNKNOWN && !aRev.getFile().isDirectory()) { - if (! checkContentsAvailable(bRev, aRev)) return false; - if (!checkAssociate(myProject, aRev.getFile())) return false; - } - else { - return false; - } - } - return true; - } - - private static boolean checkContentsAvailable(@Nullable final ContentRevision bRev, @Nullable final ContentRevision aRev) { - String bContents = null; - if (bRev != null) { - try { - bContents = bRev.getContent(); - } catch (VcsException e) { - // - } - } - String aContents = null; - if (aRev != null) { - try { - aContents = aRev.getContent(); - } catch (VcsException e) { - // - } - } - return (bContents != null) || (aContents != null); - } - - private static boolean checkAssociate(final Project project, final FilePath file) { - int rc = Messages.showDialog(project, - VcsBundle.message("diff.unknown.file.type.prompt", file.getName()), - VcsBundle.message("diff.unknown.file.type.title"), - new String[] { - VcsBundle.message("diff.unknown.file.type.associate"), - CommonBundle.getCancelButtonText() - }, 0, Messages.getQuestionIcon()); - if (rc == 0) { - FileType fileType = FileTypeChooser.associateFileType(file.getName()); - return fileType != null && !fileType.isBinary(); - } - return false; - } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeDiffRequestPresentable.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeDiffRequestPresentable.java new file mode 100644 index 000000000000..75af380ab2a9 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ChangeDiffRequestPresentable.java @@ -0,0 +1,196 @@ +/* + * Copyright 2000-2009 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.actions; + +import com.intellij.CommonBundle; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.diff.DiffContent; +import com.intellij.openapi.diff.FileContent; +import com.intellij.openapi.diff.SimpleContent; +import com.intellij.openapi.diff.SimpleDiffRequest; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.fileTypes.ex.FileTypeChooser; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsBundle; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.changes.Change; +import com.intellij.openapi.vcs.changes.ContentRevision; +import com.intellij.openapi.vcs.changes.CurrentContentRevision; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ChangeDiffRequestPresentable implements DiffRequestPresentable { + private final Project myProject; + private final Change myChange; + + public ChangeDiffRequestPresentable(final Project project, final Change change) { + myChange = change; + myProject = project; + } + + public MyResult step() { + final SimpleDiffRequest request = new SimpleDiffRequest(myProject, null); + return new MyResult(request, getRequestForChange(request)); + } + + @Nullable + private DiffPresentationReturnValue getRequestForChange(final SimpleDiffRequest request) { + if (! canShowChange()) return DiffPresentationReturnValue.removeFromList; + if (! loadCurrentContents(request, myChange)) return DiffPresentationReturnValue.quit; + return DiffPresentationReturnValue.useRequest; + } + + public boolean haveStuff() { + return checkContentsAvailable(myChange.getBeforeRevision(), myChange.getAfterRevision()); + } + + public List createActions(ShowDiffAction.DiffExtendUIFactory uiFactory) { + return uiFactory.createActions(myChange); + } + + private boolean loadCurrentContents(final SimpleDiffRequest request, final Change change) { + final ContentRevision bRev = change.getBeforeRevision(); + final ContentRevision aRev = change.getAfterRevision(); + + String beforePath = bRev != null ? bRev.getFile().getPath() : null; + String afterPath = aRev != null ? aRev.getFile().getPath() : null; + String title; + if (beforePath != null && afterPath != null && !beforePath.equals(afterPath)) { + title = beforePath + " -> " + afterPath; + } + else if (beforePath != null) { + title = beforePath; + } + else if (afterPath != null) { + title = afterPath; + } + else { + title = VcsBundle.message("diff.unknown.path.title"); + } + request.setWindowTitle(title); + + boolean result = ProgressManager.getInstance().runProcessWithProgressSynchronously(new Runnable() { + public void run() { + request.setContents(createContent(bRev), createContent(aRev)); + } + }, VcsBundle.message("progress.loading.diff.revisions"), true, myProject); + if (! result) return false; + + String beforeRevisionTitle = (bRev != null) ? bRev.getRevisionNumber().asString() : ""; + String afterRevisionTitle = (aRev != null) ? aRev.getRevisionNumber().asString() : ""; + if (beforeRevisionTitle.length() == 0) { + beforeRevisionTitle = "Base version"; + } + if (afterRevisionTitle.length() == 0) { + afterRevisionTitle = "Your version"; + } + request.setContentTitles(beforeRevisionTitle, afterRevisionTitle); + return true; + } + + @NotNull + private DiffContent createContent(final ContentRevision revision) { + ProgressManager.checkCanceled(); + if (revision == null) return new SimpleContent(""); + if (revision instanceof CurrentContentRevision) { + final CurrentContentRevision current = (CurrentContentRevision)revision; + final VirtualFile vFile = current.getVirtualFile(); + return vFile != null ? new FileContent(myProject, vFile) : new SimpleContent(""); + } + + String revisionContent; + try { + revisionContent = revision.getContent(); + } + catch(VcsException ex) { + // TODO: correct exception handling + revisionContent = null; + } + SimpleContent content = revisionContent == null + ? new SimpleContent("") + : new SimpleContent(revisionContent, revision.getFile().getFileType()); + VirtualFile vFile = revision.getFile().getVirtualFile(); + if (vFile != null) { + content.setCharset(vFile.getCharset()); + content.setBOM(vFile.getBOM()); + } + content.setReadOnly(true); + return content; + } + + private boolean canShowChange() { + final ContentRevision bRev = myChange.getBeforeRevision(); + final ContentRevision aRev = myChange.getAfterRevision(); + + if ((bRev != null && (bRev.getFile().getFileType().isBinary() || bRev.getFile().isDirectory())) || + (aRev != null && (aRev.getFile().getFileType().isBinary() || aRev.getFile().isDirectory()))) { + if (bRev != null && bRev.getFile().getFileType() == FileTypes.UNKNOWN && !bRev.getFile().isDirectory()) { + if (! checkContentsAvailable(bRev, aRev)) return false; + if (!checkAssociate(myProject, bRev.getFile())) return false; + } + else if (aRev != null && aRev.getFile().getFileType() == FileTypes.UNKNOWN && !aRev.getFile().isDirectory()) { + if (! checkContentsAvailable(bRev, aRev)) return false; + if (!checkAssociate(myProject, aRev.getFile())) return false; + } + else { + return false; + } + } + return true; + } + + private static boolean checkContentsAvailable(@Nullable final ContentRevision bRev, @Nullable final ContentRevision aRev) { + String bContents = null; + if (bRev != null) { + try { + bContents = bRev.getContent(); + } catch (VcsException e) { + // + } + } + String aContents = null; + if (aRev != null) { + try { + aContents = aRev.getContent(); + } catch (VcsException e) { + // + } + } + return (bContents != null) || (aContents != null); + } + + private static boolean checkAssociate(final Project project, final FilePath file) { + int rc = Messages.showDialog(project, + VcsBundle.message("diff.unknown.file.type.prompt", file.getName()), + VcsBundle.message("diff.unknown.file.type.title"), + new String[] { + VcsBundle.message("diff.unknown.file.type.associate"), + CommonBundle.getCancelButtonText() + }, 0, Messages.getQuestionIcon()); + if (rc == 0) { + FileType fileType = FileTypeChooser.associateFileType(file.getName()); + return fileType != null && !fileType.isBinary(); + } + return false; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffPresentationReturnValue.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffPresentationReturnValue.java new file mode 100644 index 000000000000..8cd4ead05e67 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffPresentationReturnValue.java @@ -0,0 +1,22 @@ +/* + * Copyright 2000-2009 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.actions; + +public enum DiffPresentationReturnValue { + removeFromList, + useRequest, + quit +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestPresentable.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestPresentable.java new file mode 100644 index 000000000000..c6dbc12c36ad --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/DiffRequestPresentable.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2009 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.actions; + +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.diff.DiffRequest; + +import java.util.List; + +public interface DiffRequestPresentable { + MyResult step(); + boolean haveStuff(); + List createActions(final ShowDiffAction.DiffExtendUIFactory uiFactory); + + class MyResult { + private final DiffRequest myRequest; + private final DiffPresentationReturnValue myReturnValue; + + public MyResult(DiffRequest request, DiffPresentationReturnValue returnValue) { + myRequest = request; + myReturnValue = returnValue; + } + + public DiffRequest getRequest() { + return myRequest; + } + + public DiffPresentationReturnValue getReturnValue() { + return myReturnValue; + } + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffAction.java index 619732598457..32e0c58d9ad9 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowDiffAction.java @@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diff.DiffManager; +import com.intellij.openapi.diff.DiffRequest; import com.intellij.openapi.diff.DiffTool; import com.intellij.openapi.diff.SimpleDiffRequest; import com.intellij.openapi.fileTypes.FileType; @@ -29,12 +30,10 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.IconLoader; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.VcsBundle; -import com.intellij.openapi.vcs.VcsDataKeys; -import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.*; import com.intellij.util.NotNullFunction; +import com.intellij.util.containers.Convertor; import org.jetbrains.annotations.Nullable; import javax.swing.*; @@ -193,7 +192,12 @@ public class ShowDiffAction extends AnAction implements DumbAware { newIndex = 0; } - showDiffImpl(project, changeList, newIndex, actionsFactory, showFrame); + showDiffImpl(project, ObjectsConvertor.convert(changeList, + new Convertor() { + public ChangeDiffRequestPresentable convert(Change o) { + return new ChangeDiffRequestPresentable(project, o); + } + }), newIndex, actionsFactory, showFrame); } public static void showDiffForChange(Change[] changes, int index, final Project project, @Nullable DiffExtendUIFactory actionsFactory, @@ -210,27 +214,21 @@ public class ShowDiffAction extends AnAction implements DumbAware { break; } } - showDiffImpl(project, changeList, index, actionsFactory, showFrame); + showDiffImpl(project, ObjectsConvertor.convert(changeList, + new Convertor() { + public ChangeDiffRequestPresentable convert(Change o) { + return new ChangeDiffRequestPresentable(project, o); + } + }), index, actionsFactory, showFrame); } - private static void showDiffImpl(Project project, List changeList, int index, DiffExtendUIFactory actionsFactory, boolean showFrame) { + public static void showDiffImpl(final Project project, List changeList, int index, DiffExtendUIFactory actionsFactory, boolean showFrame) { + final ChangeDiffRequest request = new ChangeDiffRequest(project, changeList, actionsFactory, showFrame); + final DiffTool tool = DiffManager.getInstance().getDiffTool(); - - final ChangeDiffRequest request = new ChangeDiffRequest(project, changeList, actionsFactory); if (! request.quickCheckHaveStuff()) return; - final SimpleDiffRequest simpleRequest = request.init(index); + final DiffRequest simpleRequest = request.init(index); if (simpleRequest != null) { - simpleRequest.passForDataContext(VcsDataKeys.DIFF_REQUEST_CHAIN, request); - - if (showFrame) { - simpleRequest.addHint(DiffTool.HINT_SHOW_FRAME); - } - else { - simpleRequest.addHint(DiffTool.HINT_SHOW_MODAL_DIALOG); - } - if (changeList.size() > 1) { - simpleRequest.addHint(DiffTool.HINT_ALLOW_NO_DIFFERENCES); - } tool.show(simpleRequest); } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowNextChangeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowNextChangeAction.java index 6c8cb846b50c..ef2554df89c0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowNextChangeAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowNextChangeAction.java @@ -18,12 +18,17 @@ package com.intellij.openapi.vcs.changes.actions; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.diff.DiffManager; +import com.intellij.openapi.diff.DiffRequest; import com.intellij.openapi.diff.SimpleDiffRequest; import com.intellij.openapi.diff.DiffViewer; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.changes.ChangeRequestChain; +import com.intellij.util.ui.UIUtil; + +import java.awt.*; /** * @author yole @@ -47,9 +52,15 @@ public class ShowNextChangeAction extends AnAction implements DumbAware { final DiffViewer diffViewer = e.getData(PlatformDataKeys.DIFF_VIEWER); if (diffViewer == null) return; - final SimpleDiffRequest request = chain.moveForward(); + final DiffRequest request = chain.moveForward(); if (request != null) { - diffViewer.setDiffRequest(request); + if (diffViewer.getContentsNumber() == request.getContents().length) { + diffViewer.setDiffRequest(request); + } else { + final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); + window.setVisible(false); + DiffManager.getInstance().getDiffTool().show(request); + } } } } \ No newline at end of file diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowPrevChangeAction.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowPrevChangeAction.java index fa8db9a65f51..618182fb37f6 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowPrevChangeAction.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/actions/ShowPrevChangeAction.java @@ -18,6 +18,8 @@ package com.intellij.openapi.vcs.changes.actions; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.PlatformDataKeys; +import com.intellij.openapi.diff.DiffManager; +import com.intellij.openapi.diff.DiffRequest; import com.intellij.openapi.diff.SimpleDiffRequest; import com.intellij.openapi.diff.DiffViewer; import com.intellij.openapi.project.Project; @@ -25,6 +27,8 @@ import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.vcs.VcsDataKeys; import com.intellij.openapi.vcs.changes.ChangeRequestChain; +import java.awt.*; + /** * @author yole */ @@ -47,9 +51,16 @@ public class ShowPrevChangeAction extends AnAction implements DumbAware { final DiffViewer diffViewer = e.getData(PlatformDataKeys.DIFF_VIEWER); if (diffViewer == null) return; - final SimpleDiffRequest request = chain.moveBack(); + + final DiffRequest request = chain.moveBack(); if (request != null) { - diffViewer.setDiffRequest(request); + if (diffViewer.getContentsNumber() == request.getContents().length) { + diffViewer.setDiffRequest(request); + } else { + final Window window = KeyboardFocusManager.getCurrentKeyboardFocusManager().getActiveWindow(); + window.setVisible(false); + DiffManager.getInstance().getDiffTool().show(request); + } } } } \ No newline at end of file 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 ea5fc3071018..2d9d21ab385a 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 @@ -33,16 +33,15 @@ import com.intellij.openapi.diff.DiffRequestFactory; import com.intellij.openapi.diff.MergeRequest; import com.intellij.openapi.diff.impl.patch.*; import com.intellij.openapi.diff.impl.patch.formove.PatchApplier; +import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.fileEditor.impl.LoadTextUtil; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; -import com.intellij.openapi.util.Ref; import com.intellij.openapi.vcs.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.Consumer; -import com.intellij.util.Processor; import com.intellij.util.containers.Convertor; import com.intellij.util.containers.MultiMap; import org.jetbrains.annotations.NotNull; @@ -83,6 +82,7 @@ public class ApplyPatchAction extends AnAction { PatchApplier.executePatchGroup(appliers); } }; + FileDocumentManager.getInstance().saveAllDocuments(); final ApplyPatchDifferentiatedDialog dialog = new ApplyPatchDifferentiatedDialog(project, callback); dialog.show(); } @@ -140,46 +140,23 @@ public class ApplyPatchAction extends AnAction { @Nullable public static ApplyPatchStatus mergeAgainstBaseVersion(final Project project, final VirtualFile file, final FilePath pathBeforeRename, final TextFilePatch patch, final PatchMergeRequestFactory mergeRequestFactory) { - final String beforeVersionId = patch.getBeforeVersionId(); - if (beforeVersionId == null) { + final ApplyPatchForBaseRevisionTexts threeTexts = ApplyPatchForBaseRevisionTexts.create(project, file, pathBeforeRename, patch); + if (threeTexts == null) { return null; } - final DefaultPatchBaseVersionProvider provider = new DefaultPatchBaseVersionProvider(project, file, beforeVersionId); - if (provider.canProvideContent()) { - final StringBuilder newText = new StringBuilder(); - final Ref contentRef = new Ref(); - final Ref statusRef = new Ref(); - try { - provider.getBaseVersionContent(pathBeforeRename, new Processor() { - public boolean process(final CharSequence text) { - newText.setLength(0); - try { - statusRef.set(patch.applyModifications(text, newText)); - } - catch(ApplyPatchException ex) { - return true; // continue to older versions - } - contentRef.set(text); - return false; - } - }); - } - catch (VcsException vcsEx) { - Messages.showErrorDialog(project, VcsBundle.message("patch.load.base.revision.error", patch.getBeforeName(), vcsEx.getMessage()), - VcsBundle.message("patch.apply.dialog.title")); - return ApplyPatchStatus.FAILURE; - } - ApplyPatchStatus status = statusRef.get(); - if (status != null) { - if (status != ApplyPatchStatus.ALREADY_APPLIED) { - return showMergeDialog(project, file, contentRef.get(), newText.toString(), mergeRequestFactory); - } - else { - return status; - } - } + ApplyPatchStatus status = threeTexts.getStatus(); + if (ApplyPatchStatus.FAILURE.equals(status)) { + final VcsException vcsExc = threeTexts.getException(); + Messages.showErrorDialog(project, VcsBundle.message("patch.load.base.revision.error", patch.getBeforeName(), + vcsExc == null ? null : vcsExc.getMessage()), VcsBundle.message("patch.apply.dialog.title")); + return status; + } + if (status != ApplyPatchStatus.ALREADY_APPLIED) { + return showMergeDialog(project, file, threeTexts.getBase(), threeTexts.getPatched(), mergeRequestFactory); + } + else { + return status; } - return null; } private static ApplyPatchStatus showMergeDialog(Project project, VirtualFile file, CharSequence content, final String patchedContent, diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java index f8263bfd6993..d1b2a9a86e98 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchDifferentiatedDialog.java @@ -17,6 +17,8 @@ package com.intellij.openapi.vcs.changes.patch; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diff.DiffRequestFactory; +import com.intellij.openapi.diff.MergeRequest; import com.intellij.openapi.diff.impl.patch.FilePatch; import com.intellij.openapi.diff.impl.patch.PatchReader; import com.intellij.openapi.diff.impl.patch.PatchSyntaxException; @@ -36,12 +38,16 @@ import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vcs.FilePathImpl; import com.intellij.openapi.vcs.ObjectsConvertor; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.ZipperUpdater; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.LocalChangeList; +import com.intellij.openapi.vcs.changes.actions.ChangeDiffRequestPresentable; +import com.intellij.openapi.vcs.changes.actions.DiffPresentationReturnValue; +import com.intellij.openapi.vcs.changes.actions.DiffRequestPresentable; import com.intellij.openapi.vcs.changes.actions.ShowDiffAction; import com.intellij.openapi.vcs.changes.ui.*; import com.intellij.openapi.vfs.LocalFileSystem; @@ -753,24 +759,42 @@ public class ApplyPatchDifferentiatedDialog extends DialogWrapper { public void actionPerformed(AnActionEvent e) { if (myPatches.isEmpty() || (! myContainBasedChanges)) return; final List changes = getAllChanges(); + Collections.sort(changes, MyChangeComparator.getInstance()); final List selectedChanges = myChangesTreeList.getSelectedChanges(); + + int selectedIdx = 0; int idx = 0; - boolean goodChange = false; + final ArrayList diffRequestPresentables = new ArrayList(changes.size()); if (! selectedChanges.isEmpty()) { final FilePatchInProgress.PatchChange c = selectedChanges.get(0); for (FilePatchInProgress.PatchChange change : changes) { - if (! change.getPatchInProgress().baseExistsOrAdded()) continue; - goodChange = true; + final FilePatchInProgress patchInProgress = change.getPatchInProgress(); + if (! patchInProgress.baseExistsOrAdded()) continue; + final DiffRequestPresentable diffRequestPresentable = change.createDiffRequestPresentable(myProject); + if (diffRequestPresentable != null) { + diffRequestPresentables.add(diffRequestPresentable); + } if (change.equals(c)) { - break; + selectedIdx = idx; } ++ idx; } } - if (! goodChange) return; - idx = (idx == changes.size()) ? 0 : idx; - ShowDiffAction.showDiffForChange(changes.toArray(new Change[changes.size()]), idx, myProject, - ShowDiffAction.DiffExtendUIFactory.NONE, false); + if (diffRequestPresentables.isEmpty()) return; + selectedIdx = (selectedIdx >= diffRequestPresentables.size()) ? 0 : selectedIdx; + ShowDiffAction.showDiffImpl(myProject, diffRequestPresentables, selectedIdx, ShowDiffAction.DiffExtendUIFactory.NONE, false); + } + } + + private static class MyChangeComparator implements Comparator { + private static final MyChangeComparator ourInstance = new MyChangeComparator(); + + public static MyChangeComparator getInstance() { + return ourInstance; + } + + public int compare(FilePatchInProgress.PatchChange o1, FilePatchInProgress.PatchChange o2) { + return o1.getPatchInProgress().getIoCurrentBase().compareTo(o2.getPatchInProgress().getIoCurrentBase()); } } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchForBaseRevisionTexts.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchForBaseRevisionTexts.java new file mode 100644 index 000000000000..d492f4b68523 --- /dev/null +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/ApplyPatchForBaseRevisionTexts.java @@ -0,0 +1,99 @@ +/* + * Copyright 2000-2009 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.openapi.diff.impl.patch.ApplyPatchException; +import com.intellij.openapi.diff.impl.patch.ApplyPatchStatus; +import com.intellij.openapi.diff.impl.patch.TextFilePatch; +import com.intellij.openapi.fileEditor.impl.LoadTextUtil; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.Processor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class ApplyPatchForBaseRevisionTexts { + private CharSequence myLocal; + private CharSequence myBase; + private String myPatched; + @NotNull + private ApplyPatchStatus myStatus; + private VcsException myException; + + @Nullable + public static ApplyPatchForBaseRevisionTexts create(final Project project, final VirtualFile file, final FilePath pathBeforeRename, + final TextFilePatch patch) { + + final String beforeVersionId = patch.getBeforeVersionId(); + if (beforeVersionId == null) { + return null; + } + final DefaultPatchBaseVersionProvider provider = new DefaultPatchBaseVersionProvider(project, file, beforeVersionId); + if (provider.canProvideContent()) { + return new ApplyPatchForBaseRevisionTexts(provider, pathBeforeRename, patch, file); + } + return null; + } + + ApplyPatchForBaseRevisionTexts(final DefaultPatchBaseVersionProvider provider, final FilePath pathBeforeRename, final TextFilePatch patch, + final VirtualFile file) { + myLocal = LoadTextUtil.loadText(file); + final StringBuilder newText = new StringBuilder(); + try { + provider.getBaseVersionContent(pathBeforeRename, new Processor() { + public boolean process(final CharSequence text) { + newText.setLength(0); + try { + myStatus = patch.applyModifications(text, newText); + } + catch(ApplyPatchException ex) { + return true; // continue to older versions + } + myBase = text; + return false; + } + }); + } + catch (VcsException vcsEx) { + myException = vcsEx; + myStatus = ApplyPatchStatus.FAILURE; + } + myPatched = newText.toString(); + } + + public CharSequence getLocal() { + return myLocal; + } + + public CharSequence getBase() { + return myBase; + } + + public String getPatched() { + return myPatched; + } + + @NotNull + public ApplyPatchStatus getStatus() { + return myStatus; + } + + public VcsException getException() { + return myException; + } +} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/FilePatchInProgress.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/FilePatchInProgress.java index 630135204f50..70f7f195131f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/FilePatchInProgress.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/FilePatchInProgress.java @@ -15,18 +15,26 @@ */ package com.intellij.openapi.vcs.changes.patch; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.diff.DiffRequestFactory; +import com.intellij.openapi.diff.MergeRequest; import com.intellij.openapi.diff.impl.patch.TextFilePatch; import com.intellij.openapi.diff.impl.patch.formove.PathMerger; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; -import com.intellij.openapi.vcs.FilePath; -import com.intellij.openapi.vcs.FilePathImpl; -import com.intellij.openapi.vcs.FileStatus; +import com.intellij.openapi.vcs.*; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.changes.CurrentContentRevision; import com.intellij.openapi.vcs.changes.SimpleContentRevision; +import com.intellij.openapi.vcs.changes.actions.ChangeDiffRequestPresentable; +import com.intellij.openapi.vcs.changes.actions.DiffPresentationReturnValue; +import com.intellij.openapi.vcs.changes.actions.DiffRequestPresentable; +import com.intellij.openapi.vcs.changes.actions.ShowDiffAction; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.vcsUtil.VcsUtil; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.ArrayList; @@ -45,6 +53,7 @@ public class FilePatchInProgress { private ContentRevision myNewContentRevision; private ContentRevision myCurrentRevision; private final List myAutoBases; + private volatile Boolean myConflicts; private File myAfterFile; @@ -93,6 +102,7 @@ public class FilePatchInProgress { myNewContentRevision = null; myCurrentRevision = null; myAfterFile = null; + myConflicts = null; final String beforeName = myPatch.getBeforeName(); if (beforeName != null) { @@ -144,6 +154,7 @@ public class FilePatchInProgress { if (FilePatchStatus.DELETED.equals(myStatus)) return null; if (myNewContentRevision == null) { + myConflicts = null; if (FilePatchStatus.ADDED.equals(myStatus)) { final FilePath newFilePath = FilePathImpl.createNonLocal(myIoCurrentBase.getAbsolutePath(), false); final String content = myPatch.getNewFileText(); @@ -156,11 +167,30 @@ public class FilePatchInProgress { newFilePath = (myCurrentBase != null) ? new FilePathImpl(myCurrentBase) : new FilePathImpl(myIoCurrentBase, false); } myNewContentRevision = new LazyPatchContentRevision(myCurrentBase, newFilePath, myPatch.getAfterVersionId(), myPatch); + if (myCurrentBase != null) { + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + public void run() { + ((LazyPatchContentRevision) myNewContentRevision).getContent(); + } + }); + } } } return myNewContentRevision; } + public boolean isConflictingChange() { + if (myConflicts == null) { + if ((myCurrentBase != null) && (myNewContentRevision instanceof LazyPatchContentRevision)) { + ((LazyPatchContentRevision) myNewContentRevision).getContent(); + myConflicts = ((LazyPatchContentRevision) myNewContentRevision).isPatchApplyFailed(); + } else { + myConflicts = false; + } + } + return myConflicts; + } + public ContentRevision getCurrentRevision() { if (FilePatchStatus.ADDED.equals(myStatus)) return null; if (myCurrentRevision == null) { @@ -182,8 +212,55 @@ public class FilePatchInProgress { public FilePatchInProgress getPatchInProgress() { return myPatchInProgress; } + + @Nullable + public DiffRequestPresentable createDiffRequestPresentable(final Project project) { + if (myPatchInProgress.isConflictingChange()) { + final ApplyPatchForBaseRevisionTexts texts = ApplyPatchForBaseRevisionTexts + .create(project, myPatchInProgress.getCurrentBase(), new FilePathImpl(myPatchInProgress.getCurrentBase()), + myPatchInProgress.getPatch()); + if (texts != null) { + return new MergedDiffRequestPresentable(project, texts, + myPatchInProgress.getCurrentBase(), myPatchInProgress.getPatch().getAfterVersionId()); + } + return null; + } else { + return new ChangeDiffRequestPresentable(project, this); + } + } } + private static class MergedDiffRequestPresentable implements DiffRequestPresentable { + private final Project myProject; + private final VirtualFile myFile; + private final String myAfterTitle; + private final ApplyPatchForBaseRevisionTexts myTexts; + + private MergedDiffRequestPresentable(final Project project, final ApplyPatchForBaseRevisionTexts texts, final VirtualFile file, final String afterTitle) { + myTexts = texts; + myProject = project; + myFile = file; + myAfterTitle = afterTitle; + } + + public MyResult step() { + final MergeRequest request = DiffRequestFactory.getInstance() + .create3WayDiffRequest(myTexts.getLocal().toString(), myTexts.getPatched(), myTexts.getBase().toString(), myProject, null); + request.setWindowTitle(VcsBundle.message("patch.apply.conflict.title", myFile.getPresentableUrl())); + request.setVersionTitles(new String[] {"Current Version", "Base Version", myAfterTitle}); + return new MyResult(request, DiffPresentationReturnValue.useRequest); + } + + public boolean haveStuff() { + return true; + } + + public List createActions(ShowDiffAction.DiffExtendUIFactory uiFactory) { + return Collections.emptyList(); + } + } + + public List getAutoBasesCopy() { final ArrayList result = new ArrayList(myAutoBases.size() + 1); result.addAll(myAutoBases); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/LazyPatchContentRevision.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/LazyPatchContentRevision.java index 83d082934298..59dcb7e6af16 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/LazyPatchContentRevision.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/LazyPatchContentRevision.java @@ -41,7 +41,7 @@ public class LazyPatchContentRevision implements ContentRevision { myPatch = patch; } - public String getContent() throws VcsException { + public String getContent() { if (myContent == null) { try { final Document doc = FileDocumentManager.getInstance().getDocument(myVf);