Document describing implemented changes in action system

$Revision: 1.2 $
Changes: available in CVS
Status: issue 27868 Dependency Tree: of issue 27868

Note: Some of the links are broken (describing new API), they will start to work, when the branch action_27868 is merged into trunk.

Abstract

This  document describes implemented API changes, implementations and usage of the new action API enhancements.

First part 1. Popup menu creation describes change of building popup in NB. This is only related change for those developers who are just using the Actions API for building
the popups, i.e. they are not action "providers".

The rest of this document describes the changes to the standard API, and explains its implementations, and their usage.

At the end 5. Summary of Action API changes it summarizes the up-to-date changes comparing to old API.

Content

1. Popup menu creation
1.1 Old scenario
1.2 Scenario describing the idea
1.3 Scenario describing the new API usage
2. Context
3. Context Aware Actions
3.1 Callback Actions
3.2 Node Actions
3.3 Other SystemAction subclasses which implement ContextAwareAction
4. Move from SystemAction to Action
5. Summary of Action API changes



1. Popup menu creation
Here is described typical scenario of popup menu creation and new ones describing the idea and API in new way.
1.1 Old scenario
Folowing way was created popup menu in NB in old-fashion:

...
// There is TopComponent tc, and was clicked at its point Point.
// 1) Retrieve actions for that top compnent
SystemAction[] sa = retrieveActionsSomehow();
// 2) Create popup.
JPopupMenu popup = createPopup(sa);
// 3) Show popup
popup.show(tc, point);
...
1.2 Scenario describing the idea
This scenarion describes the idea how the popup should be created when the changes introduced.

...
// There is TopComponent tc, and was clicked at its point Point.
// 1) Retrieve actions for that top compnent
SystemAction[] sa = retrieveActionsSomehow();

// 1a) Get context used for actions in current popup
Lookup context = retrieveContextSomehow();    // Note: this is just imaginary method.
// 1b) The actions which are ContextAwareActionS replace by its context aware instances:
Action[] aa = changeActionsToContextAwareInstancesSomehow(sa, context);    // Note: this is just imaginary method.

// 2) Create popup.
JPopupMenu popup = createPopup(aa);
// 3) Show popup
popup.show(tc, point);
...

1.3 Scenario describing the new API usage
Last scenarion shows new way of popup creation in NB with context aware actions. Note that all the work is done behind the scenes in
Utilities.actionsToPopup(Action[], Lookup context) method (btw. also TopComponent.getLookup() method).

Using the new API for the steps 1a) and 1b) (the steps 1b) and 2) merged) looks typically like this:

...
// There is TopComponent tc, and was clicked at its point Point.
// 1) Retrieve actions for that top compnent
Action[] aa = retrieveActions(); // Note: Here could be used the Action[] array.

// 1a) Get context used for actions in current popup
Lookup context = tc.getLookup();
// 1b) + 2) The actions which are ContextAwareActionS replace by its context aware instances and create popup
JPopup popup = Utilities.actionsToPopup(aa, context);

// 3) Show popup
popup.show(tc, point);
...

Important Note: This new scenario is a MUST-HAVE when creating popup menu in NB, otherwise the popup would consist of global action instances only, which in case they impelement ContextAwareAction interface, may not for correctly for the provided context.


2. Context

The one most important idea is a notion of context, which is used when building popup menu from actions. The context describes environment according the certain actions (ContextAwareActionS) work, i.e. change their enablement status and perform themself.

Comparing to the old implementation where all actions were singletons, i.e. they are all were used in "global-context". I.e. each node actions listens on global activated nodes changes, each callback actions is set/unset/reset its performer, depending in which popup is currently used.

In new implementation for actions of type ContextAwareAction are created instances which are valid for the specified context, and afterwards upon popup hiding and garbaging, the instance is also garbaged.

