DevFaqDropdownMenuAddToolbarEnabled

(Difference between revisions)
(How do I add a dropdown menu to toolbar that is selectively enabled/disabled?)
 
Line 6: Line 6:
In this case, your action also needs to implement [http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/ContextAwareAction.html ContextAwareAction].  A ContextAwareAction is a factory for other Action instances which are tied to a specific Lookup (so that, if selection changes after the popup menu for a Node is shown, the Action does not operate on the wrong object).  You can start with a subclass of javax.swing.AbstractAction, and you will need two constructors:
In this case, your action also needs to implement [http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/ContextAwareAction.html ContextAwareAction].  A ContextAwareAction is a factory for other Action instances which are tied to a specific Lookup (so that, if selection changes after the popup menu for a Node is shown, the Action does not operate on the wrong object).  You can start with a subclass of javax.swing.AbstractAction, and you will need two constructors:
-
<pre>
+
<source lang="java">
private final Lookup lookup;
private final Lookup lookup;
public MyAction() {
public MyAction() {
Line 19: Line 19:
   //set the initial enabled state
   //set the initial enabled state
   setEnabled(false);
   setEnabled(false);
-
}</pre>
+
}</source>
You will also need to implement the one method of ContextAwareAction:
You will also need to implement the one method of ContextAwareAction:
-
<pre>public Action createContextAwareInstance(Lookup actionContext) {
+
<source lang="java">
 +
public Action createContextAwareInstance(Lookup actionContext) {
   return new MyAction(actionContext);
   return new MyAction(actionContext);
-
}</pre>
+
}
 +
</source>
To enable and disable the action, we will need to listen on the lookup for the presence or absence of some object type.  If it is there, the action will be enabled;  if it is not, it will be disabled.
To enable and disable the action, we will need to listen on the lookup for the presence or absence of some object type.  If it is there, the action will be enabled;  if it is not, it will be disabled.
Line 31: Line 33:
First, we must modify our class signature to implement LookupListener:
First, we must modify our class signature to implement LookupListener:
-
<pre>
+
<source lang="java">
public class MyAction extends AbstractAction implements ContextAwareAction, LookupListener, Presenter.Toolbar {
public class MyAction extends AbstractAction implements ContextAwareAction, LookupListener, Presenter.Toolbar {
-
...</pre>
+
...</source>
Now we will handle listening on the Lookup.Result.  We want to stop listening to it when there are no PropertyChangeListeners left, so that our action can be garbage collected if not in use:
Now we will handle listening on the Lookup.Result.  We want to stop listening to it when there are no PropertyChangeListeners left, so that our action can be garbage collected if not in use:
-
<pre>
+
<source lang="java">
private LookupResult<? extends DataObject> res;
private LookupResult<? extends DataObject> res;
Line 57: Line 59:
   }
   }
}
}
-
</pre>
+
</source>
Now comes the actual implementation of LookupListener:
Now comes the actual implementation of LookupListener:
-
<pre>
+
<source lang="java">
public void resultChanged(LookupEvent ev) {
public void resultChanged(LookupEvent ev) {
   setEnabled(!res.allItems().isEmpty());
   setEnabled(!res.allItems().isEmpty());
}
}
-
</pre>
+
</source>
A bit of bookkeeping is required in getToolbarPresenter() - at least until [https://netbeans.org/bugzilla/show_bug.cgi?id=179814 issue 179814] is fixed, we will need to manually enable/disable the actions for our menu items:
A bit of bookkeeping is required in getToolbarPresenter() - at least until [https://netbeans.org/bugzilla/show_bug.cgi?id=179814 issue 179814] is fixed, we will need to manually enable/disable the actions for our menu items:
-
<pre>
+
<source lang="java">
   private final Set<Action> popupMenuActions = new WeakSet<Action>();
   private final Set<Action> popupMenuActions = new WeakSet<Action>();
   @Override
   @Override
Line 106: Line 108:
               ob.getName()));
               ob.getName()));
     }
     }
-
   }</pre>
+
   }</source>
