diff --git a/platform/platform-api/src/com/intellij/ui/SearchTextField.java b/platform/platform-api/src/com/intellij/ui/SearchTextField.java index 343bbf187a5d..f1a0ed6f6263 100644 --- a/platform/platform-api/src/com/intellij/ui/SearchTextField.java +++ b/platform/platform-api/src/com/intellij/ui/SearchTextField.java @@ -1,7 +1,6 @@ // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ui; -import com.intellij.ide.IdeBundle; import com.intellij.ide.util.PropertiesComponent; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; @@ -9,8 +8,9 @@ import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; +import com.intellij.openapi.ui.popup.JBPopupListener; +import com.intellij.openapi.ui.popup.LightweightWindowEvent; import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.NlsSafe; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.components.JBList; @@ -29,31 +29,6 @@ import java.util.ArrayList; import java.util.List; public class SearchTextField extends JPanel { - private class SearchHistoryAction extends AnAction{ - private final @NlsSafe String name; - private final boolean enabled; - - SearchHistoryAction(@NlsSafe String name, boolean enabled){ - this.name = name; - this.enabled = enabled; - getTemplatePresentation().setText(name); - getTemplatePresentation().setEnabled(enabled); - setEnabled(enabled); - } - - @Override - public void update(@NotNull AnActionEvent e) { - e.getPresentation().setText(name); - e.getPresentation().setEnabled(enabled); - } - - @Override - public void actionPerformed(@NotNull AnActionEvent e) { - myTextField.setText(getTemplatePresentation().getText()); - addCurrentTextToHistory(); - historyItemChosen(getTemplatePresentation().getText()); - } - } public static final DataKey KEY = DataKey.create("search.text.field"); public static final KeyStroke SHOW_HISTORY_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.ALT_DOWN_MASK); @@ -66,11 +41,10 @@ public class SearchTextField extends JPanel { private final MyModel myModel; private final TextFieldWithProcessing myTextField; + @Nullable private JBPopup myPopup; - private ActionPopupMenu myNativeSearchPopup; - private DefaultActionGroup myHistoryPopupActionGroup = new DefaultActionGroup(); - private final SearchHistoryAction noItemsSearchHistoryAction = new SearchHistoryAction(IdeBundle.message("no.recent.searches"), false); private String myHistoryPropertyName; + private final boolean historyPopupEnabled; public SearchTextField() { this(true); @@ -86,9 +60,9 @@ public class SearchTextField extends JPanel { public SearchTextField(boolean historyPopupEnabled, @Nullable String historyPropertyName) { super(new BorderLayout()); + this.historyPopupEnabled = historyPopupEnabled; myModel = new MyModel(); - myTextField = new TextFieldWithProcessing() { @Override public void processKeyEvent(final KeyEvent e) { @@ -133,15 +107,7 @@ public class SearchTextField extends JPanel { setHistoryPropertyName(historyPropertyName); - if (historyPopupEnabled) { - DumbAwareAction.create(event -> { - if (myNativeSearchPopup != null) { - myNativeSearchPopup.getComponent().show(myTextField, 5, myTextField.getHeight()); - } else if (myPopup == null || !myPopup.isVisible()) { - showPopup(); - } - }).registerCustomShortcutSet(KeymapUtil.getActiveKeymapShortcuts("ShowSearchHistory"), myTextField); - } else if (historyPropertyName != null) { + if (historyPropertyName != null) { myTextField.getActionMap().put("showPrevHistoryItem", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { @@ -166,20 +132,15 @@ public class SearchTextField extends JPanel { myTextField.getInputMap().put(SHOW_HISTORY_KEYSTROKE, "showNextHistoryItem"); } - myTextField.putClientProperty("JTextField.variant", "search"); + myTextField.putClientProperty("JTextField.variant", "searchWithJbPopup"); myTextField.putClientProperty("JTextField.Search.Gap", JBUIScale.scale(6)); myTextField.putClientProperty("JTextField.Search.CancelAction", (ActionListener)e -> { myTextField.setText(""); onFieldCleared(); }); - - if (historyPopupEnabled) { - myHistoryPopupActionGroup = new DefaultActionGroup(); - myNativeSearchPopup = ActionManager.getInstance() - .createActionPopupMenu(ActionPlaces.UNKNOWN, myHistoryPopupActionGroup); - updateMenu(); - myTextField.putClientProperty("JTextField.Search.FindPopup", myNativeSearchPopup.getComponent()); - } + DumbAwareAction.create(event -> { + showPopup(); + }).registerCustomShortcutSet(KeymapUtil.getActiveKeymapShortcuts("ShowSearchHistory"), myTextField); } @Override @@ -208,22 +169,6 @@ public class SearchTextField extends JPanel { protected void onFocusGained() { } - private void updateMenu() { - if (myNativeSearchPopup != null) { - myHistoryPopupActionGroup.removeAll(); - final int itemsCount = myModel.getSize(); - if (itemsCount == 0) { - myHistoryPopupActionGroup.add(noItemsSearchHistoryAction); - } - else { - for (int i = 0; i < itemsCount; i++) { - final String item = myModel.getElementAt(i); - addMenuItem(item); - } - } - } - } - /** * @deprecated unused */ @@ -289,19 +234,13 @@ public class SearchTextField extends JPanel { public void addCurrentTextToHistory() { if (myModel.addElement(getText()) && myHistoryPropertyName != null) { PropertiesComponent.getInstance().setValue(myHistoryPropertyName, StringUtil.join(getHistory(), "\n")); + reInitPopup(); } } protected void historyItemChosen(String item) { } - private void addMenuItem(@NlsSafe String item) { - if (myNativeSearchPopup != null) { - myHistoryPopupActionGroup.remove(noItemsSearchHistoryAction); - myHistoryPopupActionGroup.add(new SearchHistoryAction(item, true)); - } - } - public void selectText() { getTextEditor().selectAll(); } @@ -318,7 +257,7 @@ public class SearchTextField extends JPanel { @Override public void requestFocus() { IdeFocusManager.getGlobalInstance() - .doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(getTextEditor(), true)); + .doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(getTextEditor(), true)); } protected void setHistoryPropertyName(String historyPropertyName) { @@ -410,7 +349,7 @@ public class SearchTextField extends JPanel { public void fireContentsChanged() { fireContentsChanged(this, -1, -1); - updateMenu(); + reInitPopup(); } public void setItems(List aList) { @@ -440,19 +379,32 @@ public class SearchTextField extends JPanel { protected void showPopup() { addCurrentTextToHistory(); - if (myPopup == null || !myPopup.isVisible()) { - final JList list = new JBList<>(myModel); - final Runnable chooseRunnable = createItemChosenCallback(list); - myPopup = JBPopupFactory.getInstance().createListPopupBuilder(list) - .setMovable(false) - .setRequestFocus(true) - .setItemChoosenCallback(chooseRunnable).createPopup(); + if ((myPopup == null || !myPopup.isVisible()) && historyPopupEnabled) { + reInitPopup(); if (isShowing()) { myPopup.showUnderneathOf(getPopupLocationComponent()); } } } + private void reInitPopup() { + final JList list = new JBList<>(myModel); + final Runnable chooseRunnable = createItemChosenCallback(list); + myPopup = JBPopupFactory.getInstance().createListPopupBuilder(list) + .setMovable(false) + .setRequestFocus(true) + .addListener(new JBPopupListener() { + @Override + public void onClosed(@NotNull LightweightWindowEvent event) { + //because jbpopup can be shown only once + reInitPopup(); + } + }) + .setItemChoosenCallback(chooseRunnable).createPopup(); + myTextField.putClientProperty("JTextField.Search.FindPopup", myPopup); + myTextField.putClientProperty("JTextField.variant", "searchWithJbPopup"); + } + protected Component getPopupLocationComponent() { return this; } @@ -477,7 +429,7 @@ public class SearchTextField extends JPanel { } protected boolean preprocessEventForTextField(KeyEvent e) { - if (SHOW_HISTORY_KEYSTROKE.equals(KeyStroke.getKeyStrokeForEvent(e)) && getClientProperty("JTextField.Search.FindPopup") instanceof JPopupMenu) { + if (SHOW_HISTORY_KEYSTROKE.equals(KeyStroke.getKeyStrokeForEvent(e)) && getClientProperty("JTextField.Search.FindPopup") instanceof JBPopup) { showPopup(); return true; } diff --git a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/TextFieldWithPopupHandlerUI.java b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/TextFieldWithPopupHandlerUI.java index 5990b9e99266..bcd96d09d96c 100644 --- a/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/TextFieldWithPopupHandlerUI.java +++ b/platform/platform-impl/src/com/intellij/ide/ui/laf/darcula/ui/TextFieldWithPopupHandlerUI.java @@ -5,6 +5,7 @@ import com.intellij.icons.AllIcons; import com.intellij.ide.IdeBundle; import com.intellij.ide.ui.laf.darcula.DarculaUIUtil; import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.SystemInfo; import com.intellij.ui.ComponentUtil; @@ -221,7 +222,11 @@ public abstract class TextFieldWithPopupHandlerUI extends BasicTextFieldUI imple } public static boolean isSearchField(Component c) { - return c instanceof JTextField && "search".equals(((JTextField)c).getClientProperty(VARIANT)); + if(!(c instanceof JTextField)){ + return false; + } + var variant = ((JTextField)c).getClientProperty(VARIANT); + return "search".equals(variant) || "searchWithJbPopup".equals(variant); } public static boolean isSearchFieldWithHistoryPopup(Component c) { @@ -557,7 +562,15 @@ public abstract class TextFieldWithPopupHandlerUI extends BasicTextFieldUI imple if (extension instanceof Extension) { addExtension((Extension)extension); } - addExtension(new SearchExtension()); + addExtension(new SearchExtension(PopupState.forPopupMenu())); + addExtension(new ClearExtension()); + } + else if ("searchWithJbPopup".equals(variant)) { + Object extension = getComponent().getClientProperty("search.extension"); + if (extension instanceof Extension) { + addExtension((Extension)extension); + } + addExtension(new SearchExtension(PopupState.forPopup())); addExtension(new ClearExtension()); } } @@ -618,9 +631,13 @@ public abstract class TextFieldWithPopupHandlerUI extends BasicTextFieldUI imple private final class SearchExtension implements Extension { - private final PopupState myPopupState = PopupState.forPopupMenu(); + private final PopupState myPopupState; private Rectangle bounds; // should be bound to IconHandler#bounds + public SearchExtension(PopupState popupState){ + this.myPopupState = popupState; + } + @Override public Icon getIcon(boolean hovered) { return getSearchIcon(hovered, null != getActionOnClick()); @@ -645,16 +662,33 @@ public abstract class TextFieldWithPopupHandlerUI extends BasicTextFieldUI imple @Override public Runnable getActionOnClick() { JTextComponent component = getComponent(); - Object property = component == null ? null : component.getClientProperty(POPUP); - JPopupMenu popup = property instanceof JPopupMenu ? (JPopupMenu)property : null; - return popup == null ? null : () -> { - if (myPopupState.isRecentlyHidden()) return; // do not show new popup - Rectangle editor = getVisibleEditorRect(); - if (editor != null) { - myPopupState.prepareToShow(popup); - popup.show(component, bounds.x, editor.y + editor.height); - } - }; + if(component == null){ + return null; + } + Object property = component.getClientProperty(POPUP); + if(property instanceof JPopupMenu){ + JPopupMenu popup = (JPopupMenu) property; + return () -> { + if (myPopupState.isRecentlyHidden()) return; // do not show new popup + Rectangle editor = getVisibleEditorRect(); + if (editor != null) { + myPopupState.prepareToShow(popup); + popup.show(component, bounds.x, editor.y + editor.height); + } + }; + } + if(property instanceof JBPopup){ + JBPopup popup = (JBPopup) property; + return () -> { + if (myPopupState.isRecentlyHidden()) return; // do not show new popup + Rectangle editor = getVisibleEditorRect(); + if (editor != null) { + myPopupState.prepareToShow(popup); + popup.showUnderneathOf(component); + } + }; + } + return null; } @Override