alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

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.

* Moreover, menu is Externalizable to restore its persistent * state with minimal storage expensiveness. * * The MenuBar recognizes following objects in the folder:

    *
  • subfolders - they're turned into top-level JMenu instances *
  • instances of Component - they're added directly * to the menubar. *
  • instances of Presenter.Toolbar - their toolbar presenter * is added to the menubar. *
* before OpenAPI version 3.2, only subfolders were recognized. * *

In subfolders the following objects are recognized and added to submenus:

    *
  • nested subfolders - they're turned into submenus *
  • instances of Presenter.Menu *
  • instances of JMenuItem *
  • instances of JSeparator *
  • instances of Action *
  • executable DataObjects *
* * @author David Peroutka, Dafe Simonek, Petr Nejedly */ public class MenuBar extends JMenuBar implements Externalizable { /** the folder which represents and loads content of the menubar */ private MenuBarFolder menuBarFolder; static final long serialVersionUID =-4721949937356581268L; /** Don't call this constructor or this class will not get * initialized properly. This constructor is only for externalization. */ public MenuBar() { super(); } /** Creates a new 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

 

new blog posts

 

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.