1. /*
  2. * @(#)ObjectView.java 1.13 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text.html;
  8. import java.util.Enumeration;
  9. import java.awt.*;
  10. import javax.swing.*;
  11. import javax.swing.text.*;
  12. import java.beans.*;
  13. import java.lang.reflect.*;
  14. /**
  15. * Component decorator that implements the view interface
  16. * for <object> elements.
  17. * <p>
  18. * This view will try to load the class specified by the
  19. * <code>classid</code> attribute. If possible, the Classloader
  20. * used to load the associated Document is used.
  21. * This would typically be the same as the ClassLoader
  22. * used to load the EditorKit. If the document's
  23. * ClassLoader is null, <code>Class.forName</code> is used.
  24. * <p>
  25. * If the class can successfully be loaded, an attempt will
  26. * be made to create an instance of it by calling
  27. * <code>Class.newInstance</code>. An attempt will be made
  28. * to narrow the instance to type <code>java.awt.Component</code>
  29. * to display the object.
  30. * <p>
  31. * This view can also manage a set of parameters with limitations.
  32. * The parameters to the <object> element are expected to
  33. * be present on the associated elements attribute set as simple
  34. * strings. Each bean property will be queried as a key on
  35. * the AttributeSet, with the expectation that a non-null value
  36. * (of type String) will be present if there was a parameter
  37. * specification for the property. Reflection is used to
  38. * set the parameter. Currently, this is limited to a very
  39. * simple single parameter of type String.
  40. * <p>
  41. * A simple example HTML invocation is:
  42. * <pre>
  43. * <object classid="javax.swing.JLabel">
  44. * <param name="text" value="sample text">
  45. * </object>
  46. * </pre>
  47. *
  48. * @author Timothy Prinzing
  49. * @version 1.13 12/19/03
  50. */
  51. public class ObjectView extends ComponentView {
  52. /**
  53. * Creates a new ObjectView object.
  54. *
  55. * @param elem the element to decorate
  56. */
  57. public ObjectView(Element elem) {
  58. super(elem);
  59. }
  60. /**
  61. * Create the component. The classid is used
  62. * as a specification of the classname, which
  63. * we try to load.
  64. */
  65. protected Component createComponent() {
  66. AttributeSet attr = getElement().getAttributes();
  67. String classname = (String) attr.getAttribute(HTML.Attribute.CLASSID);
  68. try {
  69. Class c = Class.forName(classname, true,Thread.currentThread().
  70. getContextClassLoader());
  71. Object o = c.newInstance();
  72. if (o instanceof Component) {
  73. Component comp = (Component) o;
  74. setParameters(comp, attr);
  75. return comp;
  76. }
  77. } catch (Throwable e) {
  78. // couldn't create a component... fall through to the
  79. // couldn't load representation.
  80. }
  81. return getUnloadableRepresentation();
  82. }
  83. /**
  84. * Fetch a component that can be used to represent the
  85. * object if it can't be created.
  86. */
  87. Component getUnloadableRepresentation() {
  88. // PENDING(prinz) get some artwork and return something
  89. // interesting here.
  90. Component comp = new JLabel("??");
  91. comp.setForeground(Color.red);
  92. return comp;
  93. }
  94. /**
  95. * Get a Class object to use for loading the
  96. * classid. If possible, the Classloader
  97. * used to load the associated Document is used.
  98. * This would typically be the same as the ClassLoader
  99. * used to load the EditorKit. If the documents
  100. * ClassLoader is null,
  101. * <code>Class.forName</code> is used.
  102. */
  103. private Class getClass(String classname) throws ClassNotFoundException {
  104. Class klass;
  105. Class docClass = getDocument().getClass();
  106. ClassLoader loader = docClass.getClassLoader();
  107. if (loader != null) {
  108. klass = loader.loadClass(classname);
  109. } else {
  110. klass = Class.forName(classname);
  111. }
  112. return klass;
  113. }
  114. /**
  115. * Initialize this component according the KEY/VALUEs passed in
  116. * via the <param> elements in the corresponding
  117. * <object> element.
  118. */
  119. private void setParameters(Component comp, AttributeSet attr) {
  120. Class k = comp.getClass();
  121. BeanInfo bi;
  122. try {
  123. bi = Introspector.getBeanInfo(k);
  124. } catch (IntrospectionException ex) {
  125. System.err.println("introspector failed, ex: "+ex);
  126. return; // quit for now
  127. }
  128. PropertyDescriptor props[] = bi.getPropertyDescriptors();
  129. for (int i=0; i < props.length; i++) {
  130. // System.err.println("checking on props[i]: "+props[i].getName());
  131. Object v = attr.getAttribute(props[i].getName());
  132. if (v instanceof String) {
  133. // found a property parameter
  134. String value = (String) v;
  135. Method writer = props[i].getWriteMethod();
  136. if (writer == null) {
  137. // read-only property. ignore
  138. return; // for now
  139. }
  140. Class[] params = writer.getParameterTypes();
  141. if (params.length != 1) {
  142. // zero or more than one argument, ignore
  143. return; // for now
  144. }
  145. String [] args = { value };
  146. try {
  147. writer.invoke(comp, args);
  148. } catch (Exception ex) {
  149. System.err.println("Invocation failed");
  150. // invocation code
  151. }
  152. }
  153. }
  154. }
  155. }