From c003da65dcc2d077fcb0d5f069d5fdd89ff527f6 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Sat, 24 Sep 2016 09:14:45 +0300 Subject: [PATCH] Support adding a new remote from push dialog even if there are remotes Display "Define remote" action in the remote choosing popup. Since this action shows a dialog, move all popup onChosen code to doFinalStep(), to avoid potential focus issues, as recommended in ListPopupImpl._handleSelect Relates to IDEA-87099 IDEA-76454 IDEA-60389 --- .../src/git4idea/push/GitPushTargetPanel.java | 93 +++++++++++++------ 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java index 54dc05eb6e6e..ebbad016d597 100644 --- a/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java +++ b/plugins/git4idea/src/git4idea/push/GitPushTargetPanel.java @@ -29,6 +29,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.ui.popup.ListPopup; +import com.intellij.openapi.ui.popup.ListSeparator; import com.intellij.openapi.ui.popup.PopupStep; import com.intellij.openapi.ui.popup.util.BaseListPopupStep; import com.intellij.openapi.wm.IdeFocusManager; @@ -54,9 +55,12 @@ import javax.swing.tree.DefaultMutableTreeNode; import java.awt.*; import java.awt.event.*; import java.text.ParseException; +import java.util.Collection; import java.util.Comparator; import java.util.List; +import static com.intellij.util.containers.ContainerUtil.newArrayList; + public class GitPushTargetPanel extends PushTargetPanel { private static final Logger LOG = Logger.getInstance(GitPushTargetPanel.class); @@ -194,19 +198,31 @@ public class GitPushTargetPanel extends PushTargetPanel { } private void showRemoteSelector(@NotNull Component component, @NotNull Point point) { - final List remotes = getRemotes(); + List remotes = getPopupItems(); if (remotes.size() <= 1) { return; } - ListPopup popup = new ListPopupImpl(new BaseListPopupStep(null, remotes) { + ListPopup popup = new ListPopupImpl(new BaseListPopupStep(null, remotes) { @Override - public PopupStep onChosen(String selectedValue, boolean finalChoice) { - myRemoteRenderer.updateLinkText(selectedValue); - if (myFireOnChangeAction != null && !myTargetEditor.isShowing()) { - //fireOnChange only when editing completed - myFireOnChangeAction.run(); - } - return super.onChosen(selectedValue, finalChoice); + public PopupStep onChosen(@NotNull PopupItem selectedValue, boolean finalChoice) { + return doFinalStep(() -> { + if (selectedValue.isDefineRemote()) { + showDefineRemoteDialog(); + } + else { + myRemoteRenderer.updateLinkText(selectedValue.getPresentable()); + if (myFireOnChangeAction != null && !myTargetEditor.isShowing()) { + //fireOnChange only when editing completed + myFireOnChangeAction.run(); + } + } + }); + } + + @Nullable + @Override + public ListSeparator getSeparatorAbove(PopupItem value) { + return value.isDefineRemote() ? new ListSeparator() : null; } }) { @Override @@ -223,13 +239,10 @@ public class GitPushTargetPanel extends PushTargetPanel { } @NotNull - private List getRemotes() { - return ContainerUtil.map(myRepository.getRemotes(), new Function() { - @Override - public String fun(GitRemote remote) { - return remote.getName(); - } - }); + private List getPopupItems() { + List items = newArrayList(ContainerUtil.map(myRepository.getRemotes(), PopupItem::forRemote)); + items.add(PopupItem.DEFINE_REMOTE); + return items; } @Override @@ -240,16 +253,11 @@ public class GitPushTargetPanel extends PushTargetPanel { renderer.append(myError, PushLogTreeUtil.addTransparencyIfNeeded(SimpleTextAttributes.ERROR_ATTRIBUTES, isActive)); } else { - String currentRemote = myRemoteRenderer.getText(); - List remotes = getRemotes(); - if (remotes.isEmpty() || remotes.size() > 1) { - myRemoteRenderer.setSelected(isSelected); - myRemoteRenderer.setTransparent(!remotes.isEmpty() && !isActive); - myRemoteRenderer.render(renderer); - } - else { - renderer.append(currentRemote, targetTextAttributes); - } + Collection remotes = myRepository.getRemotes(); + myRemoteRenderer.setSelected(isSelected); + myRemoteRenderer.setTransparent(!remotes.isEmpty() && !isActive); + myRemoteRenderer.render(renderer); + if (!remotes.isEmpty()) { renderer.append(SEPARATOR, targetTextAttributes); if (forceRenderedText != null) { @@ -389,6 +397,35 @@ public class GitPushTargetPanel extends PushTargetPanel { } } + private static class PopupItem { + static final PopupItem DEFINE_REMOTE = new PopupItem(null); + + @Nullable GitRemote remote; + + @NotNull + static PopupItem forRemote(@NotNull GitRemote remote) { + return new PopupItem(remote); + } + + private PopupItem(@Nullable GitRemote remote) { + this.remote = remote; + } + + @NotNull + String getPresentable() { + return remote == null ? "Define Remote" : remote.getName(); + } + + boolean isDefineRemote() { + return remote == null; + } + + @Override + public String toString() { + return getPresentable(); + } + } + private class MyGitTargetFocusTraversalPolicy extends ComponentsListFocusTraversalPolicy { @NotNull @Override @@ -398,7 +435,7 @@ public class GitPushTargetPanel extends PushTargetPanel { @Override public Component getComponentAfter(Container aContainer, Component aComponent) { - if (getRemotes().size() > 1) { + if (getPopupItems().size() > 1) { return super.getComponentAfter(aContainer, aComponent); } return aComponent; @@ -406,7 +443,7 @@ public class GitPushTargetPanel extends PushTargetPanel { @Override public Component getComponentBefore(Container aContainer, Component aComponent) { - if (getRemotes().size() > 1) { + if (getPopupItems().size() > 1) { return super.getComponentBefore(aContainer, aComponent); } return aComponent;