apply patch: show diff with conflicts

This commit is contained in:
irengrig
2009-11-06 15:36:43 +03:00
parent cf44b38e0f
commit be7e174a8d
19 changed files with 682 additions and 300 deletions
@@ -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<JComponent> myBottomComponentFactory = null;
private final HashSet myHints = new HashSet();
private final Map<String, Object> myGenericData;
protected DiffRequest(Project project) {
myProject = project;
myGenericData = new HashMap<String, Object>(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<String, Object> 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);
}
/**
@@ -26,4 +26,6 @@ public interface DiffViewer {
JComponent getComponent();
JComponent getPreferredFocusedComponent();
int getContentsNumber();
}
@@ -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<String, Object> myGenericData;
public SimpleDiffRequest(Project project, String windowtitle) {
super(project);
myWindowTitle = windowtitle;
myGenericData = new HashMap<String, Object>(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<String, Object> 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;
@@ -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<String, Object> myGenericData;
private class MyGenericDataProvider extends GenericDataProvider {
private DiffPanelImpl myDiffPanel;
private MyDataProvider() {
myGenericData = new HashMap<String, Object>();
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<String, Object> 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);
}
}
}
@@ -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<String, Object> myGenericData;
public GenericDataProvider() {
myGenericData = new HashMap<String, Object>();
}
public void putData(final Map<String, Object> map) {
myGenericData.putAll(map);
}
public Object getData(String dataId) {
return myGenericData.get(dataId);
}
}
@@ -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<EditorPlace> editorPlaces = new ArrayList<EditorPlace>();
@@ -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() {
@@ -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();
}
@@ -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<Change> myChanges;
private final List<DiffRequestPresentable> 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<Change> changes, final ShowDiffAction.DiffExtendUIFactory actionsFactory) {
public ChangeDiffRequest(final Project project, final List<DiffRequestPresentable> 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<? extends AnAction> 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;
}
}
@@ -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<? extends AnAction> 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;
}
}
@@ -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
}
@@ -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<? extends AnAction> 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;
}
}
}
@@ -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<Change, DiffRequestPresentable>() {
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<Change, DiffRequestPresentable>() {
public ChangeDiffRequestPresentable convert(Change o) {
return new ChangeDiffRequestPresentable(project, o);
}
}), index, actionsFactory, showFrame);
}
private static void showDiffImpl(Project project, List<Change> changeList, int index, DiffExtendUIFactory actionsFactory, boolean showFrame) {
public static void showDiffImpl(final Project project, List<DiffRequestPresentable> 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);
}
}
@@ -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);
}
}
}
}
@@ -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);
}
}
}
}
@@ -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<CharSequence> contentRef = new Ref<CharSequence>();
final Ref<ApplyPatchStatus> statusRef = new Ref<ApplyPatchStatus>();
try {
provider.getBaseVersionContent(pathBeforeRename, new Processor<CharSequence>() {
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,
@@ -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<FilePatchInProgress.PatchChange> changes = getAllChanges();
Collections.sort(changes, MyChangeComparator.getInstance());
final List<FilePatchInProgress.PatchChange> selectedChanges = myChangesTreeList.getSelectedChanges();
int selectedIdx = 0;
int idx = 0;
boolean goodChange = false;
final ArrayList<DiffRequestPresentable> diffRequestPresentables = new ArrayList<DiffRequestPresentable>(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<FilePatchInProgress.PatchChange> {
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());
}
}
}
@@ -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<CharSequence>() {
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;
}
}
@@ -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<VirtualFile> 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<? extends AnAction> createActions(ShowDiffAction.DiffExtendUIFactory uiFactory) {
return Collections.emptyList();
}
}
public List<VirtualFile> getAutoBasesCopy() {
final ArrayList<VirtualFile> result = new ArrayList<VirtualFile>(myAutoBases.size() + 1);
result.addAll(myAutoBases);
@@ -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);