Mercurial > hg > release > thermostat-0.4
view client/core/src/main/java/com/redhat/thermostat/client/ui/MainWindow.java @ 621:210694fa00fe
Show list of agents and backends on the client
Modify the 'agent configuration' dialog on the client to show (but not
modify) agent information (including backends the agent has).
Reviewed-by: rkennke
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-September/003216.html
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Tue, 18 Sep 2012 12:43:05 -0400 |
parents | ed3f6e0a3867 |
children | 394f8798ad69 |
line wrap: on
line source
/* * Copyright 2012 Red Hat, Inc. * * This file is part of Thermostat. * * Thermostat is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * Thermostat is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Thermostat; see the file COPYING. If not see * <http://www.gnu.org/licenses/>. * * Linking this code with other modules is making a combined work * based on this code. Thus, the terms and conditions of the GNU * General Public License cover the whole combination. * * As a special exception, the copyright holders of this code give * you permission to link this code with independent modules to * produce an executable, regardless of the license terms of these * independent modules, and to copy and distribute the resulting * executable under terms of your choice, provided that you also * meet, for each linked independent module, the terms and conditions * of the license of that module. An independent module is a module * which is not derived from or based on this code. If you modify * this code, you may extend this exception to your version of the * library, but you are not obligated to do so. If you do not wish * to do so, delete this exception statement from your version. */ package com.redhat.thermostat.client.ui; import static com.redhat.thermostat.client.locale.Translate.localize; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.nio.ByteBuffer; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.ToolTipManager; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.event.TreeWillExpandListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.ExpandVetoException; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import com.redhat.thermostat.client.internal.MainView; import com.redhat.thermostat.client.locale.LocaleResources; import com.redhat.thermostat.client.osgi.service.BasicView; import com.redhat.thermostat.client.osgi.service.HostDecorator; import com.redhat.thermostat.client.osgi.service.HostFilter; import com.redhat.thermostat.client.osgi.service.MenuAction; import com.redhat.thermostat.client.osgi.service.VmDecorator; import com.redhat.thermostat.client.osgi.service.VMContextAction; import com.redhat.thermostat.client.osgi.service.VmFilter; import com.redhat.thermostat.client.ui.SearchFieldView.SearchAction; import com.redhat.thermostat.common.ActionEvent; import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ActionNotifier; import com.redhat.thermostat.common.HostsVMsLoader; import com.redhat.thermostat.common.dao.HostRef; import com.redhat.thermostat.common.dao.Ref; import com.redhat.thermostat.common.dao.VmRef; import com.redhat.thermostat.common.utils.StringUtils; import com.redhat.thermostat.swing.EdtHelper; import com.redhat.thermostat.swing.StatusBar; public class MainWindow extends JFrame implements MainView { /** * Updates a TreeModel in the background in an Swing EDT-safe manner. */ private static class BackgroundTreeModelWorker extends SwingWorker<DefaultMutableTreeNode, Void> { private JTree tree; private final DefaultTreeModel treeModel; private DefaultMutableTreeNode treeRoot; private List<HostFilter> hostFilters; private List<VmFilter> vmFilters; private List<HostDecorator> hostDecorators; private List<VmDecorator> vmDecorators; private HostsVMsLoader hostsVMsLoader; public BackgroundTreeModelWorker(DefaultTreeModel model, DefaultMutableTreeNode root, List<HostFilter> hostFilters, List<VmFilter> vmFilters, List<HostDecorator> hostDecorators, List<VmDecorator> vmDecorators, HostsVMsLoader hostsVMsLoader, JTree tree) { this.hostFilters = hostFilters; this.vmFilters = vmFilters; this.vmDecorators = vmDecorators; this.hostDecorators = hostDecorators; this.treeModel = model; this.treeRoot = root; this.hostsVMsLoader = hostsVMsLoader; this.tree = tree; } @Override protected DefaultMutableTreeNode doInBackground() throws Exception { DefaultMutableTreeNode root = new DefaultMutableTreeNode(); Collection<HostRef> hostsInRemoteModel = hostsVMsLoader.getHosts(); buildHostSubTree(root, hostsInRemoteModel); return root; } private boolean buildHostSubTree(DefaultMutableTreeNode parent, Collection<HostRef> objectsInRemoteModel) { boolean subTreeMatches = false; for (HostRef inRemoteModel : objectsInRemoteModel) { DecoratedDefaultMutableTreeNode inTreeNode = new DecoratedDefaultMutableTreeNode(inRemoteModel); boolean shouldInsert = false; if (hostFilters == null) { shouldInsert = true; } else { shouldInsert = true; for (HostFilter filter : hostFilters) { if (!filter.matches(inRemoteModel)) { shouldInsert = false; break; } } } Collection<VmRef> children = hostsVMsLoader.getVMs(inRemoteModel); boolean subtreeResult = buildVmSubTree(inTreeNode, children); if (subtreeResult) { shouldInsert = true; } if (shouldInsert) { for (HostDecorator decorator : hostDecorators) { HostFilter filter = decorator.getFilter(); if (filter != null && filter.matches(inRemoteModel)) { inTreeNode.addDecorator(decorator.getDecorator()); } } parent.add(inTreeNode); subTreeMatches = true; } } return subTreeMatches; } private boolean buildVmSubTree(DefaultMutableTreeNode parent, Collection<VmRef> objectsInRemoteModel) { boolean subTreeMatches = false; for (VmRef inRemoteModel : objectsInRemoteModel) { DecoratedDefaultMutableTreeNode inTreeNode = new DecoratedDefaultMutableTreeNode(inRemoteModel); boolean shouldInsert = false; if (vmFilters == null) { shouldInsert = true; } else { shouldInsert = true; for (VmFilter filter : vmFilters) { if (!filter.matches(inRemoteModel)) { shouldInsert = false; break; } } } if (shouldInsert) { for (VmDecorator decorator : vmDecorators) { VmFilter filter = decorator.getFilter(); if (filter != null && filter.matches(inRemoteModel)) { inTreeNode.addDecorator(decorator.getDecorator()); } } parent.add(inTreeNode); subTreeMatches = true; } } return subTreeMatches; } @Override protected void done() { DefaultMutableTreeNode sourceRoot; try { sourceRoot = get(); syncTree(sourceRoot, treeModel, treeRoot); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } private void syncTree(DefaultMutableTreeNode sourceRoot, DefaultTreeModel targetModel, DefaultMutableTreeNode targetNode) { @SuppressWarnings("unchecked") // We know what we put into these trees. List<DefaultMutableTreeNode> sourceChildren = Collections.list(sourceRoot.children()); @SuppressWarnings("unchecked") List<DefaultMutableTreeNode> targetChildren = Collections.list(targetNode.children()); for (DefaultMutableTreeNode sourceChild : sourceChildren) { Ref sourceRef = (Ref) sourceChild.getUserObject(); DefaultMutableTreeNode targetChild = null; for (DefaultMutableTreeNode aChild : targetChildren) { Ref targetRef = (Ref) aChild.getUserObject(); if (targetRef.equals(sourceRef)) { targetChild = aChild; if (sourceChild instanceof DecoratedDefaultMutableTreeNode) { DecoratedDefaultMutableTreeNode source = (DecoratedDefaultMutableTreeNode) sourceChild; ((DecoratedDefaultMutableTreeNode) targetChild).setDecorators(source.getDecorators()); } break; } } if (targetChild == null) { targetChild = new DecoratedDefaultMutableTreeNode(sourceRef); if (sourceChild instanceof DecoratedDefaultMutableTreeNode) { DecoratedDefaultMutableTreeNode source = (DecoratedDefaultMutableTreeNode) sourceChild; ((DecoratedDefaultMutableTreeNode) targetChild).setDecorators(source.getDecorators()); } targetModel.insertNodeInto(targetChild, targetNode, targetNode.getChildCount()); } syncTree(sourceChild, targetModel, targetChild); } for (DefaultMutableTreeNode targetChild : targetChildren) { Ref targetRef = (Ref) targetChild.getUserObject(); boolean matchFound = false; for (DefaultMutableTreeNode sourceChild : sourceChildren) { Ref sourceRef = (Ref) sourceChild.getUserObject(); if (targetRef.equals(sourceRef)) { matchFound = true; break; } } if (!matchFound) { targetModel.removeNodeFromParent(targetChild); } } ensureRootIsExpanded(targetModel); } private void ensureRootIsExpanded(final DefaultTreeModel model) { DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot(); tree.expandPath(new TreePath(root.getPath())); } } private static final long serialVersionUID = 5608972421496808177L; private final JMenuBar mainMenuBar = new JMenuBar(); private final MenuHelper mainMenuHelper = new MenuHelper(mainMenuBar); private JPanel contentArea = null; private SearchFieldSwingView searchField = new SearchFieldSwingView(); private JTree agentVmTree = null; private final ShutdownClient shutdownAction; private ActionNotifier<Action> actionNotifier = new ActionNotifier<>(this); private JPopupMenu vmContextMenu; private StatusBar statusBar; private final DefaultMutableTreeNode publishedRoot = new DefaultMutableTreeNode(localize(LocaleResources.MAIN_WINDOW_TREE_ROOT_NAME)); private final DefaultTreeModel publishedTreeModel = new DefaultTreeModel(publishedRoot); public MainWindow() { super(); shutdownAction = new ShutdownClient(); searchField.addActionListener(new ActionListener<SearchAction>() { @Override public void actionPerformed(ActionEvent<SearchAction> actionEvent) { switch (actionEvent.getActionId()) { case TEXT_CHANGED: fireViewAction(Action.HOST_VM_TREE_FILTER); break; } } }); agentVmTree = new JTree(publishedTreeModel); agentVmTree.setName("agentVmTree"); agentVmTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); agentVmTree.setCellRenderer(new AgentVmTreeCellRenderer()); agentVmTree.addTreeWillExpandListener(new TreeWillExpandListener() { @Override public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException { /* Yup, tree will expand */ } @Override public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException { if (new TreePath(publishedRoot.getPath()).equals(event.getPath())) { throw new ExpandVetoException(event, "root cant be collapsed"); } } }); ToolTipManager.sharedInstance().registerComponent(agentVmTree); contentArea = new JPanel(new BorderLayout()); setupMenus(); setupPanels(); this.setPreferredSize(new Dimension(800, 600)); agentVmTree.setSelectionPath(new TreePath(((DefaultMutableTreeNode) publishedTreeModel.getRoot()).getPath())); //agentVmTree.setLargeModel(true); agentVmTree.setRowHeight(25); statusBar = new StatusBar(); getContentPane().add(statusBar, BorderLayout.SOUTH); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(shutdownAction); addComponentListener(new ComponentAdapter() { @Override public void componentShown(ComponentEvent e) { fireViewAction(Action.VISIBLE); } @Override public void componentHidden(ComponentEvent e) { fireViewAction(Action.HIDDEN); } }); } private void setupMenus() { JMenu fileMenu = new JMenu(localize(LocaleResources.MENU_FILE)); fileMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1)); mainMenuBar.add(fileMenu); JMenuItem fileExitMenu = new JMenuItem(localize(LocaleResources.MENU_FILE_EXIT)); fileExitMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, InputEvent.CTRL_DOWN_MASK)); fileExitMenu.addActionListener(shutdownAction); fileMenu.add(fileExitMenu); JMenu editMenu = new JMenu(localize(LocaleResources.MENU_EDIT)); mainMenuBar.add(editMenu); JMenuItem configureClientMenuItem = new JMenuItem(localize(LocaleResources.MENU_EDIT_CONFIGURE_CLIENT)); configureClientMenuItem.setName("showClientConfig"); configureClientMenuItem.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent e) { fireViewAction(Action.SHOW_CLIENT_CONFIG); } }); editMenu.add(configureClientMenuItem); editMenu.addSeparator(); JMenuItem historyModeMenuItem = new JCheckBoxMenuItem(localize(LocaleResources.MENU_EDIT_ENABLE_HISTORY_MODE)); historyModeMenuItem.setName("historyModeSwitch"); historyModeMenuItem.setSelected(false); historyModeMenuItem.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent e) { fireViewAction(Action.SWITCH_HISTORY_MODE); } }); editMenu.add(historyModeMenuItem); JMenu viewMenu = new JMenu(localize(LocaleResources.MENU_VIEW)); mainMenuBar.add(viewMenu); JMenuItem configureAgentMenuItem = new JMenuItem(localize(LocaleResources.MENU_VIEW_AGENTS)); configureAgentMenuItem.setName("showAgentConfig"); configureAgentMenuItem.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent e) { fireViewAction(Action.SHOW_AGENT_CONFIG); } }); viewMenu.add(configureAgentMenuItem); JMenu helpMenu = new JMenu(localize(LocaleResources.MENU_HELP)); helpMenu.getPopupMenu().setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1)); mainMenuBar.add(helpMenu); JMenuItem helpAboutMenu = new JMenuItem(localize(LocaleResources.MENU_HELP_ABOUT)); helpAboutMenu.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent e) { fireViewAction(Action.SHOW_ABOUT_DIALOG); } }); helpMenu.add(helpAboutMenu); setJMenuBar(mainMenuBar); } private void setupPanels() { JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); splitPane.setOneTouchExpandable(true); JPanel navigationPanel = new JPanel(new BorderLayout()); navigationPanel.add(searchField, BorderLayout.PAGE_START); agentVmTree.addTreeSelectionListener(new TreeSelectionListener() { @Override public void valueChanged(TreeSelectionEvent e) { if (e.isAddedPath()) { fireViewAction(Action.HOST_VM_SELECTION_CHANGED); } } }); registerContextActionListener(agentVmTree); JScrollPane treeScrollPane = new JScrollPane(agentVmTree); navigationPanel.add(treeScrollPane); JPanel detailsPanel = createDetailsPanel(); navigationPanel.setMinimumSize(new Dimension(200,500)); detailsPanel.setMinimumSize(new Dimension(500, 500)); splitPane.add(navigationPanel); splitPane.add(detailsPanel); getContentPane().add(splitPane); } private void registerContextActionListener(JTree agentVmTree2) { vmContextMenu = new JPopupMenu(); agentVmTree2.addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) { Ref ref = getSelectedHostOrVm(); if (ref instanceof VmRef) { fireViewAction(Action.SHOW_VM_CONTEXT_MENU, e); } } } }); } @Override public void showVMContextActions(final List<VMContextAction> actions, final MouseEvent e) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { vmContextMenu.removeAll(); for (final VMContextAction action: actions) { JMenuItem contextAction = new JMenuItem(); contextAction.setText(action.getName()); contextAction.setToolTipText(action.getDescription()); contextAction.addActionListener(new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent e) { fireViewAction(Action.VM_CONTEXT_ACTION, action); } }); vmContextMenu.add(contextAction); } vmContextMenu.show((Component)e.getSource(), e.getX(), e.getY()); } }); } private JPanel createDetailsPanel() { JPanel result = new JPanel(new BorderLayout()); result.add(contentArea, BorderLayout.CENTER); return result; } public class ShutdownClient extends WindowAdapter implements java.awt.event.ActionListener { @Override public void windowClosing(WindowEvent e) { shutdown(); } @Override public void actionPerformed(java.awt.event.ActionEvent e) { shutdown(); } private void shutdown() { dispose(); fireViewAction(Action.SHUTDOWN); } } private static class AgentVmTreeCellRenderer extends DefaultTreeCellRenderer { private static final long serialVersionUID = 4444642511815252481L; @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { Object node = ((DefaultMutableTreeNode) value).getUserObject(); setToolTipText(createToolTipText(node)); Component component = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); if (value instanceof DecoratedDefaultMutableTreeNode) { DecoratedDefaultMutableTreeNode treeNode = (DecoratedDefaultMutableTreeNode) value; setAnnotation(treeNode, node, component); } return component; } // TODO: we can cache more, for example the full icon, not just the decoration private Map<Decorator, ImageIcon> decoratorsCache = new HashMap<>(); private void setAnnotation(DecoratedDefaultMutableTreeNode treeNode, Object value, Component component) { List<Decorator> decorators = treeNode.getDecorators(); for (Decorator dec : decorators) { String newText = dec.getLabel(getText()); setText(newText); setLabelFor(component); ImageIcon icon = decoratorsCache.get(dec); if (icon == null) { //System.err.println("cache miss: " + dec); IconDescriptor iconDescriptor = dec.getIconDescriptor(); if (iconDescriptor != null) { ByteBuffer data = iconDescriptor.getData(); icon = new ImageIcon(data.array()); decoratorsCache.put(dec, icon); } } if (icon == null) { return; } Icon currentIcon = getIcon(); switch (dec.getQuadrant()) { case BOTTOM_LEFT: int y = currentIcon.getIconHeight() - icon.getIconHeight(); paintCustomIcon(currentIcon, icon, y); break; case TOP_LEFT: paintCustomIcon(currentIcon, icon, 0); break; case MAIN: default: setIcon(icon); break; } } } private void paintCustomIcon(Icon currentIcon, ImageIcon icon, int y) { BufferedImage image = new BufferedImage(currentIcon.getIconWidth(), currentIcon.getIconHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D graphics = (Graphics2D) image.getGraphics(); currentIcon.paintIcon(null, graphics, 0, 0); graphics.drawImage(icon.getImage(), 0, y, null); setIcon(new ImageIcon(image)); } private String createToolTipText(Object value) { if (value instanceof HostRef) { HostRef hostRef = (HostRef) value; String hostNameHtml = new HtmlTextBuilder().bold(hostRef.getHostName()).toPartialHtml(); String agentIdHtml = new HtmlTextBuilder().bold(hostRef.getAgentId()).toPartialHtml(); HtmlTextBuilder builder = new HtmlTextBuilder() .appendRaw(localize(LocaleResources.TREE_HOST_TOOLTIP_HOST_NAME, hostNameHtml)) .newLine() .appendRaw(localize(LocaleResources.TREE_HOST_TOOLTIP_AGENT_ID, agentIdHtml)); return builder.toHtml(); } else if (value instanceof VmRef) { VmRef vmRef = (VmRef) value; String vmNameHtml= new HtmlTextBuilder().bold(vmRef.getName()).toPartialHtml(); String vmIdHtml = new HtmlTextBuilder().bold(vmRef.getIdString()).toPartialHtml(); HtmlTextBuilder builder = new HtmlTextBuilder() .appendRaw(localize(LocaleResources.TREE_HOST_TOOLTIP_VM_NAME, vmNameHtml)) .newLine() .appendRaw(localize(LocaleResources.TREE_HOST_TOOLTIP_VM_ID, vmIdHtml)); return builder.toHtml(); } else { return null; } } } @Override public void addActionListener(ActionListener<Action> l) { actionNotifier.addActionListener(l); } public void removeViewActionListener(ActionListener<Action> l) { actionNotifier.removeActionListener(l); } private void fireViewAction(Action action) { actionNotifier.fireAction(action); } private void fireViewAction(Action action, Object payload) { actionNotifier.fireAction(action, payload); } @Override public void updateTree(List<HostFilter> hostFilters, List<VmFilter> vmFilters, List<HostDecorator> hostDecorators, List<VmDecorator> vmDecorators, HostsVMsLoader hostsVMsLoader) { BackgroundTreeModelWorker worker = new BackgroundTreeModelWorker(publishedTreeModel, publishedRoot, hostFilters, vmFilters, hostDecorators, vmDecorators, hostsVMsLoader, agentVmTree); worker.execute(); } @SuppressWarnings("unused") // Used for debugging but not in production code. private static void printTree(PrintStream out, TreeNode node, int depth) { out.println(StringUtils.repeat(" ", depth) + node.toString()); @SuppressWarnings("unchecked") List<TreeNode> children = Collections.list(node.children()); for (TreeNode child : children) { printTree(out, child, depth + 1); } } @Override public void setWindowTitle(String title) { setTitle(title); } @Override public void showMainWindow() { try { new EdtHelper().callAndWait(new Runnable() { @Override public void run() { pack(); setVisible(true); } }); } catch (InvocationTargetException e) { throw new RuntimeException(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } @Override public void hideMainWindow() { setVisible(false); dispose(); } @Override public void setStatusBarPrimaryStatus(final String primaryStatus) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { statusBar.setPrimaryStatus(primaryStatus); } }); } @Override public void setSubView(final BasicView view) { if (view instanceof SwingComponent) { final SwingComponent swingComp = (SwingComponent)view; SwingUtilities.invokeLater(new Runnable() { @Override public void run() { contentArea.removeAll(); Component toAdd = swingComp.getUiComponent(); contentArea.add(toAdd); contentArea.revalidate(); } }); } } @Override public void addMenu(MenuAction action) { mainMenuHelper.addMenuAction(action); } @Override public void removeMenu(MenuAction action) { mainMenuHelper.removeMenuAction(action); } /** * Returns null to indicate no Ref is selected */ @Override public Ref getSelectedHostOrVm() { TreePath path = agentVmTree.getSelectionPath(); if (path == null || path.getPathCount() == 1) { return null; } return (Ref) ((DefaultMutableTreeNode) path.getLastPathComponent()).getUserObject(); } @Override public String getHostVmTreeFilterText() { return searchField.getSearchText(); } }