From 2af7100164512da2d9df0bc9d21ccf2293b5cda6 Mon Sep 17 00:00:00 2001 From: Nadya Zabrodina Date: Thu, 26 May 2016 20:55:41 +0300 Subject: [PATCH] [patch]: implement smart base root preselection and additional check that selected changes located under base dir path --- .../integration/ui/views/HistoryDialog.java | 2 ++ .../intellij/openapi/util/io/FileUtil.java | 9 ++++++ .../openapi/vcs/changes/ChangesUtil.java | 30 +++++++++++++++++++ .../patch/CreatePatchCommitExecutor.java | 13 ++++++++ .../patch/CreatePatchConfigurationPanel.java | 9 ++++++ 5 files changed, 63 insertions(+) diff --git a/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/HistoryDialog.java b/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/HistoryDialog.java index 9d2bc8acbad6..9d0c73c8d2ea 100644 --- a/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/HistoryDialog.java +++ b/platform/lvcs-impl/src/com/intellij/history/integration/ui/views/HistoryDialog.java @@ -46,6 +46,7 @@ import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.util.*; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.vcs.VcsException; +import com.intellij.openapi.vcs.changes.ChangesUtil; import com.intellij.openapi.vcs.changes.patch.CreatePatchConfigurationPanel; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ex.IdeFocusTraversalPolicy; @@ -455,6 +456,7 @@ public abstract class HistoryDialog extends FrameW CreatePatchConfigurationPanel p = new CreatePatchConfigurationPanel(myProject); p.setFileName(getDefaultPatchFile()); + p.setCommonParentPath(ChangesUtil.findCommonAncestor(myModel.getChanges())); if (!showAsDialog(p)) return; myModel.createPatch(p.getFileName(), p.getBaseDirName(), p.isReversePatch()); diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index e6235c2a36d7..fe1d2f71c628 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -212,6 +212,15 @@ public class FileUtil extends FileUtilRt { return result; } + @Nullable + public static File findAncestor(@NotNull File f1, @NotNull File f2) { + File ancestor = f1; + while (ancestor != null && !isAncestor(ancestor, f2, false)) { + ancestor = ancestor.getParentFile(); + } + return ancestor; + } + @Nullable public static File getParentFile(@NotNull File file) { return FileUtilRt.getParentFile(file); diff --git a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangesUtil.java b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangesUtil.java index 2b21d3a1730d..00f1cf55593a 100644 --- a/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangesUtil.java +++ b/platform/vcs-api/src/com/intellij/openapi/vcs/changes/ChangesUtil.java @@ -32,6 +32,7 @@ import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.Navigatable; import com.intellij.util.NullableFunction; +import com.intellij.util.ObjectUtils; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -466,4 +467,33 @@ public class ChangesUtil { public static String getDefaultChangeListName() { return VcsBundle.message("changes.default.changelist.name"); } + + /** + * Find common ancestor for changes (included both before and after files) + */ + @Nullable + public static File findCommonAncestor(@NotNull Collection changes) { + File ancestor = null; + for (Change change : changes) { + File currentChangeAncestor = getCommonBeforeAfterAncestor(change); + if (currentChangeAncestor == null) return null; + if (ancestor == null) { + ancestor = currentChangeAncestor; + } + else { + ancestor = FileUtil.findAncestor(ancestor, currentChangeAncestor); + if (ancestor == null) return null; + } + } + return ancestor; + } + + @Nullable + private static File getCommonBeforeAfterAncestor(@NotNull Change change) { + FilePath before = getBeforePath(change); + FilePath after = getAfterPath(change); + return before == null + ? ObjectUtils.assertNotNull(after).getIOFile() + : after == null ? before.getIOFile() : FileUtil.findAncestor(before.getIOFile(), after.getIOFile()); + } } diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/CreatePatchCommitExecutor.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/CreatePatchCommitExecutor.java index 95ddb8333c7f..6e8af3f4b0e8 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/CreatePatchCommitExecutor.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/CreatePatchCommitExecutor.java @@ -33,13 +33,16 @@ import com.intellij.openapi.util.DefaultJDOMExternalizer; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.openapi.vcs.AbstractVcs; import com.intellij.openapi.vcs.VcsApplicationSettings; import com.intellij.openapi.vcs.VcsBundle; import com.intellij.openapi.vcs.VcsConfiguration; import com.intellij.openapi.vcs.changes.*; import com.intellij.openapi.vcs.changes.shelf.ShelveChangesManager; import com.intellij.openapi.vcs.changes.ui.SessionDialog; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.WaitForProgressToShow; +import com.intellij.vcsUtil.VcsUtil; import org.jdom.Element; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NonNls; @@ -50,6 +53,7 @@ import javax.swing.*; import java.io.File; import java.util.Collection; import java.util.List; +import java.util.Set; public class CreatePatchCommitExecutor extends LocalCommitExecutor implements ProjectComponent, JDOMExternalizable { private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.patch.CreatePatchCommitExecutor"); @@ -136,6 +140,15 @@ public class CreatePatchCommitExecutor extends LocalCommitExecutor implements Pr } } myPanel.setFileName(ShelveChangesManager.suggestPatchName(myProject, commitMessage, new File(PATCH_PATH), null)); + File commonAncestor = ChangesUtil.findCommonAncestor(changes); + myPanel.setCommonParentPath(commonAncestor); + Set affectedVcses = ChangesUtil.getAffectedVcses(changes, myProject); + if (affectedVcses.size() == 1 && commonAncestor != null) { + VirtualFile vcsRoot = VcsUtil.getVcsRootFor(myProject, VcsUtil.getFilePath(commonAncestor)); + if (vcsRoot != null) { + myPanel.selectBasePath(vcsRoot.getPath()); + } + } myPanel.setReversePatch(false); JComponent panel = myPanel.getPanel(); diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/CreatePatchConfigurationPanel.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/CreatePatchConfigurationPanel.java index 4e4e2ee240bc..4c0d7174c26f 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/CreatePatchConfigurationPanel.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/CreatePatchConfigurationPanel.java @@ -61,6 +61,7 @@ public class CreatePatchConfigurationPanel { private ComboBox myEncoding; private JLabel myWarningLabel; private final Project myProject; + @Nullable private File myCommonParentPath; public CreatePatchConfigurationPanel(@NotNull final Project project) { myProject = project; @@ -124,6 +125,10 @@ public class CreatePatchConfigurationPanel { .getPanel(); } + public void setCommonParentPath(@Nullable File commonParentPath) { + myCommonParentPath = commonParentPath; + } + private void checkExist() { myWarningLabel.setText(new File(getFileName()).exists() ? "File with the same name already exists" : ""); } @@ -163,6 +168,10 @@ public class CreatePatchConfigurationPanel { if (StringUtil.isEmptyOrSpaces(baseDirName)) return new ValidationInfo("Base path can't be empty!", myBasePathField); File baseFile = new File(baseDirName); if (!baseFile.exists()) return new ValidationInfo("Base dir doesn't exist", myBasePathField); + if (myCommonParentPath != null && !FileUtil.isAncestor(baseFile, myCommonParentPath, false)) { + return new ValidationInfo(String.format("Base path doesn't contain all selected changes (use %s)", myCommonParentPath.getPath()), + myBasePathField); + } return null; }