E.g. when creating popup in Explorer, which certain node is selected, each such context aware action instance works accordingly to that node, i.e. each such node action instance doesn't need to listen on global activated node changes, it can retrieve the selected node from the context directly (see below), also each such callback action instance doesn't has to be watched by to set/reset/unset its action performer, it can retrieve the "performer-like" action directly from the context -> TopComponent action map (see below).

The context is described by Lookup instance. The Lookup is typically retrieved from TopComponent.getLookup() method. The default implementation of that method returns context, Lookup which lookups activated nodes of that TopComponent and ActionMap delegate of that TopComponent. The individual components which the Lookup consist of is described later.


3. Context Aware Actions
The second important idea is ContextAwareAction. It is kind of Action which creates context aware instances, which have to be used in that context and are valid for that context only. I.e when creating the popup menu in certain context it is necessary to retrieve for each context aware action its context aware instance. The context aware intstance is retrieved via the createContextAwareInstance method.

Current actions API enhancements: CallbackSystemAction, NodeAction and certain other SystemAction subclasses implement ContextAwareAction interface.

Next there is described how the standard system actions works in new way:
3.1 Callback Actions
In old time CallbackSystemAction works with ActionPerformerS, which are set/unset/reset for that action via its setActionPerformer method.

New way is that the action performer is not used and it is replaced by action which is retrieved from action map which is provided by the context working in. Let's call it "performer-like" action for purpose of this document.

The retrieval of that action is done by provided context aware instance of the callback action, which works whithin the specific context. This way it is achieved that the performer is context depedent thus it doesn't need to be changed (set/unset/reset) for the old singleton callback action instance The performer is usually same for the specified context.


How the context aware action instance finds the "action-performe-like" action from the ActionMap?
There is a contract between context provider (Lookup.Provider) which puts the action map in and each callback action instance to agree on a key which is used to find the "performer-like" action instance (it plays the old ActionPerformer role) from the action map. The key can be retrieved from callback action subclasses following way:

...
// E.g. for delete action
CallbackSystemAction globalDeleteAction = (CallbackSystemAction)SystemAction.get(DeleteAction.class);
String deleteActionKey = globalDeleteAction.getActionMapKey();
...

Each callback action is supposed to override getActionMapKey() method to provide its key. Default implementation returns the class name.

Then the key is used when the action works in specific context that way, it finds ActionMap provided by that context and tries to get the "performer-like" action using its key.

How to put the context aware instance into context action map?
If working with default scenario(see above), the action map is delegating to the TopComponent action map, i.e. when in put in TopComponent's tc action map:

...
// Put the "performer-like" action into TopComponent's (tc) ActionMap
tc.getActionMap ().put (deleteActionKey, performerLikeDeleteAction);
..

Then when the context got from that TopComponent is used for popup creation, the performerLikeDeleteAction is used in the popup as its action performer.


The advantage of this aproach is that there isn't possible any clash, which happens when working with old callback action singletons, i.e. the ActionPerformerS could be easily replaced by another ones and that could lead to incosistent state of that action whitin certain popup (context). In new impl for each specific context is used specific context aware instance of callback action which can maintain more easily the performer (via the "performer-like" action) within the context.


Important Note: When for the callback action isn't found the "performer-like" action by provided key (via getActionMapKey() method, it falls back to old behaviour working with ActionPerformerS.

3.2 Node Actions
Old Node actions (and thus also Cookie actions which are subclasses) worked the way they listened in global node changes, and has updating their state accordingly.

The new way is to create the context aware instsances of each Node action, and that context aware instance is working according nodes provided by the context. This way is possible to save the overhead, and various problems with global nodes changes. I.e. When creating popup in Explorer, the node (or cookie) context aware action is working according the selected node in the explorer.

How are the nodes put into the context?
The default implementation of TopComponentS context retrieved by TopCompoent.getLookup() provides as nodes the activated nodes, which are returned by TopComponent.getActivatedNodes() method.

