blob: cb94d3170fa68f66ecc2e7817e5f8820992988b3 [file] [log] [blame]
/*
* Copyright 2002,2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.jelly.tags.swing;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.FocusListener;
import java.awt.event.KeyListener;
import java.awt.event.WindowListener;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.RootPaneContainer;
import javax.swing.border.Border;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.jelly.JellyTagException;
import org.apache.commons.jelly.MissingAttributeException;
import org.apache.commons.jelly.XMLOutput;
import org.apache.commons.jelly.tags.core.UseBeanTag;
import org.apache.commons.jelly.tags.swing.converters.DebugGraphicsConverter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* This tag creates a Swing component and adds it to its parent tag, optionally declaring this
* component as a variable if the <i>var</i> attribute is specified.</p>
*
* <p> This tag clears the reference to it's bean after doTag runs.
* This means that child tags can access the component (bean) normally
* during execution but should not hold a reference to this
* tag after their doTag completes.
* </p>
*
* @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
* @version $Revision: 1.7 $
*/
public class ComponentTag extends UseBeanTag implements ContainerTag {
/** The Log to which logging calls will be made. */
private static final Log log = LogFactory.getLog(ComponentTag.class);
/** This is a converter that might normally be used through the
* BeanUtils product. However, it only applies to one Component
* property and not to all ints, so it's not registered with BeanUtils.
*/
private static final DebugGraphicsConverter debugGraphicsConverter = new DebugGraphicsConverter();
/** the factory of widgets */
private Factory factory;
public ComponentTag() {
}
public ComponentTag(Factory factory) {
this.factory = factory;
}
public String toString() {
Component comp = getComponent();
String componentName = (comp!=null) ? comp.getName() : null;
if (comp!=null && (componentName == null || componentName.length() == 0))
componentName = getComponent().toString();
return "ComponentTag with bean " + componentName;
}
/**
* Sets the Action of this component
*/
public void setAction(Action action) throws JellyTagException {
Component component = getComponent();
if ( component != null ) {
// lets just try set the 'action' property
try {
BeanUtils.setProperty( component, "action", action );
} catch (IllegalAccessException e) {
throw new JellyTagException(e);
} catch (InvocationTargetException e) {
throw new JellyTagException(e);
}
}
}
/**
* Sets the Font of this component
*/
public void setFont(Font font) throws JellyTagException {
Component component = getComponent();
if ( component != null ) {
// lets just try set the 'font' property
try {
BeanUtils.setProperty( component, "font", font );
}
catch (IllegalAccessException e) {
throw new JellyTagException(e);
}
catch (InvocationTargetException e) {
throw new JellyTagException(e);
}
}
}
/**
* Sets the Border of this component
*/
public void setBorder(Border border) throws JellyTagException {
Component component = getComponent();
if ( component != null ) {
try {
// lets just try set the 'border' property
BeanUtils.setProperty( component, "border", border );
}
catch (IllegalAccessException e) {
throw new JellyTagException(e);
}
catch (InvocationTargetException e) {
throw new JellyTagException(e);
}
}
}
/**
* Sets the LayoutManager of this component
*/
public void setLayout(LayoutManager layout) throws JellyTagException {
Component component = getComponent();
if ( component != null ) {
if ( component instanceof RootPaneContainer ) {
RootPaneContainer rpc = (RootPaneContainer) component;
component = rpc.getContentPane();
}
try {
// lets just try set the 'layout' property
BeanUtils.setProperty( component, "layout", layout );
}
catch (IllegalAccessException e) {
throw new JellyTagException(e);
}
catch (InvocationTargetException e) {
throw new JellyTagException(e);
}
}
}
/**
* Adds a WindowListener to this component
*/
public void addWindowListener(WindowListener listener) throws JellyTagException {
Component component = getComponent();
if ( component instanceof Window ) {
Window window = (Window) component;
window.addWindowListener(listener);
}
}
/**
* Adds a FocusListener to this component
*/
public void addFocusListener(FocusListener listener) throws JellyTagException {
Component component = getComponent();
component.addFocusListener(listener);
}
/**
* Adds a KeyListener to this component
*/
public void addKeyListener(KeyListener listener) throws JellyTagException {
Component component = getComponent();
component.addKeyListener(listener);
}
// Properties
//-------------------------------------------------------------------------
/**
* @return the visible component, if there is one.
*/
public Component getComponent() {
Object bean = getBean();
if ( bean instanceof Component ) {
return (Component) bean;
}
return null;
}
// ContainerTag interface
//-------------------------------------------------------------------------
/**
* Adds a child component to this parent
*/
public void addChild(Component component, Object constraints) throws JellyTagException {
Object parent = getBean();
if ( parent instanceof JFrame && component instanceof JMenuBar ) {
JFrame frame = (JFrame) parent;
frame.setJMenuBar( (JMenuBar) component );
}
else if ( parent instanceof RootPaneContainer ) {
RootPaneContainer rpc = (RootPaneContainer) parent;
if (constraints != null) {
rpc.getContentPane().add( component, constraints );
}
else {
rpc.getContentPane().add( component);
}
}
else if ( parent instanceof JScrollPane ) {
JScrollPane scrollPane = (JScrollPane) parent;
scrollPane.setViewportView( component );
}
else if ( parent instanceof JSplitPane) {
JSplitPane splitPane = (JSplitPane) parent;
if ( splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT ) {
if ( splitPane.getTopComponent() == null ) {
splitPane.setTopComponent( component );
}
else {
splitPane.setBottomComponent( component );
}
}
else {
if ( splitPane.getLeftComponent() == null ) {
splitPane.setLeftComponent( component );
}
else {
splitPane.setRightComponent( component );
}
}
}
else if ( parent instanceof JMenuBar && component instanceof JMenu ) {
JMenuBar menuBar = (JMenuBar) parent;
menuBar.add( (JMenu) component );
}
else if ( parent instanceof Container ) {
Container container = (Container) parent;
if (constraints != null) {
container.add( component, constraints );
}
else {
container.add( component );
}
}
}
// Implementation methods
//-------------------------------------------------------------------------
/**
* A class may be specified otherwise the Factory will be used.
*/
protected Class convertToClass(Object classObject) throws MissingAttributeException, ClassNotFoundException {
if (classObject == null) {
return null;
}
else {
return super.convertToClass(classObject);
}
}
/**
* A class may be specified otherwise the Factory will be used.
*/
protected Object newInstance(Class theClass, Map attributes, XMLOutput output) throws JellyTagException {
try {
if (theClass != null ) {
return theClass.newInstance();
} else {
return factory.newInstance();
}
} catch (IllegalAccessException e) {
throw new JellyTagException(e);
} catch (InstantiationException e) {
throw new JellyTagException(e);
}
}
/**
* Either defines a variable or adds the current component to the parent
*/
protected void processBean(String var, Object bean) throws JellyTagException {
if (var != null) {
context.setVariable(var, bean);
}
Component component = getComponent();
if ( component != null ) {
ContainerTag parentTag = (ContainerTag) findAncestorWithClass( ContainerTag.class );
if ( parentTag != null ) {
parentTag.addChild(component, getConstraint());
}
else {
if (var == null) {
throw new JellyTagException( "The 'var' attribute must be specified or this tag must be nested inside a JellySwing container tag like a widget or a layout" );
}
}
}
}
/**
* Handles wierd properties that don't quite match the Java Beans contract
*/
protected void setBeanProperties(Object bean, Map attributes) throws JellyTagException {
Component component = getComponent();
if (component != null) {
if (attributes.containsKey("location")) {
Object value = attributes.get("location");
Point p = null;
if (value instanceof Point) {
p = (Point) value;
}
else if (value != null) {
p =
(Point) ConvertUtils.convert(
value.toString(),
Point.class);
}
component.setLocation(p);
addIgnoreProperty("location");
}
if (attributes.containsKey("size")) {
Object value = attributes.get("size");
Dimension d = null;
if (value instanceof Dimension) {
d = (Dimension) value;
}
else if (value != null) {
d =
(Dimension) ConvertUtils.convert(
value.toString(),
Dimension.class);
}
component.setSize(d);
addIgnoreProperty("size");
}
if (attributes.containsKey("debugGraphicsOptions")) {
try {
Object o = debugGraphicsConverter.convert(attributes.get("debugGraphicsOptions"));
attributes.put("debugGraphicsOptions", o);
} catch (IllegalArgumentException e) {
throw new JellyTagException(e);
}
}
if (attributes.containsKey("debugGraphics")) {
try {
Object o = debugGraphicsConverter.convert(attributes.get("debugGraphics"));
attributes.put("debugGraphicsOptions", o);
} catch (IllegalArgumentException e) {
throw new JellyTagException(e);
}
addIgnoreProperty("debugGraphics");
}
super.setBeanProperties(bean, attributes);
}
}
protected Object getConstraint() {
return null;
}
/**Overrides the default UseBean functionality to clear the bean after the
* tag runs. This prevents us from keeping references to heavy Swing objects
* around for longer than they are needed.
* @see org.apache.commons.jelly.Tag#doTag(org.apache.commons.jelly.XMLOutput)
*/
public void doTag(XMLOutput output) throws JellyTagException {
super.doTag(output);
clearBean();
}
/** Sets the bean to null, to prevent it from
* sticking around in the event that this tag instance is
* cached. This method is called at the end of doTag.
*
*/
protected void clearBean() {
setBean(null);
}
}