Context Sensitive JTable (Part 2)

Now, having completed part 1, let's add a popup menu to the JTable. However, the menu item in the popup menu should invoke the same Action as invoked from the toolbar button created yesterday.

Add this to the constructor created yesterday:

Collection<? extends Action> stockActions =
        Lookups.forPath("Actions/Stock").lookupAll(Action.class);
for (Action action : stockActions) {
    popupMenu.add(new JMenuItem(action));
}

MouseListener popupListener = new PopupListener();
// Add the listener to the JTable:
table.addMouseListener(popupListener);
// Add the listener specifically to the header:
table.getTableHeader().addMouseListener(popupListener);

And here's the standard popup enablement code:

private JPopupMenu popupMenu = new JPopupMenu();

class PopupListener extends MouseAdapter {
    @Override
    public void mousePressed(MouseEvent e) {
        showPopup(e);
    }
    @Override
    public void mouseReleased(MouseEvent e) {
        showPopup(e);
    }
    private void showPopup(MouseEvent e) {
        if (e.isPopupTrigger()) {
            popupMenu.show(e.getComponent(), e.getX(), e.getY());
        }
    }
}
Comments:

This is wrong. You should use Utilities.actionsForPath then Utilities.actionsToPopup, which is simpler than the above code yet correctly handles Presenter.Popup, separators, and so on.

More subtly, the above code fails to check for ContextAwareAction. (The proxy for ShowStockAction would implement this interface.) It may happen to work if as a side effect of right-clicking the table you also happen to (first) select the TopComponent containing the table and activate its row, thus activating its corresponding nodes, and said TC contains just this one table with a possible selection: the Action with no specified context will generally fall back to using actionsGlobalContext. But that involves a number of assumptions about the contents of the window, the behavior of the native window manager and focus system, the order of delivery of selection events, etc. Such assumptions are not acceptable for any explorer-like view displaying a popup menu.

By contrast, actionsToPopup looks for a selection on the actual component being right-clicked, regardless of what the application's global selection might be. You can explicitly pass in a Lookup context if that is convenient; but you may also pass in the Component being clicked if it or an ancestor is a Lookup.Provider, which MyWindowTopComponent would be in this case.

(In case you had multiple tables with independent selections in the same TC, you would want each to implement L.P or be wrapped in a panel which did, so that aTP given the specific JTable would pay attention just to the selection in that table, regardless of which table was currently considered "active" by the TC.)

Posted by Jesse Glick on November 21, 2011 at 12:16 AM PST #

I have to thank you for this cool example. This may have some problems as pointed out by Jesse, but the idea behind all this is awesome. And i don't see why you couldn't do it for other components, like JTrees or JLists for instance. It should also ease the task of migrating a Swing application to a Netbeans application.

Regards

Posted by metator on November 30, 2011 at 06:18 AM PST #

Thanks for the cool example.
Is it possible to disable the action when the table is empty and enabled when the table is not empty?

Posted by Willy De Keyser on December 02, 2011 at 10:59 PM PST #

Hi Willy. That's already the case. The Action is context-sensitive, so if there is no Stock object selected, i.e., the table is empty, the Action will be disabled.

Posted by Geertjan on December 03, 2011 at 08:04 AM PST #

I think I have found it.
i have to put a : 'content.set(Collections.EMPTY_LIST, null);'
in the 'resultChanged(LookupEvent lookupEvent)' from my 'EditorTopComponent' where i view the jTabel.
This is the right way?

Posted by Willy De Keyser on December 03, 2011 at 07:38 PM PST #

@ Jesse,

You say Utilities.actionsToPopup "correctly handles Presenter.Popup" but in my experience, using Utilities.actionsToPopup does not get the icons (16x16) associated with the actions to show up in the resulting popup menu - or am I missing something? I believe this defect is related to http://netbeans.org/bugzilla/show_bug.cgi?id=208081. Using Geertjan's approach, you can get the icons to show in the popup, but I agree you will have to do a little bit extra to handle things like separators etc.

Posted by Osho on December 27, 2012 at 03:17 AM PST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

Geertjan Wielenga (@geertjanw) is a Principal Product Manager in the Oracle Developer Tools group living & working in Amsterdam. He is a Java technology enthusiast, evangelist, trainer, speaker, and writer. He blogs here daily.

The focus of this blog is mostly on NetBeans (a development tool primarily for Java programmers), with an occasional reference to NetBeans, and sometimes diverging to topics relating to NetBeans. And then there are days when NetBeans is mentioned, just for a change.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
12
13
14
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today