source: trunk/quest-jfcmonitor/src/main/java/de/ugoe/cs/quest/jfcmonitor/JFCComponent.java @ 850

Last change on this file since 850 was 850, checked in by fglaser, 12 years ago
  • improvements in JFCMonitor: prototype of JFCMonitors ability to log component name changes
  • Property svn:mime-type set to text/plain
File size: 11.0 KB
Line 
1
2package de.ugoe.cs.quest.jfcmonitor;
3
4import java.awt.Component;
5import java.awt.Container;
6import java.beans.PropertyChangeListener;
7import java.io.File;
8import java.lang.reflect.InvocationTargetException;
9import java.lang.reflect.Method;
10import java.security.InvalidParameterException;
11import java.util.ArrayList;
12import java.util.HashMap;
13import java.util.LinkedList;
14import java.util.List;
15import java.util.Map;
16
17import javax.accessibility.AccessibleContext;
18
19import de.ugoe.cs.util.StringTools;
20
21/**
22 * <p>
23 * This class manages information about the current GUI. It always contains the current GUI
24 * hierarchy.
25 * </p>
26 *
27 * @author Steffen Herbold, Fabian Glaser
28 * @version 1.0
29 */
30public class JFCComponent {
31
32    /**
33     * <p>
34     * Map of all known GUI components.
35     * </p>
36     */
37    private static Map<Component, JFCComponent> knownComponents =
38        new HashMap<Component, JFCComponent>();
39   
40    /**
41     * <p>
42     * List of PropertyChangeListeners that are registered on the components.
43     * </p>
44     */
45   
46    private static List<PropertyChangeListener> propertyChangeListeners =
47        new ArrayList<PropertyChangeListener>();
48
49    /**
50     * <p>
51     * Adds a AWT component to the GUI hierarchy. If the component already exists in the hierarchy,
52     * it is not added a second time.
53     * </p>
54     *
55     * @param component
56     *            component that is added
57     */
58    public static void add(Component component) {
59        add(component, find(component.getParent()));
60    }
61   
62    public static void addListener(PropertyChangeListener list){
63        propertyChangeListeners.add(list);
64    }
65
66    /**
67     * <p>
68     * Adds a AWT component to the GUI hierarchy. If the component already exists in the hierarchy,
69     * it is not added a second time.
70     * </p>
71     *
72     * @param component
73     *            component that is added
74     * @param parent
75     *            parent of the component
76     */
77    public static void add(Component component, JFCComponent parent) {
78        if (!knownComponents.containsKey(component)) {
79            knownComponents.put(component, new JFCComponent(component, parent));
80        }
81    }
82
83    /**
84     * <p>
85     * Finds a component in the GUI hierarchy and returns the corresponding JFComponent instance.
86     * Returns null if the component is not found.
87     * </p>
88     *
89     * @param component
90     *            component that is searched for
91     * @return corresponding JFComponent instance; null if the compenent is not found
92     */
93    public static JFCComponent find(Component component) {
94        return knownComponents.get(component);
95    }
96
97    /**
98     * <p>
99     * Removes a component from the GUI hierarchy. In case the component is not part of the known
100     * hierachy, nothing happens.
101     * </p>
102     *
103     * @param component
104     *            component to be removed
105     */
106    public static void remove(Component component) {
107        JFCComponent jfcComponent = knownComponents.remove(component);
108        if (jfcComponent != null) {
109            jfcComponent.removeFromParent();
110            jfcComponent.removeChildren();
111        }
112    }
113
114    /**
115     * <p>
116     * Parent of the GUI component. null means, that the component has no parent.
117     * </p>
118     */
119    private JFCComponent parent = null;
120
121    /**
122     * <p>
123     * Child components of the component.
124     * </p>
125     */
126    private List<JFCComponent> children = new LinkedList<JFCComponent>();
127
128    /**
129     * <p>
130     * Reference to the actual GUI component.
131     * </p>
132     */
133    private Component component;
134
135    /**
136     * <p>
137     * Helper attribute that contains the title of the component. Set by {@link #setTitle()}.
138     * </p>
139     */
140    private String title = null;
141
142    /**
143     * <p>
144     * Helper attribute that contains the class of the component. Set by {@link #setClass()}.
145     * </p>
146     */
147    private String componentClass = null;
148
149    /**
150     * <p>
151     * Helper attribute that contains the icon of the component. Set by {@link #setIcon()}.
152     * </p>
153     */
154    private String icon = null;
155
156    /**
157     * <p>
158     * Helper attribute that contains the icon of the component. Set by {@link #setIndex()}.
159     * </p>
160     */
161    private int index = -1;
162
163    /**
164     * <p>
165     * Constructor. Creates a new JFCComponent. Only used internally by
166     * {@link #add(Component, JFCComponent)}.
167     * </p>
168     *
169     * @param component
170     *            component associated with the JFCComponent
171     * @param parent
172     *            parent of the component; null if there is no parent
173     */
174    private JFCComponent(Component component, JFCComponent parent) {
175        if (component == null) {
176            throw new InvalidParameterException("parameter component must not be null");
177        }
178        this.component = component;
179       
180        AccessibleContext context = component.getAccessibleContext();
181        if (context != null){
182                for (PropertyChangeListener listener: propertyChangeListeners)
183                        context.addPropertyChangeListener(listener);
184        }
185       
186        this.parent = parent;
187        if (parent != null) {
188            parent.addChild(this);
189        }
190
191        if (component instanceof Container) {
192            for (Component childComponent : ((Container) component).getComponents()) {
193                add(childComponent, this);
194            }
195        }
196    }
197
198    /**
199     * <p>
200     * Adds a child component to the current component.
201     * </p>
202     *
203     * @param child
204     *            child component to be added
205     */
206    private void addChild(JFCComponent child) {
207        children.add(child);
208    }
209
210    /**
211     * <p>
212     * Returns an XML representation of the component.
213     * </p>
214     *
215     * @return XLM snippet
216     */
217    public String getXML() {
218        setClass();
219        setIcon();
220        setIndex();
221        setTitle();
222        StringBuilder builder = new StringBuilder();
223        builder.append("  <component");
224        if (parent != null){
225                builder.append(" parent=\"" + Integer.toHexString(parent.component.hashCode()) + "\"");
226        }
227        builder.append(">"+ StringTools.ENDLINE);
228        builder.append("   <param name=\"title\" value=\"" + title + "\" />" + StringTools.ENDLINE);
229        builder.append("   <param name=\"class\" value=\"" + componentClass + "\" />" +
230            StringTools.ENDLINE);
231        builder.append("   <param name=\"icon\" value=\"" + icon + "\" />" + StringTools.ENDLINE);
232        builder.append("   <param name=\"index\" value=\"" + index + "\" />" + StringTools.ENDLINE);
233        builder.append("   <param name=\"hash\" value=\"" +
234            Integer.toHexString(component.hashCode()) + "\" />" + StringTools.ENDLINE);
235        builder.append("  </component>" + StringTools.ENDLINE);
236        return builder.toString();
237    }
238   
239    /**
240     * <p>
241     * Returns an XML representation of the components children.
242     * </p>
243     * @return XML representation of children
244     */
245    public String printChildren(){
246        StringBuilder builder = new StringBuilder();
247        for (JFCComponent child: children){
248                builder.append(child.getXML());
249                builder.append(child.printChildren());
250        }
251        return builder.toString();
252    }
253
254    /**
255     * <p>
256     * Removes a child component from the current component.
257     * </p>
258     *
259     * @param child
260     *            child component to be removed
261     */
262    private void removeChild(JFCComponent child) {
263        children.remove(child);
264    }
265
266    /**
267     * <p>
268     * Removes the component from the list of children of its parent.
269     * </p>
270     */
271    private void removeFromParent() {
272        if (parent != null) {
273            parent.removeChild(this);
274        }
275    }
276
277    /**
278     * <p>
279     * Triggers the removals of all child components from the GUI hierarchy, i.e., calls
280     * {@link #remove(Component)} for all child components.
281     * </p>
282     */
283    private void removeChildren() {
284        for (JFCComponent child : children) {
285            remove(child.component);
286        }
287    }
288
289    /**
290     * <p>
291     * Sets the {@link #title} of the component. The title is defined as follows (first in the list,
292     * that is not null):
293     * <ul>
294     * <li>accessible name of the component if available</li>
295     * <li>{@link #icon} of the component</li>
296     * <li>name of the component</li>
297     * <li>coordinates of the component</li>
298     * </ul>
299     * </p>
300     */
301    private void setTitle() {
302        title = null; // reset title
303
304        AccessibleContext accessibleContext = component.getAccessibleContext();
305        if (accessibleContext != null) {
306            title = accessibleContext.getAccessibleName();
307        }
308        if (title == null) {
309            title = icon;
310        }
311        if (title == null) {
312            title = component.getName();
313        }
314        if (title == null) {
315            // use coordinates as last resort
316            title = "Pos(" + component.getX() + "," + component.getY() + ")";
317        }
318    }
319
320    /**
321     * <p>
322     * Sets the {@link #componentClass} of the component.
323     * </p>
324     */
325    private void setClass() {
326        componentClass = component.getClass().getName();
327    }
328
329    /**
330     * <p>
331     * Sets the {@link #icon} of the component.
332     * </p>
333     */
334    private void setIcon() {
335        icon = null; // reset icon
336
337        Method getIconMethod;
338        try {
339            getIconMethod = component.getClass().getMethod("getIcon", new Class[0]);
340            if (getIconMethod != null) {
341                Object iconObject = getIconMethod.invoke(component, new Object[] { });
342                if (iconObject != null) {
343                    String iconPath = iconObject.toString();
344                    if (!iconPath.contains("@")) {
345                        System.out.println("iconPath");
346                        String[] splitResult =
347                            iconPath.split(File.separatorChar == '\\' ? "\\\\" : File.separator);
348                        icon = splitResult[splitResult.length - 1];
349                    }
350                }
351            }
352        }
353        catch (SecurityException e) {}
354        catch (NoSuchMethodException e) {}
355        catch (IllegalArgumentException e) {}
356        catch (IllegalAccessException e) {}
357        catch (InvocationTargetException e) {
358            System.err.println("Found method with name " + "getIcon" + " but could not access it.");
359        }
360    }
361
362    /**
363     * <p>
364     * Sets the {@link #index} of the component as the index in the parent, if it is accessible.
365     * </p>
366     */
367    private void setIndex() {
368        index = -1; // reset index
369
370        AccessibleContext accessibleContext = component.getAccessibleContext();
371        if (accessibleContext != null) {
372            index = accessibleContext.getAccessibleIndexInParent();
373        }
374    }
375}
Note: See TracBrowser for help on using the repository browser.