Clover icon

Coverage Report

  1. Project Clover database Wed Nov 13 2024 16:21:17 GMT
  2. Package darrylbu.util

File SwingUtils.java

 

Coverage histogram

../../img/srcFileCovDistChart0.png
59% of files have more coverage

Code metrics

32
94
18
1
528
260
49
0.52
5.22
18
2.72

Classes

Class Line # Actions
SwingUtils 29 94 49
0.00%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * @(#)SwingUtils.java 1.02 11/15/08
3    *
4    */
5    /* from https://github.com/tips4java/tips4java/blob/main/source/SwingUtils.java MIT License */
6    package darrylbu.util;
7   
8    import java.awt.Component;
9    import java.awt.Container;
10    import java.lang.reflect.InvocationTargetException;
11    import java.lang.reflect.Method;
12    import java.util.ArrayList;
13    import java.util.Collections;
14    import java.util.HashMap;
15    import java.util.HashSet;
16    import java.util.List;
17    import java.util.Map;
18    import java.util.Set;
19   
20    import javax.swing.JComponent;
21    import javax.swing.UIDefaults;
22    import javax.swing.UIManager;
23   
24    /**
25    * A collection of utility methods for Swing.
26    *
27    * @author Darryl Burke
28    */
 
29    public final class SwingUtils
30    {
31   
 
32  0 toggle private SwingUtils()
33    {
34  0 throw new Error("SwingUtils is just a container for static methods");
35    }
36   
37    /**
38    * Convenience method for searching below <code>container</code> in the
39    * component hierarchy and return nested components that are instances of
40    * class <code>clazz</code> it finds. Returns an empty list if no such
41    * components exist in the container.
42    * <P>
43    * Invoking this method with a class parameter of JComponent.class will return
44    * all nested components.
45    * <P>
46    * This method invokes getDescendantsOfType(clazz, container, true)
47    *
48    * @param clazz
49    * the class of components whose instances are to be found.
50    * @param container
51    * the container at which to begin the search
52    * @return the List of components
53    */
 
54  0 toggle public static <T extends JComponent> List<T> getDescendantsOfType(
55    Class<T> clazz, Container container)
56    {
57  0 return getDescendantsOfType(clazz, container, true);
58    }
59   
60    /**
61    * Convenience method for searching below <code>container</code> in the
62    * component hierarchy and return nested components that are instances of
63    * class <code>clazz</code> it finds. Returns an empty list if no such
64    * components exist in the container.
65    * <P>
66    * Invoking this method with a class parameter of JComponent.class will return
67    * all nested components.
68    *
69    * @param clazz
70    * the class of components whose instances are to be found.
71    * @param container
72    * the container at which to begin the search
73    * @param nested
74    * true to list components nested within another listed component,
75    * false otherwise
76    * @return the List of components
77    */
 
78  0 toggle public static <T extends JComponent> List<T> getDescendantsOfType(
79    Class<T> clazz, Container container, boolean nested)
80    {
81  0 List<T> tList = new ArrayList<T>();
82  0 for (Component component : container.getComponents())
83    {
84  0 if (clazz.isAssignableFrom(component.getClass()))
85    {
86  0 tList.add(clazz.cast(component));
87    }
88  0 if (nested || !clazz.isAssignableFrom(component.getClass()))
89    {
90  0 tList.addAll(SwingUtils.<T> getDescendantsOfType(clazz,
91    (Container) component, nested));
92    }
93    }
94  0 return tList;
95    }
96   
97    /**
98    * Convenience method that searches below <code>container</code> in the
99    * component hierarchy and returns the first found component that is an
100    * instance of class <code>clazz</code> having the bound property value.
101    * Returns {@code null} if such component cannot be found.
102    * <P>
103    * This method invokes getDescendantOfType(clazz, container, property, value,
104    * true)
105    *
106    * @param clazz
107    * the class of component whose instance is to be found.
108    * @param container
109    * the container at which to begin the search
110    * @param property
111    * the className of the bound property, exactly as expressed in the
112    * accessor e.g. "Text" for getText(), "Value" for getValue().
113    * @param value
114    * the value of the bound property
115    * @return the component, or null if no such component exists in the container
116    * @throws java.lang.IllegalArgumentException
117    * if the bound property does not exist for the class or cannot be
118    * accessed
119    */
 
120  0 toggle public static <T extends JComponent> T getDescendantOfType(Class<T> clazz,
121    Container container, String property, Object value)
122    throws IllegalArgumentException
123    {
124  0 return getDescendantOfType(clazz, container, property, value, true);
125    }
126   
127    /**
128    * Convenience method that searches below <code>container</code> in the
129    * component hierarchy and returns the first found component that is an
130    * instance of class <code>clazz</code> and has the bound property value.
131    * Returns {@code null} if such component cannot be found.
132    *
133    * @param clazz
134    * the class of component whose instance to be found.
135    * @param container
136    * the container at which to begin the search
137    * @param property
138    * the className of the bound property, exactly as expressed in the
139    * accessor e.g. "Text" for getText(), "Value" for getValue().
140    * @param value
141    * the value of the bound property
142    * @param nested
143    * true to list components nested within another component which is
144    * also an instance of <code>clazz</code>, false otherwise
145    * @return the component, or null if no such component exists in the container
146    * @throws java.lang.IllegalArgumentException
147    * if the bound property does not exist for the class or cannot be
148    * accessed
149    */
 
150  0 toggle public static <T extends JComponent> T getDescendantOfType(Class<T> clazz,
151    Container container, String property, Object value,
152    boolean nested) throws IllegalArgumentException
153    {
154  0 List<T> list = getDescendantsOfType(clazz, container, nested);
155  0 return getComponentFromList(clazz, list, property, value);
156    }
157   
158    /**
159    * Convenience method for searching below <code>container</code> in the
160    * component hierarchy and return nested components of class
161    * <code>clazz</code> it finds. Returns an empty list if no such components
162    * exist in the container.
163    * <P>
164    * This method invokes getDescendantsOfClass(clazz, container, true)
165    *
166    * @param clazz
167    * the class of components to be found.
168    * @param container
169    * the container at which to begin the search
170    * @return the List of components
171    */
 
172  0 toggle public static <T extends JComponent> List<T> getDescendantsOfClass(
173    Class<T> clazz, Container container)
174    {
175  0 return getDescendantsOfClass(clazz, container, true);
176    }
177   
178    /**
179    * Convenience method for searching below <code>container</code> in the
180    * component hierarchy and return nested components of class
181    * <code>clazz</code> it finds. Returns an empty list if no such components
182    * exist in the container.
183    *
184    * @param clazz
185    * the class of components to be found.
186    * @param container
187    * the container at which to begin the search
188    * @param nested
189    * true to list components nested within another listed component,
190    * false otherwise
191    * @return the List of components
192    */
 
193  0 toggle public static <T extends JComponent> List<T> getDescendantsOfClass(
194    Class<T> clazz, Container container, boolean nested)
195    {
196  0 List<T> tList = new ArrayList<T>();
197  0 for (Component component : container.getComponents())
198    {
199  0 if (clazz.equals(component.getClass()))
200    {
201  0 tList.add(clazz.cast(component));
202    }
203  0 if (nested || !clazz.equals(component.getClass()))
204    {
205  0 tList.addAll(SwingUtils.<T> getDescendantsOfClass(clazz,
206    (Container) component, nested));
207    }
208    }
209  0 return tList;
210    }
211   
212    /**
213    * Convenience method that searches below <code>container</code> in the
214    * component hierarchy in a depth first manner and returns the first found
215    * component of class <code>clazz</code> having the bound property value.
216    * <P>
217    * Returns {@code null} if such component cannot be found.
218    * <P>
219    * This method invokes getDescendantOfClass(clazz, container, property, value,
220    * true)
221    *
222    * @param clazz
223    * the class of component to be found.
224    * @param container
225    * the container at which to begin the search
226    * @param property
227    * the className of the bound property, exactly as expressed in the
228    * accessor e.g. "Text" for getText(), "Value" for getValue(). This
229    * parameter is case sensitive.
230    * @param value
231    * the value of the bound property
232    * @return the component, or null if no such component exists in the
233    * container's hierarchy.
234    * @throws java.lang.IllegalArgumentException
235    * if the bound property does not exist for the class or cannot be
236    * accessed
237    */
 
238  0 toggle public static <T extends JComponent> T getDescendantOfClass(
239    Class<T> clazz, Container container, String property,
240    Object value) throws IllegalArgumentException
241    {
242  0 return getDescendantOfClass(clazz, container, property, value, true);
243    }
244   
245    /**
246    * Convenience method that searches below <code>container</code> in the
247    * component hierarchy in a depth first manner and returns the first found
248    * component of class <code>clazz</code> having the bound property value.
249    * <P>
250    * Returns {@code null} if such component cannot be found.
251    *
252    * @param clazz
253    * the class of component to be found.
254    * @param container
255    * the container at which to begin the search
256    * @param property
257    * the className of the bound property, exactly as expressed in the
258    * accessor e.g. "Text" for getText(), "Value" for getValue(). This
259    * parameter is case sensitive.
260    * @param value
261    * the value of the bound property
262    * @param nested
263    * true to include components nested within another listed component,
264    * false otherwise
265    * @return the component, or null if no such component exists in the
266    * container's hierarchy
267    * @throws java.lang.IllegalArgumentException
268    * if the bound property does not exist for the class or cannot be
269    * accessed
270    */
 
271  0 toggle public static <T extends JComponent> T getDescendantOfClass(
272    Class<T> clazz, Container container, String property,
273    Object value, boolean nested) throws IllegalArgumentException
274    {
275  0 List<T> list = getDescendantsOfClass(clazz, container, nested);
276  0 return getComponentFromList(clazz, list, property, value);
277    }
278   
 
279  0 toggle private static <T extends JComponent> T getComponentFromList(
280    Class<T> clazz, List<T> list, String property, Object value)
281    throws IllegalArgumentException
282    {
283  0 T retVal = null;
284  0 Method method = null;
285  0 try
286    {
287  0 method = clazz.getMethod("get" + property);
288    } catch (NoSuchMethodException ex)
289    {
290  0 try
291    {
292  0 method = clazz.getMethod("is" + property);
293    } catch (NoSuchMethodException ex1)
294    {
295  0 throw new IllegalArgumentException("Property " + property
296    + " not found in class " + clazz.getName());
297    }
298    }
299  0 try
300    {
301  0 for (T t : list)
302    {
303  0 Object testVal = method.invoke(t);
304  0 if (equals(value, testVal))
305    {
306  0 return t;
307    }
308    }
309    } catch (InvocationTargetException ex)
310    {
311  0 throw new IllegalArgumentException("Error accessing property "
312    + property + " in class " + clazz.getName());
313    } catch (IllegalAccessException ex)
314    {
315  0 throw new IllegalArgumentException("Property " + property
316    + " cannot be accessed in class " + clazz.getName());
317    } catch (SecurityException ex)
318    {
319  0 throw new IllegalArgumentException("Property " + property
320    + " cannot be accessed in class " + clazz.getName());
321    }
322  0 return retVal;
323    }
324   
325    /**
326    * Convenience method for determining whether two objects are either equal or
327    * both null.
328    *
329    * @param obj1
330    * the first reference object to compare.
331    * @param obj2
332    * the second reference object to compare.
333    * @return true if obj1 and obj2 are equal or if both are null, false
334    * otherwise
335    */
 
336  0 toggle public static boolean equals(Object obj1, Object obj2)
337    {
338  0 return obj1 == null ? obj2 == null : obj1.equals(obj2);
339    }
340   
341    /**
342    * Convenience method for mapping a container in the hierarchy to its
343    * contained components. The keys are the containers, and the values are lists
344    * of contained components.
345    * <P>
346    * Implementation note: The returned value is a HashMap and the values are of
347    * type ArrayList. This is subject to change, so callers should code against
348    * the interfaces Map and List.
349    *
350    * @param container
351    * The JComponent to be mapped
352    * @param nested
353    * true to drill down to nested containers, false otherwise
354    * @return the Map of the UI
355    */
 
356  0 toggle public static Map<JComponent, List<JComponent>> getComponentMap(
357    JComponent container, boolean nested)
358    {
359  0 HashMap<JComponent, List<JComponent>> retVal = new HashMap<JComponent, List<JComponent>>();
360  0 for (JComponent component : getDescendantsOfType(JComponent.class,
361    container, false))
362    {
363  0 if (!retVal.containsKey(container))
364    {
365  0 retVal.put(container, new ArrayList<JComponent>());
366    }
367  0 retVal.get(container).add(component);
368  0 if (nested)
369    {
370  0 retVal.putAll(getComponentMap(component, nested));
371    }
372    }
373  0 return retVal;
374    }
375   
376    /**
377    * Convenience method for retrieving a subset of the UIDefaults pertaining to
378    * a particular class.
379    *
380    * @param clazz
381    * the class of interest
382    * @return the UIDefaults of the class
383    */
 
384  0 toggle public static UIDefaults getUIDefaultsOfClass(Class clazz)
385    {
386  0 String name = clazz.getName();
387  0 name = name.substring(name.lastIndexOf(".") + 2);
388  0 return getUIDefaultsOfClass(name);
389    }
390   
391    /**
392    * Convenience method for retrieving a subset of the UIDefaults pertaining to
393    * a particular class.
394    *
395    * @param className
396    * fully qualified name of the class of interest
397    * @return the UIDefaults of the class named
398    */
 
399  0 toggle public static UIDefaults getUIDefaultsOfClass(String className)
400    {
401  0 UIDefaults retVal = new UIDefaults();
402  0 UIDefaults defaults = UIManager.getLookAndFeelDefaults();
403  0 List<?> listKeys = Collections.list(defaults.keys());
404  0 for (Object key : listKeys)
405    {
406  0 if (key instanceof String && ((String) key).startsWith(className))
407    {
408  0 String stringKey = (String) key;
409  0 String property = stringKey;
410  0 if (stringKey.contains("."))
411    {
412  0 property = stringKey.substring(stringKey.indexOf(".") + 1);
413    }
414  0 retVal.put(property, defaults.get(key));
415    }
416    }
417  0 return retVal;
418    }
419   
420    /**
421    * Convenience method for retrieving the UIDefault for a single property of a
422    * particular class.
423    *
424    * @param clazz
425    * the class of interest
426    * @param property
427    * the property to query
428    * @return the UIDefault property, or null if not found
429    */
 
430  0 toggle public static Object getUIDefaultOfClass(Class clazz, String property)
431    {
432  0 Object retVal = null;
433  0 UIDefaults defaults = getUIDefaultsOfClass(clazz);
434  0 List<Object> listKeys = Collections.list(defaults.keys());
435  0 for (Object key : listKeys)
436    {
437  0 if (key.equals(property))
438    {
439  0 return defaults.get(key);
440    }
441  0 if (key.toString().equalsIgnoreCase(property))
442    {
443  0 retVal = defaults.get(key);
444    }
445    }
446  0 return retVal;
447    }
448   
449    /**
450    * Exclude methods that return values that are meaningless to the user
451    */
452    static Set<String> setExclude = new HashSet<String>();
 
453  0 toggle static
454    {
455  0 setExclude.add("getFocusCycleRootAncestor");
456  0 setExclude.add("getAccessibleContext");
457  0 setExclude.add("getColorModel");
458  0 setExclude.add("getGraphics");
459  0 setExclude.add("getGraphicsConfiguration");
460    }
461   
462    /**
463    * Convenience method for obtaining most non-null human readable properties of
464    * a JComponent. Array properties are not included.
465    * <P>
466    * Implementation note: The returned value is a HashMap. This is subject to
467    * change, so callers should code against the interface Map.
468    *
469    * @param component
470    * the component whose proerties are to be determined
471    * @return the class and value of the properties
472    */
 
473  0 toggle public static Map<Object, Object> getProperties(JComponent component)
474    {
475  0 Map<Object, Object> retVal = new HashMap<Object, Object>();
476  0 Class<?> clazz = component.getClass();
477  0 Method[] methods = clazz.getMethods();
478  0 Object value = null;
479  0 for (Method method : methods)
480    {
481  0 if (method.getName().matches("^(is|get).*")
482    && method.getParameterTypes().length == 0)
483    {
484  0 try
485    {
486  0 Class returnType = method.getReturnType();
487  0 if (returnType != void.class
488    && !returnType.getName().startsWith("[")
489    && !setExclude.contains(method.getName()))
490    {
491  0 String key = method.getName();
492  0 value = method.invoke(component);
493  0 if (value != null && !(value instanceof Component))
494    {
495  0 retVal.put(key, value);
496    }
497    }
498    // ignore exceptions that arise if the property could not be accessed
499    } catch (IllegalAccessException ex)
500    {
501    } catch (IllegalArgumentException ex)
502    {
503    } catch (InvocationTargetException ex)
504    {
505    }
506    }
507    }
508  0 return retVal;
509    }
510   
511    /**
512    * Convenience method to obtain the Swing class from which this component was
513    * directly or indirectly derived.
514    *
515    * @param component
516    * The component whose Swing superclass is to be determined
517    * @return The nearest Swing class in the inheritance tree
518    */
 
519  0 toggle public static <T extends JComponent> Class getJClass(T component)
520    {
521  0 Class<?> clazz = component.getClass();
522  0 while (!clazz.getName().matches("javax.swing.J[^.]*$"))
523    {
524  0 clazz = clazz.getSuperclass();
525    }
526  0 return clazz;
527    }
528    }