VCS: show diff from annotate, not completed jet, but usable
authorirengrig <Irina.Chernushina@jetbrains.com>
Mon, 9 Aug 2010 15:24:54 +0000 (19:24 +0400)
committerirengrig <Irina.Chernushina@jetbrains.com>
Mon, 9 Aug 2010 15:24:54 +0000 (19:24 +0400)
21 files changed:
platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java
platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java
platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java
platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java
platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotateToggleAction.java
platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java
platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java
platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/Annotater.java [deleted file]
platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CompositeCommittedChangesProvider.java
platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java
platform/vcs-impl/src/com/intellij/openapi/vcs/history/FileHistoryPanelImpl.java
platform/vcs-impl/src/com/intellij/openapi/vcs/impl/AbstractVcsHelperImpl.java
plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/changeBrowser/CvsCommittedChangesProvider.java
plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java
plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java
plugins/git4idea/src/git4idea/GitVcs.java
plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java
plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java
plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java

index 22eaa410843b17add8ef386b5900dabd6c3bb680..b57f180933c3d956a6b60a2911cdeaa43199127f 100644 (file)
@@ -65,7 +65,7 @@ public interface TextAnnotationGutterProvider {
   /***
    * enables annotation view modifications
    */
-  List<AnAction> getPopupActions(final Editor editor);
+  List<AnAction> getPopupActions(final int line, final Editor editor);
 
   /**
    * Called when the annotations are removed from the editor gutter.
index bb5ade1b546a8d4829c9b6d225f6121e4d4d0ee1..8291578b30f7bbb41dcb325f21352c3f6dd39bbd 100644 (file)
@@ -1176,8 +1176,12 @@ class EditorGutterComponentImpl extends EditorGutterComponentEx implements Mouse
       DefaultActionGroup actionGroup = new DefaultActionGroup(EditorBundle.message("editor.annotations.action.group.name"), true);
       actionGroup.add(new CloseAnnotationsAction());
       final List<AnAction> addActions = new ArrayList<AnAction>();
+      final Point p = e.getPoint();
+      int line = myEditor.xyToLogicalPosition(new Point(0, (int)p.getY())).line;
+      if (line >= myEditor.getDocument().getLineCount()) return;
+
       for (TextAnnotationGutterProvider gutterProvider : myTextAnnotationGutters) {
-        final List<AnAction> list = gutterProvider.getPopupActions(myEditor);
+        final List<AnAction> list = gutterProvider.getPopupActions(line, myEditor);
         if (list != null) {
           for (AnAction action : list) {
             if (! addActions.contains(action)) {
index 370cf192e1ba61e95b9cbb271631b50505258d76..2dc07b928bcabe20c996ba6d3fd4ace1c5a8cc2f 100644 (file)
@@ -72,7 +72,7 @@ public abstract class AbstractVcsHelper {
     showErrors(Arrays.asList(e), s);
   }
 
-  public abstract void showAnnotation(FileAnnotation annotation, VirtualFile file);
+  public abstract void showAnnotation(FileAnnotation annotation, VirtualFile file, AbstractVcs vcs);
 
   public abstract void showDifferences(final VcsFileRevision cvsVersionOn, final VcsFileRevision cvsVersionOn1, final File file);
 
index eda912583fabd3e11377f3d0838f11f89b69a820..2c4bcc8a9d7f7a36c3c04d668baf17cede74b85c 100644 (file)
@@ -19,6 +19,7 @@ package com.intellij.openapi.vcs;
 import com.intellij.openapi.vcs.changes.committed.DecoratorManager;
 import com.intellij.openapi.vcs.changes.committed.VcsCommittedListsZipper;
 import com.intellij.openapi.vcs.changes.committed.VcsCommittedViewAuxiliary;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
 import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
 import com.intellij.openapi.vcs.versionBrowser.ChangesBrowserSettingsEditor;
 import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
@@ -55,4 +56,7 @@ public interface CommittedChangesProvider<T extends CommittedChangeList, U exten
    * since may be different for different VCSs
    */
   int getUnlimitedCountValue();
+
+  @Nullable
+  T getOneList(final RepositoryLocation location, final VcsRevisionNumber number) throws VcsException;
 }
index 7c815c363b3700927b946957b449c60d42bab8e8..b7b6cff18f3a53887293f6b2e8aa8cbfe0605ab6 100644 (file)
@@ -15,9 +15,7 @@
  */
 package com.intellij.openapi.vcs.actions;
 
-import com.intellij.openapi.actionSystem.AnAction;
-import com.intellij.openapi.actionSystem.AnActionEvent;
-import com.intellij.openapi.actionSystem.ToggleAction;
+import com.intellij.openapi.actionSystem.*;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.editor.colors.ColorKey;
@@ -36,23 +34,32 @@ import com.intellij.openapi.progress.ProgressManager;
 import com.intellij.openapi.progress.Task;
 import com.intellij.openapi.project.DumbAware;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.MessageType;
+import com.intellij.openapi.util.IconLoader;
 import com.intellij.openapi.util.Key;
 import com.intellij.openapi.util.Ref;
 import com.intellij.openapi.util.registry.Registry;
 import com.intellij.openapi.vcs.*;
 import com.intellij.openapi.vcs.annotate.*;
 import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
+import com.intellij.openapi.vcs.changes.Change;
+import com.intellij.openapi.vcs.changes.actions.ShowDiffAction;
+import com.intellij.openapi.vcs.changes.ui.ChangesComparator;
+import com.intellij.openapi.vcs.changes.ui.ChangesViewBalloonProblemNotifier;
 import com.intellij.openapi.vcs.history.VcsFileRevision;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
 import com.intellij.openapi.vcs.impl.BackgroundableActionEnabledHandler;
 import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
 import com.intellij.openapi.vcs.impl.UpToDateLineNumberProviderImpl;
 import com.intellij.openapi.vcs.impl.VcsBackgroundableActions;
+import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.util.Consumer;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.awt.*;
+import java.io.File;
 import java.util.*;
 import java.util.List;
 
@@ -152,7 +159,7 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
     final VirtualFile file = FileDocumentManager.getInstance().getFile(editor.getDocument());
     if (project == null) return;
     final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstance(project);
