void (final ChooseByNamePopupComponent.Callback callback, final ModalityState modalityState, final boolean allowMultipleSelection) { myPreviouslyFocusedComponent = WindowManagerEx.getInstanceEx().getFocusedComponent(myProject); myActionListener = callback; myTextFieldPanel.setLayout(new BoxLayout(myTextFieldPanel, BoxLayout.Y_AXIS)); final JPanel hBox = new JPanel(); hBox.setLayout(new BoxLayout(hBox, BoxLayout.X_AXIS)); JPanel caption2Tools = new JPanel(new BorderLayout()); String promptText = myModel.getPromptText(); if (promptText != null) { JLabel label = new JLabel(promptText); label.setFont(StartupUiUtil.getLabelFont().deriveFont(Font.BOLD)); caption2Tools.add(label, BorderLayout.WEST); } if (promptText != null || isCheckboxVisible()) { caption2Tools.add(hBox, BorderLayout.EAST); } String checkBoxName = myModel.getCheckBoxName(); Color fg = UIUtil.getLabelDisabledForeground(); Color color = StartupUiUtil.isUnderDarcula() ? ColorUtil.shift(fg, 1.2) : ColorUtil.shift(fg, 0.7); String text; if (checkBoxName == null) { text = ""; } else { HtmlBuilder builder = new HtmlBuilder().append(checkBoxName); if (myCheckBoxShortcut != null && myCheckBoxShortcut.getShortcuts().length > 0) { builder.append(" ") .append(HtmlChunk.tag("b") .attr("color", ColorUtil.toHex(color)).addText(KeymapUtil.getShortcutsText(myCheckBoxShortcut.getShortcuts()))); } text = builder.wrapWith("html").toString(); } myCheckBox.setText(text); myCheckBox.setAlignmentX(SwingConstants.RIGHT); myCheckBox.setBorder(null); myCheckBox.setSelected(myModel.loadInitialCheckBoxState()); if (checkBoxName == null) { myCheckBox.setVisible(false); } addCard(myCheckBox, CHECK_BOX_CARD); addCard(new HintLabel(myModel.getNotInMessage()), NOT_FOUND_IN_PROJECT_CARD); addCard(new HintLabel(IdeBundle.message("label.choosebyname.no.matches.found")), NOT_FOUND_CARD); JPanel searching = new JPanel(new BorderLayout(5, 0)); searching.add(new AsyncProcessIcon("searching"), BorderLayout.WEST); searching.add(new HintLabel(IdeBundle.message("label.choosebyname.searching")), BorderLayout.CENTER); addCard(searching, SEARCHING_CARD); myCard.show(myCardContainer, CHECK_BOX_CARD); if (isCheckboxVisible()) { hBox.add(myCardContainer); } final DefaultActionGroup group = new DefaultActionGroup(); group.add(new ShowFindUsagesAction() { @Override public PsiElement @NotNull [] getElements() { List<Object> objects = myListModel.getItems(); List<PsiElement> elements = new ArrayList<>(objects.size()); for (Object object : objects) { if (object instanceof PsiElement) { elements.add((PsiElement)object); } else if (object instanceof DataProvider) { ContainerUtil.addIfNotNull(elements, CommonDataKeys.PSI_ELEMENT.getData((DataProvider)object)); } } return PsiUtilCore.toPsiElementArray(elements); } }); final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar("ChooseByNameBase", group, true); actionToolbar.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY); final JComponent toolbarComponent = actionToolbar.getComponent(); actionToolbar.setTargetComponent(toolbarComponent); toolbarComponent.setBorder(null); if (myToolArea == null) { myToolArea = new JLabel(JBUIScale.scaleIcon(EmptyIcon.create(1, 24))); } else { myToolArea.setBorder(JBUI.Borders.emptyLeft(6)); // space between checkbox and filter/show all in view buttons } hBox.add(myToolArea); hBox.add(toolbarComponent); myTextFieldPanel.add(caption2Tools); new MyCopyReferenceAction() .registerCustomShortcutSet(ActionManager.getInstance().getAction(IdeActions.ACTION_COPY).getShortcutSet(), myTextField); myTextFieldPanel.add(myTextField); Font editorFont = EditorUtil.getEditorFont(); myTextField.setFont(editorFont); myTextField.putClientProperty("caretWidth", JBUIScale.scale(EditorUtil.getDefaultCaretWidth())); if (checkBoxName != null) { if (myCheckBoxShortcut != null) { new DumbAwareAction(IdeBundle.messagePointer("action.AnActionButton.text.change.goto.check.box")) { @Override public void actionPerformed(@NotNull AnActionEvent e) { myCheckBox.setSelected(!myCheckBox.isSelected()); } }.registerCustomShortcutSet(myCheckBoxShortcut, myTextField); } } if (isCloseByFocusLost()) { myTextField.addFocusListener(new FocusAdapter() { @Override public void focusLost(@NotNull final FocusEvent e) { if (Registry.is("focus.follows.mouse.workarounds")) { if (myFocusPoint != null) { PointerInfo pointerInfo = MouseInfo.getPointerInfo(); if (pointerInfo != null && myFocusPoint.equals(pointerInfo.getLocation())) { // Ignore the loss of focus if the mouse hasn't moved between the last dropdown resize // and the loss of focus event. This happens in focus follows mouse mode if the mouse is // over the dropdown and it resizes to leave the mouse outside the dropdown. IdeFocusManager.getInstance(myProject).requestFocus(myTextField, true); myFocusPoint = null; return; } } myFocusPoint = null; } cancelListUpdater(); // cancel thread as early as possible myHideAlarm.addRequest(() -> { JBPopup popup = JBPopupFactory.getInstance().getChildFocusedPopup(e.getComponent()); if (popup != null) { popup.addListener(new JBPopupListener() { @Override public void onClosed(@NotNull LightweightWindowEvent event) { if (event.isOk()) { hideHint(); } } }); } else { Component oppositeComponent = e.getOppositeComponent(); if (oppositeComponent == myCheckBox) { IdeFocusManager.getInstance(myProject).requestFocus(myTextField, true); return; } if (oppositeComponent != null && !(oppositeComponent instanceof JFrame) && myList.isShowing() && (oppositeComponent == myList || SwingUtilities.isDescendingFrom(myList, oppositeComponent))) { IdeFocusManager.getInstance(myProject).requestFocus(myTextField, true);// Otherwise me may skip some KeyEvents return; } if (isDescendingFromTemporarilyFocusableToolWindow(oppositeComponent)) { return; // Allow toolwindows to gain focus (used by QuickDoc shown in a toolwindow) } if (UIUtil.haveCommonOwner(oppositeComponent, e.getComponent())) { return; } hideHint(); } }, 5); } }); } myCheckBox.addItemListener(__ -> rebuildList(false)); myCheckBox.setFocusable(false); myTextField.getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(@NotNull DocumentEvent e) { SelectionPolicy toSelect = currentChosenInfo != null && currentChosenInfo.hasSamePattern(ChooseByNameBase.this) ? PreserveSelection.INSTANCE : SelectMostRelevant.INSTANCE; rebuildList(toSelect, myRebuildDelay, ModalityState.current(), null); } }); final Set<KeyStroke> upShortcuts = getShortcuts(IdeActions.ACTION_EDITOR_MOVE_CARET_UP); final Set<KeyStroke> downShortcuts = getShortcuts(IdeActions.ACTION_EDITOR_MOVE_CARET_DOWN); myTextField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(@NotNull KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER && (e.getModifiers() & InputEvent.SHIFT_MASK) != 0) { myClosedByShiftEnter = true; close(true); } if (!myListScrollPane.isVisible()) { return; } final int keyCode; // Add support for user-defined 'caret up/down' shortcuts. KeyStroke stroke = KeyStroke.getKeyStrokeForEvent(e); if (upShortcuts.contains(stroke)) { keyCode = KeyEvent.VK_UP; } else if (downShortcuts.contains(stroke)) { keyCode = KeyEvent.VK_DOWN; } else { keyCode = e.getKeyCode(); } switch (keyCode) { case KeyEvent.VK_DOWN -> ScrollingUtil.moveDown(myList, e.getModifiersEx()); case KeyEvent.VK_UP -> ScrollingUtil.moveUp(myList, e.getModifiersEx()); case KeyEvent.VK_PAGE_UP -> ScrollingUtil.movePageUp(myList); case KeyEvent.VK_PAGE_DOWN -> ScrollingUtil.movePageDown(myList); case KeyEvent.VK_TAB -> close(true); case KeyEvent.VK_ENTER -> { if (myList.getSelectedValue() == EXTRA_ELEM) { myMaximumListSizeLimit += myListSizeIncreasing; rebuildList(new SelectIndex(myList.getSelectedIndex()), myRebuildDelay, ModalityState.current(), null); e.consume(); } } } } }); myTextField.addActionListener(__ -> { if (!getChosenElements().isEmpty()) { doClose(true); } }); myList.setFocusable(false); myList.setSelectionMode(allowMultipleSelection ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION : ListSelectionModel.SINGLE_SELECTION); new ClickListener() { @Override public boolean onClick(@NotNull MouseEvent e, int clickCount) { if (!myTextField.hasFocus()) { IdeFocusManager.getInstance(myProject).requestFocus(myTextField, true); } if (clickCount == 2) { int selectedIndex = myList.getSelectedIndex(); Rectangle selectedCellBounds = myList.getCellBounds(selectedIndex, selectedIndex); if (selectedCellBounds != null && selectedCellBounds.contains(e.getPoint())) { // Otherwise it was reselected in the selection listener if (myList.getSelectedValue() == EXTRA_ELEM) { myMaximumListSizeLimit += myListSizeIncreasing; rebuildList(new SelectIndex(selectedIndex), myRebuildDelay, ModalityState.current(), null); } else { doClose(true); } } return true; } return false; } }.installOn(myList); ListCellRenderer modelRenderer = myModel.getListCellRenderer(); //noinspection unchecked myList.setCellRenderer((list, value, index, isSelected, cellHasFocus) -> AstLoadingFilter.disallowTreeLoading( () -> modelRenderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus) )); myList.setVisibleRowCount(16); myList.setFont(editorFont); myList.addListSelectionListener(__ -> { if (checkDisposed()) { return; } chosenElementMightChange(); updateDocumentation(); List<Object> chosenElements = getChosenElements(); if (!chosenElements.isEmpty()) { currentChosenInfo = new SelectionSnapshot(getTrimmedText(), new HashSet<>(chosenElements)); } }); myListScrollPane = ScrollPaneFactory.createScrollPane(myList, true); myTextFieldPanel.setBorder(JBUI.Borders.empty(5)); showTextFieldPanel(); myInitialized = true; if (modalityState != null) { rebuildList(SelectionPolicyKt.fromIndex(myInitialIndex), 0, modalityState, null); } }