From 4f4cfd42a4b8521be24764c48c8097286d65735f Mon Sep 17 00:00:00 2001 From: irengrig Date: Mon, 9 Aug 2010 19:24:54 +0400 Subject: [PATCH] VCS: show diff from annotate, not completed jet, but usable --- .../editor/TextAnnotationGutterProvider.java | 2 +- .../impl/EditorGutterComponentImpl.java | 6 +- .../openapi/vcs/AbstractVcsHelper.java | 2 +- .../openapi/vcs/CommittedChangesProvider.java | 4 + .../vcs/actions/AnnotateToggleAction.java | 161 ++++++++++++++++-- .../vcs/actions/AnnotationFieldGutter.java | 4 +- .../AnnotationGutterLineConvertorProxy.java | 4 +- .../openapi/vcs/annotate/Annotater.java | 51 ------ .../annotate/TextAnnotationPresentation.java | 3 +- .../CommittedChangesVisibilityPredicate.java | 5 +- .../CompositeCommittedChangesProvider.java | 6 + .../IncomingChangesVisibilityPredicate.java | 5 +- .../vcs/history/FileHistoryPanelImpl.java | 52 +++--- .../vcs/impl/AbstractVcsHelperImpl.java | 19 ++- .../CvsCommittedChangesProvider.java | 35 ++++ .../cvsBrowser/ui/BrowserPanel.java | 5 +- .../history/CvsHistoryProvider.java | 2 +- plugins/git4idea/src/git4idea/GitVcs.java | 3 +- .../GitCommittedChangeListProvider.java | 25 ++- .../HgCachingCommitedChangesProvider.java | 14 ++ .../history/SvnCommittedChangesProvider.java | 108 +++++++++++- 21 files changed, 402 insertions(+), 114 deletions(-) delete mode 100644 platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/Annotater.java diff --git a/platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java b/platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java index 22eaa410843b..b57f180933c3 100644 --- a/platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java +++ b/platform/platform-api/src/com/intellij/openapi/editor/TextAnnotationGutterProvider.java @@ -65,7 +65,7 @@ public interface TextAnnotationGutterProvider { /*** * enables annotation view modifications */ - List getPopupActions(final Editor editor); + List getPopupActions(final int line, final Editor editor); /** * Called when the annotations are removed from the editor gutter. diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java index bb5ade1b546a..8291578b30f7 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/EditorGutterComponentImpl.java @@ -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 addActions = new ArrayList(); + 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 list = gutterProvider.getPopupActions(myEditor); + final List list = gutterProvider.getPopupActions(line, myEditor); if (list != null) { for (AnAction action : list) { if (! addActions.contains(action)) { diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java b/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java index 370cf192e1ba..2dc07b928bca 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/AbstractVcsHelper.java @@ -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); diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java b/platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java index eda912583fab..2c4bcc8a9d7f 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/CommittedChangesProvider.java @@ -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 gutters = new ArrayList(); 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 myGutters; private final List myActions; private MySwitchAnnotationSourceAction mySwitchAction; + private final List> myPopupLineNumberListeners; public MyAnnotationPresentation(@NotNull final HighlightAnnotationsActions highlighting, @Nullable final AnnotationSourceSwitcher switcher, - final EditorGutterComponentEx gutter, - List gutters) { + final EditorGutterComponentEx gutter, final List gutters, final AnAction... actions) { myHighlighting = highlighting; mySwitcher = switcher; myGutters = gutters; + myPopupLineNumberListeners = new LinkedList>(); - myActions = new ArrayList(myHighlighting.getList()); + myActions = new ArrayList(); + myActions.add(Separator.getInstance()); + if (actions != null) { + final List actionsList = Arrays.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 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 getActions() { + public List getActions(int line) { + for (Consumer 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 { + 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 changes = new LinkedList(); + 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 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; + } + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java index c54ca5b5f338..9ee9edb5b72c 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationFieldGutter.java @@ -99,8 +99,8 @@ class AnnotationFieldGutter implements ActiveAnnotationGutter { return myPresentation.getColor(line); } - public List getPopupActions(final Editor editor) { - return myPresentation.getActions(); + public List getPopupActions(int line, final Editor editor) { + return myPresentation.getActions(line); } public void gutterClosed() { diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java index 6cd1cb0092bb..52ce811f0cd7 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/actions/AnnotationGutterLineConvertorProxy.java @@ -68,8 +68,8 @@ public class AnnotationGutterLineConvertorProxy implements ActiveAnnotationGutte return myDelegate.getBgColor(currentLine, editor); } - public List getPopupActions(Editor editor) { - return myDelegate.getPopupActions(editor); + public List 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 index b4f718fc3cc5..000000000000 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/Annotater.java +++ /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); - } - -} diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java index 9c13afd02a31..1fca77641739 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/annotate/TextAnnotationPresentation.java @@ -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 getActions(); + List getActions(int line); } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java index fe376e3b16d2..94d4fca858a1 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/CommittedChangesVisibilityPredicate.java @@ -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 myMap; private final Set myEnabledVcs = new HashSet(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java index 7b10a69d83eb..c3d080bac8d0 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/committed/IncomingChangesVisibilityPredicate.java @@ -16,9 +16,10 @@ 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 myRevisionToVirtualFile = new HashMap(); - 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 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 fileAnnotationRef = new Ref(); final Ref exceptionRef = new Ref(); - 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() { + public void consume(LogInformationWrapper wrapper) { + if (result[0] != null) return; + final List 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 getCommittedChanges(ChangeBrowserSettings settings, RepositoryLocation location, final int maxCount) throws VcsException { CvsRepositoryLocation cvsLocation = (CvsRepositoryLocation) location; return loadCommittedChanges(settings, cvsLocation.getModuleName(), cvsLocation.getEnvironment(), cvsLocation.getRootFile()); diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java index 87c4fc0fc076..4e4d95033fad 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsBrowser/ui/BrowserPanel.java @@ -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")); diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java index 744f35c474fa..4b6ad47caba7 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/history/CvsHistoryProvider.java @@ -171,7 +171,7 @@ public class CvsHistoryProvider implements VcsHistoryProvider { @Nullable public VcsRevisionNumber calcCurrentRevisionNumber() { - return getCurrentRevision(myFilePath); + return myFilePath == null ? null : getCurrentRevision(myFilePath); } @Override diff --git a/plugins/git4idea/src/git4idea/GitVcs.java b/plugins/git4idea/src/git4idea/GitVcs.java index 4f69c496b5c5..5e2d107c71f9 100644 --- a/plugins/git4idea/src/git4idea/GitVcs.java +++ b/plugins/git4idea/src/git4idea/GitVcs.java @@ -338,8 +338,7 @@ public class GitVcs extends AbstractVcs { */ @Override public CommittedChangesProvider getCommittedChangesProvider() { - // TODO Temporary disabled: return myCommittedChangeListProvider; - return null; + return myCommittedChangeListProvider; } /** diff --git a/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java b/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java index d8bd592e96d2..569d888a7ffb 100644 --- a/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java +++ b/plugins/git4idea/src/git4idea/changes/GitCommittedChangeListProvider.java @@ -49,7 +49,7 @@ import java.util.List; /** * The provider for committed change lists */ -public class GitCommittedChangeListProvider implements CachingCommittedChangesProvider { +public class GitCommittedChangeListProvider implements CommittedChangesProvider { /** * 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() { + public void consume(GitSimpleHandler h) { + h.addParameters("-n1"); + h.addParameters(number.asString()); + } + }, new Consumer() { + @Override + public void consume(CommittedChangeList committedChangeList) { + result[0] = committedChangeList; + } + }, false); + return result[0]; + } + public int getFormatVersion() { return 0; } diff --git a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java index e0024efbb318..bad269b1dcaf 100644 --- a/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java +++ b/plugins/hg4idea/src/org/zmlx/hg4idea/provider/HgCachingCommitedChangesProvider.java @@ -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 list = getCommittedChanges(settings, location, 1); + if (list.size() == 1) { + return list.get(0); + } + return null; + } } diff --git a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java index 45e7114caedb..daff6f2f5c95 100644 --- a/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java +++ b/plugins/svn4idea/src/org/jetbrains/idea/svn/history/SvnCommittedChangesProvider.java @@ -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; }