Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
WindowUtilities |
|
| 2.95;2.95 |
1 | /* |
|
2 | Wotonomy: OpenStep design patterns for pure Java applications. |
|
3 | Copyright (C) 2000 Michael Powers |
|
4 | ||
5 | This library is free software; you can redistribute it and/or |
|
6 | modify it under the terms of the GNU Lesser General Public |
|
7 | License as published by the Free Software Foundation; either |
|
8 | version 2.1 of the License, or (at your option) any later version. |
|
9 | ||
10 | This library is distributed in the hope that it will be useful, |
|
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 | Lesser General Public License for more details. |
|
14 | ||
15 | You should have received a copy of the GNU Lesser General Public |
|
16 | License along with this library; if not, see http://www.gnu.org |
|
17 | */ |
|
18 | ||
19 | package net.wotonomy.ui.swing.util; |
|
20 | ||
21 | import java.awt.Component; |
|
22 | import java.awt.Container; |
|
23 | import java.awt.Dialog; |
|
24 | import java.awt.Dimension; |
|
25 | import java.awt.Point; |
|
26 | import java.awt.Toolkit; |
|
27 | import java.awt.Window; |
|
28 | import java.util.ArrayList; |
|
29 | import java.util.Collection; |
|
30 | import java.util.Collections; |
|
31 | import java.util.HashMap; |
|
32 | import java.util.Iterator; |
|
33 | import java.util.List; |
|
34 | import java.util.Map; |
|
35 | ||
36 | /** |
|
37 | * A collection of window-related utilities. |
|
38 | * |
|
39 | * @author michael@mpowers.net |
|
40 | * @author $Author: cgruber $ |
|
41 | * @version $Revision: 904 $ |
|
42 | * $Date: 2006-02-18 23:19:05 +0000 (Sat, 18 Feb 2006) $ |
|
43 | * |
|
44 | */ |
|
45 | 0 | public class WindowUtilities |
46 | { |
|
47 | ||
48 | /** |
|
49 | * Place frame at center (vertically and horizontally) of screen. |
|
50 | */ |
|
51 | public static final int CENTER = 0; |
|
52 | ||
53 | /** |
|
54 | * Center dialog on frame area of parent, if any. |
|
55 | */ |
|
56 | public static final int CENTER_PARENT = 1; |
|
57 | ||
58 | /** |
|
59 | * Place lower and to the right of the last window |
|
60 | * placed in this manner. Will wrap to top and left |
|
61 | * of screen as necessary. |
|
62 | */ |
|
63 | public static final int CASCADE = 10; |
|
64 | ||
65 | // cascade state |
|
66 | 0 | private static int lastX = 0; |
67 | 0 | private static int lastY = 0; |
68 | 0 | private static int incrementX = 20; |
69 | 0 | private static int incrementY = 20; |
70 | ||
71 | /** |
|
72 | * Place the window in the center of the screen. |
|
73 | * Note: don't forget to first set the size of your window. |
|
74 | * This is a convenience method and simply calls place() with |
|
75 | * the CENTER parameter. |
|
76 | * @param aWindow The window to be centered. |
|
77 | * @see #place |
|
78 | */ |
|
79 | public static void center( Window aWindow ) |
|
80 | { |
|
81 | 0 | place( aWindow, CENTER ); |
82 | 0 | } |
83 | ||
84 | /** |
|
85 | * Place lower and to the right of the last window |
|
86 | * placed in this manner. Will wrap to top and left |
|
87 | * of screen as necessary. |
|
88 | * This is a convenience method and simply calls place() with |
|
89 | * the CASCADE parameter. |
|
90 | * @param aWindow The window to be cascaded. |
|
91 | * @see #place |
|
92 | */ |
|
93 | public static void cascade( Window aWindow ) |
|
94 | { |
|
95 | 0 | place( aWindow, CASCADE ); |
96 | 0 | } |
97 | ||
98 | /** |
|
99 | * Place the window in the specified location. |
|
100 | * Note: don't forget to first set the size of your window. |
|
101 | * @param aWindow The window to be placed. |
|
102 | * @param location Where on screen to place the frame. |
|
103 | */ |
|
104 | public static void place( Window aWindow, int location) |
|
105 | { |
|
106 | 0 | Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); |
107 | 0 | Dimension mySize = aWindow.getSize(); |
108 | 0 | int x = (aWindow.getLocation()).x; |
109 | 0 | int y = (aWindow.getLocation()).y; |
110 | 0 | float aspectRatio = (float)screenSize.height/(float)screenSize.width; |
111 | ||
112 | // hack to make windows appear on left monitor if dual monitor |
|
113 | // if aspect ratio is less than 0.6, assume dual monitor |
|
114 | 0 | if (aspectRatio < 0.6) |
115 | { |
|
116 | 0 | screenSize.width = screenSize.width/2; |
117 | } |
|
118 | ||
119 | 0 | switch (location) |
120 | { |
|
121 | case CENTER_PARENT: |
|
122 | 0 | if ( ( ! ( aWindow instanceof Dialog ) ) |
123 | 0 | || ( ((Dialog)aWindow).getParent() == null ) ) |
124 | //1.2 || ( ((Dialog)aWindow).getOwner() == null ) ) |
|
125 | { |
|
126 | 0 | place( aWindow, CENTER ); |
127 | 0 | return; |
128 | } |
|
129 | 0 | Point parentLocation = (((Dialog)aWindow).getParent()).getLocation(); |
130 | //1.2 (((Dialog)aWindow).getOwner()).getLocation(); |
|
131 | 0 | Dimension parentSize = (((Dialog)aWindow).getParent()).getSize(); |
132 | ||
133 | //1.2 Dimension parentSize = (((Dialog)aWindow).getOwner()).getSize(); |
|
134 | ||
135 | 0 | if (parentSize.width > mySize.width) |
136 | { |
|
137 | 0 | x = ((parentSize.width - mySize.width)/2) + parentLocation.x; |
138 | } |
|
139 | 0 | if (parentSize.height > mySize.height) |
140 | { |
|
141 | 0 | y = ((parentSize.height - mySize.height)/2) + parentLocation.y; |
142 | 0 | } |
143 | 0 | break; |
144 | case CENTER: |
|
145 | 0 | if (screenSize.width > mySize.width) |
146 | { |
|
147 | 0 | x = (screenSize.width - mySize.width)/2; |
148 | } |
|
149 | 0 | if (screenSize.height > mySize.height) |
150 | { |
|
151 | 0 | y = (screenSize.height - mySize.height)/2; |
152 | 0 | } |
153 | 0 | break; |
154 | case CASCADE: |
|
155 | 0 | x = lastX + incrementX; |
156 | 0 | if ( x + mySize.width > screenSize.width ) |
157 | { |
|
158 | 0 | x = incrementX; |
159 | } |
|
160 | 0 | y = lastY + incrementY; |
161 | 0 | if ( y + mySize.height > screenSize.height ) |
162 | { |
|
163 | 0 | y = incrementY; |
164 | } |
|
165 | 0 | lastX = x; |
166 | 0 | lastY = y; |
167 | 0 | break; |
168 | default: |
|
169 | // don't move the frame |
|
170 | 0 | Point p = aWindow.getLocation(); |
171 | 0 | x = p.x; |
172 | 0 | y = p.y; |
173 | break; |
|
174 | } |
|
175 | 0 | aWindow.setLocation(x,y); |
176 | 0 | } |
177 | ||
178 | /** |
|
179 | * Returns the first parent Window of the specified component. |
|
180 | * |
|
181 | * @param c the Component whose parent will be found. |
|
182 | * @return the Window that contains the component, |
|
183 | * or null if the component does not have a valid Frame parent. |
|
184 | */ |
|
185 | public static Window getWindowForComponent(Component c) |
|
186 | { |
|
187 | 0 | for(Component p = c; p != null; p = p.getParent()) { |
188 | 0 | if (p instanceof Window) { |
189 | 0 | return (Window) p; |
190 | } |
|
191 | } |
|
192 | 0 | return null; |
193 | } |
|
194 | ||
195 | ||
196 | ||
197 | /** |
|
198 | * Prints out a list of all components to System.out. |
|
199 | * @param aContainer the Container whose components will be listed. |
|
200 | */ |
|
201 | public static void dumpComponents( Container aContainer ) |
|
202 | { |
|
203 | 0 | dumpComponents( aContainer, "" ); |
204 | 0 | } |
205 | ||
206 | protected static void dumpComponents( Container aContainer, String padding ) |
|
207 | { |
|
208 | 0 | Component c = null; |
209 | 0 | int count = aContainer.getComponentCount(); |
210 | 0 | for ( int i = 0; i < count; i++ ) |
211 | { |
|
212 | 0 | c = aContainer.getComponent( i ); |
213 | 0 | if ( c instanceof javax.swing.JComponent ) |
214 | { |
|
215 | 0 | System.out.println( padding + c.getClass() + ": " |
216 | 0 | + ((javax.swing.JComponent)c).getAccessibleContext().getAccessibleName() ); |
217 | 0 | } |
218 | else |
|
219 | { |
|
220 | 0 | System.out.println( padding + c.getClass() + ": " + c.getName() ); |
221 | } |
|
222 | 0 | if ( c instanceof Container ) |
223 | { |
|
224 | 0 | dumpComponents( (Container) c, padding + " " ); |
225 | } |
|
226 | } |
|
227 | 0 | } |
228 | ||
229 | /** |
|
230 | * Gets a list of all children of a specified container, sorted by position. |
|
231 | * Components are sorted from top to bottom and then left to right. |
|
232 | * @param aContainer The container whose children are to be returned. |
|
233 | * @result A List containing the sorted components. |
|
234 | */ |
|
235 | public static List getSortedChildComponents( Container aContainer ) |
|
236 | { |
|
237 | 0 | List result = new ArrayList( getAllChildComponents( aContainer ) ); |
238 | 0 | Collections.sort( result, new PositionComparator( aContainer ) ); |
239 | 0 | return result; |
240 | } |
|
241 | ||
242 | public static void dumpSortedChildComponents( Container aContainer ) |
|
243 | { |
|
244 | 0 | Component c = null; |
245 | 0 | Iterator it = getSortedChildComponents( aContainer ).iterator(); |
246 | 0 | while ( it.hasNext() ) |
247 | { |
|
248 | 0 | c = (Component) it.next(); |
249 | 0 | System.out.println( c.getLocation() + " : " + c.getClass() ); |
250 | 0 | } |
251 | 0 | } |
252 | ||
253 | public static void dumpNamedChildComponents( Container aContainer ) |
|
254 | { |
|
255 | 0 | Iterator it = getUniqueNameMap( getSortedChildComponents( aContainer ) ).values().iterator(); |
256 | 0 | while ( it.hasNext() ) |
257 | { |
|
258 | 0 | System.out.println( it.next() ); |
259 | 0 | } |
260 | 0 | } |
261 | ||
262 | /** |
|
263 | * Generates a unique name for each object in a list and returns |
|
264 | * a map that maps the objects to the names. The name is based |
|
265 | * on the class of the object in the object list. |
|
266 | * @param anObjectList A List of objects. |
|
267 | * @return A Map that maps the objects in the list to the generated names. |
|
268 | */ |
|
269 | public static Map getUniqueNameMap( List anObjectList ) |
|
270 | { |
|
271 | 0 | Map namesToObjects = new HashMap(anObjectList.size(), 1F); |
272 | 0 | Map objectsToNames = new HashMap(anObjectList.size(), 1F); |
273 | ||
274 | 0 | Object o = null; |
275 | 0 | String name = null; |
276 | 0 | int lastIndex = 0; |
277 | 0 | Iterator it = anObjectList.iterator(); |
278 | 0 | while ( it.hasNext() ) |
279 | { |
|
280 | 0 | o = it.next(); |
281 | 0 | name = o.getClass().getName(); |
282 | 0 | lastIndex = name.lastIndexOf( "." ); |
283 | 0 | if ( lastIndex != -1 ) |
284 | { |
|
285 | 0 | name = name.substring( lastIndex+1 ); |
286 | } |
|
287 | 0 | name = incrementString( name ); |
288 | 0 | while ( namesToObjects.get( name ) != null ) |
289 | { |
|
290 | 0 | name = incrementString( name ); |
291 | 0 | } |
292 | 0 | namesToObjects.put( name, o ); |
293 | 0 | objectsToNames.put( o, name ); |
294 | 0 | } |
295 | ||
296 | 0 | return objectsToNames; |
297 | } |
|
298 | ||
299 | /** |
|
300 | * Numerically increments a string. For example, "hello" becomes "hello1" |
|
301 | * and "hello1" becomes "hello2" while "hello999" becomes "hello1000". |
|
302 | * @param aString a String to be incremented. |
|
303 | * @return The incremented String. |
|
304 | */ |
|
305 | public static String incrementString( String aString ) |
|
306 | { |
|
307 | 0 | int i = aString.length()-1; |
308 | 0 | while ( ( i >= 0 ) && ( Character.isDigit( aString.charAt( i ) ) ) ) |
309 | { |
|
310 | 0 | i--; |
311 | 0 | } |
312 | ||
313 | 0 | if ( i == aString.length()-1 ) |
314 | { // no numerics at end of string, increment manually |
|
315 | 0 | return aString + "1"; |
316 | } |
|
317 | ||
318 | 0 | String alpha = aString.substring( 0, i+1 ); |
319 | 0 | String numeric = aString.substring( i+1 ); |
320 | 0 | numeric = Integer.toString( Integer.parseInt( numeric ) + 1 ); |
321 | ||
322 | 0 | return alpha + numeric; |
323 | ||
324 | } |
|
325 | ||
326 | /** |
|
327 | * Gets all children of the specified container. |
|
328 | * @param aContainer the Container to be searched. |
|
329 | * @return A Collection containing all of the child components of the container. |
|
330 | */ |
|
331 | public static Collection getAllChildComponents( Container aContainer ) |
|
332 | { |
|
333 | 0 | Collection result = new ArrayList(); |
334 | 0 | addAllChildComponents( aContainer, result ); |
335 | 0 | return result; |
336 | } |
|
337 | ||
338 | /** |
|
339 | * Adds all children of the specified container to the specified collection. |
|
340 | * @param aContainer the Container to be searched. |
|
341 | * @param aCollection the Collection to which the child components will be added. |
|
342 | */ |
|
343 | protected static void addAllChildComponents( Container aContainer, Collection aCollection ) |
|
344 | { |
|
345 | 0 | Component c = null; |
346 | 0 | int count = aContainer.getComponentCount(); |
347 | 0 | for ( int i = 0; i < count; i++ ) |
348 | { |
|
349 | 0 | c = aContainer.getComponent( i ); |
350 | 0 | aCollection.add( c ); |
351 | 0 | if ( c instanceof Container ) |
352 | { |
|
353 | 0 | addAllChildComponents( (Container) c, aCollection ); |
354 | } |
|
355 | } |
|
356 | 0 | } |
357 | ||
358 | /** |
|
359 | * Sets each child component's tooltip to show the name generated from |
|
360 | * getComponentNameMap(). |
|
361 | * (We're doing this so the tooltip authors can know how to reference |
|
362 | * the components.) |
|
363 | * @param aContainer the Container whose components will be labeled. |
|
364 | */ |
|
365 | public static void labelComponents( Container aContainer ) |
|
366 | { |
|
367 | 0 | Map nameToComponent = getNameToComponentMap( aContainer ); |
368 | 0 | Map nameToName = new HashMap(nameToComponent.size(), 1F); |
369 | 0 | Iterator it = nameToComponent.keySet().iterator(); |
370 | String key; |
|
371 | 0 | while ( it.hasNext() ) |
372 | { |
|
373 | 0 | key = it.next().toString(); |
374 | 0 | nameToName.put( key, key ); |
375 | 0 | } |
376 | 0 | labelComponents( aContainer, nameToName ); |
377 | 0 | } |
378 | ||
379 | /** |
|
380 | * Sets each child component's tooltip to show a given string retrieved |
|
381 | * from a map using the component's generated name as a key. |
|
382 | * @param aContainer the Container whose components will be labeled. |
|
383 | * @param aNameMap a Map of generated names to string values. |
|
384 | */ |
|
385 | public static void labelComponents( Container aContainer, Map aNameMap ) |
|
386 | { |
|
387 | 0 | if ( aNameMap == null ) return; |
388 | ||
389 | String key; |
|
390 | Object o ; |
|
391 | 0 | Iterator it = aNameMap.keySet().iterator(); |
392 | 0 | Map nameToComponent = getNameToComponentMap( aContainer ); |
393 | 0 | while ( it.hasNext() ) |
394 | { |
|
395 | 0 | key = it.next().toString(); |
396 | 0 | o = nameToComponent.get( key ); |
397 | 0 | if ( o instanceof javax.swing.JComponent ) |
398 | { |
|
399 | 0 | ((javax.swing.JComponent)o).setToolTipText( aNameMap.get( key ).toString() ); |
400 | 0 | } |
401 | } |
|
402 | 0 | } |
403 | ||
404 | /** |
|
405 | * Generates a deterministically unique name for each component in a |
|
406 | * container. The name is based on the name of the class of the component |
|
407 | * followed by a number. Each class of component is numbered based on it's |
|
408 | * position in the container, sorted from top to bottom and left to right. |
|
409 | * @param aContainer the Container whose components will named. |
|
410 | * @return a Map that maps each component to its name. |
|
411 | */ |
|
412 | public static Map getComponentToNameMap( Container aContainer ) |
|
413 | { |
|
414 | 0 | return getUniqueNameMap( getSortedChildComponents( aContainer ) ); |
415 | } |
|
416 | ||
417 | /** |
|
418 | * Maps a deterministically unique name to a component in a |
|
419 | * container. The name is based on the name of the class of the component |
|
420 | * followed by a number. Each class of component is numbered based on it's |
|
421 | * position in the container, sorted from top to bottom and left to right. |
|
422 | * @param aContainer the Container whose components will named. |
|
423 | * @return a Map that maps each component to its name. |
|
424 | */ |
|
425 | public static Map getNameToComponentMap( Container aContainer ) |
|
426 | { |
|
427 | 0 | Map componentToName = getComponentToNameMap( aContainer ); |
428 | 0 | Map result = new HashMap(componentToName.size(), 1F); |
429 | 0 | Iterator it = componentToName.keySet().iterator(); |
430 | Object key; |
|
431 | 0 | while ( it.hasNext() ) |
432 | { |
|
433 | 0 | key = it.next(); |
434 | 0 | result.put( componentToName.get( key ), key ); |
435 | 0 | } |
436 | 0 | return result; |
437 | } |
|
438 | ||
439 | /** |
|
440 | * Sets the tooltips of all components in a container to the |
|
441 | * respective names of those components. (We're using this |
|
442 | * so the tooltip authors can know how to reference the components.) |
|
443 | * @param aContainer the Container whose components will be labeled. |
|
444 | */ |
|
445 | public static void nameComponents( Container aContainer ) |
|
446 | { |
|
447 | 0 | nameComponents( aContainer, "" ); |
448 | 0 | } |
449 | ||
450 | protected static void nameComponents( Container aContainer, String path ) |
|
451 | { |
|
452 | 0 | Component c = null; |
453 | 0 | String className = null; |
454 | 0 | int index = 0; |
455 | 0 | int count = aContainer.getComponentCount(); |
456 | 0 | for ( int i = 0; i < count; i++ ) |
457 | { |
|
458 | 0 | c = aContainer.getComponent( i ); |
459 | 0 | className = c.getClass().getName(); |
460 | 0 | className = className.substring( className.lastIndexOf( '.' ) + 1 ); |
461 | 0 | System.out.println( path + className ); |
462 | 0 | if ( c instanceof javax.swing.JComponent ) |
463 | { |
|
464 | // ((javax.swing.JComponent)c).setToolTipText( path + className + " (" + c.getName() + ")" ); |
|
465 | 0 | ((javax.swing.JComponent)c).setToolTipText( c.getName() ); |
466 | } |
|
467 | 0 | if ( c instanceof Container ) |
468 | { |
|
469 | 0 | nameComponents( (Container) c, path + className + "." ); |
470 | } |
|
471 | } |
|
472 | 0 | } |
473 | ||
474 | /** |
|
475 | * Sets the enabled state of a container and all of its components. |
|
476 | * @param aContainer the Container whose components will be enabled. |
|
477 | * @param isEnabled True if enabled, false id disabled. |
|
478 | */ |
|
479 | public static void enableComponents( Container aContainer, boolean isEnabled ) |
|
480 | { |
|
481 | 0 | Component c = null; |
482 | 0 | String className = null; |
483 | 0 | int index = 0; |
484 | 0 | int count = aContainer.getComponentCount(); |
485 | 0 | for ( int i = 0; i < count; i++ ) |
486 | { |
|
487 | 0 | c = aContainer.getComponent( i ); |
488 | 0 | if ( c instanceof Container ) |
489 | { |
|
490 | 0 | enableComponents( (Container) c, isEnabled ); |
491 | 0 | } |
492 | else |
|
493 | { |
|
494 | 0 | c.setEnabled( isEnabled ); |
495 | } |
|
496 | } |
|
497 | 0 | aContainer.setEnabled( isEnabled ); |
498 | 0 | } |
499 | ||
500 | } |
|
501 | ||
502 | /* |
|
503 | * $Log$ |
|
504 | * Revision 1.2 2006/02/18 23:19:05 cgruber |
|
505 | * Update imports and maven dependencies. |
|
506 | * |
|
507 | * Revision 1.1 2006/02/16 13:22:22 cgruber |
|
508 | * Check in all sources in eclipse-friendly maven-enabled packages. |
|
509 | * |
|
510 | * Revision 1.2 2001/02/17 16:52:05 mpowers |
|
511 | * Changes in imports to support building with jdk1.1 collections. |
|
512 | * |
|
513 | * Revision 1.1.1.1 2000/12/21 15:51:55 mpowers |
|
514 | * Contributing wotonomy. |
|
515 | * |
|
516 | * Revision 1.2 2000/12/20 16:25:46 michael |
|
517 | * Added log to all files. |
|
518 | * |
|
519 | * |
|
520 | */ |
|
521 |