TransformAlwaysToConditionallyEnabledAction
Transforming CallableSystemAction Into CookieAction
Contributed By Varun Nischal
This is based on the existing tutorial. That tutorial, lets you get started with the NetBeans Plugin-Development, by creating an Always Enabled (see CallableSystemAction), without using any Wizard and that too smoothly.
[[{TableOfContentsTitle=TableOfContents} | {TableOfContents title='Table of Contents'}]]
Pre-requisites
If you don’t have prior experience with NetBeans Platform, read that tutorial. That's a must! Now, after you have done that, you might like to explore a bit more. So, you should give the following a read as well(if you want you can skip it for a while and read it along with my tutorial),
- This overview will quickly familiarize you with how NetBeans plug-in modules interact with the NetBeans infrastructure and with each other.
Now, you're ready for transformation. So, lets get started then!
What's CookieAction?
"An action dependent on the cookies of the selected nodes", as defined in the Javadocs! Exactly, so when you have done following transformation, you would see the action, but would be enabled, only when the node is selected, which supports particular Cookies. You will understand more, as you read further.
Getting Started
Here, we are going to transform an Action from one type to another, i.e. from CallableSystemAction TO CookieAction, sounds cool! Though, never tried! Well, here I am sharing with you another tips and tricks to make it possible, without using New File Type Wizard. We will make use of SayCheez.java, which was made in the reference tutorial.
Solution
So, to start with, remove the
CallableSystemActionand let the class {SayCheez} inherit from CookieAction, like this;
public final class SayCheez extends CookieAction {Now, don’t remove the already existing implementations of abstract methods of
CallableSystemAction,
@Override public void performAction() { //throw new UnsupportedOperationException("Not supported yet."); String msg = "I'm plugged in!"; NotifyDescriptor d = new NotifyDescriptor.Message(msg, NotifyDescriptor.INFORMATION_MESSAGE); DialogDisplayer.getDefault().notify(d); } @Override public String getName() { //throw new UnsupportedOperationException("Not supported yet."); return NbBundle.getMessage(SayCheez.class, "CTL_SayCheez"); } @Override public HelpCtx getHelpCtx() { //throw new UnsupportedOperationException("Not supported yet."); return HelpCtx.DEFAULT_HELP; } @Override protected String iconResource() { //Replace org/nvarun/tat with your path/to/icon //see attachments to download icon24_TransformAlwaysToConditionallyEnabledAction.png return "org/nvarun/tat/icon24_TransformAlwaysToConditionallyEnabledAction.png"; } // Newly Added @Override protected void initialize() { super.initialize(); // see org.openide.util.actions.SystemAction.iconResource() Javadoc for more details putValue("noIconInMenu", Boolean.TRUE); } // Newly Added @Override protected boolean asynchronous() { return false; } }Now, just add the following 2 methods TO let the
class SayCheezimplement all the abstract methods defined by {CookieAction}.
@Override protected Class<?>[] cookieClasses() { return new Class[]<tt>$Interface}.class}; } protected int mode() { return CookieAction.{$mode}; }
Please note, that {$Interface} needs to be replaced by appropriate interface, i.e. it could be either of the following Cookie class(es), which are basically interfaces/abstract class(es);
- 1. Project
- 2. OpenCookie
- 3. EditCookie
- 4. EditorCookie
- 5. DataObject (Abstract Class, NOT an Interface)
EditorCookiefor this transformation. Also, {$mode} needs to be replaced with either {MODE_EXACTLY_ONE}[[[1 | [1]] or MODE_ALL[[2].
- 1. User Selects One Node
- 2. User May Select Multiple Nodes
MODE_EXACTLY_ONEfor this transformation.
MODE_EXACTLY_ONE
- Action will be enabled if there is exactly one selected node and it supports the given cookies.
MODE_ALL
- Action will be enabled if there are one or more selected nodes and all of them support the given cookies.
EditorCookie! Now, alter the {performAction} method like this,
@Override protected void performAction(Node[] activatedNodes) { {$Interface} ref = activatedNodes[0].getLookup().lookup({$Interface}.class); // TODO use {$Interface} }Here, ref is basically the reference to either the interface/class being made, which is being assigned a subclass reference, it could be of great use. Now, add your code for
DialogDisplayerused in reference tutorial, in place of TODO comment.
String msg = "I'm plugged in!"; NotifyDescriptor d = new NotifyDescriptor.Message(msg, NotifyDescriptor.INFORMATION_MESSAGE); DialogDisplayer.getDefault().notify(d);
See, it was too easy! Anyways, the changes in XML Layer, which shall be done with respect to the change in the Action type, some of them are as follows and rest will be the mentioned in the next part of this series.
Tricks for Menu Item, Toolbar Button, Shortcut Keys
Trick #1
- As you had made a Global Menu Item and Toolbar Button with
CallableSystemAction
, so no changes required, for transformation.
Trick #2
- If you had made use of Shortcut Keys earlier, still no changes required.
org-nvarun-tat" with your package name, in which {SayCheez} resides.
Ready to Install/Reload
- Not yet, firstly, recall if you saw some red underlines present in the code, Add relevant Module Dependencies...(see tutorial) to get rid of them, so finally your code looks like this;
Transformed Source Code
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ //package {$your-package}; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.cookies.EditorCookie; import org.openide.nodes.Node; import org.openide.util.HelpCtx; import org.openide.util.NbBundle; import org.openide.util.actions.CookieAction; /** * * @author Varun Nischal (nvarun@NetBeans.org) */ public class SayCheez extends CookieAction { @Override protected void performAction(Node[] activatedNodes) { EditorCookie ref = activatedNodes[0].getLookup().lookup(EditorCookie.class); String msg = "I'm plugged in!"; NotifyDescriptor d = new NotifyDescriptor.Message(msg, NotifyDescriptor.INFORMATION_MESSAGE); DialogDisplayer.getDefault().notify(d); } @Override public String getName() { return NbBundle.getMessage(SayCheez.class, "CTL_SayCheez"); } @Override protected void initialize() { super.initialize(); // see org.openide.util.actions.SystemAction.iconResource() Javadoc for more details putValue("noIconInMenu", Boolean.TRUE); } @Override protected String iconResource() { //Replace org/nvarun/tat with your path/to/icon //see attachments to download icon24_TransformAlwaysToConditionallyEnabledAction.png return "org/nvarun/tat/icon24_TransformAlwaysToConditionallyEnabledAction.png"; } public HelpCtx getHelpCtx() { return HelpCtx.DEFAULT_HELP; } @Override protected boolean asynchronous() { return false; } @Override protected int mode() { return CookieAction.MODE_EXACTLY_ONE; } @Override protected Class<?>[] cookieClasses() { return new Class[]{EditorCookie.class}; } }
Module's XML Layer
- By the way, we missed one thing, what to do with the XML Layer. Don't worry, just see the following tips about your existing layer.xml, formed in reference tutorial. This is how it looks;
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem-1_1.dtd"> <filesystem> <folder name="Actions"> <folder name="Tools"> <file name="org-nvarun-tat-SayCheez.instance"/> </folder> </folder>
- Here, more tags are added, when you make this action, File Type OR Editor Context-sensitive;
<!--Code To Be Added-->
- Add relevant code, and you could also be ready for making it context-sensitive, however for time being, leave it as it is. I will tell you later how to add the code.
<folder name="Menu"> <folder name="Tools"> <file name="org-nvarun-tat-SayCheez.shadow"> <attr name="originalFile" stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/> <attr name="position" intvalue="150"/> </file> <file name="org-nvarun-tat-separatorAfter.instance"> <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/> <attr name="position" intvalue="175"/> </file> <file name="org-nvarun-tat-separatorBefore.instance"> <attr name="instanceClass" stringvalue="javax.swing.JSeparator"/> <attr name="position" intvalue="125"/> </file> </folder> </folder> <folder name="Toolbars"> <folder name="Build"> <file name="org-nvarun-tat-SayCheez.shadow"> <attr name="originalFile" stringvalue="Actions/Tools/org-nvarun-tat-SayCheez.instance"/> <attr name="position" intvalue="325"/> </file> </folder> </folder> </filesystem>
- Replace "
org-nvarun-tat
" with your package name, in which {SayCheez} resides.
Installing and Using the Plug-in Module
Refer to the reference tutorial, on how to Install and use your plug-in module. If you liked it, feel free to give feedback, because this tutorial can only get better, if you actively participate in community.
Version Compatability
Works with NetBeans 6.0, 6.1 as said above. Try this out on your version, and make sure to notify us if anything goes wrong!
Thanks for following, enjoy and have fun!