3.3 Other SystemAction subclasses which implement ContextAwareAction
There are also some other action subclasses which implement ContextAwareAction interface, those are e.g. ToolsAction, PropertiesAction, PasteAction etc. Those implementations are specific to each one, and could be examined by code review, but for most cases the implementations are irrelevant for their usage.


4. Move from SystemAction to Action

There is created possibility to use direct Action implelementations instead of SystemAction Therefore were new API enhancements in Node, AbstractNode and NodeOp classes introduced, and some old API is deprecated.
See the table.

Important Note: There is currently no support for creating Action type subclasses, i.e. action couterparts for CallbackSystemActionNodeAction etc. It will be subject of later changes. Therefore currently the developers aren't yet encouraged to move from the SystemAction subclasses to Action types yet (but it is fully possible for direct SystemAction subclasses, where no additional API support is required).

5. Summary of Action API changes

The table shows the changes to old API, their replacements, and enhancements by new API's (also some problems coping with especially the lack of good names for methods in node API).

Old API
Desciption of old API change
New API enancement/replacement
Description of new API change


ContextAwareAction interface
and its Action cretateContextAwareInstance() method
Provides context aware actions, it means that the action creates context aware
 action instances for each specified context.


TopComponent.getLookup() method
Provide default implementation of context. The default context provides lookup for nodes,
 which delegates
to TopComponent.getActivatedNodes() method and for action map
 which delegatest to TopComponent.getActionMap().


JPopupMenu Utilities.actionsToPopup(Action[], Lookup context) method
Utility method whic builds popup from action array, it retrieves the context
 aware action instances for the specified context, and builds the popup menu.


JPopupMenu Utilities.actionsToPopup(Action[], Componet) method
Utility helper method. There are certaing cases there isn't direct reference to TopComponent,
thus to its context (getLookup() method), or could be used form more general scenerion.
This method finds the context following way, it traverses the components up
to the component hierarchy behinning from the specified component and
searches for first Lookup.Provider instance (which is typically TopComponent) if found the provider,
its Lookup instance is used as the context, if not there is created Lookup
which delegates to composite action map (which consists of all action maps
of the searched component hierarchy), and that instance
 is used as context. Then the Utilities.actionsToPopup(Action[], Lookup context) is called.


CallbackSystemAction implements ContextAwareAction
See above.


Object CallbackSystemAction.getActionMapKey() method
This method returns the key which is then used to find the action which performs the callback. See above.


NodeAction implements ContextAwareAction
See above.


Some direct SystemAction subclasses implement ContextAwareAction
See above.
SystemAction[] Node.getActions()
deprecated
Action[] Node.getActions(false)
See above.
SystemAction[] Node.getContextActions
deprecated
Action[] Node.getActions(true)
See above.
SystemAction Node.getDefaultAction()
deprecated, and changed from abstract to return null as default impl.
Action Node.getPreferredAction()
See above.
AbstractNode.setDefaultAction(SystemAction)
deprecated
AbstractNode.setPreferredAction(Action)
See above.
SystemAction[] AbstractNode.createActions()
it is not deprecated yet, but looses its effect in new usage
N/A yet, it is needed to figure out some way later.
See above.
SystemAction[] NodeOp.getDefaultActions()
deprecated
No replacement, its useless now.
See above.


Action[] NodeOp.findActions(Node[])
Utility method for retrieving actions for node array.
static Actions.connect(AbstractButton, SystemAction)
deprecated
static Actions.connect(AbstractButton, Action)
Replaces the older method working with SystemAction.
static Actions.connect(JMenuItem, SystemAction, boolean)
deprecated
static Actions.connect(JMenuItem, SystemAction, boolean) method
Replaces the older method working with SystemAction.



Send comments and patches to openide-dev@netbeans.org or attach them to issue 27868.



Project Features

About this Project

openide was started in November 2009, is owned by Antonin Nebuzelsky, and has 7 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20140418.2d69abc). © 2013, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close