/* From http://www.objectdefinitions.com/odblog/2011/how-to-fix-right-click-selection-and-jpopupmenu-so-your-jtree-feels-native/ */ package edu.mbl.jif.imaging.nav.dirtree; //import com.jgoodies.looks.windows.WindowsLookAndFeel; import javax.swing.*; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; // TODO: Copy to jif.gui /** * A JTree with mouse listener logic to select items on right click, * before showing a popup * * Also sets the magic PopupMenu property to fix the windows look and * feel, so that clicking outside the popup will select items in the * tree first time, rather than even being consumed by the closing popup */ public class FixedPopupJTree extends JTree { static { //Set the magic property which makes the first click outside the popup //capable of selecting tree nodes, as well as dismissing the popup. UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE); } public FixedPopupJTree() { getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); addMouseListener(new ShowPopupMouseListener()); } private class ShowPopupMouseListener extends MouseAdapter { public void mousePressed(MouseEvent e) { showMenuIfPopupTrigger(e); } public void mouseClicked(MouseEvent e) { showMenuIfPopupTrigger(e); } public void mouseReleased(MouseEvent e) { showMenuIfPopupTrigger(e); } private void showMenuIfPopupTrigger(final MouseEvent e) { if (e.isPopupTrigger()) { //set the new selections before showing the popup setSelectedItemsOnPopupTrigger(e); //build an example popup menu from selections JPopupMenu menu = new JPopupMenu(); for ( TreePath p : getSelectionPaths()) { menu.add(new JMenuItem(p.getLastPathComponent().toString())); } //show the menu, offsetting from the mouse click slightly menu.show((Component)e.getSource(), e.getX() + 3, e.getY() + 3); } } /** * Fix for right click not selecting tree nodes - * We want to implement the following behaviour which matches windows explorer: * If the item under the click is not already selected, clear the current selections and select the * item, prior to showing the popup. * If the item under the click is already selected, keep the current selection(s) */ private void setSelectedItemsOnPopupTrigger(MouseEvent e) { TreePath p = getPathForLocation(e.getX(), e.getY()); if ( ! getSelectionModel().isPathSelected(p)) { getSelectionModel().setSelectionPath(p); } } } //A simple test frame to show the effect of these fixes public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { // try { // UIManager.setLookAndFeel(WindowsLookAndFeel.class.getName()); // } catch (Exception e) { // e.printStackTrace(); // } FixedPopupJTree fixedPopupJTree = new FixedPopupJTree(); TreeModel treeModel = createExampleTreeModel(); fixedPopupJTree.setModel(treeModel); JFrame frame = new JFrame(); frame.getContentPane().add(new JScrollPane(fixedPopupJTree)); frame.setSize(new Dimension(300, 600)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLocationRelativeTo(null); //centre on screen frame.setVisible(true); } }); } private static TreeModel createExampleTreeModel() { DefaultMutableTreeNode root = new DefaultMutableTreeNode("root"); for ( int child = 0; child <=10 ; child++) { root.add(new DefaultMutableTreeNode("child-" + child)); } DefaultTreeModel treeModel = new DefaultTreeModel(root); return treeModel; } }