void (@NotNull final MavenProjectsManager projectsManager, @NotNull final JButton button, @NotNull final Consumer<? super MavenProject> callback) { button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { List<MavenProject> projectList = projectsManager.getProjects(); if (projectList.isEmpty()) { JBPopupFactory.getInstance().createMessage( MavenProjectBundle.message("popup.content.maven.projects.not.found")).showUnderneathOf(button); return; } DefaultMutableTreeNode root = buildTree(projectList); final Map<MavenProject, String> projectsNameMap = MavenProjectNamer.generateNameMap(projectList); final Tree projectTree = new Tree(root); projectTree.setRootVisible(false); projectTree.setCellRenderer(new NodeRenderer() { @Override public void customizeCellRenderer(@NotNull JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { if (value instanceof DefaultMutableTreeNode) { MavenProject mavenProject = (MavenProject)((DefaultMutableTreeNode)value).getUserObject(); value = projectsNameMap.get(mavenProject); setIcon(MavenIcons.MavenProject); } super.customizeCellRenderer(tree, value, selected, expanded, leaf, row, hasFocus); } }); TreeSpeedSearch.installOn(projectTree, false, o -> { Object lastPathComponent = o.getLastPathComponent(); if (!(lastPathComponent instanceof DefaultMutableTreeNode)) return null; Object userObject = ((DefaultMutableTreeNode)lastPathComponent).getUserObject(); //noinspection SuspiciousMethodCalls return projectsNameMap.get(userObject); }); final Ref<JBPopup> popupRef = new Ref<>(); final Runnable clickCallBack = () -> { TreePath path = projectTree.getSelectionPath(); if (path == null) return; Object lastPathComponent = path.getLastPathComponent(); if (!(lastPathComponent instanceof DefaultMutableTreeNode)) return; Object object = ((DefaultMutableTreeNode)lastPathComponent).getUserObject(); if (object == null) return; // may be it's the root callback.consume((MavenProject)object); popupRef.get().closeOk(null); }; projectTree.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { clickCallBack.run(); e.consume(); } } }); JBPopup popup = new PopupChooserBuilder(projectTree) .setTitle(RunnerBundle.message("maven.select.project")) .setResizable(true) .setItemChosenCallback(clickCallBack).setAutoselectOnMouseMove(true) .setCloseOnEnter(false) .createPopup(); popupRef.set(popup); popup.showUnderneathOf(button); } private DefaultMutableTreeNode buildTree(List<MavenProject> projectList) { MavenProject[] projects = projectList.toArray(new MavenProject[0]); Arrays.sort(projects, new MavenProjectNamer.MavenProjectComparator()); Map<MavenProject, DefaultMutableTreeNode> projectsToNode = new HashMap<>(); for (MavenProject mavenProject : projects) { projectsToNode.put(mavenProject, new DefaultMutableTreeNode(mavenProject)); } DefaultMutableTreeNode root = new DefaultMutableTreeNode(); for (MavenProject mavenProject : projects) { DefaultMutableTreeNode parent; MavenProject aggregator = projectsManager.findAggregator(mavenProject); if (aggregator != null) { parent = projectsToNode.get(aggregator); } else { parent = root; } parent.add(projectsToNode.get(mavenProject)); } return root; } }); }