Creating custom actions.
ProjectViewer allows other plugin developers too interact with the file trees
by creating custom actions to be executed on the nodes. Actions can be added
to the tree's context menu or to the viewer's toolbar. It's recommended to
extend the context menu, since there's only so much useful space in the
toolbar for new actions.
Creating a new action is very simple:
- Create a new class that extends {@link projectviewer.action.Action Action}.
- Implement the {@link projectviewer.action.Action#actionPerformed(ActionEvent)
actionPerformed()} method to execute the desired operations.
- Register the action in the context menu
({@link projectviewer.vpt.VPTContextMenu#registerAction(Action) registerAction()})
or in the toolbar
({@link projectviewer.ProjectViewer#registerAction(Action) registerAction()})
by calling the appropriate method.
The menu item show in the context menu is provided by the
{@link projectviewer.action.Action#getMenuItem() getMenuItem()} of the Action
class. Subclasses are welcome to override this method to provide other kinds
of menu items (a sub-menu, for example). For the toolbar button, the
{@link projectviewer.action.Action#getButton() getButton()} method is used.
Before showing the menu item in the context menu, ProjectViewer will call
the {@link projectviewer.action.Action#prepareForNode(VPTNode) prepareForNode()}
method in all actions registered in the context menu. This allows each action to
decide if it should be shown for the given node and what message to show, for
example. For the toolbar buttons, this method is never called, so the
toolbar buttons should be able to be executed regardless of the current tree
selection. If your action depends on a certain kind of node, add it to the
context menu, and not to the toolbar. If you want to add it to the toolbar,
check for the node type in your actionPerformed() implementation.
Another important thing to notice in the prepareForNode() method is that
the actions should check is the node is of a certain type, and not if the
node is not of a certain type. For example, use "node.isFile()" and not
"!node.isDirectory()". This ensures that the action will not do anything
wrong if a different node type is added in the future to PV, or if another
plugin adds a new node type to PV.
It's important to notice that the instance given to the registerAction
methods is not the instance used by the viewer instances. Those instances are
used as prototypes, and the viewers use {@link projectviewer.action.Action#clone()
clone()} to get instances for the specific viewer. After the cloning, the
{@link projectviewer.action.Action#setViewer(ProjectViewer) setViewer()} method
is called, so the actions have a reference to the viewers where they are being
used. This also means that you should not use the constructor of your Action
implementation to instantiate GUI components. Instantiations of GUI components
should be done lazily in the getMenuItem() or getButton()
methods. The default implementation already does this, so you should only worry
about this if you are overriding one of these methods.
|