Search code examples
javaswingjtreejpopupmenu

JTree rightclick behaviour like in any Filebrowser


I am trying to implement a JTree to represent a database! The Root is the database, which can have several relations. Each relation can have attributes and functional dependencies. Each node (database, relation, attribute and fd) has a different rightclick menu. The first step was to implement the popdown menu in the standard way (first leftclick on a node, then rightclick to show popupmenu).

Now I want to change it to the standard behaviour of file-explorers. A rightclick selects the node and shows the correct popupmenu.

Currently I am able to rightclick and show a popupmenu, but the menu is incorrect. It is the menu of the previous selected node.

Here is an examplepicture of the tree:

enter image description here

This here is my class:

public class ShowPopupMouseListener extends MouseAdapter {
  // Refernece: http://goo.gl/plojB
  private JTree tree;
  private JPopupMenu dbPopUpMenu;
  private JPopupMenu relPopUpMenu;
  private JPopupMenu attrPopUpMenu;
  private JPopupMenu fdPopUpMenu;
  private AttrPopupFactory attrPopupFactory;

  public ShowPopupMouseListener(JTree jTree) {
    this.tree = jTree;
    DbPopupFactory dbPopupFactory = new DbPopupFactory(tree);
    dbPopUpMenu = dbPopupFactory.getDbPopupMenu();

    RelPopupFactory relPopupFactory = new RelPopupFactory(tree);
    relPopUpMenu = relPopupFactory.getRelPopupMenu();

    attrPopupFactory = new AttrPopupFactory(tree);
    attrPopUpMenu = attrPopupFactory.getAttrPopupMenu();

    FdPopupFactory fdPopupFactory = new FdPopupFactory(tree);
    fdPopUpMenu = fdPopupFactory.getFdPopupMenu();
  }

  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()) {
      setSelectedItemsOnPopupTrigger(e);

      if (tree.getLastSelectedPathComponent() instanceof DatabaseNode) {
        addRightClickPopUpMenu(tree, dbPopUpMenu);
      } else if (tree.getLastSelectedPathComponent() instanceof RelationNode) {
        addRightClickPopUpMenu(tree, relPopUpMenu);
      } else if (tree.getLastSelectedPathComponent() instanceof AttributeNode) {
        attrPopupFactory.updateKeyCheckboxes();
        addRightClickPopUpMenu(tree, attrPopUpMenu);
      } else if (tree.getLastSelectedPathComponent() instanceof FunctionalDependencyNode) {
        addRightClickPopUpMenu(tree, fdPopUpMenu);
      }
    }
  }

  private void addRightClickPopUpMenu(Component component,
      final JPopupMenu popUpMenu) {
    component.addMouseListener(new MouseAdapter() {
      public void mousePressed(MouseEvent e) {
        if (e.isPopupTrigger()) {
          showPopUpMenu(e);
        }
      }

      public void mouseReleased(MouseEvent e) {
        if (e.isPopupTrigger()) {
          showPopUpMenu(e);
        }
      }

      private void showPopUpMenu(MouseEvent e) {
        popUpMenu.show(e.getComponent(), e.getX(), e.getY());
      }
    });
  }

  private void setSelectedItemsOnPopupTrigger(MouseEvent e) {
    TreePath p = tree.getPathForLocation(e.getX(), e.getY());
    if (!tree.getSelectionModel().isPathSelected(p)) {
      tree.getSelectionModel().setSelectionPath(p);
    }
  }

}

And in my tree I initialize it the following way:

UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE);
tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
tree.addMouseListener(new ShowPopupMouseListener(tree));

Any suggestions why this is not working?


Solution

  • You should try keeping things simple, the following is all you really need:

     class RightMouseListener implements MouseListener {
    
        @Override
        public void mouseClicked(MouseEvent e) {
    
            if (SwingUtilities.isRightMouseButton(e)) {
    
                int row = tree.getClosestRowForLocation(e.getX(), e.getY());
                tree.setSelectionRow(row);
                popupMenu.show(e.getComponent(), e.getX(), e.getY());
            }
        }
    
        ...
    
        //other overrides
    
        ...
     };
    

    This is the bare minimum you need to achieve the functionality you're asking for, you can obviously add more custom functionality as needed.