AbstractPopup (@NotNull UsageViewImpl usageView, @NotNull ShowUsagesPopupData showUsagesPopupData, @NotNull Runnable itemChoseCallback, @NotNull Consumer<? super AbstractPopup> tableResizer) { ThreadingAssertions.assertEventDispatchThread(); @NotNull JTable table = showUsagesPopupData.table; @NotNull AtomicReference<AbstractPopup> popupRef = showUsagesPopupData.popupRef; @NotNull ShowUsagesActionHandler actionHandler = showUsagesPopupData.actionHandler; @NotNull ShowUsagesParameters parameters = showUsagesPopupData.parameters; @NotNull Project project = parameters.project; @NotNull DialogPanel headerPanel = showUsagesPopupData.header.panel; SpeedSearchAdvertiser advertiser = new SpeedSearchAdvertiser(); String hint = getSecondInvocationHint(actionHandler); JPanel advertiserComponent = null; boolean hintAdded = advertiser.addAdvertisement(hint); boolean speedSearchAdded = advertiser.addSpeedSearchAdvertisement() != null; if (hintAdded || speedSearchAdded) { advertiserComponent = advertiser.getComponent(); } PopupChooserBuilder<?> builder = JBPopupFactory.getInstance().createPopupChooserBuilder(table). setTitle(showUsagesPopupData.header.getTitle()). setAdvertiser(advertiserComponent). setMovable(true). setResizable(true). setCancelKeyEnabled(true). setDimensionServiceKey(DIMENSION_SERVICE_KEY); PropertiesComponent properties = PropertiesComponent.getInstance(project); boolean addCodePreview = properties.isValueSet(PREVIEW_PROPERTY_KEY); OnePixelSplitter contentSplitter = null; if (addCodePreview) { contentSplitter = new OnePixelSplitter(true, .6f); contentSplitter.setSplitterProportionKey(SPLITTER_SERVICE_KEY); contentSplitter.setDividerPositionStrategy(Splitter.DividerPositionStrategy.KEEP_SECOND_SIZE); contentSplitter.getDivider().setBackground(OnePixelDivider.BACKGROUND); builder.setContentSplitter(contentSplitter); } Disposable contentDisposable = Disposer.newDisposable(); KeyboardShortcut shortcut = UsageViewUtil.getShowUsagesWithSettingsShortcut(); if (shortcut != null) { new DumbAwareAction() { @Override public void actionPerformed(@NotNull AnActionEvent e) { cancel(popupRef.get()); showDialogAndRestart(parameters, actionHandler); } }.registerCustomShortcutSet(new CustomShortcutSet(shortcut.getFirstKeyStroke()), table); } shortcut = getShowUsagesShortcut(); if (shortcut != null) { new DumbAwareAction() { @Override public void actionPerformed(@NotNull AnActionEvent e) { cancel(popupRef.get(), actionHandler, CLOSE_REASON_CHANGE_SCOPE); showUsagesInMaximalScope(parameters, actionHandler); } }.registerCustomShortcutSet(new CustomShortcutSet(shortcut.getFirstKeyStroke()), table); } DefaultActionGroup filteringGroup = new DefaultActionGroup(); usageView.addFilteringActions(filteringGroup); filteringGroup.add(ActionManager.getInstance().getAction("UsageGrouping.FileStructure")); filteringGroup.add(new ToggleAction(UsageViewBundle.message("preview.usages.action.text"), null, AllIcons.Actions.PreviewDetailsVertically) { @Override public boolean isSelected(@NotNull AnActionEvent e) { return properties.isValueSet(PREVIEW_PROPERTY_KEY); } @Override public @NotNull ActionUpdateThread getActionUpdateThread() { return ActionUpdateThread.BGT; } @Override public void setSelected(@NotNull AnActionEvent e, boolean state) { if (e.getDataContext() != DataContext.EMPTY_CONTEXT) { // Avoid fake events properties.setValue(PREVIEW_PROPERTY_KEY, state); cancel(popupRef.get(), actionHandler, CLOSE_REASON_PREVIEW); WindowStateService.getInstance().putSize(DIMENSION_SERVICE_KEY, null); showElementUsages(parameters, actionHandler); } } }); JPanel northPanel = new JPanel(new GridBagLayout()); GridBag gc = new GridBag().nextLine(); ActionToolbar actionToolbar = createActionToolbar(table, filteringGroup); JComponent toolbarComponent = actionToolbar.getComponent(); toolbarComponent.setOpaque(false); northPanel.add(toolbarComponent, gc.next()); if (!(actionHandler.getMaximalScope() instanceof LocalSearchScope)) { DefaultActionGroup scopeChooserGroup = new DefaultActionGroup(createScopeChooser(project, contentDisposable, usageView, showUsagesPopupData)); ActionToolbar scopeChooserToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.SHOW_USAGES_POPUP_TOOLBAR, scopeChooserGroup, true); scopeChooserToolbar.setTargetComponent(table); scopeChooserToolbar.setLayoutPolicy(ActionToolbar.NOWRAP_LAYOUT_POLICY); ((ActionToolbarImpl) scopeChooserToolbar).setForceMinimumSize(true); JComponent component = scopeChooserToolbar.getComponent(); component.setBorder(JBUI.Borders.empty()); component.setOpaque(false); northPanel.add(component, gc.next()); } Dimension fillerSize = JBUI.size(8, 0); northPanel.add(new Box.Filler(fillerSize, fillerSize, fillerSize), gc.next().weightx(1.0)); DefaultActionGroup settingsGroup = new DefaultActionGroup( new SettingsAction(project, () -> cancel(popupRef.get()), showDialogAndRestartRunnable(parameters, actionHandler))); actionToolbar = createActionToolbar(table, settingsGroup); ((ActionToolbarImpl) actionToolbar).setForceMinimumSize(true); JComponent settingsToolbarComponent = actionToolbar.getComponent(); settingsToolbarComponent.setOpaque(false); if (Registry.is("ide.usages.popup.show.options.string")) { JLabel optionsLabel = new JLabel(actionHandler.getPresentation().getOptionsString()); if (ExperimentalUI.isNewUI()) { optionsLabel.setForeground(JBUI.CurrentTheme.ContextHelp.FOREGROUND); } northPanel.add(optionsLabel, gc.next()); } northPanel.add(settingsToolbarComponent, gc.next()); builder.setNorthComponent(northPanel); PopupUpdateProcessor processor = new PopupUpdateProcessor(usageView.getProject()) { @Override public void updatePopup(Object lookupItemObject) {/*not used*/} }; builder.addListener(processor); if (addCodePreview) { SimpleColoredComponent previewTitle = new SimpleColoredComponent(); PopupUtil.applyPreviewTitleInsets(previewTitle); UsagePreviewPanel usagePreviewPanel = new UsagePreviewPanel(project, usageView.getPresentation(), false) { @Override public Dimension getPreferredSize() { return new Dimension(table.getWidth(), Math.max(getHeight(), getLineHeight() * 5)); } @Override public Dimension getMinimumSize() { Dimension size = super.getMinimumSize(); size.height = getLineHeight() * 5; return size; } }; PropertyChangeListener lineHeightListener = e -> { if ((Integer)e.getNewValue() > 0) { tableResizer.accept(popupRef.get()); } }; usagePreviewPanel.addPropertyChangeListener(UsagePreviewPanel.LINE_HEIGHT_PROPERTY, lineHeightListener); Disposer.register(contentDisposable, () -> usagePreviewPanel.removePropertyChangeListener(lineHeightListener)); Disposer.register(contentDisposable, usagePreviewPanel); JPanel previewPanel = new JPanel(new BorderLayout()); previewPanel.add(previewTitle, BorderLayout.NORTH); previewPanel.add(usagePreviewPanel.createComponent(), BorderLayout.CENTER); contentSplitter.setSecondComponent(previewPanel); if (ExperimentalUI.isNewUI()) { previewPanel.setBackground(JBUI.CurrentTheme.Popup.BACKGROUND); previewTitle.setOpaque(false); } new DoubleClickListener() { @Override protected boolean onDoubleClick(@NotNull MouseEvent event) { if (event.getSource() != table) return false; itemChoseCallback.run(); return true; } }.installOn(table); builder.setAutoselectOnMouseMove(false).setCloseOnEnter(false). registerKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), __ -> itemChoseCallback.run()); Runnable updatePreviewRunnable = () -> { if (popupRef.get().isDisposed()) return; int[] selectedRows = table.getSelectedRows(); String file = null; List<UsageInfoAdapter> adapters = new ArrayList<>(); for (int row : selectedRows) { Object value = table.getModel().getValueAt(row, 0); if (value instanceof UsageNode) { Usage usage = ((UsageNode)value).getUsage(); if (usage instanceof UsageInfoAdapter adapter) { file = adapter.getPath(); adapters.add(adapter); } } } String selectedFile = file; UsageAdaptersKt.getUsageInfo(adapters, project).thenAccept(selectedUsages -> { ReadAction.nonBlocking(() -> UsagePreviewPanel.isOneAndOnlyOnePsiFileInUsages(selectedUsages)) .finishOnUiThread(ModalityState.nonModal(), isOneAndOnlyOnePsiFileInUsages -> { usagePreviewPanel.updateLayout(selectedUsages); previewTitle.clear(); if (isOneAndOnlyOnePsiFileInUsages && selectedFile != null) { previewTitle.append(PathUtil.getFileName(selectedFile), SimpleTextAttributes.REGULAR_ATTRIBUTES); } }) .expireWith(contentDisposable) .submit(AppExecutorUtil.getAppExecutorService()); }); }; Alarm previewUpdater = new Alarm(contentDisposable); table.getSelectionModel().addListSelectionListener(e -> { if (!e.getValueIsAdjusting() && !previewUpdater.isDisposed()) { previewUpdater.addRequest(updatePreviewRunnable, 50); } }); } else { builder.setAutoselectOnMouseMove(true).setItemChosenCallback(itemChoseCallback).setCloseOnEnter(true); } AbstractPopup popup = (AbstractPopup)builder.createPopup(); JComponent content = popup.getContent(); Disposer.register(popup, contentDisposable); // Replace compound header by ShowUsagesHeader. A little hack because there is no suitable popup API // CWM: new API method in popup API should be introduced for setting headerPanel CaptionPanel captionPanel = popup.getTitle(); Container parent = captionPanel.getParent(); if (parent != null) { parent.remove(captionPanel); parent.add(headerPanel); new WindowMoveListener(headerPanel).installTo(headerPanel); } if (ExperimentalUI.isNewUI()) { headerPanel.setBorder( JBUI.Borders.compound(JBUI.Borders.customLineBottom(JBUI.CurrentTheme.CustomFrameDecorations.separatorForeground()), PopupUtil.getComplexPopupHorizontalHeaderBorder())); headerPanel.setBackground(JBUI.CurrentTheme.ComplexPopup.HEADER_BACKGROUND); Color background = JBUI.CurrentTheme.Popup.BACKGROUND; northPanel.setBackground(background); table.setBackground(background); northPanel.setBorder(createComplexPopupToolbarBorder()); toolbarComponent.setBorder(JBUI.Borders.empty()); settingsToolbarComponent.setBorder(JBUI.Borders.emptyLeft(8)); if (contentSplitter != null) { contentSplitter.setBackground(background); contentSplitter.setOpaque(true); Insets textFieldBorderInsets = JBUI.CurrentTheme.ComplexPopup.textFieldBorderInsets(); //noinspection UseDPIAwareInsets contentSplitter.setBlindZone(() -> new Insets(0, textFieldBorderInsets.left, 0, textFieldBorderInsets.right)); } } else { headerPanel.setBorder(JBUI.Borders.empty(2, 15, 2, 2)); headerPanel.setBackground(JBUI.CurrentTheme.Popup.headerBackground(true)); } parameters.minWidth.set(-1); for (AnAction action : filteringGroup.getChildren(null)) { action.unregisterCustomShortcutSet(usageView.getComponent()); action.registerCustomShortcutSet(action.getShortcutSet(), content); } for (AnAction action : showUsagesPopupData.pinGroup.getChildren(null)) { action.unregisterCustomShortcutSet(usageView.getComponent()); action.registerCustomShortcutSet(action.getShortcutSet(), content); } /* save toolbar actions for using later, in automatic filter toggling in {@link #restartShowUsagesWithFiltersToggled(List} */ popup.setUserData(addCodePreview ? Arrays.asList(filteringGroup, contentSplitter) : Collections.singletonList(filteringGroup)); popup.setDataProvider(dataId -> { if (UsageView.USAGE_VIEW_SETTINGS_KEY.is(dataId)) { return usageView.getUsageViewSettings(); } else { return null; } }); popupRef.set(popup); return popup; }