VCS: shelved changes: navigatable show diff: allow conflicting changes to be shown...
authorirengrig <Irina.Chernushina@jetbrains.com>
Tue, 2 Feb 2010 11:29:45 +0000 (14:29 +0300)
committerirengrig <Irina.Chernushina@jetbrains.com>
Tue, 2 Feb 2010 11:29:45 +0000 (14:29 +0300)
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/FilePatchInProgress.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/MergedDiffRequestPresentable.java [new file with mode: 0644]
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/DiffShelvedChangesAction.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/shelf/ShelvedChange.java

index 69ebbc89e9e2487206678759532b73c1dd6d65bc..a785c66343d6758f8b48c8eb9567815a50e39788 100644 (file)
  */
 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.ApplyPatchException;
 import com.intellij.openapi.diff.impl.patch.ApplyPatchStatus;
 import com.intellij.openapi.diff.impl.patch.FilePatch;
 import com.intellij.openapi.diff.impl.patch.TextFilePatch;
@@ -27,23 +23,25 @@ import com.intellij.openapi.diff.impl.patch.formove.PathMerger;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.util.Pair;
-import com.intellij.openapi.vcs.*;
+import com.intellij.openapi.vcs.FilePath;
+import com.intellij.openapi.vcs.FilePathImpl;
+import com.intellij.openapi.vcs.FileStatus;
 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.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.io.File;
-import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
 
 public class FilePatchInProgress implements Strippable {
   private final TextFilePatch myPatch;
@@ -238,36 +236,6 @@ public class FilePatchInProgress implements Strippable {
     }
   }
 
-  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);
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/MergedDiffRequestPresentable.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/MergedDiffRequestPresentable.java
new file mode 100644 (file)
index 0000000..377f9b1
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2000-2010 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.actionSystem.AnAction;
+import com.intellij.openapi.diff.DiffRequestFactory;
+import com.intellij.openapi.diff.MergeRequest;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vcs.VcsBundle;
+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 java.util.Collections;
+import java.util.List;
+
+public class MergedDiffRequestPresentable implements DiffRequestPresentable {
+  private final Project myProject;
+  private final VirtualFile myFile;
+  private final String myAfterTitle;
+  private final ApplyPatchForBaseRevisionTexts myTexts;
+
+  public 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();
+  }
+}
index 248ebc54016d4d02436ebbd6342171cde9e2ce5b..8133ecc3c6b2ea77f3ab86010d64a6e2baf72574 100644 (file)
@@ -18,25 +18,29 @@ package com.intellij.openapi.vcs.changes.shelf;
 import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.diff.DiffRequestFactory;
 import com.intellij.openapi.diff.MergeRequest;
-import com.intellij.openapi.diff.impl.patch.ApplyPatchContext;
-import com.intellij.openapi.diff.impl.patch.ApplyPatchException;
-import com.intellij.openapi.diff.impl.patch.PatchSyntaxException;
-import com.intellij.openapi.diff.impl.patch.TextFilePatch;
+import com.intellij.openapi.diff.impl.patch.*;
 import com.intellij.openapi.project.DumbAware;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.MessageType;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.openapi.vcs.FilePath;
 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.actions.ChangeDiffRequestPresentable;
+import com.intellij.openapi.vcs.changes.actions.DiffRequestPresentable;
 import com.intellij.openapi.vcs.changes.actions.ShowDiffAction;
-import com.intellij.openapi.vcs.changes.patch.ApplyPatchAction;
+import com.intellij.openapi.vcs.changes.patch.ApplyPatchForBaseRevisionTexts;
+import com.intellij.openapi.vcs.changes.patch.MergedDiffRequestPresentable;
 import com.intellij.openapi.vcs.changes.patch.PatchMergeRequestFactory;
 import com.intellij.openapi.vcs.changes.ui.ChangesComparator;
+import com.intellij.openapi.vcs.changes.ui.ChangesViewBalloonProblemNotifier;
 import com.intellij.openapi.vfs.VirtualFile;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