If we want the drop-down button to do something when it is clicked on the right side (not in the popup area with the down-arrow), we can implement actionPerformed(ActionEvent) to do whatever that is.
If we want the drop-down button to do something when it is clicked on the right side (not in the popup area with the down-arrow), we can implement actionPerformed(ActionEvent) to do whatever that is.
For an older detailed example of manually creating a context-aware drop-down toolbar button (without DropDownButtonFactory, circa NetBeans 6.0), see [http://article.gmane.org/gmane.comp.java.netbeans.modules.openide.devel/35436 see this post], posted in [http://thread.gmane.org/gmane.comp.java.netbeans.modules.openide.devel/35424 on the old dev@openide NetBeans mailing lists].
For an older detailed example of manually creating a context-aware drop-down toolbar button (without DropDownButtonFactory, circa NetBeans 6.0), see [http://article.gmane.org/gmane.comp.java.netbeans.modules.openide.devel/35436 see this post], posted in [http://thread.gmane.org/gmane.comp.java.netbeans.modules.openide.devel/35424 on the old dev@openide NetBeans mailing lists].

Current revision as of 20:35, 24 July 2010

How do I add a dropdown menu to toolbar that is selectively enabled/disabled?

Create an Action as described in the general FAQ for to add a dropdown menu to a toolbar.

In this case, your action also needs to implement ContextAwareAction. A ContextAwareAction is a factory for other Action instances which are tied to a specific Lookup (so that, if selection changes after the popup menu for a Node is shown, the Action does not operate on the wrong object). You can start with a subclass of javax.swing.AbstractAction, and you will need two constructors:

private final Lookup lookup;
public MyAction() {
  this (Utilities.actionsGlobalContext());
}
 
private MyAction(Lookup lookup) {
  this.lookup = lookup;
  Icon icon = ImageUtilities.image2Icon(
    ImageUtilities.loadImage("com/foo/icon.gif"));
  putValue(SMALL_ICON, icon);
  //set the initial enabled state
  setEnabled(false);
}

You will also need to implement the one method of ContextAwareAction:

public Action createContextAwareInstance(Lookup actionContext) {
  return new MyAction(actionContext);
}

To enable and disable the action, we will need to listen on the lookup for the presence or absence of some object type. If it is there, the action will be enabled; if it is not, it will be disabled.

Since we do not want to start listening on the global selection context until something actually cares whether the action is enabled or not, so we will override add/removePropertyChangeListener() to notice that and listen or not.

First, we must modify our class signature to implement LookupListener:

public class MyAction extends AbstractAction implements ContextAwareAction, LookupListener, Presenter.Toolbar {
...

Now we will handle listening on the Lookup.Result. We want to stop listening to it when there are no PropertyChangeListeners left, so that our action can be garbage collected if not in use:

private LookupResult<? extends DataObject> res;
 
@Override
public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
  boolean startListening = getPropertyChangeListeners().length == 0;
  super.addPropertyChangeListener(l);
  if (startListening) {
    res = lookup.lookupResult(MyType.class);
    res.addLookupListener(this);
  }
}
 
@Override
public synchronized void removePropertyChangeListener(PropertyChangeListener l) {
  super.removePropertyChangeListener(l);
  if (getPropertyChangeListeners().length == 0) {
    res.removeLookupListener(this);
    res = null;
  }
}

Now comes the actual implementation of LookupListener:

public void resultChanged(LookupEvent ev) {
  setEnabled(!res.allItems().isEmpty());
}

A bit of bookkeeping is required in getToolbarPresenter() - at least until issue 179814 is fixed, we will need to manually enable/disable the actions for our menu items:

  private final Set<Action> popupMenuActions = new WeakSet<Action>();
  @Override
  public Component getToolbarPresenter() {
    JPopupMenu menu = new JPopupMenu();
    Action actionOne = new DemoMenuAction("One");
    Action actionTwo = new DemoMenuAction("Two");
    menu.add(new JMenuItem(actionOne));
    menu.add(new JMenuItem(actionTwo));
    popupMenuActions.add(actionOne);
    popupMenuActions.add(actionTwo);
    //add action listeners to the menu items to do what you want
    Icon icon = (Icon) getValue(SMALL_ICON);
    JButton result = DropDownButtonFactory.createDropDownButton(icon, menu);
    result.setAction(this);
    return result;
  }
 
  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);
    for (Action a : popupMenuActions) {
      if (a != null) { //WeakSet iterator can return null
        a.setEnabled(enabled);
      }
    }
  }
 
  private class DemoMenuAction extends AbstractAction {
    DemoMenuAction(String name) {
      putValue(NAME, name);
      setEnabled (MyAction.this.isEnabled());
    }
 
    @Override
    public void actionPerformed(ActionEvent e) {
      DataObject ob = res.allInstances().iterator().next();
      DialogDisplayer.getDefault().notify(new NotifyDescriptor.Message(
              ob.getName()));
    }
  }

If we want the drop-down button to do something when it is clicked on the right side (not in the popup area with the down-arrow), we can implement actionPerformed(ActionEvent) to do whatever that is.

For an older detailed example of manually creating a context-aware drop-down toolbar button (without DropDownButtonFactory, circa NetBeans 6.0), see see this post, posted in on the old dev@openide NetBeans mailing lists.

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