vcs: do not create fake Changes to show diff from update dialog
authorAleksey Pivovarov <AMPivovarov@gmail.com>
Thu, 2 Jul 2015 14:14:30 +0000 (17:14 +0300)
committerAleksey Pivovarov <AMPivovarov@gmail.com>
Thu, 3 Sep 2015 16:28:11 +0000 (19:28 +0300)
Someone could try to use them and will get errors

platform/vcs-impl/src/com/intellij/openapi/vcs/update/ShowUpdatedDiffAction.java

index 3fc16f5bcf71f7a096e836602e2d3c440d30ab8f..850ccb8c1fedeaa0cdd169a2739a719134f765d5 100644 (file)
  */
 package com.intellij.openapi.vcs.update;
 
-import com.intellij.diff.DiffDialogHints;
+import com.intellij.diff.*;
+import com.intellij.diff.actions.impl.GoToChangePopupBuilder;
+import com.intellij.diff.chains.DiffRequestChain;
+import com.intellij.diff.chains.DiffRequestProducer;
+import com.intellij.diff.chains.DiffRequestProducerException;
+import com.intellij.diff.contents.DiffContent;
+import com.intellij.diff.requests.DiffRequest;
+import com.intellij.diff.requests.SimpleDiffRequest;
 import com.intellij.history.ByteContent;
 import com.intellij.history.Label;
 import com.intellij.openapi.actionSystem.*;
-import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
+import com.intellij.openapi.progress.ProcessCanceledException;
+import com.intellij.openapi.progress.ProgressIndicator;
 import com.intellij.openapi.project.DumbAware;
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.util.Condition;
 import com.intellij.openapi.util.Pair;
+import com.intellij.openapi.util.UserDataHolder;
+import com.intellij.openapi.util.UserDataHolderBase;
 import com.intellij.openapi.util.io.FileUtil;
 import com.intellij.openapi.vcs.FilePath;
 import com.intellij.openapi.vcs.FileStatus;
 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.ContentRevision;
-import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffAction;
-import com.intellij.openapi.vcs.changes.actions.diff.ShowDiffContext;
-import com.intellij.openapi.vcs.history.VcsRevisionNumber;
-import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.openapi.vfs.encoding.EncodingProjectManager;
+import com.intellij.openapi.vcs.changes.actions.diff.ChangeGoToChangePopupAction;
 import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
+import com.intellij.util.Consumer;
 import com.intellij.vcsUtil.VcsUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.io.File;
