void () { AnAction myShowFilterPopupAction = new MyShowFilterPopupAction(); myFilterContextButton = new ActionButton(myShowFilterPopupAction, null, ActionPlaces.UNKNOWN, ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE) { @Override public Icon getIcon() { return filterIcon.getLiveIndicatorIcon(!mySelectedContextName.equals(FindInProjectUtil.getPresentableName(FindModel.SearchContext.ANY))); } }; myShowFilterPopupAction.registerCustomShortcutSet(myShowFilterPopupAction.getShortcutSet(), this); header = new FindPopupHeader(myProject, myFilterContextButton, new MyPinAction()); ItemListener liveResultsPreviewUpdateListener = __ -> scheduleResultsUpdate(); header.cbFileFilter.addItemListener(__ -> { if (header.cbFileFilter.isSelected()) { header.fileMaskField.setEnabled(true); if (header.cbFileFilter.getClientProperty("dontRequestFocus") == null) { IdeFocusManager.getInstance(myProject).requestFocus(header.fileMaskField, true); header.fileMaskField.getEditor().selectAll(); } } else { header.fileMaskField.setEnabled(false); if (header.cbFileFilter.getClientProperty("dontRequestFocus") == null) { IdeFocusManager.getInstance(myProject).requestFocus(mySearchComponent, true); } } }); header.cbFileFilter.addItemListener(liveResultsPreviewUpdateListener); header.fileMaskField.addActionListener(__ -> scheduleResultsUpdate()); Component editorComponent = header.fileMaskField.getEditor().getEditorComponent(); if (editorComponent instanceof EditorTextField etf) { etf.addDocumentListener(new DocumentListener() { @Override public void documentChanged(@NotNull com.intellij.openapi.editor.event.DocumentEvent event) { onFileMaskChanged(); } }); } else { if (editorComponent instanceof JTextComponent) { ((JTextComponent)editorComponent).getDocument().addDocumentListener(new DocumentAdapter() { @Override protected void textChanged(@NotNull DocumentEvent e) { onFileMaskChanged(); } }); } else { assert false; } } myResetFiltersAction = DumbAwareAction.create(event -> resetAllFilters()); myResetFiltersAction.registerCustomShortcutSet(new CustomShortcutSet(RESET_FILTERS), this); myOKButton = new JButton(FindBundle.message("find.popup.find.button")); myReplaceAllButton = new JButton(FindBundle.message("find.popup.replace.all.button")); myReplaceSelectedButton = new JButton(FindBundle.message("find.popup.replace.selected.button", 0)); myOkActionListener = __ -> doOK(true); myReplaceAllButton.setOpaque(false); myReplaceAllButton.addActionListener(__ -> doOK(false)); myReplaceSelectedButton.setOpaque(false); myReplaceSelectedButton.addActionListener(e -> { int rowToSelect = myResultsPreviewTable.getSelectionModel().getMinSelectionIndex(); Map<Integer, Usage> usages = getSelectedUsages(); if (usages == null) { return; } myHelper.updateFindSettings(); CommandProcessor.getInstance().executeCommand(myProject, () -> { for (Map.Entry<Integer, Usage> entry : usages.entrySet()) { try { boolean success = ReplaceInProjectManager.getInstance(myProject) .replaceSingleUsage(entry.getValue(), myHelper.getModel(), Collections.emptySet()); if (!success) return; ((DefaultTableModel)myResultsPreviewTable.getModel()).removeRow(entry.getKey()); } catch (FindManager.MalformedReplacementStringException ex) { if (!ApplicationManager.getApplication().isUnitTestMode()) { Messages.showErrorDialog(this, ex.getMessage(), FindBundle.message("find.replace.invalid.replacement.string.title")); } break; } } ApplicationManager.getApplication().invokeLater(() -> { if (myResultsPreviewTable.getRowCount() > rowToSelect) { myResultsPreviewTable.getSelectionModel().setSelectionInterval(rowToSelect, rowToSelect); } ScrollingUtil.ensureSelectionExists(myResultsPreviewTable); }); }, FindBundle.message("find.replace.command"), null); }); myOKButton.setOpaque(false); myOKButton.addActionListener(myOkActionListener); boolean enterAsOK = false; AnAction openInRightSplit = ActionManager.getInstance().getAction(ACTION_OPEN_IN_RIGHT_SPLIT); if (openInRightSplit != null) { ShortcutSet set = openInRightSplit.getShortcutSet(); new MyEnterAction(false).registerCustomShortcutSet(set, this); } new MyEnterAction(enterAsOK).registerCustomShortcutSet(new CustomShortcutSet(ENTER), this); DumbAwareAction.create( __ -> myOkActionListener.actionPerformed(null)).registerCustomShortcutSet(new CustomShortcutSet(ENTER_WITH_MODIFIERS), this); DumbAwareAction.create(__ -> myReplaceAllButton.doClick()).registerCustomShortcutSet(new CustomShortcutSet(REPLACE_ALL), this); myReplaceAllButton.setToolTipText(KeymapUtil.getKeystrokeText(REPLACE_ALL)); List<Shortcut> navigationKeyStrokes = new ArrayList<>(); KeyStroke viewSourceKeyStroke = KeymapUtil.getKeyStroke(CommonShortcuts.getViewSource()); if (viewSourceKeyStroke != null && !Comparing.equal(viewSourceKeyStroke, ENTER_WITH_MODIFIERS) && !Comparing.equal(viewSourceKeyStroke, ENTER)) { navigationKeyStrokes.add(new KeyboardShortcut(viewSourceKeyStroke, null)); } KeyStroke editSourceKeyStroke = KeymapUtil.getKeyStroke(CommonShortcuts.getEditSource()); if (editSourceKeyStroke != null && !Comparing.equal(editSourceKeyStroke, ENTER_WITH_MODIFIERS) && !Comparing.equal(editSourceKeyStroke, ENTER)) { navigationKeyStrokes.add(new KeyboardShortcut(editSourceKeyStroke, null)); } if (!navigationKeyStrokes.isEmpty()) { DumbAwareAction.create(e -> navigateToSelectedUsage(e)) .registerCustomShortcutSet(new CustomShortcutSet(navigationKeyStrokes.toArray(Shortcut.EMPTY_ARRAY)), this); } myResultsPreviewTableModel = createTableModel(); myResultsPreviewTable = new JBTable(myResultsPreviewTableModel) { @Override public Dimension getPreferredScrollableViewportSize() { return new Dimension(getWidth(), 1 + getRowHeight() * 4); } }; myResultsPreviewTable.setFocusable(false); myResultsPreviewTable.putClientProperty(RenderingUtil.ALWAYS_PAINT_SELECTION_AS_FOCUSED, true); myResultsPreviewTable.getEmptyText().setShowAboveCenter(false); myResultsPreviewTable.setShowColumns(false); myResultsPreviewTable.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); myResultsPreviewTable.setShowGrid(false); myResultsPreviewTable.setIntercellSpacing(JBUI.emptySize()); mySearchComponent = new JBTextAreaWithMixedAccessibleContext(myResultsPreviewTable.getAccessibleContext(), FindBundle.message("find.popup.search.empty.text")); mySearchComponent.setColumns(25); mySearchComponent.setRows(1); mySearchComponent.getAccessibleContext().setAccessibleName(FindBundle.message("find.search.accessible.name")); myReplaceComponent = new JBTextAreaWithMixedAccessibleContext(myResultsPreviewTable.getAccessibleContext(), FindBundle.message("find.popup.replace.empty.text")); myReplaceComponent.setColumns(25); myReplaceComponent.setRows(1); myReplaceComponent.getAccessibleContext().setAccessibleName(FindBundle.message("find.replace.accessible.name")); mySearchTextArea = new SearchTextArea(mySearchComponent, true); myReplaceTextArea = new SearchTextArea(myReplaceComponent, false); myCaseSensitiveAction = new MySwitchStateToggleAction("find.popup.case.sensitive", ToggleOptionName.CaseSensitive, AllIcons.Actions.MatchCase, AllIcons.Actions.MatchCaseHovered, AllIcons.Actions.MatchCaseSelected, myCaseSensitiveState); myWholeWordsAction = new MySwitchStateToggleAction("find.whole.words", ToggleOptionName.WholeWords, AllIcons.Actions.Words, AllIcons.Actions.WordsHovered, AllIcons.Actions.WordsSelected, myWholeWordsState); myRegexAction = new MySwitchStateToggleAction("find.regex", ToggleOptionName.Regex, AllIcons.Actions.Regex, AllIcons.Actions.RegexHovered, AllIcons.Actions.RegexSelected, myRegexState, new TooltipLinkProvider.TooltipLink(FindBundle.message("find.regex.help.link"), RegExHelpPopup.createRegExLinkRunnable(mySearchTextArea))); List<Component> searchExtraButtons = mySearchTextArea.setExtraActions(myCaseSensitiveAction, myWholeWordsAction, myRegexAction); AnAction preserveCaseAction = new MySwitchStateToggleAction("find.options.replace.preserve.case", ToggleOptionName.PreserveCase, AllIcons.Actions.PreserveCase, AllIcons.Actions.PreserveCaseHover, AllIcons.Actions.PreserveCaseSelected, myPreserveCaseState); List<Component> replaceExtraButtons = myReplaceTextArea.setExtraActions(preserveCaseAction); Pair<FindPopupScopeUI.ScopeType, JComponent>[] scopeComponents = myScopeUI.getComponents(); myScopeDetailsPanel = new JPanel(new CardLayout()); List<AnAction> scopeActions = new ArrayList<>(scopeComponents.length); for (Pair<FindPopupScopeUI.ScopeType, JComponent> scopeComponent : scopeComponents) { FindPopupScopeUI.ScopeType scopeType = scopeComponent.first; scopeActions.add(new MySelectScopeToggleAction(scopeType)); myScopeDetailsPanel.add(scopeType.name, scopeComponent.second); } myScopeSelectionToolbar = createScopeToolbar(scopeActions.toArray(AnAction.EMPTY_ARRAY)); myScopeSelectionToolbar.setMinimumButtonSize(ActionToolbar.DEFAULT_MINIMUM_BUTTON_SIZE); mySelectedScope = scopeComponents[0].first; TableHoverListener.DEFAULT.removeFrom(myResultsPreviewTable); new DoubleClickListener() { @Override protected boolean onDoubleClick(@NotNull MouseEvent event) { if (event.getSource() != myResultsPreviewTable) return false; navigateToSelectedUsage(null); return true; } }.installOn(myResultsPreviewTable); ActionManager actionManager = ActionManager.getInstance(); ActionGroup copyGroup = (ActionGroup)actionManager.getAction("FindInFiles.Results.ContextMenu"); ActionPopupMenu popupMenu = actionManager.createActionPopupMenu(ActionPlaces.POPUP, copyGroup); myResultsPreviewTable.setComponentPopupMenu(popupMenu.getComponent()); myResultsPreviewTable.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { myResultsPreviewTable.transferFocus(); } }); applyFont(JBFont.label(), myResultsPreviewTable); JComponent[] tableAware = {mySearchComponent, myReplaceComponent, myReplaceSelectedButton}; for (JComponent component : tableAware) { ScrollingUtil.installActions(myResultsPreviewTable, false, component); } ActionListener helpAction = __ -> HelpManager.getInstance().invokeHelp("reference.dialogs.findinpath"); registerKeyboardAction(helpAction,KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0),JComponent.WHEN_IN_FOCUSED_WINDOW); registerKeyboardAction(helpAction,KeyStroke.getKeyStroke(KeyEvent.VK_HELP, 0),JComponent.WHEN_IN_FOCUSED_WINDOW); KeymapManager keymapManager = KeymapManager.getInstance(); Keymap activeKeymap = keymapManager != null ? keymapManager.getActiveKeymap() : null; if (activeKeymap != null) { ShortcutSet findNextShortcutSet = new CustomShortcutSet(activeKeymap.getShortcuts("FindNext")); ShortcutSet findPreviousShortcutSet = new CustomShortcutSet(activeKeymap.getShortcuts("FindPrevious")); DumbAwareAction findNextAction = DumbAwareAction.create(event -> { int selectedRow = myResultsPreviewTable.getSelectedRow(); if (selectedRow >= 0 && selectedRow < myResultsPreviewTable.getRowCount() - 1) { myResultsPreviewTable.setRowSelectionInterval(selectedRow + 1, selectedRow + 1); ScrollingUtil.ensureIndexIsVisible(myResultsPreviewTable, selectedRow + 1, 1); } }); DumbAwareAction findPreviousAction = DumbAwareAction.create(event -> { int selectedRow = myResultsPreviewTable.getSelectedRow(); if (selectedRow > 0 && selectedRow <= myResultsPreviewTable.getRowCount() - 1) { myResultsPreviewTable.setRowSelectionInterval(selectedRow - 1, selectedRow - 1); ScrollingUtil.ensureIndexIsVisible(myResultsPreviewTable, selectedRow - 1, 1); } }); for (JComponent component : tableAware) { findNextAction.registerCustomShortcutSet(findNextShortcutSet, component); findPreviousAction.registerCustomShortcutSet(findPreviousShortcutSet, component); } } myUsagePreviewTitle = new SimpleColoredComponent(); myUsageViewPresentation = new UsageViewPresentation(); myUsagePreviewPanel = new UsagePreviewPanel(myProject, myUsageViewPresentation, true) { @Override public Dimension getPreferredSize() { return new Dimension(myResultsPreviewTable.getWidth(), Math.max(getHeight(), getLineHeight() * 15)); } }; Disposer.register(myDisposable, myUsagePreviewPanel); Runnable updatePreviewRunnable = () -> { if (Disposer.isDisposed(myDisposable)) return; int[] selectedRows = myResultsPreviewTable.getSelectedRows(); if (selectedRows.length > 1 || selectedRows.length == 1 && selectedRows[0] != 0) { myHelper.updateFindSettings(); } myReplaceSelectedButton.setEnabled(selectedRows.length > 0); String file = null; List<UsageInfoAdapter> adapters = new ArrayList<>(); for (int row : selectedRows) { Object value = myResultsPreviewTable.getModel().getValueAt(row, 0); UsageInfoAdapter adapter = ((FindPopupItem)value).getUsage(); file = adapter.getPath(); adapters.add(adapter); } String selectedFile = file; UsageAdaptersKt.getUsageInfo(adapters, myProject).thenAccept(selectedUsages -> { ReadAction.nonBlocking(() -> UsagePreviewPanel.isOneAndOnlyOnePsiFileInUsages(selectedUsages)) .finishOnUiThread(ModalityState.nonModal(), isOneAndOnlyOnePsiFileInUsages -> { myReplaceSelectedButton.setText(FindBundle.message("find.popup.replace.selected.button", selectedUsages.size())); FindInProjectUtil.setupViewPresentation(myUsageViewPresentation, myHelper.getModel().clone()); myUsagePreviewPanel.updateLayout(selectedUsages); myUsagePreviewTitle.clear(); if (isOneAndOnlyOnePsiFileInUsages && selectedFile != null) { myUsagePreviewTitle.append(PathUtil.getFileName(selectedFile), SimpleTextAttributes.REGULAR_ATTRIBUTES); VirtualFile virtualFile = VfsUtil.findFileByIoFile(new File(selectedFile), true); String locationPath = virtualFile == null ? null : getPresentablePath(myProject, virtualFile.getParent(), 120); if (locationPath != null) { myUsagePreviewTitle.append(spaceAndThinSpace() + locationPath, new SimpleTextAttributes(STYLE_PLAIN, UIUtil.getContextHelpForeground())); } } }) .expireWith(myDisposable) .submit(AppExecutorUtil.getAppExecutorService()); }); }; myResultsPreviewTable.getSelectionModel().addListSelectionListener(e -> { if (e.getValueIsAdjusting() || Disposer.isDisposed(myPreviewUpdater)) return; myPreviewUpdater.addRequest(updatePreviewRunnable, 50); }); DocumentAdapter documentAdapter = new DocumentAdapter() { @Override protected void textChanged(@NotNull DocumentEvent e) { if (myDialog == null) return; if (e.getDocument() == mySearchComponent.getDocument()) { scheduleResultsUpdate(); } if (e.getDocument() == myReplaceComponent.getDocument()) { applyTo(myHelper.getModel()); if (myHelper.getModel().isRegularExpressions()) { myComponentValidator.updateInfo(getValidationInfo(myHelper.getModel())); } ApplicationManager.getApplication().invokeLater(updatePreviewRunnable); } } }; mySearchComponent.getDocument().addDocumentListener(documentAdapter); myReplaceComponent.getDocument().addDocumentListener(documentAdapter); mySearchRescheduleOnCancellationsAlarm = new Alarm(); myPreviewSplitter = new OnePixelSplitter(true, .33f); myPreviewSplitter.setSplitterProportionKey(SPLITTER_SERVICE_KEY); myPreviewSplitter.getDivider().setBackground(OnePixelDivider.BACKGROUND); JBScrollPane scrollPane = new JBScrollPane(myResultsPreviewTable) { @Override public Dimension getMinimumSize() { Dimension size = super.getMinimumSize(); size.height = myResultsPreviewTable.getPreferredScrollableViewportSize().height; return size; } }; myPreviewSplitter.setFirstComponent(scrollPane); JPanel bottomPanel = new JPanel(new MigLayout("flowx, ins 0 0 0 0, fillx, hidemode 3, gap 0")); myNewTabCheckbox = new JBCheckBox(FindBundle.message("find.open.in.new.tab.checkbox"), FindSettings.getInstance().isShowResultsInSeparateView()); myNewTabCheckbox.setOpaque(false); bottomPanel.add(myNewTabCheckbox); myNewTabCheckbox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { FindSettings.getInstance().setShowResultsInSeparateView(myNewTabCheckbox.isSelected()); } }); myOKHintLabel = new JBLabel(""); myOKHintLabel.setEnabled(false); myNavigationHintLabel = new JBLabel(""); myNavigationHintLabel.setEnabled(false); myNavigationHintLabel.setFont(JBUI.Fonts.smallFont()); Insets insets = myOKButton.getInsets(); String btnGapLeft = "gapleft " + Math.max(0, JBUIScale.scale(12) - insets.left - insets.right) + "px"; bottomPanel.add(myNavigationHintLabel, btnGapLeft); bottomPanel.add(Box.createHorizontalGlue(), "growx, pushx"); bottomPanel.add(myOKHintLabel); bottomPanel.add(myOKButton, btnGapLeft); bottomPanel.add(myReplaceAllButton, btnGapLeft); bottomPanel.add(myReplaceSelectedButton, btnGapLeft); myCodePreviewComponent = myUsagePreviewPanel.createComponent(); JPanel previewPanel = new JPanel(new BorderLayout()); previewPanel.add(myUsagePreviewTitle, BorderLayout.NORTH); previewPanel.add(myCodePreviewComponent, BorderLayout.CENTER); myPreviewSplitter.setSecondComponent(previewPanel); JPanel scopesPanel = new JPanel(); new RowBuilder(scopesPanel) .gap(26) .add(myScopeSelectionToolbar.getComponent()) .addResizable(myScopeDetailsPanel); setLayout(new MigLayout("flowx, ins 0, gap 0, fillx, hidemode 3")); myIsPinned.set(UISettings.getInstance().getPinFindInPath()); if (ExperimentalUI.isNewUI()) { Color background = JBUI.CurrentTheme.Popup.BACKGROUND; header.panel.setBorder(JBUI.Borders.compound(JBUI.Borders.customLineBottom(JBUI.CurrentTheme.CustomFrameDecorations.separatorForeground()), PopupUtil.getComplexPopupHorizontalHeaderBorder())); header.panel.setBackground(JBUI.CurrentTheme.ComplexPopup.HEADER_BACKGROUND); header.cbFileFilter.setOpaque(false); setBackground(background); mySearchTextArea.setOpaque(false); mySearchTextArea.setBorder(PopupUtil.createComplexPopupTextFieldBorder()); myReplaceTextArea.setOpaque(false); myReplaceTextArea.setBorder(PopupUtil.createComplexPopupTextFieldBorder()); scopesPanel.setOpaque(false); myScopeSelectionToolbar.getComponent().setOpaque(false); myScopeDetailsPanel.setOpaque(false); UIUtil.setOpaqueRecursively(myScopeDetailsPanel, false); myResultsPreviewTable.setBackground(background); previewPanel.setBackground(background); scopesPanel.setBorder(JBUI.Borders.empty(JBUI.CurrentTheme.FindPopup.scopesPanelInsets())); myScopeSelectionToolbar.setBorder(JBUI.Borders.empty()); Insets textFieldBorderInsets = JBUI.CurrentTheme.ComplexPopup.textFieldBorderInsets(); //noinspection UseDPIAwareInsets myPreviewSplitter.setBlindZone(() -> new Insets(0, textFieldBorderInsets.left, 0, textFieldBorderInsets.right)); bottomPanel.setBorder(JBUI.Borders.empty(JBUI.CurrentTheme.FindPopup.bottomPanelInsets())); bottomPanel.setBackground(JBUI.CurrentTheme.Advertiser.background()); scrollPane.setBorder(JBUI.Borders.emptyBottom(4)); } else { header.panel.setBorder(JBUI.Borders.empty(2, 5)); mySearchTextArea.setBorder(JBUI.Borders.compound( JBUI.Borders.customLine(JBUI.CurrentTheme.BigPopup.searchFieldBorderColor(), 1, 0, 1, 0), JBUI.Borders.empty(1, 0, 2, 0))); myReplaceTextArea.setBorder(JBUI.Borders.compound( JBUI.Borders.customLine(JBUI.CurrentTheme.BigPopup.searchFieldBorderColor(), 0, 0, 1, 0), JBUI.Borders.empty(1, 0, 2, 0))); scopesPanel.setBorder(JBUI.Borders.empty(3, 5)); bottomPanel.setBorder(JBUI.Borders.empty(5)); scrollPane.setBorder(JBUI.Borders.empty()); } PopupUtil.applyPreviewTitleInsets(myUsagePreviewTitle); add(header.panel, "growx, pushx, wrap"); add(mySearchTextArea, "pushx, growx, wrap"); add(myReplaceTextArea, "pushx, growx, wrap"); add(scopesPanel, "pushx, growx, ax left, wrap"); add(myPreviewSplitter, "pushx, growx, growy, pushy, wrap"); add(bottomPanel, "pushx, growx, dock south"); List<Component> focusOrder = new ArrayList<>(); focusOrder.add(mySearchComponent); focusOrder.add(myReplaceComponent); focusOrder.addAll(searchExtraButtons); focusOrder.addAll(replaceExtraButtons); focusOrder.add(header.cbFileFilter); ContainerUtil.addAll(focusOrder, focusableComponents(myScopeDetailsPanel)); focusOrder.add(editorComponent); ContainerUtil.addAll(focusOrder, focusableComponents(bottomPanel)); setFocusCycleRoot(true); setFocusTraversalPolicy(new ListFocusTraversalPolicy(focusOrder)); if (SystemInfo.isMac) { List<JButton> principalButtons = new ArrayList<>(); principalButtons.add(myOKButton); Touchbar.setButtonActions(bottomPanel, null, principalButtons, myOKButton, new DefaultActionGroup(myCaseSensitiveAction, myWholeWordsAction, myRegexAction)); } }