|
What this is
Other links
The source code/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun * Microsystems, Inc. All Rights Reserved. */ package org.openide.awt; import java.awt.Component; import java.awt.EventQueue; import java.awt.event.*; import java.io.*; import java.util.*; import javax.swing.*; import org.openide.ErrorManager; import org.openide.loaders.*; import org.openide.cookies.InstanceCookie; import org.openide.filesystems.FileObject; import org.openide.filesystems.Repository; import org.openide.nodes.*; import org.openide.util.actions.Presenter; import org.openide.util.*; /** An extended version of swing's JMenuBar. This menubar can * load its content from the folder where its "disk image" is stored.
In subfolders the following objects are recognized and added to submenus:
MenuBar from given folder.
* @param folder The folder from which to create the content of the menubar.
* If the parameter is null, default menu folder is obtained.
*/
public MenuBar(DataFolder folder) {
super();
setBorder (javax.swing.BorderFactory.createEmptyBorder());
DataFolder theFolder = folder;
if (theFolder == null) {
FileObject fo = Repository.getDefault().getDefaultFileSystem().findResource("Menu");
if (fo == null) throw new IllegalStateException("No Menu/"); // NOI18N
theFolder = DataFolder.findFolder(fo);
}
startLoading(theFolder);
if(folder != null) {
getAccessibleContext().setAccessibleDescription(folder.getName());
}
}
public void addImpl (Component c, Object constraint, int idx) {
//Issue 17559, Apple's screen menu bar implementation blindly casts
//added components as instances of JMenu. Silently ignore any non-menu
//items on Mac if the screen menu flag is true.
if (Utilities.getOperatingSystem() == Utilities.OS_MAC &&
Boolean.getBoolean ("apple.laf.useScreenMenuBar")) { //NOI18N
if (!(c instanceof JMenu)) {
return;
}
}
super.addImpl (c, constraint, idx);
}
/** Blocks until the menubar is completely created. */
public void waitFinished () {
menuBarFolder.instanceFinished();
}
/** Saves the contents of this object to the specified stream.
*
* @exception IOException Includes any I/O exceptions that may occur
*/
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(menuBarFolder.getFolder());
}
/**
* Restores contents of this object from the specified stream.
*
* @exception ClassNotFoundException If the class for an object being
* restored cannot be found.
*/
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
startLoading((DataFolder)in.readObject());
}
/** Starts loading of this menu from menu folder */
void startLoading (final DataFolder folder) {
menuBarFolder = new MenuBarFolder(folder);
}
/** Convert an array of instance cookies to instances, adds them
* to given list.
* @param arr array of instance cookies
* @param list list to add created objects to
*/
static void allInstances (InstanceCookie[] arr, java.util.List list) {
ErrorManager err = ErrorManager.getDefault();
Exception ex = null;
for (int i = 0; i < arr.length; i++) {
Exception newEx = null;
try {
Object o = arr[i].instanceCreate();
list.add (o);
} catch (ClassNotFoundException e) {
newEx = e;
} catch (IOException e) {
newEx = e;
}
if (newEx != null) {
ErrorManager.Annotation[] anns = err.findAnnotations(newEx);
if (anns == null || anns.length == 0) {
// if the exception is not annotated, assign it low
// priority
err.annotate(newEx, err.INFORMATIONAL, null, null, null, null);
}
err.copyAnnotation(newEx, ex);
ex = newEx;
}
}
// if there was an exception => notify it
if (ex != null) {
err.notify (ex);
}
}
/** This class can be used to fill the content of given
* MenuBar from the given DataFolder .
*/
private final class MenuBarFolder extends FolderInstance {
/** List of the components this FolderInstance manages. */
private ArrayList managed = new ArrayList();
/** Creates a new menubar folder on the specified DataFolder .
* @param folder a DataFolder to work with
*/
public MenuBarFolder (final DataFolder folder) {
super(folder);
recreate ();
}
/** Removes the components added by this FolderInstance from the MenuBar.
* Called when menu is refreshed. */
private void cleanUp() {
for (Iterator it = managed.iterator(); it.hasNext(); ) {
MenuBar.this.remove((Component)it.next());
}
managed.clear();
}
/** Adds the component to the MenuBar after the last added one */
private void addComponent (Component c) {
MenuBar.this.add(c, managed.size());
managed.add(c);
}
/** Full name of the data folder's primary file separated by dots.
* @return the name
*/
public String instanceName () {
return MenuBar.class.getName();
}
/** Returns the root class of all objects.
* @return MenuBar.class
*/
public Class instanceClass () {
return MenuBar.class;
}
/** Accepts only cookies that can provide a Component
* or a Presenter.Toolbar .
* @param cookie the instance cookie to test
* @return true if the cookie is accepted.
*/
protected InstanceCookie acceptCookie (InstanceCookie cookie)
throws IOException, ClassNotFoundException {
Class cls = cookie.instanceClass();
return Component.class.isAssignableFrom(cls) ||
Presenter.Toolbar.class.isAssignableFrom(cls)
? cookie : null;
}
/** Returns an InstanceCookie of a JMenu
* for the specified DataFolder .
*
* @param df a DataFolder to create the cookie for
* @return an InstanceCookie for the specified folder
*/
protected InstanceCookie acceptFolder (DataFolder df) {
return new InstanceSupport.Instance(new LazyMenu(df, false));
}
/** Updates the MenuBar represented by this folder.
*
* @param cookies array of instance cookies for the folder
* @return the updated MenuBar representee
*/
protected Object createInstance (InstanceCookie[] cookies)
throws IOException, ClassNotFoundException {
final LinkedList ll = new LinkedList ();
allInstances (cookies, ll);
final MenuBar mb = MenuBar.this;
cleanUp(); //remove the stuff we've added last time
// fill with new content
Iterator it = ll.iterator ();
while (it.hasNext()) {
Object obj = it.next ();
if (obj instanceof Presenter.Toolbar) {
obj = ((Presenter.Toolbar)obj).getToolbarPresenter();
if (obj instanceof JButton) { // tune the presenter a bit
((JButton)obj).setBorderPainted(false);
}
}
if (obj instanceof Component) addComponent((Component) obj);
}
mb.validate();
mb.repaint();
return mb;
}
/** For outer class access to the data folder */
DataFolder getFolder () {
return folder;
}
/** Recreate the instance in AWT thread. */
protected Task postCreationTask (Runnable run) {
return new AWTTask (run);
}
}
/** Menu based on the folder content whith lazy items creation. */
private static class LazyMenu extends JMenuPlus implements NodeListener, Runnable {
DataFolder master;
boolean icon;
MenuFolder slave;
/** Constructor. */
public LazyMenu(final DataFolder df, boolean icon) {
master = df;
this.icon = icon;
// Listen for changes in Node's DisplayName/Icon
Node n = master.getNodeDelegate ();
n.addNodeListener (org.openide.nodes.NodeOp.weakNodeListener (this, n));
updateProps();
}
private void updateProps() {
// set the text and be aware of mnemonics
Node n = master.getNodeDelegate ();
Actions.setMenuText(this, n.getDisplayName (), true);
if (icon) setIcon (new ImageIcon (
n.getIcon (java.beans.BeanInfo.ICON_COLOR_16x16)));
}
/** Update the properties. Exported via Runnable interface so it
* can be rescheduled. */
public void run() {
updateProps();
}
/** If the display name changes, than change the name of the menu.*/
public void propertyChange (java.beans.PropertyChangeEvent ev) {
if (
Node.PROP_DISPLAY_NAME.equals (ev.getPropertyName ()) ||
Node.PROP_NAME.equals (ev.getPropertyName ()) ||
Node.PROP_ICON.equals (ev.getPropertyName ())
) {
// update the properties in AWT queue
if (EventQueue.isDispatchThread ()) {
updateProps(); // do the update synchronously
} else {
EventQueue.invokeLater (this);
}
}
}
// The rest of the NodeListener implementation
public void childrenAdded (NodeMemberEvent ev) {}
public void childrenRemoved (NodeMemberEvent ev) {}
public void childrenReordered(NodeReorderEvent ev) {}
public void nodeDestroyed (NodeEvent ev) {}
/** Overrides superclass method to lazy create popup. */
public JPopupMenu getPopupMenu() {
doInitialize();
return super.getPopupMenu();
}
private void doInitialize() {
if(slave == null) {
slave = new MenuFolder(); // will do the tracking
slave.waitFinished();
}
}
/** This class can be used to update a JMenu instance
* from the given DataFolder .
*/
private class MenuFolder extends FolderInstance {
/**
* Start tracking the content of the master folder.
* It will cause initial update of the Menu
*/
public MenuFolder () {
super(master);
recreate ();
}
/** The name of the menu
* @return the name
*/
public String instanceName () {
return LazyMenu.class.getName();
}
/** Returns the class of represented menu.
* @return JMenu.class
*/
public Class instanceClass () {
return JMenu.class;
}
/** If no instance cookie, tries to create execution action on the
* data object.
*/
protected InstanceCookie acceptDataObject (DataObject dob) {
InstanceCookie ic = super.acceptDataObject (dob);
if (ic == null) {
JMenuItem item = ExecBridge.createMenuItem (dob);
return item != null ? new InstanceSupport.Instance (item) : null;
} else {
return ic;
}
}
/**
* Accepts only cookies that can provide Menu .
* @param cookie an InstanceCookie to test
* @return true if the cookie can provide accepted instances
*/
protected InstanceCookie acceptCookie(InstanceCookie cookie)
throws IOException, ClassNotFoundException {
// [pnejedly] Don't try to optimize this by InstanceCookie.Of
// It will load the classes few ms later from instanceCreate
// anyway and more instanceOf calls take longer
Class c = cookie.instanceClass();
boolean is =
Presenter.Menu.class.isAssignableFrom (c) ||
JMenuItem.class.isAssignableFrom (c) ||
JSeparator.class.isAssignableFrom (c) ||
Action.class.isAssignableFrom (c);
return is ? cookie : null;
}
/**
* Returns a Menu.Folder cookie for the specified
* DataFolder .
* @param df a DataFolder to create the cookie for
* @return a Menu.Folder for the specified folder
*/
protected InstanceCookie acceptFolder(DataFolder df) {
return new InstanceSupport.Instance(new LazyMenu(df, true));
}
/** Updates the JMenu represented by this folder.
* @param cookies array of instance cookies for the folder
* @return the updated JMenu representee
*/
protected Object createInstance(InstanceCookie[] cookies)
throws IOException, ClassNotFoundException {
JMenu m = LazyMenu.this;
//synchronized (this) { // see #15917 - attachment from 2001/09/27
LinkedList cInstances = new LinkedList();
allInstances (cookies, cInstances);
m.removeAll();
// #11848, #13013. Enablement should be set immediatelly,
// popup will be created on-demand.
// m.setEnabled(!cInstances.isEmpty());
// TODO: fill it with empty sign instead
if(cInstances.isEmpty()) {
JMenuItem item = new JMenuItem(
NbBundle.getMessage(DataObject.class, "CTL_EmptyMenu"));
item.setEnabled(false);
m.add(item);
}
// clear first - refresh the menu's content
boolean addSeparator = false;
// sync to prevent from concurrent modifications of
// cookie instances list
Iterator it = cInstances.iterator();
while (it.hasNext()) {
Object obj = it.next();
if (obj instanceof Presenter.Menu) {
obj = ((Presenter.Menu)obj).getMenuPresenter();
}
if (obj instanceof JMenuItem) {
if(addSeparator) {
m.addSeparator();
addSeparator = false;
}
m.add((JMenuItem)obj);
} else if (obj instanceof JSeparator) {
addSeparator = getMenuComponentCount() > 0;
} else if (obj instanceof Action) {
if(addSeparator) {
m.addSeparator();
addSeparator = false;
}
Action a = (Action)obj;
JMenuItem item = new JMenuItem ();
Actions.connect (item, a, false);
m.add (item);
}
}
return m;
}
/** Recreate the instance in AWT thread.
*/
protected Task postCreationTask (Runnable run) {
return new AWTTask (run);
}
}
}
}
|
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.