IDEA-60323 Support editing subversion commit messages

also from file history tab
This commit is contained in:
irengrig
2012-10-25 12:28:18 +04:00
parent 47a7a2e8ec
commit ff0dec4382
9 changed files with 154 additions and 26 deletions
@@ -23,6 +23,7 @@ import com.intellij.openapi.vcs.changes.ChangeRequestChain;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.pointers.VirtualFilePointer;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NonNls;
import java.io.File;
@@ -60,6 +61,6 @@ public interface VcsDataKeys {
DataKey<Object> LABEL_AFTER = DataKey.create("LABEL_AFTER");
DataKey<String> PRESET_COMMIT_MESSAGE = DataKey.create("PRESET_COMMIT_MESSAGE");
DataKey<CommitMessageI> COMMIT_MESSAGE_CONTROL = DataKey.create("COMMIT_MESSAGE_CONTROL");
DataKey<Runnable> REMOTE_HISTORY_CHANGED_LISTENER = DataKey.create("REMOTE_HISTORY_CHANGED_LISTENER");
DataKey<Consumer<String>> REMOTE_HISTORY_CHANGED_LISTENER = DataKey.create("REMOTE_HISTORY_CHANGED_LISTENER");
DataKey<RepositoryLocation> REMOTE_HISTORY_LOCATION = DataKey.create("REMOTE_HISTORY_LOCATION");
}
@@ -18,6 +18,7 @@ package com.intellij.openapi.vcs.history;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.VcsKey;
import com.intellij.openapi.vcs.annotate.VcsAnnotation;
import com.intellij.util.Consumer;
import com.intellij.util.containers.SLRUMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -58,6 +59,15 @@ public class VcsHistoryCache {
}
}
public void editCached(final FilePath filePath, final VcsKey vcsKey, final Consumer<List<VcsFileRevision>> consumer) {
synchronized (myLock) {
final CachedHistory cachedHistory = myHistoryCache.get(new HistoryCacheBaseKey(filePath, vcsKey));
if (cachedHistory != null) {
consumer.consume(cachedHistory.getRevisions());
}
}
}
@Nullable
public <C extends Serializable, T extends VcsAbstractHistorySession> T getFull(final FilePath filePath, final VcsKey vcsKey,
@NotNull final VcsCacheableHistorySessionFactory<C, T> factory) {
@@ -69,7 +69,7 @@ public class CommittedChangesPanel extends JPanel implements TypeSafeDataProvide
private final List<Runnable> myShouldBeCalledOnDispose;
private volatile boolean myDisposed;
private volatile boolean myInLoad;
private Runnable myIfNotCachedReloader;
private Consumer<String> myIfNotCachedReloader;
public CommittedChangesPanel(Project project, final CommittedChangesProvider provider, final ChangeBrowserSettings settings,
@Nullable final RepositoryLocation location, @Nullable ActionGroup extraActions) {
@@ -109,9 +109,9 @@ public class CommittedChangesPanel extends JPanel implements TypeSafeDataProvide
final AnAction anAction = ActionManager.getInstance().getAction("CommittedChanges.Refresh");
anAction.registerCustomShortcutSet(CommonShortcuts.getRerun(), this);
myBrowser.addFilter(myFilterComponent);
myIfNotCachedReloader = myLocation == null ? null : new Runnable() {
myIfNotCachedReloader = myLocation == null ? null : new Consumer<String>() {
@Override
public void run() {
public void consume(String s) {
refreshChanges(false);
}
};
@@ -1208,8 +1208,14 @@ public class FileHistoryPanelImpl extends PanelWithActionsAndCloseButton {
}
else if (VcsDataKeys.VCS_FILE_REVISIONS.is(dataId)) {
return getSelectedRevisions();
}
else if (VcsDataKeys.CHANGES.is(dataId)) {
} else if (VcsDataKeys.REMOTE_HISTORY_CHANGED_LISTENER.is(dataId)) {
return new Consumer<String>() {
@Override
public void consume(String s) {
myDualView.rebuild();
}
};
} else if (VcsDataKeys.CHANGES.is(dataId)) {
return getChanges();
}
else if (VcsDataKeys.VCS_VIRTUAL_FILE.is(dataId)) {
+1 -2
View File
@@ -39,8 +39,7 @@
<action id="PropertiesDiff" class="org.jetbrains.idea.svn.actions.ShowPropertiesDiffAction" popup="true" icon="SvnIcons.PropertiesDiff">
<add-to-group group-id="RepositoryChangesBrowserToolbar" anchor="last"/>
</action>
<action id="EditCommitMessage" class="org.jetbrains.idea.svn.history.SvnEditCommitMessageAction" popup="true" icon="AllIcons.Actions.Edit"
text="Edit Revision Comment" description="Edit revision comment. Previous message is rewritten.">
<action id="EditCommitMessage" class="org.jetbrains.idea.svn.history.SvnEditCommitMessageAction" popup="true">
<add-to-group group-id="CommittedChangesToolbar" anchor="last"/>
</action>
@@ -33,6 +33,7 @@ import com.intellij.openapi.vcs.VcsException;
import com.intellij.openapi.vcs.changes.ChangeList;
import com.intellij.openapi.vcs.changes.committed.CommittedChangesCache;
import com.intellij.openapi.vcs.ui.VcsBalloonProblemNotifier;
import com.intellij.util.Consumer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.svn.SvnUtil;
@@ -59,12 +60,17 @@ public class SvnEditCommitMessageAction extends AnAction {
final SvnChangeList svnList = (SvnChangeList) lists[0];
Project project = PlatformDataKeys.PROJECT.getData(dc);
project = project == null ? ProjectManager.getInstance().getDefaultProject() : project;
final Consumer<String> listener = VcsDataKeys.REMOTE_HISTORY_CHANGED_LISTENER.getData(dc);
askAndEditRevision(svnList.getNumber(), svnList.getComment(), svnList.getLocation(), project, listener, false);
}
public static void askAndEditRevision(final long number, final String oldComment, final SvnRepositoryLocation location, Project project, Consumer<String> listener, final boolean fromVersionControl) {
final String edited = Messages.showMultilineInputDialog(project, "Attention! Previous message will be lost!\n\nNew revision comment:",
"Edit Revision # " + svnList.getNumber() + " Comment", svnList.getComment(), Messages.getInformationIcon(), null);
if (edited == null || edited.trim().equals(svnList.getComment().trim())) return;
final Runnable listener = VcsDataKeys.REMOTE_HISTORY_CHANGED_LISTENER.getData(dc);
ProgressManager.getInstance().run(new EditMessageTask(project, edited, svnList, listener));
"Edit Revision # " + number + " Comment", oldComment,
Messages.getInformationIcon(), null);
if (edited == null || edited.trim().equals(oldComment.trim())) return;
ProgressManager.getInstance().run(new EditMessageTask(project, edited, location, number, listener, fromVersionControl));
}
@Override
@@ -99,25 +105,34 @@ public class SvnEditCommitMessageAction extends AnAction {
return cr instanceof MarkerVcsContentRevision && SvnVcs.getKey().equals(((MarkerVcsContentRevision) cr).getVcsKey());
}*/
private static class EditMessageTask extends Task.Backgroundable {
static class EditMessageTask extends Task.Backgroundable {
private final String myNewMessage;
private final SvnChangeList myChangeList;
private final Runnable myListener;
private final SvnRepositoryLocation myLocation;
private final long myNumber;
private final Consumer<String> myListener;
private final boolean myFromVersionControl;
private VcsException myException;
private final SvnVcs myVcs;
private EditMessageTask(@Nullable Project project, final String newMessage, final SvnChangeList changeList, Runnable listener) {
EditMessageTask(@Nullable Project project,
final String newMessage,
final SvnRepositoryLocation location,
final long number,
Consumer<String> listener,
boolean fromVersionControl) {
super(project, "Edit Revision Comment");
myNewMessage = newMessage;
myChangeList = changeList;
myLocation = location;
myNumber = number;
myListener = listener;
myFromVersionControl = fromVersionControl;
myVcs = SvnVcs.getInstance(myProject);
}
@Override
public void run(@NotNull ProgressIndicator indicator) {
final SVNWCClient client = myVcs.createWCClient();
final String url = myChangeList.getLocation().getURL();
final String url = myLocation.getURL();
final SVNURL root;
try {
root = SvnUtil.getRepositoryRoot(myVcs, SVNURL.parseURIEncoded(url));
@@ -125,7 +140,7 @@ public class SvnEditCommitMessageAction extends AnAction {
myException = new VcsException("Can not determine repository root for URL: " + url);
return;
}
client.doSetRevisionProperty(root, SVNRevision.create(myChangeList.getNumber()), "svn:log",
client.doSetRevisionProperty(root, SVNRevision.create(myNumber), "svn:log",
SVNPropertyValue.create(myNewMessage), false, null);
}
catch (SVNException e) {
@@ -139,14 +154,18 @@ public class SvnEditCommitMessageAction extends AnAction {
AbstractVcsHelper.getInstance(myProject).showError(myException, myTitle);
} else {
if (myListener != null) {
myListener.run();
myListener.consume(myNewMessage);
}
if (! myProject.isDefault()) {
CommittedChangesCache.getInstance(myProject).commitMessageChanged(myVcs,
myChangeList.getLocation(), myChangeList.getNumber(), myNewMessage);
CommittedChangesCache.getInstance(myProject).commitMessageChanged(myVcs, myLocation, myNumber, myNewMessage);
}
if (myFromVersionControl) {
VcsBalloonProblemNotifier.showOverVersionControlView(myProject, "Revision #" + myNumber + " comment " +
"changed to:\n'" + myNewMessage + "'", MessageType.INFO);
} else {
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Revision #" + myNumber + " comment " +
"changed to:\n'" + myNewMessage + "'", MessageType.INFO);
}
VcsBalloonProblemNotifier.showOverChangesView(myProject, "Revision #" + myChangeList.getNumber() + " comment " +
"changed to:\n'" + myNewMessage + "'", MessageType.INFO);
}
}
}
@@ -0,0 +1,89 @@
/*
* Copyright 2000-2012 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 org.jetbrains.idea.svn.history;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePathImpl;
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
import com.intellij.openapi.vcs.VcsDataKeys;
import com.intellij.openapi.vcs.VcsKey;
import com.intellij.openapi.vcs.history.VcsFileRevision;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.Consumer;
import org.jetbrains.idea.svn.SvnVcs;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 10/25/12
* Time: 10:22 AM
*/
public class SvnEditCommitMessageFromFileHistoryAction extends AnAction {
public SvnEditCommitMessageFromFileHistoryAction() {
super("Edit Revision Comment", "Edit revision comment. Previous message is rewritten.", AllIcons.Actions.Edit);
}
@Override
public void actionPerformed(AnActionEvent e) {
final Project project = e.getData(PlatformDataKeys.PROJECT);
if (project == null) return;
final VcsKey vcsKey = e.getData(VcsDataKeys.VCS);
if (vcsKey == null || ! SvnVcs.getKey().equals(vcsKey)) return;
final VcsFileRevision revision = e.getData(VcsDataKeys.VCS_FILE_REVISION);
final VirtualFile revisionVirtualFile = e.getData(VcsDataKeys.VCS_VIRTUAL_FILE);
if (revision == null || revisionVirtualFile == null) return;
final SvnFileRevision svnFileRevision = (SvnFileRevision) revision;
final Consumer<String> listener = VcsDataKeys.REMOTE_HISTORY_CHANGED_LISTENER.getData(e.getDataContext());
SvnEditCommitMessageAction.askAndEditRevision(svnFileRevision.getRevision().getNumber(), svnFileRevision.getCommitMessage(),
(SvnRepositoryLocation) svnFileRevision.getChangedRepositoryPath(), project, new Consumer<String>() {
@Override
public void consume(final String newMessage) {
svnFileRevision.setCommitMessage(newMessage);
if (listener != null) {
listener.consume(newMessage);
}
ProjectLevelVcsManager.getInstance(project).getVcsHistoryCache().editCached(new FilePathImpl(revisionVirtualFile), vcsKey,
new Consumer<List<VcsFileRevision>>() {
@Override
public void consume(List<VcsFileRevision> revisions) {
for (VcsFileRevision fileRevision : revisions) {
if (! (fileRevision instanceof SvnFileRevision)) continue;
if (((SvnFileRevision) fileRevision).getRevision().getNumber() == svnFileRevision.getRevision().getNumber()) {
((SvnFileRevision) fileRevision).setCommitMessage(newMessage);
break;
}
}
}
});
}
}, true);
}
@Override
public void update(AnActionEvent e) {
final VcsKey vcsKey = e.getData(VcsDataKeys.VCS);
final boolean isSvn = SvnVcs.getKey().equals(vcsKey);
e.getPresentation().setVisible(isSvn);
final VcsFileRevision revision = e.getData(VcsDataKeys.VCS_FILE_REVISION);
e.getPresentation().setEnabled(isSvn && revision != null);
}
}
@@ -47,7 +47,7 @@ public class SvnFileRevision implements VcsFileRevision {
private final static Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.history.SvnFileRevision");
private final Date myDate;
private final String myCommitMessage;
private String myCommitMessage;
private final String myAuthor;
private final VcsRevisionNumber myRevisionNumber;
private final SvnVcs myVCS;
@@ -178,6 +178,10 @@ public class SvnFileRevision implements VcsFileRevision {
return myCopyFromPath;
}
public void setCommitMessage(String message) {
myCommitMessage = message;
}
private class ContentLoader implements Runnable {
private final SVNRevision myRevision;
private final SVNRevision myPegRevision;
@@ -474,7 +474,7 @@ public class SvnHistoryProvider
}
public AnAction[] getAdditionalActions(final Runnable refresher) {
return new AnAction[]{ ShowAllAffectedGenericAction.getInstance(), new MergeSourceDetailsAction()};
return new AnAction[]{ ShowAllAffectedGenericAction.getInstance(), new MergeSourceDetailsAction(), new SvnEditCommitMessageFromFileHistoryAction()};
}
public boolean isDateOmittable() {