+import java.util.*;
 
 /**
  * @author yole
@@ -44,27 +48,6 @@ import java.util.List;
 public class DiffShelvedChangesAction extends AnAction implements DumbAware {
   public void actionPerformed(final AnActionEvent e) {
     showShelvedChangesDiff(e.getDataContext());
-    /*Project project = e.getData(PlatformDataKeys.PROJECT);
-    final ShelvedChangeList[] changeLists = e.getData(ShelvedChangesViewManager.SHELVED_CHANGELIST_KEY);
-    List<ShelvedChange> shelvedChanges = e.getData(ShelvedChangesViewManager.SHELVED_CHANGE_KEY);
-    if ((shelvedChanges == null || shelvedChanges.isEmpty()) && changeLists != null && changeLists.length > 0) {
-      shelvedChanges = changeLists [0].getChanges();
-    }
-    if (shelvedChanges != null && shelvedChanges.size() > 0) {
-      ShelvedChange c = shelvedChanges.get(0);
-      Change change = c.getChange(project);
-      if (isConflictingChange(change)) {
-        try {
-          if (showConflictingChangeDiff(project, c)) {
-            return;
-          }
-        }
-        catch (Exception ex) {
-          // ignore and fallback to regular diff
-        }
-      }
-    }
-    ActionManager.getInstance().getAction("ChangesView.Diff").actionPerformed(e);*/
   }
 
   public static void showShelvedChangesDiff(final DataContext dc) {
@@ -79,45 +62,102 @@ public class DiffShelvedChangesAction extends AnAction implements DumbAware {
 
     if (changeLists == null) return;
 
-    Change toSelect = null;
     final List<ShelvedChange> changesFromFirstList = changeLists[0].getChanges();
-    if (shelvedChanges != null) {
-      for (final ShelvedChange fromList : changesFromFirstList) {
-        for (ShelvedChange shelvedChange : shelvedChanges) {
-          if (fromList.equals(shelvedChange)) {
-            toSelect = fromList.getChange(project);
-            break;
+
+    Collections.sort(changesFromFirstList, new MyComparator(project));
+
+    int toSelectIdx = 0;
+    final ArrayList<DiffRequestPresentable> diffRequestPresentables = new ArrayList<DiffRequestPresentable>();
+    ApplyPatchContext context = new ApplyPatchContext(project.getBaseDir(), 0, false, false);
+    final PatchesPreloader preloader = new PatchesPreloader();
+
+    final List<String> missing = new LinkedList<String>();
+    for (final ShelvedChange shelvedChange : changesFromFirstList) {
+      final Change change = shelvedChange.getChange(project);
+      final String beforePath = shelvedChange.getBeforePath();
+      try {
+        VirtualFile f = FilePatch.findPatchTarget(context, beforePath, shelvedChange.getAfterPath(), beforePath == null);
+        if ((f == null) || (! f.exists())) {
+          if (beforePath != null) {
+            missing.add(beforePath);
+          }
+          continue;
+        }
+
+        if (isConflictingChange(change)) {
+          TextFilePatch patch = preloader.getPatch(shelvedChange);
+          if (patch == null) continue;
+
+          final FilePath pathBeforeRename = context.getPathBeforeRename(f);
+
+          final ApplyPatchForBaseRevisionTexts threeTexts = ApplyPatchForBaseRevisionTexts.create(project, f, pathBeforeRename, patch);
+          if ((threeTexts == null) || (threeTexts.getStatus() == null) || (ApplyPatchStatus.FAILURE.equals(threeTexts.getStatus()))) {
+            continue;
           }
+
+          diffRequestPresentables.add(new MergedDiffRequestPresentable(project, threeTexts, f, "Shelved Version"));
         }
-        if (toSelect != null) break;
+        else {
+          diffRequestPresentables.add(new ChangeDiffRequestPresentable(project, change));
+        }
+      }
+      catch (IOException e) {
+        continue;
+      }
+      if ((shelvedChanges != null) && shelvedChanges.contains(shelvedChange)) {
+        // just added
+        toSelectIdx = diffRequestPresentables.size() - 1;
       }
     }
+    if (! missing.isEmpty()) {
+      // 7-8
+      ChangesViewBalloonProblemNotifier.showMe(project, "Show Diff: Cannot find base for: " + StringUtil.join(missing, ",\n"), MessageType.WARNING);
+    }
 
-    final Change[] changes = new Change[changesFromFirstList.size()];
-    for (int i = 0; i < changesFromFirstList.size(); i++) {
-      final ShelvedChange shelvedChange = changesFromFirstList.get(i);
-      changes[i] = shelvedChange.getChange(project);
+    ShowDiffAction.showDiffImpl(project, diffRequestPresentables, toSelectIdx, ShowDiffAction.DiffExtendUIFactory.NONE, true);
+  }
+
+  private static class PatchesPreloader {
+    private final Map<String, List<TextFilePatch>> myFilePatchesMap;
+
+    private PatchesPreloader() {
+      myFilePatchesMap = new HashMap<String, List<TextFilePatch>>();
     }
-    Arrays.sort(changes, ChangesComparator.getInstance());
 
-    int toSelectIdx = 0;
-    for (int i = 0; i < changes.length; i++) {
-      if (toSelect == changes[i]) {
-        toSelectIdx = i;
+    @Nullable
+    public TextFilePatch getPatch(final ShelvedChange shelvedChange) {
+      List<TextFilePatch> textFilePatches = myFilePatchesMap.get(shelvedChange.getPatchPath());
+      if (textFilePatches == null) {
+        try {
+          textFilePatches = ShelveChangesManager.loadPatches(shelvedChange.getPatchPath());
+        }
+        catch (IOException e) {
+          return null;
+        }
+        catch (PatchSyntaxException e) {
+          return null;
+        }
+        myFilePatchesMap.put(shelvedChange.getPatchPath(), textFilePatches);
+      }
+      for (TextFilePatch textFilePatch : textFilePatches) {
+        if (shelvedChange.getBeforePath().equals(textFilePatch.getBeforeName())) {
+          return textFilePatch;
+        }
       }
+      return null;
     }
-    ShowDiffAction.showDiffForChange(changes, toSelectIdx, project);
   }
 
-  private static boolean showConflictingChangeDiff(final Project project, final ShelvedChange c) throws PatchSyntaxException, IOException {
-    TextFilePatch patch = c.loadFilePatch();
-    if (patch == null) return false;
+  private final static class MyComparator implements Comparator<ShelvedChange> {
+    private final Project myProject;
 
-    ApplyPatchContext context = new ApplyPatchContext(project.getBaseDir(), 0, false, false);
-    VirtualFile f = patch.findFileToPatch(context);
-    if (f == null) return false;
+    public MyComparator(Project project) {
+      myProject = project;
+    }
 
-    return ApplyPatchAction.mergeAgainstBaseVersion(project, f, context, patch, ShelvedChangeDiffRequestFactory.INSTANCE) != null;
+    public int compare(final ShelvedChange o1, final ShelvedChange o2) {
+      return ChangesComparator.getInstance().compare(o1.getChange(myProject), o2.getChange(myProject));
+    }
   }
 
   private static boolean isConflictingChange(final Change change) {
index 398a692114f2c643c3bb89f68c74af828a62989e..eabdd4733b46e06868f9b78ae7c710664a3fa6cd 100644 (file)
@@ -231,4 +231,8 @@ public class ShelvedChange {
       return 0;
     }
   }
+
+  public String getPatchPath() {
+    return myPatchPath;
+  }
 }