Lots of clean up with XML generated menus. Need some documentation

and action code inserted.
This commit is contained in:
grail%cafebabe.org 1999-01-16 05:24:25 +00:00
parent a533b0fdd1
commit 77a3223cd1
2 changed files with 300 additions and 168 deletions

View File

@ -53,31 +53,21 @@ import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuBar;
/*
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JSeparator;
*/
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.BoxLayout;
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;
import com.sun.xml.tree.XmlDocumentBuilder;
import com.sun.xml.tree.TreeWalker;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
//import netscape.orion.toolbars.BarLayout;
//import netscape.orion.toolbars.CollapsibleToolbarPanel;
//import netscape.orion.toolbars.NSButton;
@ -282,49 +272,14 @@ public class GeneralFrame extends JFrame
* @return a menubar built from the file
*/
protected JMenuBar buildMenu(String file) {
String id;
JMenuBar menubar = null;
Node node;
TreeWalker tree;
InputSource input;
XmlDocument doc;
URL linkURL;
Element current;
URL url;
XMLMenuBuilder builder = new XMLMenuBuilder();
try {
// handle to the document
input = Resolver.getSource(getClass().getResource(file), false);
// build the doc
doc = XmlDocumentBuilder.createXmlDocument(input, false);
// get the root node
current = doc.getDocumentElement();
// create a tree
tree = new TreeWalker(current);
// pull out the properties if any
node = tree.getNextElement("link");
if (node != null) {
current = (Element)node;
linkURL = getClass().getResource(current.getAttribute("href"));
prop = new Properties();
prop.load(linkURL.openStream());
}
// build the menu bar
node = tree.getNextElement("menubar");
if (node == null) { // what? no menubar? screw that, i'm outta here
return menubar;
}
current = (Element)node;
menubar = new JMenuBar();
widgets.put(current.getAttribute("id"), menubar);
node = tree.getNext();
while (node != null) {
processNode(node);
node = tree.getNext();
}
url = getClass().getResource(file);
builder.buildFrom(url.openStream());
menubar = (JMenuBar)builder.getComponent();
} catch (Throwable t) {
t.printStackTrace();
}
@ -332,121 +287,6 @@ public class GeneralFrame extends JFrame
return menubar;
}
protected void processNode(Node node)
throws SAXParseException {
Element current = null;
Container con = null;
JComponent item = buildItem(node);
if (item != null) {
Element parent;
current = (Element)node;
parent = (Element)current.getParentNode();
con = (Container)widgets.get(parent.getAttribute("id"));
if (con != null) {
// what's the frequency kenneth?
String label = getReferencedLabel(current, "label");
if (label != null) ((JMenuItem)item).setText(label);
label = getReferencedLabel(current, "accel");
if (label != null) ((JMenuItem)item).setMnemonic(label.charAt(0));
con.add(item);
}
}
}
/**
*/
protected JComponent buildItem(Node node)
throws SAXParseException {
JComponent item = null;
Element current = null;
Element parent = null;
if (node.getNodeType() == 1) {
current = (Element)node;
parent = (Element)current.getParentNode();
item = createFromElement(current);
}
return item;
}
/**
* Reads the an attribute from the XML element. If the element is
* crossed referenced to a string property (it starts with '$'),
* look it up.
*
* @param current the current XML element
* @param attr the attribute to look up
*/
protected String getReferencedLabel(Element current, String attr)
throws SAXParseException {
String label = current.getAttribute(attr);
if (prop == null) return label;
// if there's a key, and it begins with '$', look up in properties
if (label != null && label.charAt(0) == '$') {
String key = label.substring(1);
label = prop.getProperty(key);
}
return label;
}
/**
* Create components that can be added to a menu.
*
* @param current the XML element node to be processed
* @return the component composed from the element
*/
protected JComponent createFromElement(Element current)
throws SAXParseException {
String tag = current.getTagName();
JComponent item = null;
// if it's a container (menu) we need to store it into
// widgets
if (tag.equals("menu")) { // menu tag
String my_id = current.getAttribute("id");
item = new JMenu();
widgets.put(my_id, item);
} else if (tag.equals("menuitem")) { // menu item tag
String type = current.getAttribute("type");
if (type == null) {
item = new JMenuItem();
} else {
if (type.equals("separator")) { // type = separator
item = new JSeparator(SwingConstants.HORIZONTAL);
} else if (type.equals("checkbox")) { // type = checkbox
String value = current.getAttribute("value");
JCheckBoxMenuItem cb = new JCheckBoxMenuItem();
item = cb;
if (value != null) {
cb.setState(value.trim().toLowerCase().equals("true"));
}
} else if (type.equals("radio")) { // type = radio
ButtonGroup bg;
String group = current.getAttribute("group");
item = new JRadioButtonMenuItem();
if (group != null) {
if (groups.containsKey(group)) {
bg = (ButtonGroup)groups.get(group);
} else {
bg = new ButtonGroup();
groups.put(group, bg);
}
bg.add((JRadioButtonMenuItem)item);
}
}
}
}
return item;
}
protected Component buildStatusBar() {
JPanel res = new JPanel();
res.setLayout(new BoxLayout(res, BoxLayout.X_AXIS));

View File

@ -0,0 +1,292 @@
/* -*- 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;
import javax.swing.JComponent;
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;
import com.sun.xml.tree.XmlDocumentBuilder;
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.
* <LI>Action lookups to an action factory of some sort.
* </UL>
*/
public class XMLMenuBuilder {
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";
static final int ELEMENT_TYPE = 1;
Hashtable widget_parents;
Hashtable button_group;
Properties properties;
JMenuBar component;
/**
* Build a menu builder which operates on XML formatted data
*/
public XMLMenuBuilder() {
widget_parents = new Hashtable();
button_group = new Hashtable();
}
/**
* Build a menu builder which operates on XML formatted data
*
* @param stream the stream containing the XML data assumes
* a single menubar in the file
*/
public XMLMenuBuilder(InputStream stream) {
super();
buildFrom(stream);
}
/**
* 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 {
doc = XmlDocumentBuilder.createXmlDocument(stream, false);
current = doc.getDocumentElement();
tree = new TreeWalker(current);
// get the link tag for this file
node = tree.getNextElement("head");
// get into head and get the first element
node = node.getFirstChild();
node = node.getNextSibling();
// 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();
}
}
/**
* Set the element as the item containing configuration for the
* builder
*
* @param config the element containing configuration data
*/
public void setConfiguration(Element config) {
try {
URL linkURL;
// get the string properties
if (config.getAttribute("href") != null
&& config.getAttribute("role").equals("stringprops")
&& config.getTagName().equals("link")) {
linkURL = getClass().getResource(config.getAttribute("href"));
properties = new Properties();
properties.load(linkURL.openStream());
}
} catch (IOException io) {
io.printStackTrace();
}
}
/**
* 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
current = (Element)tree.getNextElement("menubar");
component = new JMenuBar();
// store its "id" so we can use it for lookups as we add its children
widget_parents.put(current.getAttribute(id_attr), component);
// iterate through every node
node = tree.getNext();
while (node != null) {
processNode(node);
node = tree.getNext();
}
}
/**
* @return the menubar built by this builder
*/
public JComponent getComponent() {
return component;
}
public void configureForOwner(JComponent component) {
}
public void associateClass(Class c, Object o) {
}
protected void processNode(Node node) {
JComponent container = null;
JComponent item = null;
if (node.getNodeType() == ELEMENT_TYPE) {
item = buildComponent((Element)node);
// find out where we stash the item
if (item != null) {
Element current = (Element)node;
Element parent = (Element)current.getParentNode();
String label;
// look up the parent container and add it there
container =
(JComponent)widget_parents.get(parent.getAttribute(id_attr));
label = getReferencedLabel(current, label_attr);
if (label != null) ((JMenuItem)item).setText(label);
label = getReferencedLabel(current, accel_attr);
if (label != null) ((JMenuItem)item).setMnemonic(label.charAt(0));
container.add(item);
}
}
}
protected JComponent buildComponent(Element current) {
String tag = current.getTagName();
JComponent comp = null;
// menu tag
if (tag.equals(menu_tag)) {
String my_id = current.getAttribute(id_attr);
comp = new JMenu();
widget_parents.put(my_id, comp);
} else if (tag.equals(menuitem_tag)) { // menuitem tag
String type = current.getAttribute(type_attr);
if (type == null) { // no type ? it's a regular menuitem
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);
}
}
return comp;
}
protected JRadioButtonMenuItem buildRadioMenuItem(Element current) {
String group = current.getAttribute(group_attr);
ButtonGroup bg;
JRadioButtonMenuItem comp = new JRadioButtonMenuItem();
// 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;
}
protected JCheckBoxMenuItem buildCheckBoxMenuItem(Element current) {
return new JCheckBoxMenuItem();
}
protected JSeparator buildSeparator(Element current) {
return new JSeparator();
}
protected JMenuItem buildMenuItem(Element current) {
return new JMenuItem();
}
protected String getReferencedLabel(Element current, String attr) {
String label = current.getAttribute(attr);
if (properties == null) return label;
// if it starts with a '$' we crossreference to properties
if (label != null && label.charAt(0) == '$') {
String key = label.substring(1);
label = properties.getProperty(key, label);
}
return label;
}
public static void main(String[] args) throws Exception {
javax.swing.JFrame frame = new javax.swing.JFrame("Foo bar");
XMLMenuBuilder builder = new XMLMenuBuilder();
URL url = builder.getClass().getResource("menus.xml");
builder.buildFrom(url.openStream());
frame.setJMenuBar((JMenuBar)builder.getComponent());
frame.pack();
frame.setVisible(true);
}
}