-    AbstractVcs vcs = plVcsManager.getVcsFor(file);
+    final AbstractVcs vcs = plVcsManager.getVcsFor(file);
     if (vcs == null) return;
     final AnnotationProvider annotationProvider = vcs.getAnnotationProvider();
 
@@ -188,12 +195,16 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
         }
         if (fileAnnotationRef.isNull()) return;
 
-        doAnnotate(editor, project, file, fileAnnotationRef.get());
+        doAnnotate(editor, project, file, fileAnnotationRef.get(), vcs);
       }
     });
   }
 
-  public static void doAnnotate(final Editor editor, final Project project, final VirtualFile file, final FileAnnotation fileAnnotation) {
+  public static void doAnnotate(final Editor editor,
+                                final Project project,
+                                final VirtualFile file,
+                                final FileAnnotation fileAnnotation,
+                                final AbstractVcs vcs) {
     String upToDateContent = fileAnnotation.getAnnotatedContent();
 
     final UpToDateLineNumberProvider getUpToDateLineNumber = new UpToDateLineNumberProviderImpl(
@@ -214,7 +225,14 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
     final HighlightAnnotationsActions highlighting = new HighlightAnnotationsActions(project, file, fileAnnotation, editorGutterComponentEx);
     final List<AnnotationFieldGutter> gutters = new ArrayList<AnnotationFieldGutter>();
     final AnnotationSourceSwitcher switcher = fileAnnotation.getAnnotationSourceSwitcher();
-    final MyAnnotationPresentation presentation = new MyAnnotationPresentation(highlighting, switcher, editorGutterComponentEx, gutters);
+    final MyAnnotationPresentation presentation;
+    if (vcs.getCommittedChangesProvider() != null) {
+      final ShowDiffFromAnnotation showDiff = new ShowDiffFromAnnotation(getUpToDateLineNumber, fileAnnotation, vcs, file);
+      presentation = new MyAnnotationPresentation(highlighting, switcher, editorGutterComponentEx, gutters, showDiff);
+      presentation.addLineNumberListener(showDiff);
+    } else {
+      presentation = new MyAnnotationPresentation(highlighting, switcher, editorGutterComponentEx, gutters);
+    }
 
     if (switcher != null) {
 
@@ -375,15 +393,25 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
     private final List<AnnotationFieldGutter> myGutters;
     private final List<AnAction> myActions;
     private MySwitchAnnotationSourceAction mySwitchAction;
+    private final List<Consumer<Integer>> myPopupLineNumberListeners;
 
     public MyAnnotationPresentation(@NotNull final HighlightAnnotationsActions highlighting, @Nullable final AnnotationSourceSwitcher switcher,
-                                    final EditorGutterComponentEx gutter,
-                                    List<AnnotationFieldGutter> gutters) {
+                                    final EditorGutterComponentEx gutter, final List<AnnotationFieldGutter> gutters, final AnAction... actions) {
       myHighlighting = highlighting;
       mySwitcher = switcher;
       myGutters = gutters;
-
-      myActions = new ArrayList<AnAction>(myHighlighting.getList());
+      myPopupLineNumberListeners = new LinkedList<Consumer<Integer>>();
+
+      myActions = new ArrayList<AnAction>();
+      myActions.add(Separator.getInstance());
+      if (actions != null) {
+        final List<AnAction> actionsList = Arrays.<AnAction>asList(actions);
+        if (! actionsList.isEmpty()) {
+          myActions.addAll(actionsList);
+          myActions.add(new Separator());
+        }
+      }
+      myActions.addAll(myHighlighting.getList());
       if (mySwitcher != null) {
         mySwitchAction = new MySwitchAnnotationSourceAction(mySwitcher, gutter);
         myActions.add(mySwitchAction);
@@ -391,6 +419,10 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
       myActions.add(new ShowHideColorsAction(myGutters, gutter));
     }
 
+    public void addLineNumberListener(final Consumer<Integer> listener) {
+      myPopupLineNumberListeners.add(listener);
+    }
+
     public EditorFontType getFontType(final int line) {
       return myHighlighting.isLineBold(line) ? EditorFontType.BOLD : EditorFontType.PLAIN;
     }
@@ -400,7 +432,10 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
       return mySwitcher.getAnnotationSource(line).getColor();
     }
 
-    public List<AnAction> getActions() {
+    public List<AnAction> getActions(int line) {
+      for (Consumer<Integer> listener : myPopupLineNumberListeners) {
+        listener.consume(line);
+      }
       return myActions;
     }
 
@@ -443,4 +478,108 @@ public class AnnotateToggleAction extends ToggleAction implements DumbAware {
       myGutter.revalidateMarkup();
     }
   }
+
+  private static class ShowDiffFromAnnotation extends AnAction implements Consumer<Integer> {
+    private final UpToDateLineNumberProvider myLineNumberProvider;
+    private final FileAnnotation myFileAnnotation;
+    private final AbstractVcs myVcs;
+    private final VirtualFile myFile;
+    private RepositoryLocation myLocationFor;
+    private int currentLine;
+
+    private ShowDiffFromAnnotation(final UpToDateLineNumberProvider lineNumberProvider,
+                                   final FileAnnotation fileAnnotation, final AbstractVcs vcs, final VirtualFile file) {
+      super(VcsBundle.message("updated.info.tree.show.diff.text"), VcsBundle.message("updated.info.tree.show.diff.text"), IconLoader.getIcon("/actions/diff.png"));
+      myLineNumberProvider = lineNumberProvider;
+      myFileAnnotation = fileAnnotation;
+      myVcs = vcs;
+      myFile = file;
+      final CommittedChangesProvider provider = myVcs.getCommittedChangesProvider();
+      final VirtualFile root = ProjectLevelVcsManager.getInstance(vcs.getProject()).getVcsRootFor(file);
+      myLocationFor = provider.getLocationFor(new FilePathImpl(root));
+      currentLine = -1;
+    }
+
+    @Override
+    public void consume(Integer integer) {
+      currentLine = integer;
+    }
+
+    @Override
+    public void update(AnActionEvent e) {
+      e.getPresentation().setVisible(getActualLineNumber(e) >= 0);
+    }
+
+    private int getActualLineNumber(final AnActionEvent e) {
+      final DataContext dc = e.getDataContext();
+      if (currentLine < 0) return -1;
+      return myLineNumberProvider.getLineNumber(currentLine);
+    }
+
+    @Override
+    public void actionPerformed(AnActionEvent e) {
+      final int actualNumber = getActualLineNumber(e);
+      if (actualNumber < 0) return;
+
+      final VcsRevisionNumber revisionNumber = myFileAnnotation.getLineRevisionNumber(actualNumber);
+      if (revisionNumber != null) {
+        final VcsException[] exc = new VcsException[1];
+        final List<Change> changes = new LinkedList<Change>();
+        ProgressManager.getInstance().run(new Task.Backgroundable(myVcs.getProject(),
+                                                                  "Loading revision " + revisionNumber.asString() + " contents", true, BackgroundFromStartOption.getInstance()) {
+          @Override
+          public void run(@NotNull ProgressIndicator indicator) {
+            final CommittedChangesProvider provider = myVcs.getCommittedChangesProvider();
+            try {
+              final CommittedChangeList cl = provider.getOneList(myLocationFor, revisionNumber);
+              if (cl == null) {
+                ChangesViewBalloonProblemNotifier.showMe(myVcs.getProject(), "Can not load data for show diff", MessageType.ERROR);
+                return;
+              }
+              changes.addAll(cl.getChanges());
+              Collections.sort(changes, ChangesComparator.getInstance());
+            }
+            catch (VcsException e1) {
+              exc[0] = e1;
+            }
+          }
+
+          @Override
+          public void onSuccess() {
+            if (exc[0] != null) {
+              ChangesViewBalloonProblemNotifier.showMe(myVcs.getProject(), "Can not show diff: " + exc[0].getMessage(), MessageType.ERROR);
+            } else if (! changes.isEmpty()) {
+              int idx = findSelfInList(changes);
+              ShowDiffAction.showDiffForChange(changes.toArray(new Change[changes.size()]), idx, myVcs.getProject());
+            }
+          }
+        });
+      }
+    }
+
+    private int findSelfInList(List<Change> changes) {
+      int idx = -1;
+      final File ioFile = new File(myFile.getPath());
+      for (int i = 0; i < changes.size(); i++) {
+        final Change change = changes.get(i);
+        if ((change.getAfterRevision() != null) && (change.getAfterRevision().getFile().getIOFile().equals(ioFile))) {
+          idx = i;
+          break;
+        }
+      }
+      if (idx >= 0) return idx;
+      idx = 0;
+      // try to use name only
+      final String name = ioFile.getName();
+      for (int i = 0; i < changes.size(); i++) {
+        final Change change = changes.get(i);
+        if ((change.getAfterRevision() != null) && (change.getAfterRevision().getFile().getName().equals(name))) {
+          idx = i;
+          break;
+        }
+      }
+
+      return idx;
+    }
+  }
 }
index c54ca5b5f338e21a8a3f7cc9cfea54e7b8b90f3e..9ee9edb5b72c1fe203f7985e2fa0c43dd655659e 100644 (file)
@@ -99,8 +99,8 @@ class AnnotationFieldGutter implements ActiveAnnotationGutter {
     return myPresentation.getColor(line);
   }
 
-  public List<AnAction> getPopupActions(final Editor editor) {
-    return myPresentation.getActions();
+  public List<AnAction> getPopupActions(int line, final Editor editor) {
+    return myPresentation.getActions(line);
   }
 
   public void gutterClosed() {
index 6cd1cb0092bb58d04ad9759da21a8628fb336633..52ce811f0cd7280f5b371ba05a14996c2d585d03 100644 (file)
@@ -68,8 +68,8 @@ public class AnnotationGutterLineConvertorProxy implements ActiveAnnotationGutte
     return myDelegate.getBgColor(currentLine, editor);
   }
 
-  public List<AnAction> getPopupActions(Editor editor) {
-    return myDelegate.getPopupActions(editor);
+  public List<AnAction> getPopupActions(int line, Editor editor) {
+    return myDelegate.getPopupActions(line, editor);
   }
 
   public void gutterClosed() {
diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/Annotater.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/Annotater.java
deleted file mode 100644 (file)
index b4f718f..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * 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.annotate;
-
-import com.intellij.openapi.editor.Editor;
-import com.intellij.openapi.fileEditor.FileEditorManager;
-import com.intellij.openapi.fileEditor.OpenFileDescriptor;
-import com.intellij.openapi.project.Project;
-import com.intellij.openapi.ui.Messages;
-import com.intellij.openapi.vcs.VcsBundle;
-import com.intellij.openapi.vcs.actions.AnnotateToggleAction;
-import com.intellij.openapi.vfs.VirtualFile;
-
-public class Annotater {
-
-  private final Project myProject;
-  private final VirtualFile myVirtualFile;
-  private final FileAnnotation myFileAnnotation;
-
-  public Annotater(FileAnnotation fileAnnotation, Project project, VirtualFile virtualFile) {
-    myFileAnnotation = fileAnnotation;
-    myProject = project;
-    myVirtualFile = virtualFile;
-  }
-
-  public void showAnnotation() {
-    OpenFileDescriptor openFileDescriptor = new OpenFileDescriptor(myProject, myVirtualFile);
-    Editor editor = FileEditorManager.getInstance(myProject).openTextEditor(openFileDescriptor, true);
-    if (editor == null) {
-      Messages.showMessageDialog(VcsBundle.message("message.text.cannot.open.editor", myVirtualFile.getPresentableUrl()),
-                                 VcsBundle.message("message.title.cannot.open.editor"), Messages.getInformationIcon());
-      return;
-    }
-
-    AnnotateToggleAction.doAnnotate(editor, myProject, myVirtualFile, myFileAnnotation);
-  }
-
-}
index 9c13afd02a316f0c666feb9d7d8236aa1de1b672..1fca77641739db0acbda8c206f4f857dbad8648e 100644 (file)
@@ -18,10 +18,11 @@ package com.intellij.openapi.vcs.annotate;
 import com.intellij.openapi.actionSystem.AnAction;
 import com.intellij.openapi.editor.colors.ColorKey;
 import com.intellij.openapi.editor.colors.EditorFontType;
+
 import java.util.List;
 
 public interface TextAnnotationPresentation {
   EditorFontType getFontType(int line);
   ColorKey getColor(int line);
-  List<AnAction> getActions();
+  List<AnAction> getActions(int line);
 }
index fe376e3b16d2a85f6335edbb051d0a74ffd6b240..94d4fca858a13aee97a75944e66e2f0071a9012f 100644 (file)
@@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.changes.committed;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vcs.AbstractVcs;
 import com.intellij.openapi.vcs.ProjectLevelVcsManager;
+import com.intellij.openapi.vcs.VcsType;
 import com.intellij.util.NotNullFunction;
 import org.jetbrains.annotations.NotNull;
 
@@ -29,10 +30,10 @@ public class CommittedChangesVisibilityPredicate implements NotNullFunction<Proj
   public Boolean fun(final Project project) {
     final AbstractVcs[] abstractVcses = ProjectLevelVcsManager.getInstance(project).getAllActiveVcss();
     for(AbstractVcs vcs: abstractVcses) {
-      if (vcs.getCommittedChangesProvider() != null) {
+      if (vcs.getCommittedChangesProvider() != null && VcsType.centralized.equals(vcs.getType())) {
         return Boolean.TRUE;
       }
     }
     return Boolean.FALSE;
   }
-}
\ No newline at end of file
+}
index f7467391a721010f66fc3e11d6e7a839b708bb0c..161437057e835c05acfaa46ced046860bb428683 100644 (file)
@@ -19,6 +19,7 @@ package com.intellij.openapi.vcs.changes.committed;
 import com.intellij.openapi.actionSystem.AnAction;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.vcs.*;
+import com.intellij.openapi.vcs.history.VcsRevisionNumber;
 import com.intellij.openapi.vcs.versionBrowser.ChangeBrowserSettings;
 import com.intellij.openapi.vcs.versionBrowser.ChangesBrowserSettingsEditor;
 import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
@@ -151,6 +152,11 @@ public class CompositeCommittedChangesProvider implements CommittedChangesProvid
     throw new UnsupportedOperationException();
   }
 
+  @Override
+  public CommittedChangeList getOneList(RepositoryLocation location, VcsRevisionNumber number) {
+    throw new UnsupportedOperationException();
+  }
+
   public static class CompositeChangeBrowserSettings extends ChangeBrowserSettings {
     private final Map<AbstractVcs, ChangeBrowserSettings> myMap;
     private final Set<AbstractVcs> myEnabledVcs = new HashSet<AbstractVcs>();
index 7b10a69d83eb90a70460bb4675f9da1fd7f7526a..c3d080bac8d008ea1249ddab5ded68c50d85d168 100644 (file)
 package com.intellij.openapi.vcs.changes.committed;
 
 import com.intellij.openapi.project.Project;
-import com.intellij.openapi.vcs.ProjectLevelVcsManager;
 import com.intellij.openapi.vcs.AbstractVcs;
 import com.intellij.openapi.vcs.CachingCommittedChangesProvider;
+import com.intellij.openapi.vcs.ProjectLevelVcsManager;
+import com.intellij.openapi.vcs.VcsType;
 import com.intellij.util.NotNullFunction;
 import org.jetbrains.annotations.NotNull;
 
@@ -30,7 +31,7 @@ public class IncomingChangesVisibilityPredicate implements NotNullFunction<Proje
   public Boolean fun(final Project project) {
     final AbstractVcs[] abstractVcses = ProjectLevelVcsManager.getInstance(project).getAllActiveVcss();
     for(AbstractVcs vcs: abstractVcses) {
-      if (vcs.getCommittedChangesProvider() instanceof CachingCommittedChangesProvider) {
+      if (vcs.getCommittedChangesProvider() instanceof CachingCommittedChangesProvider && VcsType.centralized.equals(vcs.getType())) {
         return Boolean.TRUE;
       }
     }
index afe93acabff98255d2d28bc223c7be020e9d58cb..0c3e3c6921725010257932b991e4777fcf859f7a 100644 (file)
@@ -111,7 +111,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
   private String myOriginalComment = "";
   private final DefaultActionGroup myPopupActions;
 
-  private final Project myProject;
+  private final AbstractVcs myVcs;
   private final VcsHistoryProvider myProvider;
   private final AnnotationProvider myAnnotationProvider;
   private VcsHistorySession myHistorySession;
@@ -265,20 +265,20 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
   private static final DateFormat DATE_FORMAT = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);
   private final Map<VcsFileRevision, VirtualFile> myRevisionToVirtualFile = new HashMap<VcsFileRevision, VirtualFile>();
 
-  public FileHistoryPanelImpl(Project project,
-                              FilePath filePath, final String repositoryPath, VcsHistorySession session,
+  public FileHistoryPanelImpl(AbstractVcs vcs,
+                              FilePath filePath, VcsHistorySession session,
                               VcsHistoryProvider provider,
                               AnnotationProvider annotationProvider,
                               ContentManager contentManager, final Runnable refresher) {
     super(contentManager, provider.getHelpId() != null ? provider.getHelpId() : "reference.versionControl.toolwindow.history");
+    myVcs = vcs;
     myProvider = provider;
     myAnnotationProvider = annotationProvider;
-    myProject = project;
     myRefresher = refresher;
     myHistorySession = session;         
     myFilePath = filePath;
 
-    COLUMNS = createColumnList(project, provider, session);
+    COLUMNS = createColumnList(myVcs.getProject(), provider, session);
 
     myComments = new JEditorPane(UIUtil.HTML_MIME, "");
     myComments.setPreferredSize(new Dimension(150, 100));
@@ -298,11 +298,11 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
     @NonNls String storageKey = "FileHistory." + provider.getClass().getName();
     if (treeHistoryProvider != null) {
       myDualView = new DualView(new TreeNodeOnVcsRevision(null, treeHistoryProvider.createTreeOn(myHistorySession.getRevisionList())),
-                                COLUMNS, storageKey, project);
+                                COLUMNS, storageKey, myVcs.getProject());
     }
     else {
       myDualView = new DualView(new TreeNodeOnVcsRevision(null, wrapWithTreeElements(myHistorySession.getRevisionList())), COLUMNS,
-                                storageKey, project);
+                                storageKey, myVcs.getProject());
       myDualView.switchToTheFlatMode();
     }
     final TableLinkMouseListener listener = new TableLinkMouseListener();
@@ -330,7 +330,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
     // todo react to event?
     myUpdateAlarm.addRequest(new Runnable() {
       public void run() {
-        if (myProject.isDisposed()) {
+        if (myVcs.getProject().isDisposed()) {
           return;
         }
         final boolean refresh = (! myInRefresh) && myHistorySession.shouldBeRefreshed();
@@ -556,7 +556,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
       revision = getFirstSelectedRevision();
       final String message = revision.getCommitMessage();
       myOriginalComment = message;
-      @NonNls final String text = IssueLinkHtmlRenderer.formatTextIntoHtml(myProject, message);
+      @NonNls final String text = IssueLinkHtmlRenderer.formatTextIntoHtml(myVcs.getProject(), message);
       myComments.setText(text);
       myComments.setCaretPosition(0);
     }
@@ -584,7 +584,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
       if (content2 == null) throw new VcsException("Failed to load content for revision " + right.getRevisionNumber().asString());
 
 
-      SimpleDiffRequest diffData = new SimpleDiffRequest(myProject, myFilePath.getPresentableUrl());
+      SimpleDiffRequest diffData = new SimpleDiffRequest(myVcs.getProject(), myFilePath.getPresentableUrl());
 
       diffData.addHint(DiffTool.HINT_SHOW_FRAME);
 
@@ -693,7 +693,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
   }
 
   private VcsConfiguration getConfiguration() {
-    return VcsConfiguration.getInstance(myProject);
+    return VcsConfiguration.getInstance(myVcs.getProject());
   }
 
   private DefaultActionGroup createPopupActions() {
@@ -757,7 +757,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
   }
 
   private void refreshImpl() {
-    new AbstractCalledLater(myProject, ModalityState.NON_MODAL) {
+    new AbstractCalledLater(myVcs.getProject(), ModalityState.NON_MODAL) {
       public void run() {
         if (myInRefresh) return;
         myInRefresh = true;
@@ -806,12 +806,12 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
 
       int selectionSize = sel.size();
       if (selectionSize > 1) {
-        showDifferences(myProject, sel.get(0), sel.get(sel.size() - 1));
+        showDifferences(myVcs.getProject(), sel.get(0), sel.get(sel.size() - 1));
       }
       else if (selectionSize == 1) {
         final VcsRevisionNumber currentRevisionNumber = myHistorySession.getCurrentRevisionNumber();
         if (currentRevisionNumber != null) {
-          showDifferences(myProject, getFirstSelectedRevision(), new CurrentRevision(myFilePath.getVirtualFile(), currentRevisionNumber));
+          showDifferences(myVcs.getProject(), getFirstSelectedRevision(), new CurrentRevision(myFilePath.getVirtualFile(), currentRevisionNumber));
         }
       }
     }
@@ -880,7 +880,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
     protected void actionPerformed() {
       final VcsFileRevision revision = getFirstSelectedRevision();
       if (getVirtualFile() != null) {
-        if (!new ReplaceFileConfirmationDialog(myProject, VcsBundle.message("acton.name.get.revision"))
+        if (!new ReplaceFileConfirmationDialog(myVcs.getProject(), VcsBundle.message("acton.name.get.revision"))
           .confirmFor(new VirtualFile[]{getVirtualFile()})) {
           return;
         }
@@ -926,14 +926,14 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
         };
       }
       if (refresh != null) {
-        ProgressManager.getInstance().runProcessWithProgressSynchronously(refresh, "Refreshing files...", false, myProject);
+        ProgressManager.getInstance().runProcessWithProgressSynchronously(refresh, "Refreshing files...", false, myVcs.getProject());
       }
     }
 
     private void getVersion(final VcsFileRevision revision) {
       final VirtualFile file = getVirtualFile();
       if ((file != null) && !file.isWritable()) {
-        if (ReadonlyStatusHandler.getInstance(myProject).ensureFilesWritable(file).hasReadonlyFiles()) {
+        if (ReadonlyStatusHandler.getInstance(myVcs.getProject()).ensureFilesWritable(file).hasReadonlyFiles()) {
           return;
         }
       }
@@ -961,7 +961,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
       try {
         ApplicationManager.getApplication().runWriteAction(new Runnable() {
           public void run() {
-            CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
+            CommandProcessor.getInstance().executeCommand(myVcs.getProject(), new Runnable() {
                 public void run() {
                   try {
                     write(finalRevisionContent);
@@ -975,7 +975,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
           }
         });
         if (file != null) {
-          VcsDirtyScopeManager.getInstance(myProject).fileDirty(file);
+          VcsDirtyScopeManager.getInstance(myVcs.getProject()).fileDirty(file);
         }
       }
       finally {
@@ -1027,7 +1027,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
     private void writeContentToDocument(final Document document, byte[] revisionContent) throws IOException {
       final String content = StringUtil.convertLineSeparators(new String(revisionContent, myFilePath.getCharset().name()));
 
-      CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
+      CommandProcessor.getInstance().executeCommand(myVcs.getProject(), new Runnable() {
         public void run() {
           document.replaceString(0, document.getTextLength(), content);
         }
@@ -1053,7 +1053,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
       boolean enabled = revision != null && revVFile != null && !fileType.isBinary();
 
       if (enabled) {
-        final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstance(myProject);
+        final ProjectLevelVcsManager plVcsManager = ProjectLevelVcsManager.getInstance(myVcs.getProject());
         enabled &= (! (((ProjectLevelVcsManagerImpl) plVcsManager).getBackgroundableActionHandler(
           VcsBackgroundableActions.ANNOTATE).isInProgress(key(revVFile, revision))));
       }
@@ -1070,14 +1070,14 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
       final VirtualFile revisionVirtualFile = e.getData(VcsDataKeys.VCS_VIRTUAL_FILE);
       if ((revision == null) || (revisionVirtualFile == null)) return;
 
-      final BackgroundableActionEnabledHandler handler = ((ProjectLevelVcsManagerImpl) ProjectLevelVcsManager.getInstance(myProject)).
+      final BackgroundableActionEnabledHandler handler = ((ProjectLevelVcsManagerImpl) ProjectLevelVcsManager.getInstance(myVcs.getProject())).
         getBackgroundableActionHandler(VcsBackgroundableActions.ANNOTATE);
       handler.register(key(revisionVirtualFile, revision));
 
       final Ref<FileAnnotation> fileAnnotationRef = new Ref<FileAnnotation>();
       final Ref<VcsException> exceptionRef = new Ref<VcsException>();
 
-      ProgressManager.getInstance().run(new Task.Backgroundable(myProject, VcsBundle.message("retrieving.annotations"), true,
+      ProgressManager.getInstance().run(new Task.Backgroundable(myVcs.getProject(), VcsBundle.message("retrieving.annotations"), true,
           BackgroundFromStartOption.getInstance()) {
         public void run(@NotNull ProgressIndicator indicator) {
           try {
@@ -1102,7 +1102,7 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
           }
           if (fileAnnotationRef.isNull()) return;
 
-          AbstractVcsHelper.getInstance(myProject).showAnnotation(fileAnnotationRef.get(), revisionVirtualFile);
+          AbstractVcsHelper.getInstance(myProject).showAnnotation(fileAnnotationRef.get(), revisionVirtualFile, myVcs);
         }
       });
     }
@@ -1118,14 +1118,14 @@ public class FileHistoryPanelImpl<S extends CommittedChangeList, U extends Chang
       }
       VirtualFile virtualFileForRevision = createVirtualFileForRevision(firstSelectedRevision);
       if (virtualFileForRevision != null) {
-        return new OpenFileDescriptor(myProject, virtualFileForRevision);
+        return new OpenFileDescriptor(myVcs.getProject(), virtualFileForRevision);
       }
       else {
         return null;
       }
     }
     else if (PlatformDataKeys.PROJECT.is(dataId)) {
-      return myProject;
+      return myVcs.getProject();
     }
     else if (VcsDataKeys.VCS_FILE_REVISION.is(dataId)) {
       return firstSelectedRevision;
index 7d931e509fea7e8b4e34bdfc3fade8af3d26d919..1a5fd6dc375377848956088a207493e7ecc50d25 100644 (file)
@@ -27,7 +27,10 @@ import com.intellij.openapi.application.ModalityState;
 import com.intellij.openapi.command.CommandProcessor;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.diff.*;
+import com.intellij.openapi.editor.Editor;
 import com.intellij.openapi.fileEditor.FileDocumentManager;
+import com.intellij.openapi.fileEditor.FileEditorManager;
+import com.intellij.openapi.fileEditor.OpenFileDescriptor;
 import com.intellij.openapi.fileTypes.FileType;
 import com.intellij.openapi.fileTypes.FileTypeManager;
 import com.intellij.openapi.progress.ProgressIndicator;
@@ -41,7 +44,7 @@ import com.intellij.openapi.util.Comparing;
 import com.intellij.openapi.util.Disposer;
 import com.intellij.openapi.util.Getter;
 import com.intellij.openapi.vcs.*;
-import com.intellij.openapi.vcs.annotate.Annotater;
+import com.intellij.openapi.vcs.actions.AnnotateToggleAction;
 import com.intellij.openapi.vcs.annotate.AnnotationProvider;
 import com.intellij.openapi.vcs.annotate.FileAnnotation;
 import com.intellij.openapi.vcs.changes.BackgroundFromStartOption;
@@ -160,7 +163,7 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper {
     private FileHistoryPanelImpl ensureHistoryPanelCreated() {
       if (myFileHistoryPanel == null) {
         ContentManager contentManager = ProjectLevelVcsManagerEx.getInstanceEx(myVcs.getProject()).getContentManager();
-        myFileHistoryPanel = new FileHistoryPanelImpl(myVcs.getProject(), myPath, myRepositoryPath, mySession, myVcsHistoryProvider,
+        myFileHistoryPanel = new FileHistoryPanelImpl(myVcs, myPath, mySession, myVcsHistoryProvider,
                                                       myAnnotationProvider, contentManager, myRefresher);
       }
       return myFileHistoryPanel;
@@ -436,8 +439,16 @@ public class AbstractVcsHelperImpl extends AbstractVcsHelper {
     return exceptions;
   }
 
-  public void showAnnotation(FileAnnotation annotation, VirtualFile file) {
-    new Annotater(annotation, myProject, file).showAnnotation();
+  public void showAnnotation(FileAnnotation annotation, VirtualFile file, AbstractVcs vcs) {
+    OpenFileDescriptor openFileDescriptor = new OpenFileDescriptor(myProject, file);
+    Editor editor = FileEditorManager.getInstance(myProject).openTextEditor(openFileDescriptor, true);
+    if (editor == null) {
+      Messages.showMessageDialog(VcsBundle.message("message.text.cannot.open.editor", file.getPresentableUrl()),
+                                 VcsBundle.message("message.title.cannot.open.editor"), Messages.getInformationIcon());
+      return;
+    }
+
+    AnnotateToggleAction.doAnnotate(editor, myProject, file, annotation, vcs);
   }
 
   public void showDifferences(final VcsFileRevision version1, final VcsFileRevision version2, final File file) {
index 9a3f39f56c034a215366ec374bf4a9de1ec8e16f..e75f05c3cadb00b8ab671c9c8c526c87ea1e03c2 100644 (file)
@@ -130,6 +130,41 @@ public class CvsCommittedChangesProvider implements CachingCommittedChangesProvi
     return 0;
   }
 
+  @Nullable
+  @Override
+  public CvsChangeList getOneList(RepositoryLocation location, final VcsRevisionNumber number) throws VcsException {
+    CvsRepositoryLocation cvsLocation = (CvsRepositoryLocation) location;
+    final String module = cvsLocation.getModuleName();
+    final CvsEnvironment connectionSettings = cvsLocation.getEnvironment();
+    if (connectionSettings.isOffline()) {
+      return null;
+    }
+    final CvsChangeListsBuilder builder = new CvsChangeListsBuilder(module, connectionSettings, myProject, cvsLocation.getRootFile());
+
+    final CvsChangeList[] result = new CvsChangeList[1];
+    final CvsResult executionResult = runRLogOperation(connectionSettings, module, new Date(1000), null, new Consumer<LogInformationWrapper>() {
+      public void consume(LogInformationWrapper wrapper) {
+        if (result[0] != null) return;
+        final List<RevisionWrapper> wrappers = builder.revisionWrappersFromLog(wrapper);
+        if (wrappers != null) {
+          for (RevisionWrapper revisionWrapper : wrappers) {
+            if (Comparing.equal(revisionWrapper.getRevision().getNumber(), number.asString())) {
+              result[0] = builder.addRevision(revisionWrapper);
+            }
+          }
+        }
+      }
+    });
+
+    if (executionResult.isCanceled()) {
+      throw new ProcessCanceledException();
+    }
+    else if (! executionResult.hasNoErrors()) {
+      throw executionResult.composeError();
+    }
+    return result[0];
+  }
+
   public List<CvsChangeList> getCommittedChanges(ChangeBrowserSettings settings, RepositoryLocation location, final int maxCount) throws VcsException {
     CvsRepositoryLocation cvsLocation = (CvsRepositoryLocation) location;
     return loadCommittedChanges(settings, cvsLocation.getModuleName(), cvsLocation.getEnvironment(), cvsLocation.getRootFile());
index 87c4fc0fc076351b15aba713486363ea9899f3a9..4e4d95033fadfba8c4af83f1561b8d4f329ac99e 100644 (file)
@@ -172,9 +172,10 @@ public class BrowserPanel extends JPanel implements DataProvider, CvsTabbedWindo
     public void actionPerformed(AnActionEvent e) {
       VcsVirtualFile vcsVirtualFile = (VcsVirtualFile)getCvsVirtualFile();
       try {
-        final FileAnnotation annotation = CvsVcs2.getInstance(myProject)
+        final CvsVcs2 vcs = CvsVcs2.getInstance(myProject);
+        final FileAnnotation annotation = vcs
             .createAnnotation(vcsVirtualFile, vcsVirtualFile.getRevision(), myCvsRootConfiguration);
-        AbstractVcsHelper.getInstance(myProject).showAnnotation(annotation, vcsVirtualFile);
+        AbstractVcsHelper.getInstance(myProject).showAnnotation(annotation, vcsVirtualFile, vcs);
       }
       catch (VcsException e1) {
         AbstractVcsHelper.getInstance(myProject).showError(e1, CvsBundle.message("operation.name.annotate"));
index 744f35c474fa6ff8b8089c39e2455abe5f919839..4b6ad47caba72258c7045cf523cd9569257d70e1 100644 (file)
@@ -171,7 +171,7 @@ public class CvsHistoryProvider implements VcsHistoryProvider {
 
     @Nullable
     public VcsRevisionNumber calcCurrentRevisionNumber() {
-      return getCurrentRevision(myFilePath);
+      return myFilePath == null ? null : getCurrentRevision(myFilePath);
     }
 
     @Override
index 4f69c496b5c55c3023a63b56f3b4bad21ac104c9..5e2d107c71f968d44d4bfb55ee438237c6c8544e 100644 (file)
@@ -338,8 +338,7 @@ public class GitVcs extends AbstractVcs<CommittedChangeList> {
    */
   @Override
   public CommittedChangesProvider getCommittedChangesProvider() {
-    // TODO Temporary disabled: return myCommittedChangeListProvider;
-    return null;
+    return myCommittedChangeListProvider;
   }
 
   /**
index d8bd592e96d2c0284cad9083aae4e6ee6b1949c0..569d888a7ffbeb885bdc2d098ddd2aabc63beb2c 100644 (file)
@@ -49,7 +49,7 @@ import java.util.List;
 /**
  * The provider for committed change lists
  */
-public class GitCommittedChangeListProvider implements CachingCommittedChangesProvider<CommittedChangeList, ChangeBrowserSettings> {
+public class GitCommittedChangeListProvider implements CommittedChangesProvider<CommittedChangeList, ChangeBrowserSettings> {
   /**
    * the logger
    */
@@ -224,6 +224,29 @@ public class GitCommittedChangeListProvider implements CachingCommittedChangesPr
     return -1;
   }
 
+  @Override
+  public CommittedChangeList getOneList(RepositoryLocation location, final VcsRevisionNumber number) throws VcsException {
+    final GitRepositoryLocation l = (GitRepositoryLocation)location;
+    VirtualFile root = LocalFileSystem.getInstance().findFileByIoFile(l.getRoot());
+    if (root == null) {
+      throw new VcsException("The repository does not exists anymore: " + l.getRoot());
+    }
+
+    final CommittedChangeList[] result = new CommittedChangeList[1];
+    GitUtil.getLocalCommittedChanges(myProject, root, new Consumer<GitSimpleHandler>() {
+      public void consume(GitSimpleHandler h) {
+        h.addParameters("-n1");
+        h.addParameters(number.asString());
+      }
+    }, new Consumer<CommittedChangeList>() {
+      @Override
+      public void consume(CommittedChangeList committedChangeList) {
+        result[0] = committedChangeList;
+      }
+    }, false);
+    return result[0];
+  }
+
   public int getFormatVersion() {
     return 0;
   }
index e0024efbb318b0c1c1bda44ea31ab4055384641c..bad269b1dcafd0bafddb47ef1998e408ea41f8c0 100644 (file)
@@ -268,4 +268,18 @@ public class HgCachingCommitedChangesProvider
   public int getUnlimitedCountValue() {
     return -1;
   }
+
+  @Override
+  public CommittedChangeList getOneList(RepositoryLocation location, VcsRevisionNumber number) throws VcsException {
+    final ChangeBrowserSettings settings = createDefaultSettings();
+    settings.USE_CHANGE_AFTER_FILTER = true;
+    settings.USE_CHANGE_BEFORE_FILTER = true;
+    settings.CHANGE_AFTER = number.asString();
+    settings.CHANGE_BEFORE = number.asString();
+    final List<CommittedChangeList> list = getCommittedChanges(settings, location, 1);
+    if (list.size() == 1) {
+      return list.get(0);
+    }
+    return null;
+  }
 }
index 45e7114caedb5c39d7749b8694ce08f2ae838523..daff6f2f5c95f8739a4c1925f0c85455296f8a57 100644 (file)
@@ -39,17 +39,17 @@ import com.intellij.util.ThrowableConsumer;
 import com.intellij.util.containers.MultiMap;
 import com.intellij.util.messages.MessageBusConnection;
 import org.jetbrains.annotations.Nullable;
+import org.jetbrains.idea.svn.SvnAuthenticationNotifier;
 import org.jetbrains.idea.svn.SvnBundle;
 import org.jetbrains.idea.svn.SvnUtil;
 import org.jetbrains.idea.svn.SvnVcs;
 import org.jetbrains.idea.svn.actions.ConfigureBranchesAction;
-import org.tmatesoft.svn.core.ISVNLogEntryHandler;
-import org.tmatesoft.svn.core.SVNException;
-import org.tmatesoft.svn.core.SVNLogEntry;
-import org.tmatesoft.svn.core.SVNURL;
+import org.tmatesoft.svn.core.*;
 import org.tmatesoft.svn.core.io.SVNRepository;
+import org.tmatesoft.svn.core.wc.SVNInfo;
 import org.tmatesoft.svn.core.wc.SVNLogClient;
 import org.tmatesoft.svn.core.wc.SVNRevision;
+import org.tmatesoft.svn.core.wc.SVNWCClient;
 
 import java.io.DataInput;
 import java.io.DataOutput;
@@ -490,6 +490,106 @@ public class SvnCommittedChangesProvider implements CachingCommittedChangesProvi
     return 0;
   }
 
+  @Override
+  public SvnChangeList getOneList(final RepositoryLocation location, VcsRevisionNumber number) throws VcsException {
+    final String url = ((SvnRepositoryLocation)location).getURL();
+    final long revision;
+    try {
+      revision = Long.parseLong(number.asString());
+    } catch (NumberFormatException e) {
+      throw new VcsException(e);
+    }
+
+    final SvnChangeList[] result = new SvnChangeList[1];
+    final SVNLogClient logger;
+    final SVNRevision revisionBefore;
+    final SVNURL repositoryUrl;
+    final SVNURL svnurl;
+    try {
+      logger = myVcs.createLogClient();
+      revisionBefore = SVNRevision.create(revision);
+
+      svnurl = SVNURL.parseURIEncoded(url);
+      final SVNWCClient client = myVcs.createWCClient();
+      SVNInfo info = client.doInfo(svnurl, SVNRevision.UNDEFINED, SVNRevision.HEAD);
+      if (info == null) {
+        throw new VcsException("Can not get repository URL");
+      }
+      repositoryUrl = info.getRepositoryRootURL();
+    }
+    catch (SVNException e) {
+      throw new VcsException(e);
+    }
+
+    tryExactHit((SvnRepositoryLocation)location, result, logger, revisionBefore, repositoryUrl, svnurl);
+    if (result[0] == null) {
+      tryByRoot(result, logger, revisionBefore, repositoryUrl);
+      if (result[0] == null) {
+        tryStepByStep((SvnRepositoryLocation)location, result, logger, revisionBefore, repositoryUrl, svnurl);
+      }
+    }
+    return result[0];
+  }
+
+  private void tryByRoot(SvnChangeList[] result, SVNLogClient logger, SVNRevision revisionBefore, SVNURL repositoryUrl) throws VcsException {
+    final boolean authorized = SvnAuthenticationNotifier.passiveValidation(myProject, repositoryUrl);
+    if (! authorized) return;
+    tryExactHit(new SvnRepositoryLocation(repositoryUrl.toString()), result, logger, revisionBefore, repositoryUrl, repositoryUrl);
+  }
+
+  private void tryStepByStep(final SvnRepositoryLocation svnRepositoryLocation,
+                             final SvnChangeList[] result,
+                             SVNLogClient logger,
+                             final SVNRevision revisionBefore, final SVNURL repositoryUrl, SVNURL svnurl) throws VcsException {
+    try {
+      logger.doLog(svnurl, null, SVNRevision.UNDEFINED, SVNRevision.HEAD, revisionBefore,
+                   false, true, true, 0, null,
+                   new ISVNLogEntryHandler() {
+                     public void handleLogEntry(SVNLogEntry logEntry) {
+                       if (myProject.isDisposed()) throw new ProcessCanceledException();
+                       if (logEntry.getDate() == null) {
+                         // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe
+                         return;
+                       }
+                       if (logEntry.getRevision() == revisionBefore.getNumber()) {
+                         result[0] = new SvnChangeList(myVcs, svnRepositoryLocation, logEntry, repositoryUrl.toString());
+                       }
+                     }
+                   });
+    }
+    catch (SVNException e) {
+      throw new VcsException(e);
+    }
+  }
+
+  private void tryExactHit(final SvnRepositoryLocation location,
+                           final SvnChangeList[] result,
+                           SVNLogClient logger,
+                           SVNRevision revisionBefore,
+                           final SVNURL repositoryUrl, SVNURL svnurl) throws VcsException {
+    try {
+      logger.doLog(svnurl, null, SVNRevision.UNDEFINED, revisionBefore, revisionBefore,
+                   false, true, false, 1, null,
+                   new ISVNLogEntryHandler() {
+                     public void handleLogEntry(SVNLogEntry logEntry) {
+                       if (myProject.isDisposed()) throw new ProcessCanceledException();
+                       if (logEntry.getDate() == null) {
+                         // do not add lists without info - this situation is possible for lists where there are paths that user has no rights to observe
+                         return;
+                       }
+                       result[0] = new SvnChangeList(myVcs, (SvnRepositoryLocation) location, logEntry, repositoryUrl.toString());
+                     }
+                   });
+    }
+    catch (SVNException e) {
+      if (SVNErrorCode.FS_CATEGORY == e.getErrorMessage().getErrorCode().getCategory()) {
+        // pass to step by step looking for revision
+        return;
+      }
+      throw new VcsException(e);
+    }
+  }
+
   public int getFormatVersion() {
     return VERSION_WITH_REPLACED_PATHS;
   }