1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jelly.tags.swing;
17
18
19 import java.awt.Component;
20 import java.awt.Container;
21 import java.awt.Dimension;
22 import java.awt.Font;
23 import java.awt.LayoutManager;
24 import java.awt.Point;
25 import java.awt.Window;
26 import java.awt.event.FocusListener;
27 import java.awt.event.KeyListener;
28 import java.awt.event.WindowListener;
29 import java.lang.reflect.InvocationTargetException;
30 import java.util.Map;
31
32 import javax.swing.Action;
33 import javax.swing.JFrame;
34 import javax.swing.JMenu;
35 import javax.swing.JMenuBar;
36 import javax.swing.JScrollPane;
37 import javax.swing.JSplitPane;
38 import javax.swing.RootPaneContainer;
39 import javax.swing.border.Border;
40
41 import org.apache.commons.beanutils.BeanUtils;
42 import org.apache.commons.beanutils.ConvertUtils;
43 import org.apache.commons.jelly.JellyTagException;
44 import org.apache.commons.jelly.MissingAttributeException;
45 import org.apache.commons.jelly.XMLOutput;
46 import org.apache.commons.jelly.tags.core.UseBeanTag;
47 import org.apache.commons.jelly.tags.swing.converters.DebugGraphicsConverter;
48 import org.apache.commons.logging.Log;
49 import org.apache.commons.logging.LogFactory;
50
51 /***
52 * This tag creates a Swing component and adds it to its parent tag, optionally declaring this
53 * component as a variable if the <i>var</i> attribute is specified.</p>
54 *
55 * <p> This tag clears the reference to it's bean after doTag runs.
56 * This means that child tags can access the component (bean) normally
57 * during execution but should not hold a reference to this
58 * tag after their doTag completes.
59 * </p>
60 *
61 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
62 * @version $Revision: 1.7 $
63 */
64 public class ComponentTag extends UseBeanTag implements ContainerTag {
65
66 /*** The Log to which logging calls will be made. */
67 private static final Log log = LogFactory.getLog(ComponentTag.class);
68
69 /*** This is a converter that might normally be used through the
70 * BeanUtils product. However, it only applies to one Component
71 * property and not to all ints, so it's not registered with BeanUtils.
72 */
73 private static final DebugGraphicsConverter debugGraphicsConverter = new DebugGraphicsConverter();
74
75 /*** the factory of widgets */
76 private Factory factory;
77
78 public ComponentTag() {
79 }
80
81 public ComponentTag(Factory factory) {
82 this.factory = factory;
83 }
84
85 public String toString() {
86 String componentName = getComponent().getName();
87 if (componentName == null || componentName.length() == 0)
88 componentName = getComponent().toString();
89 return "ComponentTag with bean " + componentName;
90 }
91
92 /***
93 * Sets the Action of this component
94 */
95 public void setAction(Action action) throws JellyTagException {
96 Component component = getComponent();
97 if ( component != null ) {
98
99 try {
100 BeanUtils.setProperty( component, "action", action );
101 } catch (IllegalAccessException e) {
102 throw new JellyTagException(e);
103 } catch (InvocationTargetException e) {
104 throw new JellyTagException(e);
105 }
106 }
107 }
108
109 /***
110 * Sets the Font of this component
111 */
112 public void setFont(Font font) throws JellyTagException {
113 Component component = getComponent();
114 if ( component != null ) {
115
116 try {
117 BeanUtils.setProperty( component, "font", font );
118 }
119 catch (IllegalAccessException e) {
120 throw new JellyTagException(e);
121 }
122 catch (InvocationTargetException e) {
123 throw new JellyTagException(e);
124 }
125 }
126 }
127
128 /***
129 * Sets the Border of this component
130 */
131 public void setBorder(Border border) throws JellyTagException {
132 Component component = getComponent();
133 if ( component != null ) {
134 try {
135
136 BeanUtils.setProperty( component, "border", border );
137 }
138 catch (IllegalAccessException e) {
139 throw new JellyTagException(e);
140 }
141 catch (InvocationTargetException e) {
142 throw new JellyTagException(e);
143 }
144 }
145 }
146
147 /***
148 * Sets the LayoutManager of this component
149 */
150 public void setLayout(LayoutManager layout) throws JellyTagException {
151 Component component = getComponent();
152 if ( component != null ) {
153 if ( component instanceof RootPaneContainer ) {
154 RootPaneContainer rpc = (RootPaneContainer) component;
155 component = rpc.getContentPane();
156 }
157
158 try {
159
160 BeanUtils.setProperty( component, "layout", layout );
161 }
162 catch (IllegalAccessException e) {
163 throw new JellyTagException(e);
164 }
165 catch (InvocationTargetException e) {
166 throw new JellyTagException(e);
167 }
168 }
169 }
170
171 /***
172 * Adds a WindowListener to this component
173 */
174 public void addWindowListener(WindowListener listener) throws JellyTagException {
175 Component component = getComponent();
176 if ( component instanceof Window ) {
177 Window window = (Window) component;
178 window.addWindowListener(listener);
179 }
180 }
181
182 /***
183 * Adds a FocusListener to this component
184 */
185 public void addFocusListener(FocusListener listener) throws JellyTagException {
186 Component component = getComponent();
187 component.addFocusListener(listener);
188 }
189
190 /***
191 * Adds a KeyListener to this component
192 */
193 public void addKeyListener(KeyListener listener) throws JellyTagException {
194 Component component = getComponent();
195 component.addKeyListener(listener);
196 }
197
198
199
200
201 /***
202 * @return the visible component, if there is one.
203 */
204 public Component getComponent() {
205 Object bean = getBean();
206 if ( bean instanceof Component ) {
207 return (Component) bean;
208 }
209 return null;
210 }
211
212
213
214
215
216 /***
217 * Adds a child component to this parent
218 */
219 public void addChild(Component component, Object constraints) throws JellyTagException {
220 Object parent = getBean();
221 if ( parent instanceof JFrame && component instanceof JMenuBar ) {
222 JFrame frame = (JFrame) parent;
223 frame.setJMenuBar( (JMenuBar) component );
224 }
225 else if ( parent instanceof RootPaneContainer ) {
226 RootPaneContainer rpc = (RootPaneContainer) parent;
227 if (constraints != null) {
228 rpc.getContentPane().add( component, constraints );
229 }
230 else {
231 rpc.getContentPane().add( component);
232 }
233 }
234 else if ( parent instanceof JScrollPane ) {
235 JScrollPane scrollPane = (JScrollPane) parent;
236 scrollPane.setViewportView( component );
237 }
238 else if ( parent instanceof JSplitPane) {
239 JSplitPane splitPane = (JSplitPane) parent;
240 if ( splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT ) {
241 if ( splitPane.getTopComponent() == null ) {
242 splitPane.setTopComponent( component );
243 }
244 else {
245 splitPane.setBottomComponent( component );
246 }
247 }
248 else {
249 if ( splitPane.getLeftComponent() == null ) {
250 splitPane.setLeftComponent( component );
251 }
252 else {
253 splitPane.setRightComponent( component );
254 }
255 }
256 }
257 else if ( parent instanceof JMenuBar && component instanceof JMenu ) {
258 JMenuBar menuBar = (JMenuBar) parent;
259 menuBar.add( (JMenu) component );
260 }
261 else if ( parent instanceof Container ) {
262 Container container = (Container) parent;
263 if (constraints != null) {
264 container.add( component, constraints );
265 }
266 else {
267 container.add( component );
268 }
269 }
270 }
271
272
273
274
275
276 /***
277 * A class may be specified otherwise the Factory will be used.
278 */
279 protected Class convertToClass(Object classObject) throws MissingAttributeException, ClassNotFoundException {
280 if (classObject == null) {
281 return null;
282 }
283 else {
284 return super.convertToClass(classObject);
285 }
286 }
287
288 /***
289 * A class may be specified otherwise the Factory will be used.
290 */
291 protected Object newInstance(Class theClass, Map attributes, XMLOutput output) throws JellyTagException {
292 try {
293 if (theClass != null ) {
294 return theClass.newInstance();
295 } else {
296 return factory.newInstance();
297 }
298 } catch (IllegalAccessException e) {
299 throw new JellyTagException(e);
300 } catch (InstantiationException e) {
301 throw new JellyTagException(e);
302 }
303 }
304
305
306 /***
307 * Either defines a variable or adds the current component to the parent
308 */
309 protected void processBean(String var, Object bean) throws JellyTagException {
310 if (var != null) {
311 context.setVariable(var, bean);
312 }
313 Component component = getComponent();
314 if ( component != null ) {
315 ContainerTag parentTag = (ContainerTag) findAncestorWithClass( ContainerTag.class );
316 if ( parentTag != null ) {
317 parentTag.addChild(component, getConstraint());
318 }
319 else {
320 if (var == null) {
321 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" );
322 }
323 }
324 }
325 }
326
327 /***
328 * Handles wierd properties that don't quite match the Java Beans contract
329 */
330 protected void setBeanProperties(Object bean, Map attributes) throws JellyTagException {
331
332 Component component = getComponent();
333 if (component != null) {
334 if (attributes.containsKey("location")) {
335 Object value = attributes.get("location");
336 Point p = null;
337 if (value instanceof Point) {
338 p = (Point) value;
339 }
340 else if (value != null) {
341 p =
342 (Point) ConvertUtils.convert(
343 value.toString(),
344 Point.class);
345 }
346 component.setLocation(p);
347 addIgnoreProperty("location");
348 }
349
350 if (attributes.containsKey("size")) {
351 Object value = attributes.get("size");
352 Dimension d = null;
353 if (value instanceof Dimension) {
354 d = (Dimension) value;
355 }
356 else if (value != null) {
357 d =
358 (Dimension) ConvertUtils.convert(
359 value.toString(),
360 Dimension.class);
361 }
362 component.setSize(d);
363 addIgnoreProperty("size");
364 }
365
366 if (attributes.containsKey("debugGraphicsOptions")) {
367 try {
368 Object o = debugGraphicsConverter.convert(attributes.get("debugGraphicsOptions"));
369 attributes.put("debugGraphicsOptions", o);
370 } catch (IllegalArgumentException e) {
371 throw new JellyTagException(e);
372 }
373 }
374
375 if (attributes.containsKey("debugGraphics")) {
376 try {
377 Object o = debugGraphicsConverter.convert(attributes.get("debugGraphics"));
378 attributes.put("debugGraphicsOptions", o);
379 } catch (IllegalArgumentException e) {
380 throw new JellyTagException(e);
381 }
382
383 addIgnoreProperty("debugGraphics");
384 }
385
386 super.setBeanProperties(bean, attributes);
387 }
388 }
389
390 protected Object getConstraint() {
391 return null;
392 }
393
394 /***Overrides the default UseBean functionality to clear the bean after the
395 * tag runs. This prevents us from keeping references to heavy Swing objects
396 * around for longer than they are needed.
397 * @see org.apache.commons.jelly.Tag#doTag(org.apache.commons.jelly.XMLOutput)
398 */
399 public void doTag(XMLOutput output) throws JellyTagException {
400 super.doTag(output);
401 clearBean();
402 }
403
404 /*** Sets the bean to null, to prevent it from
405 * sticking around in the event that this tag instance is
406 * cached. This method is called at the end of doTag.
407 *
408 */
409 protected void clearBean() {
410 setBean(null);
411 }
412 }