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

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