X

Geertjan's Blog

  • August 21, 2015

Overriding Default Context-Sensitive Action Enablement

Geertjan Wielenga
Product Manager

By default, when you create an Action that is context sensitive, via the New Action wizard, the NetBeans Platform looks out for the types that are of interest to you and, when they're in the Lookup, enables your Action. In the case below, when multiple Parts are in the Lookup, i.e., typically, multiple PartNodes are selected and their underlying Part objects are published, the Action will automatically be enabled:

@ActionID(
category = "Parts",
id = "org.car.viewer.PartComparatorAction"
)
@ActionRegistration(
displayName = "#CTL_PartComparatorAction"
)
@ActionReference(
path = "Menu/File",
position = 1200)
@Messages("CTL_PartComparatorAction=Compare Parts")
public final class PartComparatorAction implements ActionListener {
private final List<Part> context;
public PartComparatorAction(List<Part> context) {
this.context = context;
}
@Override
public void actionPerformed(ActionEvent ev) {
StringBuilder sb = new StringBuilder();
for (Part part : context) {
sb.append(part.getName()).append(" ");
}
StatusDisplayer.getDefault().setStatusText(sb.toString());
}
}

However, the default behavior is such that even when only one Part object is exposed to the Lookup, the Action is enabled, as shown below:

The above doesn't really make sense because you need more than one of something to make it worthwhile to compare. To override this default behavior, you can abandon the default underlying class and implement your own enablement strategy.

Begin by including "lazy = false", shown in bold below, which will generate layer.xml entries that, instead of delegating to the internal NetBeans Platform code for handling enablement, lets you provide that enablement yourself, as shown here:

@ActionID(
category = "Parts",
id = "org.car.viewer.PartComparatorAction"
)
@ActionRegistration(lazy = false,
displayName = "NOTUSED"
)
@ActionReference(
path = "Menu/File",
position = 1200)
@Messages("CTL_PartComparatorAction=Compare Parts")
public final class PartComparatorAction extends AbstractAction {
Lookup context;
public PartComparatorAction() {
context = Utilities.actionsGlobalContext();
putValue(NAME, Bundle.CTL_PartComparatorAction());
}
@Override
public boolean isEnabled() {
return context.lookupAll(Part.class).size() > 1;
}
@Override
public void actionPerformed(ActionEvent ev) {
StringBuilder sb = new StringBuilder();
for (Part part : context.lookupAll(Part.class)) {
sb.append(part.getName()).append(" ");
}
StatusDisplayer.getDefault().setStatusText(sb.toString());
}
}

Now, as is implied by the isEnabled method above, only when more than one object of interest is in the Lookup, will the Action be enabled. Below you can see that, in contrast to the earlier screenshot, the Action is disabled here because of the code above, which overrides the default behavior:

Note that in the second code scenario, you get hold of the Lookup yourself, you check whether the correct objects are available in the Lookup and then enable/disable as appropriate, and you also iterate through the objects in the Lookup to process them when the Action is invoked. In the default scenario, all this is done for you automatically, with the downside that even when only one object is available the Action will be enabled.

Also see:

Join the discussion

Comments ( 1 )
  • slawekmikula Friday, August 21, 2015

    Thanks Geertjan for switching back for a while from HTML5 etc. to to core RCP functions :)

    This and previous posts about Nodes gives me much new information how to handle this kind of functionality - e.g. enabling action - in much simplier way. I was using ContextAwareAction to provide this function.


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.