1 /*
2 * Copyright 1998-2004 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 package javax.swing.text.html;
26
27 import java.util.Enumeration;
28 import java.awt;
29 import javax.swing;
30 import javax.swing.text;
31 import java.beans;
32 import java.lang.reflect;
33
34 /**
35 * Component decorator that implements the view interface
36 * for <object> elements.
37 * <p>
38 * This view will try to load the class specified by the
39 * <code>classid</code> attribute. If possible, the Classloader
40 * used to load the associated Document is used.
41 * This would typically be the same as the ClassLoader
42 * used to load the EditorKit. If the document's
43 * ClassLoader is null, <code>Class.forName</code> is used.
44 * <p>
45 * If the class can successfully be loaded, an attempt will
46 * be made to create an instance of it by calling
47 * <code>Class.newInstance</code>. An attempt will be made
48 * to narrow the instance to type <code>java.awt.Component</code>
49 * to display the object.
50 * <p>
51 * This view can also manage a set of parameters with limitations.
52 * The parameters to the <object> element are expected to
53 * be present on the associated elements attribute set as simple
54 * strings. Each bean property will be queried as a key on
55 * the AttributeSet, with the expectation that a non-null value
56 * (of type String) will be present if there was a parameter
57 * specification for the property. Reflection is used to
58 * set the parameter. Currently, this is limited to a very
59 * simple single parameter of type String.
60 * <p>
61 * A simple example HTML invocation is:
62 * <pre>
63 * <object classid="javax.swing.JLabel">
64 * <param name="text" value="sample text">
65 * </object>
66 * </pre>
67 *
68 * @author Timothy Prinzing
69 */
70 public class ObjectView extends ComponentView {
71
72 /**
73 * Creates a new ObjectView object.
74 *
75 * @param elem the element to decorate
76 */
77 public ObjectView(Element elem) {
78 super(elem);
79 }
80
81 /**
82 * Create the component. The classid is used
83 * as a specification of the classname, which
84 * we try to load.
85 */
86 protected Component createComponent() {
87 AttributeSet attr = getElement().getAttributes();
88 String classname = (String) attr.getAttribute(HTML.Attribute.CLASSID);
89 try {
90 Class c = Class.forName(classname, true,Thread.currentThread().
91 getContextClassLoader());
92 Object o = c.newInstance();
93 if (o instanceof Component) {
94 Component comp = (Component) o;
95 setParameters(comp, attr);
96 return comp;
97 }
98 } catch (Throwable e) {
99 // couldn't create a component... fall through to the
100 // couldn't load representation.
101 }
102
103 return getUnloadableRepresentation();
104 }
105
106 /**
107 * Fetch a component that can be used to represent the
108 * object if it can't be created.
109 */
110 Component getUnloadableRepresentation() {
111 // PENDING(prinz) get some artwork and return something
112 // interesting here.
113 Component comp = new JLabel("??");
114 comp.setForeground(Color.red);
115 return comp;
116 }
117
118 /**
119 * Get a Class object to use for loading the
120 * classid. If possible, the Classloader
121 * used to load the associated Document is used.
122 * This would typically be the same as the ClassLoader
123 * used to load the EditorKit. If the documents
124 * ClassLoader is null,
125 * <code>Class.forName</code> is used.
126 */
127 private Class getClass(String classname) throws ClassNotFoundException {
128 Class klass;
129
130 Class docClass = getDocument().getClass();
131 ClassLoader loader = docClass.getClassLoader();
132 if (loader != null) {
133 klass = loader.loadClass(classname);
134 } else {
135 klass = Class.forName(classname);
136 }
137 return klass;
138 }
139
140 /**
141 * Initialize this component according the KEY/VALUEs passed in
142 * via the <param> elements in the corresponding
143 * <object> element.
144 */
145 private void setParameters(Component comp, AttributeSet attr) {
146 Class k = comp.getClass();
147 BeanInfo bi;
148 try {
149 bi = Introspector.getBeanInfo(k);
150 } catch (IntrospectionException ex) {
151 System.err.println("introspector failed, ex: "+ex);
152 return; // quit for now
153 }
154 PropertyDescriptor props[] = bi.getPropertyDescriptors();
155 for (int i=0; i < props.length; i++) {
156 // System.err.println("checking on props[i]: "+props[i].getName());
157 Object v = attr.getAttribute(props[i].getName());
158 if (v instanceof String) {
159 // found a property parameter
160 String value = (String) v;
161 Method writer = props[i].getWriteMethod();
162 if (writer == null) {
163 // read-only property. ignore
164 return; // for now
165 }
166 Class[] params = writer.getParameterTypes();
167 if (params.length != 1) {
168 // zero or more than one argument, ignore
169 return; // for now
170 }
171 Object [] args = { value };
172 try {
173 writer.invoke(comp, args);
174 } catch (Exception ex) {
175 System.err.println("Invocation failed");
176 // invocation code
177 }
178 }
179 }
180 }
181
182 }