| /* |
| * 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); |
| } |
| } |