-import java.lang.ref.SoftReference;
-import java.util.Iterator;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 
 public class ShowUpdatedDiffAction extends AnAction implements DumbAware {
   @Override
@@ -62,179 +65,154 @@ public class ShowUpdatedDiffAction extends AnAction implements DumbAware {
   }
 
   private boolean isEnabled(final DataContext dc) {
-    final Iterable<Pair<VirtualFilePointer,FileStatus>> iterable = VcsDataKeys.UPDATE_VIEW_FILES_ITERABLE.getData(dc);
+    final Iterable<Pair<VirtualFilePointer, FileStatus>> iterable = VcsDataKeys.UPDATE_VIEW_FILES_ITERABLE.getData(dc);
     return iterable != null;
   }
 
   public void actionPerformed(AnActionEvent e) {
     final DataContext dc = e.getDataContext();
-    if ((! isVisible(dc)) || (! isEnabled(dc))) return;
+    if ((!isVisible(dc)) || (!isEnabled(dc))) return;
 
     final Project project = CommonDataKeys.PROJECT.getData(dc);
-    final Iterable<Pair<VirtualFilePointer, FileStatus>> iterable = VcsDataKeys.UPDATE_VIEW_FILES_ITERABLE.getData(dc);
-    final Label before = (Label) VcsDataKeys.LABEL_BEFORE.getData(dc);
-    final Label after = (Label) VcsDataKeys.LABEL_AFTER.getData(dc);
-
+    final Iterable<Pair<VirtualFilePointer, FileStatus>> iterable = e.getRequiredData(VcsDataKeys.UPDATE_VIEW_FILES_ITERABLE);
+    final Label before = (Label)e.getRequiredData(VcsDataKeys.LABEL_BEFORE);
+    final Label after = (Label)e.getRequiredData(VcsDataKeys.LABEL_AFTER);
     final String selectedUrl = VcsDataKeys.UPDATE_VIEW_SELECTED_PATH.getData(dc);
 
-    Iterable<Change> changes = new MyIterableWrapper(iterable.iterator(), before, after, project);
-    Condition<Change> selection = new MySelectionMarker(selectedUrl);
-    ShowDiffAction.showDiffForChange(project, changes, selection, new ShowDiffContext(DiffDialogHints.FRAME));
+    MyDiffRequestChain requestChain = new MyDiffRequestChain(project, iterable, before, after, selectedUrl);
+    DiffManager.getInstance().showDiff(project, requestChain, DiffDialogHints.FRAME);
   }
 
-  private static class MySelectionMarker implements Condition<Change> {
-    private final String mySelectedPath;
-    private boolean myFirstSelected;
+  private static class MyDiffRequestChain extends UserDataHolderBase implements DiffRequestChain, GoToChangePopupBuilder.Chain {
+    @Nullable private final Project myProject;
+    @NotNull private final Label myBefore;
+    @NotNull private final Label myAfter;
+    @NotNull private final List<MyDiffRequestProducer> myRequests = new ArrayList<MyDiffRequestProducer>();
 
-    public MySelectionMarker(String selectedPath) {
-      mySelectedPath = selectedPath;
-    }
+    private int myIndex;
 
-    public boolean value(Change change) {
-      if (mySelectedPath == null) {
-        if (myFirstSelected) {
-          myFirstSelected = true;
-          return true;
-        }
-        return false;
-      }
-      final MyCheckpointContentRevision revision = (MyCheckpointContentRevision)(change.getBeforeRevision() == null ? change.getAfterRevision() : change.getBeforeRevision());
-      final String url = revision.getUrl();
-      return mySelectedPath.equals(url);
-    }
-  }
-
-  private static class MyIterableWrapper implements Iterable<Change> {
-    private final Iterator<Pair<VirtualFilePointer, FileStatus>> myVfIterator;
-    private final Label myBefore;
-    private final Label myAfter;
-    @NotNull private final Project myProject;
-
-    private MyIterableWrapper(Iterator<Pair<VirtualFilePointer, FileStatus>> vfIterator,
-                              final Label before,
-                              final Label after,
-                              @NotNull Project project) {
-      myVfIterator = vfIterator;
+    public MyDiffRequestChain(@Nullable Project project,
+                              @NotNull Iterable<Pair<VirtualFilePointer, FileStatus>> iterable,
+                              @NotNull Label before,
+                              @NotNull Label after,
+                              @Nullable String selectedUrl) {
+      myProject = project;
       myBefore = before;
       myAfter = after;
-      myProject = project;
-    }
 
-    public Iterator<Change> iterator() {
-      return new MyIteratorWrapper(myVfIterator, myBefore, myAfter, myProject);
-    }
-  }
-
-  private static class MyLoader {
-    private final Label myLabel;
-
-    private MyLoader(Label label) {
-      myLabel = label;
-    }
-
-    @Nullable
-    public String convert(final VirtualFilePointer pointer, @NotNull Project project) {
-      if (pointer == null) return null;
-      final String path = pointer.getPresentableUrl();
-      final ByteContent byteContent = myLabel.getByteContent(FileUtil.toSystemIndependentName(path));
-      if (byteContent == null || byteContent.isDirectory() || byteContent.getBytes() == null) {
-        return null;
+      int selected = -1;
+      for (Pair<VirtualFilePointer, FileStatus> pair : iterable) {
+        if (selected == -1 && pair.first.getUrl().equals(selectedUrl)) selected = myRequests.size();
+        myRequests.add(new MyDiffRequestProducer(pair.first, pair.second));
       }
-      final VirtualFile vf = pointer.getFile();
-      if (vf == null) {
-        return LoadTextUtil.getTextByBinaryPresentation(byteContent.getBytes(), EncodingProjectManager.getInstance(project).getDefaultCharset()).toString();
-      }
-      else {
-        return LoadTextUtil.getTextByBinaryPresentation(byteContent.getBytes(), vf).toString();
-      }
-    }
-  }
-
-  private static class MyCheckpointContentRevision implements ContentRevision {
-    private SoftReference<String> myContent;
-    private final MyLoader myLoader;
-    private final VirtualFilePointer myPointer;
-    private final boolean myBefore;
-    @NotNull private final Project myProject;
-
-    private MyCheckpointContentRevision(final VirtualFilePointer pointer, final MyLoader loader, final boolean before, @NotNull Project project) {
-      myLoader = loader;
-      myPointer = pointer;
-      myBefore = before;
-      myProject = project;
+      if (selected != -1) myIndex = selected;
     }
 
-    public String getContent() throws VcsException {
-      final String s = com.intellij.reference.SoftReference.dereference(myContent);
-      if (s != null) {
-        return s;
-      }
-
-      final String loaded = myLoader.convert(myPointer, myProject);
-      myContent = new SoftReference<String>(loaded);
-
-      return loaded;
+    @NotNull
+    @Override
+    public List<MyDiffRequestProducer> getRequests() {
+      return myRequests;
     }
 
-    public String getUrl() {
-      return myPointer.getUrl();
+    @Override
+    public int getIndex() {
+      return myIndex;
     }
 
-    @NotNull
-    public FilePath getFile() {
-      return VcsUtil.getFilePath(myPointer.getPresentableUrl(), false);
+    @Override
+    public void setIndex(int index) {
+      myIndex = index;
     }
 
     @NotNull
-    public VcsRevisionNumber getRevisionNumber() {
-      return new VcsRevisionNumber() {
-        public String asString() {
-          return myBefore ? "Before update" : "After update";
+    @Override
+    public AnAction createGoToChangeAction(@NotNull Consumer<Integer> onSelected) {
+      return new ChangeGoToChangePopupAction.Fake<MyDiffRequestChain>(this, myIndex, onSelected) {
+        @NotNull
+        @Override
+        protected FilePath getFilePath(int index) {
+          return myRequests.get(index).getFilePath();
         }
 
-        public int compareTo(VcsRevisionNumber o) {
-          return myBefore ? -1 : 1;
+        @NotNull
+        @Override
+        protected FileStatus getFileStatus(int index) {
+          return myRequests.get(index).getFileStatus();
         }
       };
     }
-  }
 
-  private static class MyIteratorWrapper implements Iterator<Change> {
-    private final MyLoader myBeforeLoader;
-    private final MyLoader myAfterLoader;
-    private final Iterator<Pair<VirtualFilePointer, FileStatus>> myVfIterator;
-    @NotNull private final Project myProject;
-
-    public MyIteratorWrapper(final Iterator<Pair<VirtualFilePointer, FileStatus>> vfIterator,
-                             final Label before,
-                             final Label after,
-                             @NotNull Project project) {
-      myVfIterator = vfIterator;
-      myProject = project;
-      myBeforeLoader = new MyLoader(before);
-      myAfterLoader = new MyLoader(after);
-    }
+    private class MyDiffRequestProducer implements DiffRequestProducer {
+      @NotNull private final VirtualFilePointer myFilePointer;
+      @NotNull private final FileStatus myFileStatus;
+      @NotNull private final FilePath myFilePath;
 
-    public boolean hasNext() {
-      return myVfIterator.hasNext();
-    }
+      public MyDiffRequestProducer(@NotNull VirtualFilePointer filePointer, @NotNull FileStatus fileStatus) {
+        myFilePointer = filePointer;
+        myFileStatus = fileStatus;
 
-    public Change next() {
-      final Pair<VirtualFilePointer, FileStatus> pair = myVfIterator.next();
-      final VirtualFilePointer pointer = pair.getFirst();
+        myFilePath = VcsUtil.getFilePath(myFilePointer.getPresentableUrl(), false);
+      }
 
-      MyCheckpointContentRevision before = new MyCheckpointContentRevision(pointer, myBeforeLoader, true, myProject);
-      MyCheckpointContentRevision after = new MyCheckpointContentRevision(pointer, myAfterLoader, false, myProject);
-      if (FileStatus.ADDED.equals(pair.getSecond())) {
-        before = null;
-      } else if (FileStatus.DELETED.equals(pair.getSecond())) {
-        after = null;
+      @NotNull
+      @Override
+      public String getName() {
+        return myFilePointer.getUrl();
+      }
+
+      @NotNull
+      public FilePath getFilePath() {
+        return myFilePath;
+      }
+
+      @NotNull
+      public FileStatus getFileStatus() {
+        return myFileStatus;
+      }
+
+      @NotNull
+      @Override
+      public DiffRequest process(@NotNull UserDataHolder context, @NotNull ProgressIndicator indicator)
+        throws DiffRequestProducerException, ProcessCanceledException {
+        try {
+          DiffContent content1;
+          DiffContent content2;
+
+          if (FileStatus.ADDED.equals(myFileStatus)) {
+            content1 = DiffContentFactory.getInstance().createEmpty();
+          }
+          else {
+            byte[] bytes1 = loadContent(myFilePointer, myBefore);
+            content1 = DiffContentFactoryImpl.getInstanceImpl().createFromBytes(myProject, myFilePath, bytes1);
+          }
+
+          if (FileStatus.DELETED.equals(myFileStatus)) {
+            content2 = DiffContentFactory.getInstance().createEmpty();
+          }
+          else {
+            byte[] bytes2 = loadContent(myFilePointer, myAfter);
+            content2 = DiffContentFactoryImpl.getInstanceImpl().createFromBytes(myProject, myFilePath, bytes2);
+          }
+
+          String title = DiffRequestFactoryImpl.getContentTitle(myFilePath);
+          return new SimpleDiffRequest(title, content1, content2, "Before update", "After update");
+        }
+        catch (IOException e) {
+          throw new DiffRequestProducerException("Can't load content", e);
+        }
       }
-      return new Change(before, after, pair.getSecond());
     }
 
-    public void remove() {
-      throw new UnsupportedOperationException();
+    @NotNull
+    private static byte[] loadContent(@NotNull VirtualFilePointer filePointer, @NotNull Label label) throws DiffRequestProducerException {
+      String path = filePointer.getPresentableUrl();
+      ByteContent byteContent = label.getByteContent(FileUtil.toSystemIndependentName(path));
+
+      if (byteContent == null || byteContent.isDirectory() || byteContent.getBytes() == null) {
+        throw new DiffRequestProducerException("Can't load content");
+      }
+
+      return byteContent.getBytes();
     }
   }
 }