mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-119238 Git and Hg Amend Commit: amend message updated for multi-root selection changes
*last messaged for all committed repositories stored to map; *amended message reconstructed using current selected repositories
This commit is contained in:
@@ -24,10 +24,13 @@ import com.intellij.openapi.util.Ref;
|
|||||||
import com.intellij.openapi.util.ThrowableComputable;
|
import com.intellij.openapi.util.ThrowableComputable;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vcs.CheckinProjectPanel;
|
import com.intellij.openapi.vcs.CheckinProjectPanel;
|
||||||
|
import com.intellij.openapi.vcs.FilePath;
|
||||||
|
import com.intellij.openapi.vcs.FilePathImpl;
|
||||||
import com.intellij.openapi.vcs.VcsException;
|
import com.intellij.openapi.vcs.VcsException;
|
||||||
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
|
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.ui.NonFocusableCheckBox;
|
import com.intellij.ui.NonFocusableCheckBox;
|
||||||
|
import com.intellij.util.Function;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -36,8 +39,9 @@ import javax.swing.*;
|
|||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.util.Collection;
|
import java.io.File;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Nadya Zabrodina
|
* @author Nadya Zabrodina
|
||||||
@@ -51,6 +55,7 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp
|
|||||||
@Nullable private String myPreviousMessage;
|
@Nullable private String myPreviousMessage;
|
||||||
@Nullable private String myAmendedMessage;
|
@Nullable private String myAmendedMessage;
|
||||||
@NotNull protected final CheckinProjectPanel myCheckinPanel;
|
@NotNull protected final CheckinProjectPanel myCheckinPanel;
|
||||||
|
@Nullable private Map<VirtualFile, String> myMessagesForRoots;
|
||||||
|
|
||||||
public DvcsCommitAdditionalComponent(@NotNull final Project project, @NotNull CheckinProjectPanel panel) {
|
public DvcsCommitAdditionalComponent(@NotNull final Project project, @NotNull CheckinProjectPanel panel) {
|
||||||
myCheckinPanel = panel;
|
myCheckinPanel = panel;
|
||||||
@@ -76,14 +81,16 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp
|
|||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
if (myAmend.isSelected()) {
|
if (myAmend.isSelected()) {
|
||||||
if (myPreviousMessage.equals(myCheckinPanel.getCommitMessage())) { // if user has already typed something, don't revert it
|
if (myPreviousMessage.equals(myCheckinPanel.getCommitMessage())) { // if user has already typed something, don't revert it
|
||||||
if (myAmendedMessage == null) {
|
if (myMessagesForRoots == null) {
|
||||||
loadMessageInModalTask(project);
|
loadMessagesInModalTask(project); //load all commit messages for all repositories
|
||||||
|
}
|
||||||
|
String message = constructAmendedMessage();
|
||||||
|
if (!StringUtil.isEmptyOrSpaces(message)) {
|
||||||
|
myAmendedMessage = message;
|
||||||
|
substituteCommitMessage(myAmendedMessage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else { // checkbox is selected not the first time
|
|
||||||
substituteCommitMessage(myAmendedMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// there was the amended message, but user has changed it => not reverting
|
// there was the amended message, but user has changed it => not reverting
|
||||||
@@ -96,6 +103,20 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp
|
|||||||
myPanel.add(myAmend, c);
|
myPanel.add(myAmend, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String constructAmendedMessage() {
|
||||||
|
Set<VirtualFile> selectedRoots = getVcsRoots(getSelectedFilePaths()); // get only selected files
|
||||||
|
LinkedHashSet<String> messages = ContainerUtil.newLinkedHashSet();
|
||||||
|
if (myMessagesForRoots != null) {
|
||||||
|
for (VirtualFile root : selectedRoots) {
|
||||||
|
String message = myMessagesForRoots.get(root);
|
||||||
|
if (message != null) {
|
||||||
|
messages.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DvcsUtil.joinMessagesOrNull(messages);
|
||||||
|
}
|
||||||
|
|
||||||
public JComponent getComponent() {
|
public JComponent getComponent() {
|
||||||
return myPanel;
|
return myPanel;
|
||||||
}
|
}
|
||||||
@@ -104,19 +125,15 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp
|
|||||||
myAmend.setSelected(false);
|
myAmend.setSelected(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadMessageInModalTask(@NotNull Project project) {
|
private void loadMessagesInModalTask(@NotNull Project project) {
|
||||||
try {
|
try {
|
||||||
String messageFromVcs =
|
myMessagesForRoots =
|
||||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable<String, VcsException>() {
|
ProgressManager.getInstance().runProcessWithProgressSynchronously(new ThrowableComputable<Map<VirtualFile,String>, VcsException>() {
|
||||||
@Override
|
@Override
|
||||||
public String compute() throws VcsException {
|
public Map<VirtualFile, String> compute() throws VcsException {
|
||||||
return getLastCommitMessage();
|
return getLastCommitMessages();
|
||||||
}
|
}
|
||||||
}, "Reading commit message...", false, project);
|
}, "Reading commit message...", false, project);
|
||||||
if (!StringUtil.isEmptyOrSpaces(messageFromVcs)) {
|
|
||||||
substituteCommitMessage(messageFromVcs);
|
|
||||||
myAmendedMessage = messageFromVcs;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (VcsException e) {
|
catch (VcsException e) {
|
||||||
Messages.showErrorDialog(getComponent(), "Couldn't load commit message of the commit to amend.\n" + e.getMessage(),
|
Messages.showErrorDialog(getComponent(), "Couldn't load commit message of the commit to amend.\n" + e.getMessage(),
|
||||||
@@ -133,24 +150,32 @@ public abstract class DvcsCommitAdditionalComponent implements RefreshableOnComp
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private String getLastCommitMessage() throws VcsException {
|
private Map<VirtualFile, String> getLastCommitMessages() throws VcsException {
|
||||||
Collection<VirtualFile> roots = getRoots();
|
Map<VirtualFile, String> messagesForRoots = new HashMap<VirtualFile, String>();
|
||||||
|
Collection<VirtualFile> roots = myCheckinPanel.getRoots(); //all committed vcs roots, not only selected
|
||||||
final Ref<VcsException> exception = Ref.create();
|
final Ref<VcsException> exception = Ref.create();
|
||||||
LinkedHashSet<String> messages = ContainerUtil.newLinkedHashSet();
|
|
||||||
for (VirtualFile root : roots) {
|
for (VirtualFile root : roots) {
|
||||||
String message = getLastCommitMessage(root);
|
String message = getLastCommitMessage(root);
|
||||||
if (message != null) {
|
messagesForRoots.put(root, message);
|
||||||
messages.add(message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!exception.isNull()) {
|
if (!exception.isNull()) {
|
||||||
throw exception.get();
|
throw exception.get();
|
||||||
}
|
}
|
||||||
return DvcsUtil.joinMessagesOrNull(messages);
|
return messagesForRoots;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
protected abstract Collection<VirtualFile> getRoots();
|
private List<FilePath> getSelectedFilePaths() {
|
||||||
|
return ContainerUtil.map(myCheckinPanel.getFiles(), new Function<File, FilePath>() {
|
||||||
|
@Override
|
||||||
|
public FilePath fun(File file) {
|
||||||
|
return new FilePathImpl(file, file.isDirectory());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
protected abstract Set<VirtualFile> getVcsRoots(Collection<FilePath> files);
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected abstract String getLastCommitMessage(@NotNull VirtualFile repo) throws VcsException;
|
protected abstract String getLastCommitMessage(@NotNull VirtualFile repo) throws VcsException;
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ import com.intellij.openapi.ui.ComboBox;
|
|||||||
import com.intellij.openapi.util.Ref;
|
import com.intellij.openapi.util.Ref;
|
||||||
import com.intellij.openapi.util.io.FileUtil;
|
import com.intellij.openapi.util.io.FileUtil;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vcs.*;
|
import com.intellij.openapi.vcs.CheckinProjectPanel;
|
||||||
|
import com.intellij.openapi.vcs.FilePath;
|
||||||
|
import com.intellij.openapi.vcs.ObjectsConvertor;
|
||||||
|
import com.intellij.openapi.vcs.VcsException;
|
||||||
import com.intellij.openapi.vcs.changes.*;
|
import com.intellij.openapi.vcs.changes.*;
|
||||||
import com.intellij.openapi.vcs.changes.ui.SelectFilePathsDialog;
|
import com.intellij.openapi.vcs.changes.ui.SelectFilePathsDialog;
|
||||||
import com.intellij.openapi.vcs.checkin.CheckinChangeListSpecificComponent;
|
import com.intellij.openapi.vcs.checkin.CheckinChangeListSpecificComponent;
|
||||||
@@ -33,7 +36,10 @@ import com.intellij.openapi.vcs.checkin.CheckinEnvironment;
|
|||||||
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
|
import com.intellij.openapi.vcs.ui.RefreshableOnComponent;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.ui.GuiUtils;
|
import com.intellij.ui.GuiUtils;
|
||||||
import com.intellij.util.*;
|
import com.intellij.util.ArrayUtil;
|
||||||
|
import com.intellij.util.FunctionUtil;
|
||||||
|
import com.intellij.util.NullableFunction;
|
||||||
|
import com.intellij.util.PairConsumer;
|
||||||
import com.intellij.util.containers.ContainerUtil;
|
import com.intellij.util.containers.ContainerUtil;
|
||||||
import com.intellij.util.containers.Convertor;
|
import com.intellij.util.containers.Convertor;
|
||||||
import com.intellij.util.ui.UIUtil;
|
import com.intellij.util.ui.UIUtil;
|
||||||
@@ -643,8 +649,8 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@NotNull
|
@NotNull
|
||||||
protected Set<VirtualFile> getRoots() {
|
protected Set<VirtualFile> getVcsRoots(Collection<FilePath> filePaths) {
|
||||||
return GitUtil.gitRoots(getSelectedFilePaths());
|
return GitUtil.gitRoots(filePaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -665,16 +671,6 @@ public class GitCheckinEnvironment implements CheckinEnvironment {
|
|||||||
return h.run();
|
return h.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private List<FilePath> getSelectedFilePaths() {
|
|
||||||
return ContainerUtil.map(myCheckinPanel.getFiles(), new Function<File, FilePath>() {
|
|
||||||
@Override
|
|
||||||
public FilePath fun(File file) {
|
|
||||||
return new FilePathImpl(file, file.isDirectory());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getUsersList(final Project project) {
|
private List<String> getUsersList(final Project project) {
|
||||||
return NewGitUsersComponent.getInstance(project).get();
|
return NewGitUsersComponent.getInstance(project).get();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,8 +284,8 @@ public class HgCheckinEnvironment implements CheckinEnvironment {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
protected Collection<VirtualFile> getRoots() {
|
protected Set<VirtualFile> getVcsRoots(Collection<FilePath> filePaths) {
|
||||||
return HgUtil.getHgRepositories(myProject);
|
return HgUtil.hgRoots(myProject, filePaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -240,6 +240,23 @@ public abstract class HgUtil {
|
|||||||
return getNearestHgRoot(VcsUtil.getVcsRootFor(project, filePath));
|
return getNearestHgRoot(VcsUtil.getVcsRootFor(project, filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get hg roots for paths
|
||||||
|
*
|
||||||
|
* @param filePaths the context paths
|
||||||
|
* @return a set of git roots
|
||||||
|
*/
|
||||||
|
public static Set<VirtualFile> hgRoots(@NotNull Project project, final Collection<FilePath> filePaths) {
|
||||||
|
HashSet<VirtualFile> rc = new HashSet<VirtualFile>();
|
||||||
|
for (FilePath path : filePaths) {
|
||||||
|
final VirtualFile root = getHgRootOrNull(project, path);
|
||||||
|
if (root != null) {
|
||||||
|
rc.add(root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Mercurial root for the given file path or null if non exists:
|
* Gets the Mercurial root for the given file path or null if non exists:
|
||||||
* the root should not only be in directory mappings, but also the .hg repository folder should exist.
|
* the root should not only be in directory mappings, but also the .hg repository folder should exist.
|
||||||
|
|||||||
Reference in New Issue
Block a user