1999-01-16 05:24:25 +00:00
|
|
|
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License
|
|
|
|
* Version 1.0 (the "License"); you may not use this file except in
|
|
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS"
|
|
|
|
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
|
|
|
* the License for the specific language governing rights and limitations
|
|
|
|
* under the License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Grendel mail/news client.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
|
|
* Corporation. Portions created by Netscape are Copyright (C) 1997
|
|
|
|
* Netscape Communications Corporation. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Created: Giao Nguyen <grail@cafebabe.org>, 13 Jan 1999.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package grendel.ui;
|
|
|
|
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
import java.net.URL;
|
|
|
|
import java.util.Hashtable;
|
|
|
|
import java.util.Properties;
|
|
|
|
|
1999-02-09 08:05:42 +00:00
|
|
|
import java.awt.Container;
|
|
|
|
|
1999-01-16 05:24:25 +00:00
|
|
|
import javax.swing.JComponent;
|
1999-01-20 06:40:16 +00:00
|
|
|
import javax.swing.JFrame;
|
1999-01-16 05:24:25 +00:00
|
|
|
import javax.swing.JMenuBar;
|
|
|
|
import javax.swing.JMenu;
|
|
|
|
import javax.swing.JMenuItem;
|
|
|
|
import javax.swing.JSeparator;
|
|
|
|
import javax.swing.JCheckBoxMenuItem;
|
|
|
|
import javax.swing.JRadioButtonMenuItem;
|
|
|
|
import javax.swing.ButtonGroup;
|
|
|
|
|
|
|
|
import org.w3c.dom.Element;
|
|
|
|
import org.w3c.dom.Node;
|
|
|
|
|
|
|
|
import com.sun.xml.parser.Resolver;
|
|
|
|
import com.sun.xml.parser.Parser;
|
|
|
|
import com.sun.xml.tree.XmlDocument;
|
1999-02-28 23:53:40 +00:00
|
|
|
// import com.sun.xml.tree.XmlDocumentBuilder;
|
1999-01-16 05:24:25 +00:00
|
|
|
import com.sun.xml.tree.TreeWalker;
|
|
|
|
import org.xml.sax.InputSource;
|
|
|
|
import org.xml.sax.SAXException;
|
|
|
|
import org.xml.sax.SAXParseException;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a menu bar from an XML data source. This builder supports:
|
|
|
|
* <UL>
|
|
|
|
* <LI>Text label cross referencing to a properties file.
|
1999-01-20 06:40:16 +00:00
|
|
|
* <LI>Action lookups.
|
1999-01-16 05:24:25 +00:00
|
|
|
* </UL>
|
|
|
|
*/
|
1999-02-09 08:05:42 +00:00
|
|
|
public class XMLMenuBuilder extends XMLWidgetBuilder {
|
1999-01-16 05:24:25 +00:00
|
|
|
static final String id_attr = "id";
|
|
|
|
static final String menu_tag = "menu";
|
|
|
|
static final String label_attr = "label";
|
|
|
|
static final String separator_attr = "separator";
|
|
|
|
static final String menuitem_tag = "menuitem";
|
|
|
|
static final String checkbox_attr = "checkbox";
|
|
|
|
static final String radio_attr = "radio";
|
|
|
|
static final String group_attr = "group";
|
|
|
|
static final String accel_attr = "accel";
|
|
|
|
static final String type_attr = "type";
|
|
|
|
|
1999-03-06 07:08:01 +00:00
|
|
|
/**
|
|
|
|
* The button group indexed by its name.
|
|
|
|
*/
|
|
|
|
protected Hashtable button_group;
|
|
|
|
|
1999-01-20 06:40:16 +00:00
|
|
|
Hashtable actions;
|
1999-01-16 05:24:25 +00:00
|
|
|
JMenuBar component;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a menu builder which operates on XML formatted data
|
1999-01-20 06:40:16 +00:00
|
|
|
*
|
1999-02-09 08:05:42 +00:00
|
|
|
* @param ref the reference point for properties location
|
1999-01-20 06:40:16 +00:00
|
|
|
* @param actionList array of UIAction objects to map to
|
1999-01-16 05:24:25 +00:00
|
|
|
*/
|
1999-02-09 08:05:42 +00:00
|
|
|
public XMLMenuBuilder(Class ref, UIAction[] actionList) {
|
1999-01-16 05:24:25 +00:00
|
|
|
button_group = new Hashtable();
|
1999-01-20 06:40:16 +00:00
|
|
|
actions = new Hashtable();
|
1999-02-09 08:05:42 +00:00
|
|
|
this.ref = ref;
|
1999-01-16 05:24:25 +00:00
|
|
|
|
1999-01-20 06:40:16 +00:00
|
|
|
if (actionList != null) {
|
|
|
|
for (int i = 0; i < actionList.length; i++) {
|
|
|
|
actions.put(actionList[i].getName(), actionList[i]);
|
|
|
|
}
|
|
|
|
}
|
1999-02-09 08:05:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a menu builder which operates on XML formatted data
|
|
|
|
*
|
|
|
|
* @param frame reference point for properties location
|
|
|
|
* @param actionList array of UIAction objects to map to
|
|
|
|
*/
|
|
|
|
public XMLMenuBuilder(JFrame frame, UIAction[] actionList) {
|
|
|
|
this(frame.getClass(), actionList);
|
1999-01-16 05:24:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read the input stream and build a menubar from it
|
|
|
|
*
|
|
|
|
* @param stream the stream containing the XML data
|
|
|
|
*/
|
|
|
|
public void buildFrom(InputStream stream) {
|
|
|
|
XmlDocument doc;
|
|
|
|
TreeWalker tree;
|
|
|
|
Node node;
|
|
|
|
URL linkURL;
|
|
|
|
Element current;
|
|
|
|
|
|
|
|
try {
|
1999-02-28 23:53:40 +00:00
|
|
|
doc = XmlDocument.createXmlDocument(stream, false);
|
1999-01-16 05:24:25 +00:00
|
|
|
current = doc.getDocumentElement();
|
|
|
|
tree = new TreeWalker(current);
|
|
|
|
|
|
|
|
// get the link tag for this file
|
1999-01-29 06:42:41 +00:00
|
|
|
// node = tree.getNextElement("head");
|
1999-01-16 05:24:25 +00:00
|
|
|
// get into head and get the first element
|
1999-01-29 06:42:41 +00:00
|
|
|
node =
|
|
|
|
tree.getNextElement("head").getElementsByTagName("link").item(0);
|
|
|
|
// node = node.getFirstChild();
|
|
|
|
// node = node.getNextSibling();
|
1999-01-16 05:24:25 +00:00
|
|
|
|
|
|
|
// set the configuration contained in this node
|
|
|
|
setConfiguration((Element)node);
|
|
|
|
|
|
|
|
// skip to the body
|
|
|
|
buildFrom(new TreeWalker(tree.getNextElement("body")));
|
|
|
|
} catch (Throwable t) {
|
|
|
|
t.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-02-09 08:05:42 +00:00
|
|
|
|
1999-01-16 05:24:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a menu bar from the data in the tree
|
|
|
|
*
|
|
|
|
* @param tree the tree containing the full set of a menubar tag
|
|
|
|
*/
|
|
|
|
public void buildFrom(TreeWalker tree) {
|
|
|
|
Element current ;
|
|
|
|
Node node;
|
|
|
|
|
|
|
|
// skip to the "menubar" tag
|
1999-01-24 12:02:31 +00:00
|
|
|
node = tree.getNextElement("menubar");
|
|
|
|
current = (Element)node;
|
1999-01-16 05:24:25 +00:00
|
|
|
component = new JMenuBar();
|
|
|
|
|
|
|
|
// iterate through every node
|
1999-01-24 12:02:31 +00:00
|
|
|
node = node.getFirstChild();
|
|
|
|
node = node.getNextSibling();
|
|
|
|
|
|
|
|
// at the very first menu tag
|
1999-01-16 05:24:25 +00:00
|
|
|
while (node != null) {
|
1999-01-24 12:02:31 +00:00
|
|
|
processNode(node, component);
|
|
|
|
node = node.getNextSibling();
|
1999-01-16 05:24:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return the menubar built by this builder
|
|
|
|
*/
|
1999-01-20 06:40:16 +00:00
|
|
|
public JMenuBar getComponent() {
|
1999-01-16 05:24:25 +00:00
|
|
|
return component;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void configureForOwner(JComponent component) {
|
|
|
|
}
|
|
|
|
|
|
|
|
public void associateClass(Class c, Object o) {
|
|
|
|
}
|
|
|
|
|
1999-03-06 07:08:01 +00:00
|
|
|
/**
|
|
|
|
* Process the node. This method will call <code>buildComponent</code>.
|
|
|
|
* @param node the node to process
|
|
|
|
* @param parent the parent component to add the information from
|
|
|
|
* this node to
|
|
|
|
*/
|
1999-01-24 12:02:31 +00:00
|
|
|
protected void processNode(Node node, JComponent parent) {
|
1999-01-16 05:24:25 +00:00
|
|
|
JComponent container = null;
|
|
|
|
JComponent item = null;
|
|
|
|
|
1999-03-01 07:12:55 +00:00
|
|
|
if (node.getNodeType() != Node.ELEMENT_NODE) return; // can't process it
|
1999-01-16 05:24:25 +00:00
|
|
|
|
1999-02-09 08:05:42 +00:00
|
|
|
// things will recurse through here
|
|
|
|
item = buildComponent((Element)node, (JComponent)parent);
|
|
|
|
|
|
|
|
// find out where we stash the item
|
|
|
|
if (item != null) {
|
|
|
|
Element current = (Element)node;
|
|
|
|
parent.add(item);
|
1999-01-16 05:24:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-03-06 07:08:01 +00:00
|
|
|
/**
|
|
|
|
* Build the component at the current XML element and add to the parent
|
|
|
|
* @param current the current element
|
|
|
|
* @param parent the parent to add to
|
|
|
|
*/
|
1999-01-24 12:02:31 +00:00
|
|
|
protected JComponent buildComponent(Element current, JComponent parent) {
|
1999-01-16 05:24:25 +00:00
|
|
|
String tag = current.getTagName();
|
|
|
|
JComponent comp = null;
|
1999-01-20 06:40:16 +00:00
|
|
|
String label = null;;
|
1999-01-16 05:24:25 +00:00
|
|
|
|
|
|
|
// menu tag
|
|
|
|
if (tag.equals(menu_tag)) {
|
1999-01-24 12:02:31 +00:00
|
|
|
Node node;
|
1999-01-20 06:40:16 +00:00
|
|
|
JMenu menu = new JMenu();
|
1999-01-16 05:24:25 +00:00
|
|
|
String my_id = current.getAttribute(id_attr);
|
1999-01-20 06:40:16 +00:00
|
|
|
comp = menu;
|
|
|
|
|
|
|
|
label = getReferencedLabel(current, label_attr);
|
|
|
|
if (label != null) ((JMenuItem)comp).setText(label);
|
|
|
|
menu.setActionCommand(my_id);
|
1999-01-24 12:02:31 +00:00
|
|
|
node = current.getFirstChild().getNextSibling();
|
1999-01-20 06:40:16 +00:00
|
|
|
|
1999-01-24 12:02:31 +00:00
|
|
|
// loop through all its children
|
|
|
|
while (node != null) {
|
|
|
|
processNode(node, menu);
|
|
|
|
node = node.getNextSibling();
|
|
|
|
}
|
1999-01-16 05:24:25 +00:00
|
|
|
} else if (tag.equals(menuitem_tag)) { // menuitem tag
|
|
|
|
String type = current.getAttribute(type_attr);
|
1999-01-20 06:40:16 +00:00
|
|
|
UIAction action;
|
|
|
|
|
|
|
|
// which type of menuitem?
|
1999-02-28 23:53:40 +00:00
|
|
|
if (type == null || type.equals("")) {
|
|
|
|
// no type ? it's a regular menuitem
|
1999-01-16 05:24:25 +00:00
|
|
|
comp = buildMenuItem(current);
|
|
|
|
} else if (type.equals(separator_attr)) { // separator
|
|
|
|
comp = buildSeparator(current);
|
|
|
|
} else if (type.equals(checkbox_attr)) { // checkboxes
|
|
|
|
comp = buildCheckBoxMenuItem(current);
|
|
|
|
} else if (type.equals(radio_attr)) { // radio
|
|
|
|
comp = buildRadioMenuItem(current);
|
|
|
|
}
|
1999-01-20 06:40:16 +00:00
|
|
|
}
|
|
|
|
|
1999-01-16 05:24:25 +00:00
|
|
|
return comp;
|
|
|
|
}
|
1999-03-06 07:08:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Build a JRadioMenuItem
|
|
|
|
* @param current the element that describes the JRadioMenuItem
|
|
|
|
* @return the built component
|
|
|
|
*/
|
1999-01-16 05:24:25 +00:00
|
|
|
protected JRadioButtonMenuItem buildRadioMenuItem(Element current) {
|
|
|
|
String group = current.getAttribute(group_attr);
|
|
|
|
ButtonGroup bg;
|
|
|
|
JRadioButtonMenuItem comp = new JRadioButtonMenuItem();
|
1999-03-06 07:08:01 +00:00
|
|
|
finishComponent(comp, current);
|
1999-01-16 05:24:25 +00:00
|
|
|
|
|
|
|
// do we add to a button group?
|
|
|
|
if (group != null) {
|
|
|
|
if (button_group.containsKey(group)) {
|
|
|
|
bg = (ButtonGroup)button_group.get(group);
|
|
|
|
} else {
|
|
|
|
bg = new ButtonGroup();
|
|
|
|
button_group.put(group, bg);
|
|
|
|
}
|
|
|
|
bg.add((JRadioButtonMenuItem)comp);
|
|
|
|
}
|
|
|
|
|
|
|
|
return comp;
|
|
|
|
}
|
|
|
|
|
1999-03-06 07:08:01 +00:00
|
|
|
/**
|
|
|
|
* Build a JCheckBoxMenuItem.
|
|
|
|
* @param current the element that describes the JCheckBoxMenuItem
|
|
|
|
* @return the built component
|
|
|
|
*/
|
1999-01-16 05:24:25 +00:00
|
|
|
protected JCheckBoxMenuItem buildCheckBoxMenuItem(Element current) {
|
1999-03-06 07:08:01 +00:00
|
|
|
JCheckBoxMenuItem item = new JCheckBoxMenuItem();
|
|
|
|
finishComponent(item, current);
|
|
|
|
return item;
|
1999-01-16 05:24:25 +00:00
|
|
|
}
|
|
|
|
|
1999-03-06 07:08:01 +00:00
|
|
|
/**
|
|
|
|
* Build a JSeparator.
|
|
|
|
* @param current the element that describes the JSeparator
|
|
|
|
* @return the built component
|
|
|
|
*/
|
1999-01-16 05:24:25 +00:00
|
|
|
protected JSeparator buildSeparator(Element current) {
|
|
|
|
return new JSeparator();
|
|
|
|
}
|
|
|
|
|
1999-03-06 07:08:01 +00:00
|
|
|
/**
|
|
|
|
* Build a JMenuItem.
|
|
|
|
* @param current the element that describes the JMenuItem
|
|
|
|
* @return the built component
|
|
|
|
*/
|
1999-01-16 05:24:25 +00:00
|
|
|
protected JMenuItem buildMenuItem(Element current) {
|
1999-03-06 07:08:01 +00:00
|
|
|
JMenuItem item = new JMenuItem();
|
|
|
|
finishComponent(item, current);
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void finishComponent(JMenuItem item, Element current) {
|
|
|
|
String label = getReferencedLabel(current, label_attr);
|
|
|
|
UIAction action = null;
|
|
|
|
|
|
|
|
if (label != null) {
|
|
|
|
item.setText(label);
|
|
|
|
}
|
|
|
|
|
|
|
|
label = current.getAttribute("action");
|
|
|
|
if (label != null
|
|
|
|
&& (action = (UIAction)actions.get(label)) != null) {
|
|
|
|
item.addActionListener(action);
|
|
|
|
}
|
|
|
|
|
|
|
|
label = getReferencedLabel(current, accel_attr);
|
|
|
|
if (label != null) {
|
|
|
|
item.setMnemonic(label.charAt(0));
|
|
|
|
}
|
1999-01-16 05:24:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
|
|
javax.swing.JFrame frame = new javax.swing.JFrame("Foo bar");
|
1999-01-24 12:02:31 +00:00
|
|
|
XMLMenuBuilder builder = new XMLMenuBuilder(frame, new UIAction[0]);
|
1999-01-16 05:24:25 +00:00
|
|
|
URL url = builder.getClass().getResource("menus.xml");
|
|
|
|
builder.buildFrom(url.openStream());
|
|
|
|
frame.setJMenuBar((JMenuBar)builder.getComponent());
|
|
|
|
frame.pack();
|
|
|
|
frame.setVisible(true);
|
|
|
|
}
|
|
|
|
}
|