View Javadoc

1   /*
2    * Copyright 2002,2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.jelly.tags.swt;
17  
18  import java.lang.reflect.Constructor;
19  import java.lang.reflect.InvocationTargetException;
20  import java.util.Map;
21  
22  import org.apache.commons.jelly.JellyTagException;
23  import org.apache.commons.jelly.XMLOutput;
24  import org.apache.commons.jelly.tags.core.UseBeanTag;
25  import org.apache.commons.jelly.tags.swt.converters.ColorConverter;
26  import org.apache.commons.jelly.tags.swt.converters.PointConverter;
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  import org.eclipse.swt.SWT;
30  import org.eclipse.swt.custom.ScrolledComposite;
31  import org.eclipse.swt.graphics.Color;
32  import org.eclipse.swt.graphics.Point;
33  import org.eclipse.swt.graphics.RGB;
34  import org.eclipse.swt.widgets.Control;
35  import org.eclipse.swt.widgets.Widget;
36  
37  /***
38   * This tag creates an SWT widget based on the parent tag, optionally declaring
39   * this widget as a variable if the <i>var</i> attribute is specified.</p>
40   *
41   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
42   * @author <a href="mailto:ckl@dacelo.nl">Christiaan ten Klooster</a>
43   * @version 1.1
44   */
45  public class WidgetTag extends UseBeanTag {
46  
47      /*** The Log to which logging calls will be made. */
48      private static final Log log = LogFactory.getLog(WidgetTag.class);
49  
50      protected Widget parent;
51      private int style = SWT.NULL;
52  
53      public WidgetTag(Class widgetClass) {
54          super(widgetClass);
55      }
56  
57      public WidgetTag(Class widgetClass, int style) {
58          super(widgetClass);
59          this.style = style;
60      }
61  
62      public String toString() {
63          return "WidgetTag[widget=" + getWidget() + "]";
64      }
65  
66      // Properties
67      //-------------------------------------------------------------------------
68  
69      /***
70       * @return the visible widget, if there is one.
71       */
72      public Widget getWidget() {
73          Object bean = getBean();
74          if (bean instanceof Widget) {
75              return (Widget) bean;
76          }
77          return null;
78      }
79  
80      /***
81       * @return the parent widget which this widget will be added to.
82       */
83      public Widget getParentWidget() {
84  
85          if (parent == null) {
86              WidgetTag tag = (WidgetTag) findAncestorWithClass(WidgetTag.class);
87              if (tag != null) {
88                  return tag.getWidget();
89              }
90          }
91  
92          return parent;
93      }
94  
95      // Tag interface
96      //-------------------------------------------------------------------------
97      public void doTag(XMLOutput output) throws JellyTagException {
98          Map attributes = getAttributes();
99          Object parent = attributes.remove("parent");
100         if (parent != null) {
101             if (parent instanceof Widget) {
102                 this.parent = (Widget) parent;
103             } else {
104                 throw new JellyTagException(
105                     "The parent attribute is not a Widget, it is of type: "
106                         + parent.getClass().getName()
107                         + " value: "
108                         + parent);
109             }
110         }
111         super.doTag(output);
112         clearBean();
113     }
114 
115     // Implementation methods
116     //-------------------------------------------------------------------------
117 
118     /***
119      * Factory method to create a new widget
120      */
121     protected Object newInstance(Class theClass, Map attributes, XMLOutput output)
122         throws JellyTagException {
123         int style = getStyle(attributes);
124 
125         // now lets call the constructor with the parent
126         Widget parent = getParentWidget();
127 
128         Widget widget = (Widget) createWidget(theClass, parent, style);
129         if (parent != null) {
130             attachWidgets(parent, widget);
131         }
132 
133         return widget;
134     }
135 
136     /*
137      * @see org.apache.commons.jelly.tags.core.UseBeanTag#setBeanProperties(java.lang.Object, java.util.Map)
138      */
139     protected void setBeanProperties(Object bean, Map attributes) throws JellyTagException {
140 
141         if (bean instanceof Control) {
142             Control control = (Control) bean;
143 
144             // Special handling of size property as the Control object breaks the
145             // JavaBean naming conventions by overloading the setSize() method
146             Object size = attributes.remove("size");
147             setSize(control, size);
148 
149             // Special handling of color property as the Control object breaks the
150             // JavaBean naming conventions by overloading the setBackground() or setForeground() method
151             Object colorValue = attributes.remove("background");
152             Color background =
153                 (colorValue instanceof Color)
154                     ? (Color) colorValue : getColor(control, colorValue);
155             control.setBackground(background);
156 
157             colorValue = attributes.remove("foreground");
158             Color foreground =
159                 (colorValue instanceof Color)
160                     ? (Color) colorValue : getColor(control, colorValue);
161             control.setForeground(foreground);
162         }
163 
164         super.setBeanProperties(bean, attributes);
165     }
166 
167     /***
168      * Get a color for the control
169      * @param control
170      * @param colorValue
171      */
172     protected Color getColor(Control control, Object colorValue) {
173         Color color = null;
174         if (colorValue != null) {
175             RGB rgb = null;
176             if (color instanceof Color) {
177                 color = (Color) colorValue;
178             } else {
179                 rgb = ColorConverter.getInstance().parse(colorValue.toString());
180                 color = new Color(control.getDisplay(), rgb);
181             }
182         }
183         return color;
184     }
185 
186     /***
187      * set the size of the control
188      * @param control
189      * @param size
190      */
191     protected void setSize(Control control, Object size) {
192         Point point = null;
193         if (size != null) {
194             if (size instanceof Point) {
195                 point = (Point) size;
196             } else {
197                 point = PointConverter.getInstance().parse(size.toString());
198             }
199             control.setSize(point);
200         }
201 
202     }
203 
204     /***
205      * Provides a strategy method to allow a new child widget to be attached to
206      * its parent
207      *
208      * @param parent is the parent widget which is never null
209      * @param widget is the new child widget to be attached to the parent
210      */
211     protected void attachWidgets(Object parent, Widget widget) throws JellyTagException {
212         // set the content that will be scrolled if the parent is a ScrolledComposite
213         if (parent instanceof ScrolledComposite && widget instanceof Control) {
214             ScrolledComposite scrolledComposite = (ScrolledComposite) parent;
215             scrolledComposite.setContent((Control) widget);
216         }
217     }
218 
219     /***
220      * Factory method to create an instance of the given Widget class with
221      * the given parent and SWT style
222      *
223      * @param theClass is the type of widget to create
224      * @param parent is the parent widget
225      * @param style the SWT style code
226      * @return the new Widget
227      */
228     protected Object createWidget(Class theClass, Widget parent, int style)
229         throws JellyTagException {
230         if (theClass == null) {
231             throw new JellyTagException("No Class available to create the new widget");
232         }
233 
234         try {
235             if (parent == null) {
236                 // lets try call a constructor with a single style
237                 Class[] types = { int.class };
238                 Constructor constructor = theClass.getConstructor(types);
239                 if (constructor != null) {
240                     Object[] arguments = { new Integer(style)};
241                     return constructor.newInstance(arguments);
242                 }
243             } else {
244                 // lets try to find the constructor with 2 arguments with the 2nd argument being an int
245                 Constructor[] constructors = theClass.getConstructors();
246                 if (constructors != null) {
247                     for (int i = 0, size = constructors.length; i < size; i++) {
248                         Constructor constructor = constructors[i];
249                         Class[] types = constructor.getParameterTypes();
250                         if (types.length == 2 && types[1].isAssignableFrom(int.class)) {
251                             if (types[0].isAssignableFrom(parent.getClass())) {
252                                 Object[] arguments = { parent, new Integer(style)};
253                                 return constructor.newInstance(arguments);
254                             }
255                         }
256                     }
257                 }
258             }
259             return theClass.newInstance();
260         } catch (NoSuchMethodException e) {
261             throw new JellyTagException(e);
262         } catch (InstantiationException e) {
263             throw new JellyTagException(e);
264         } catch (IllegalAccessException e) {
265             throw new JellyTagException(e);
266         } catch (InvocationTargetException e) {
267             throw new JellyTagException(e);
268         }
269     }
270 
271     /***
272      * Creates the SWT style code for the current attributes
273      * @return the SWT style code
274      */
275     protected int getStyle(Map attributes) throws JellyTagException {
276         String text = (String) attributes.remove("style");
277         if (text != null) {
278             return SwtHelper.parseStyle(SWT.class, text);
279         }
280         return style;
281     }
282     
283     /*** Sets the bean to null, to prevent it from
284      * sticking around in the event that this tag instance is
285      * cached. This method is called at the end of doTag.
286      *
287      */
288     protected void clearBean() {
289         setBean(null);
290     }
291 }