CreateConditionallyEnabledActionFromScratch

Creating Conditionally Enabled Action From Scratch

Contributed By Varun Nischal


This tutorial is based on an existing tutorial. That tutorial, lets you get started with the NetBeans Plugin-Development, as easily as possible.

[[{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 plugin-development. So, lets get started then!


Getting Started


Aim of this tutorial, is to let you make an Conditionally Enabled (see CookieAction) Action, without using New File Type Wizard.

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.

Creating Project


So, here are the following steps to create a NetBeans Module;

  1. Goto File > New Project...
  2. Choose NetBeans Modules from Categories and then, select Module from related Projects.
  3. Wizard opens...Now, follow steps as mentioned in this tutorial.

Creating a Menu Item and Toolbar Button


This is what existing tutorial states,

You use the NetBeans plug-in module file templates to create the basis of the module's functionality. When you use a file template, the IDE registers the item that you create in the layer.xml file. After using a wizard to create the file template, you use the NetBeans API List to continue developing the module.

We won't be using any Wizard, as said before. So, follow these steps to create your Action;

  1. Right-click Project Node, pops-up a Context-Menu!
  2. Select New > Java Class...
  3. Write SayCheez in Class Name and press Finish.

Without Using Action Wizard


The existing tutorial creates Action using New File Type Wizard!

Now, we will extend
SayCheez
by {CookieAction}, and you would be prompted by NetBeans, to implement all abstract methods. Press Alt-Insert, let the IDE implement them.

So, you can see the following structure of SayCheez.java;


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

//package {$your-package};

import org.openide.nodes.Node;
import org.openide.util.HelpCtx;
import org.openide.util.actions.CookieAction;

/**
 *
 * @author Varun Nischal (nvarun@NetBeans.org)
 */
public class SayCheez extends CookieAction {

    @Override
    protected int mode() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    protected Class<?>[] cookieClasses() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    protected void performAction(Node[] arg0) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String getName() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public HelpCtx getHelpCtx() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

}

Do following changes in these methods;

  • mode
    @Override
    protected int mode() {
        //throw new UnsupportedOperationException("Not supported yet.");
        return CookieAction.{$mode};
    }
  • {$mode} needs to be replaced with either
     MODE_EXACTLY_ONE
    [[[1 | [1]] or {MODE_ALL}[[2].
    1. User Selects One Node (I'm using this)
    2. User May Select Multiple Nodes
  • cookieClasses
    @Override
    protected Class<?>[] cookieClasses() {
        //throw new UnsupportedOperationException("Not supported yet.");
        return new Class[]<tt>$Interface}.class};
    }
  • 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
      (I'm using this)
    5. DataObject
      (Abstract Class, NOT an Interface)
  • I will be using
    MODE_EXACTLY_ONE
    for 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.
  • In our case, its
    EditorCookie
    ! Now, alter the {performAction} method like this,
Note- as I have choosen
EditorCookie
, means Action would be enabled if there's atleast a single file opened in editor, else it would be disabled. Similarly for others as well!
  • performAction
    @Override
    protected void performAction() {
        EditorCookie ref = activatedNodes[0].getLookup().lookup(EditorCookie.class); 
        //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);  
    }
  • getName
    @Override
    public String getName() {
        //throw new UnsupportedOperationException("Not supported yet.");
        return NbBundle.getMessage(SayCheez.class, "CTL_SayCheez");
    }

  • getHelpCtx
Its declared in HelpCtx.Provider which is implemented by this class.
    @Override
    public HelpCtx getHelpCtx() {
        //throw new UnsupportedOperationException("Not supported yet.");
        return HelpCtx.DEFAULT_HELP;
    }

You must be wondering what to do with,
NbBundle.getMessage(SayCheez.class, "CTL_SayCheez");
No need to worry, when you first created this project, a file called Bundle.properties gets created into <tt>$your-package</tt>, where SayCheez.java is present. Just add the following line into properties file, and continue coding!
CTL_SayCheez=Say Cheez...
# You may change the content on the right side of this assignment operator.

Add following methods

  • initialize
Initialize the action. The default implementation just enabled it. Read more...
    @Override
    protected void initialize() {
        super.initialize();
        // see org.openide.util.actions.SystemAction.iconResource() Javadoc for more details
        putValue("noIconInMenu", Boolean.TRUE);
    }    
  • asynchronous
If true, this action should be performed asynchronously in a private thread. Read more...
    //Added
    @Override
    protected boolean asynchronous() {
        return false;
    }

Where's the Icon?

  • Hey, this is the question, asked by the IDE, when you create a Global Toolbar Button using Action Wizard. Here, as we are doing everything from scratch, without using any Wizard.
  • So, you need to keep in mind, that Toolbar Button is visible, only if you have an icon for it.
  • So, add the following code, i.e. override
    iconResource()
    @Override
    protected String iconResource() {
        //Replace org/nvarun/tat with your path/to/icon
        return "org/nvarun/tat/icon24_CreateConditionallyEnabledActionFromScratch.png";
    }
    //see attachments to download icon24_CreateConditionallyEnabledActionFromScratch.png

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;

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 editorCookie = activatedNodes[0].getLookup().lookup(EditorCookie.class);
        //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
    protected int mode() {
        //throw new UnsupportedOperationException("Not supported yet.");
        return CookieAction.MODE_EXACTLY_ONE;
    }

    @Override
    protected Class<?>[] cookieClasses() {
        //throw new UnsupportedOperationException("Not supported yet.");
        return new Class[]{EditorCookie.class};
    }

    @Override	
    public String getName() {
        //throw new UnsupportedOperationException("Not supported yet.");
        return NbBundle.getMessage(SayCheez.class, "CTL_SayCheez");
    }

    // Newly Added
    @Override
    protected void initialize() {
        super.initialize();
        // see org.openide.util.actions.SystemAction.iconResource() Javadoc for more details
        putValue("noIconInMenu", Boolean.TRUE);
    }    

    @Override
    public HelpCtx getHelpCtx() {
        //throw new UnsupportedOperationException("Not supported yet.");
        return HelpCtx.DEFAULT_HELP;
    }

    // Newly Added
    @Override
    protected boolean asynchronous() {
        return false;
    }
}

Module's XML Layer

  • By the way, we missed one thing, register this Action in XML Layer. Don't worry, its easy, open your layer.xml. Add the following code within
    filesystem
    tags;

    <folder name="Actions">
        <folder name="Tools">        
            <file name="org-nvarun-tat-SayCheez.instance"/>
        </folder>
    </folder>
    <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>

  • Replace "org-nvarun-tat" with your package name, in which
    SayCheez 
    resides.

Installing and Using the Plug-in Module


Refer to this tutorial, on how to Install and use your plug-in module. If you liked it, feel free 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!

Thank you!

Not logged in. Log in, Register

By use of this website, you agree to the NetBeans Policies and Terms of Use. © 2012, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo