/*
* JBoss, Home of Professional Open Source
* Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.jboss.as.cli.gui;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.text.BadLocationException;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.jboss.as.cli.gui.ManagementModelNode.AttributeDescription;
import org.jboss.as.cli.gui.ManagementModelNode.UserObject;
/**
* This class contains a JTree view of the management model that allows you to build commands by
* clicking nodes and operations.
*
* @author Stan Silvert ssilvert@redhat.com (C) 2012 Red Hat Inc.
*/
public class ManagementModel extends JPanel {
private static final String GENERAL_HELP_TEXT = "Right-click a node to choose an operation. Close/Open a folder to refresh. Hover for help.";
private static final String FILTER_TOOLTIP_HELP = "Display the root nodes containing the given text.";
private CliGuiContext cliGuiCtx;
private JTree tree;
// used for the true root '/'
public ManagementModel(CliGuiContext cliGuiCtx) {
this(new ManagementModelNode(cliGuiCtx), cliGuiCtx);
}
public ManagementModel(ManagementModelNode root, CliGuiContext cliGuiCtx) {
this.cliGuiCtx = cliGuiCtx;
setLayout(new BorderLayout(10,10));
this.tree = makeTree(root);
add(new JLabel(GENERAL_HELP_TEXT), BorderLayout.NORTH);
add(new JScrollPane(tree), BorderLayout.CENTER);
add(makeFilterPanel(tree), BorderLayout.SOUTH);
}
/**
* Find a node in the tree. The node must be "visible" to be found.
* @param address The full address of the node matching ManagementModelNode.addressPath()
* @return The node, or null if not found.
*/
public ManagementModelNode findNode(String address) {
ManagementModelNode root = (ManagementModelNode)tree.getModel().getRoot();
Enumeration<javax.swing.tree.TreeNode> allNodes = root.depthFirstEnumeration();
while (allNodes.hasMoreElements()) {
ManagementModelNode node = (ManagementModelNode)allNodes.nextElement();
if (node.addressPath().equals(address)) return node;
}
return null;
}
private JPanel makeFilterPanel(JTree tree) {
Box filterBox = Box.createHorizontalBox();
JLabel filterLabel = new JLabel("Filter:");
filterLabel.setToolTipText(FILTER_TOOLTIP_HELP);
filterBox.add(filterLabel);
filterBox.add(Box.createHorizontalStrut(5));
JTextField filterInput = new JTextField(30);
filterBox.add(filterInput);
JButton clearButton = new JButton("Clear");
clearButton.setToolTipText("Clear the filter");
clearButton.addActionListener(new ClearFilterListener(filterInput));
clearButton.setEnabled(false);
filterInput.getDocument().addDocumentListener(new FilterDocumentListener(tree, clearButton));
filterBox.add(clearButton);
// Make filterBox half of width of panel
JPanel filterPanel = new JPanel(new GridLayout(1,2));
filterPanel.add(filterBox);
filterPanel.add(Box.createGlue());
return filterPanel;
}
private JTree makeTree(ManagementModelNode root) {
root.explore();
JTree tree = new CommandBuilderTree(cliGuiCtx, new DefaultTreeModel(root));
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree.addTreeExpansionListener(new ManagementTreeExpansionListener((DefaultTreeModel) tree.getModel()));
tree.addTreeSelectionListener(new ManagementTreeSelectionListener());
tree.addMouseListener(new ManagementTreeMouseListener(tree));
return tree;
}
/**
* Get the node that has been selected by the user, or null if
* nothing is selected.
* @return The node or <code>null</code>
*/
public ManagementModelNode getSelectedNode() {
if (tree.getSelectionPath() == null) return null;
return (ManagementModelNode)tree.getSelectionPath().getLastPathComponent();
}
private class ClearFilterListener implements ActionListener {
private JTextField filterInput;
ClearFilterListener(JTextField filterInput) {
this.filterInput = filterInput;
}
public void actionPerformed(ActionEvent e) {
filterInput.setText("");
}
}
private class FilterDocumentListener implements DocumentListener {
private JTree tree;
private JButton clearButton;
FilterDocumentListener(JTree tree, JButton clearButton) {
this.tree = tree;
this.clearButton = clearButton;
}
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void changedUpdate(DocumentEvent e) {
String fieldText = null;
try {
fieldText = e.getDocument().getText(0, e.getDocument().getLength());
} catch (BadLocationException ble) {
ble.printStackTrace(); // should never happen
return;
}
clearButton.setEnabled(fieldText.length() > 0);
DefaultTreeModel model = (DefaultTreeModel)tree.getModel();
ManagementModelNode root = (ManagementModelNode)model.getRoot();
root.explore(); // refresh all children
Enumeration nodes = root.children();
List<ManagementModelNode> removeList = new ArrayList<ManagementModelNode>();
while (nodes.hasMoreElements()) {
ManagementModelNode node = (ManagementModelNode)nodes.nextElement();
if (!node.getUserObject().toString().contains(fieldText)) {
removeList.add(node);
}
}
for (ManagementModelNode node : removeList) {
root.remove(node);
}
model.nodeStructureChanged(root);
}
}
/**
* Listener that populates (or refreshes) the children when a node is expanded.
*/
private class ManagementTreeExpansionListener implements TreeExpansionListener {
private DefaultTreeModel treeModel;
public ManagementTreeExpansionListener(DefaultTreeModel treeModel) {
this.treeModel = treeModel;
}
public void treeCollapsed(TreeExpansionEvent tee) {
// do nothing
}
public void treeExpanded(TreeExpansionEvent tee) {
ManagementModelNode node = (ManagementModelNode) tee.getPath().getLastPathComponent();
node.explore();
treeModel.nodeStructureChanged(node);
}
}
/**
* Listener that populates the command line with the address of the selected node.
*/
private class ManagementTreeSelectionListener implements TreeSelectionListener {
public void valueChanged(TreeSelectionEvent tse) {
ManagementModelNode selected = (ManagementModelNode) tse.getPath().getLastPathComponent();
cliGuiCtx.getCommandLine().getCmdText().setText(selected.addressPath());
}
}
/**
* Listener that triggers the operationMenu menu containing operations.
*/
private class ManagementTreeMouseListener extends MouseAdapter {
private JTree tree;
private OperationMenu operationMenu;
private GraphingMenu graphingMenu;
public ManagementTreeMouseListener(JTree tree) {
this.tree = tree;
this.operationMenu = new OperationMenu(cliGuiCtx, tree);
this.graphingMenu = new GraphingMenu(cliGuiCtx, tree);
}
@Override
public void mouseReleased(MouseEvent e) {
if (!e.isPopupTrigger()) return;
showPopup(e);
}
@Override
public void mousePressed(MouseEvent e) {
if (!e.isPopupTrigger()) return;
showPopup(e);
}
private void showPopup(MouseEvent e) {
int selRow = tree.getRowForLocation(e.getX(), e.getY());
if (selRow == -1) return;
TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
tree.setSelectionPath(selPath);
ManagementModelNode node = (ManagementModelNode)selPath.getLastPathComponent();
UserObject usrObj = (UserObject)node.getUserObject();
AttributeDescription attrDesc = usrObj.getAttributeDescription();
if ((attrDesc != null) && attrDesc.isGraphable()) {
// graphingMenu.show(node, e.getX(), e.getY());
} else {
operationMenu.show(node, e.getX(), e.getY());
}
}
}
}