001: /*
002: * GUIUtils.java
003: *
004: * Copyright (C) 2002, 2003, 2004, 2005, 2006 Takis Diakoumis
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License
008: * as published by the Free Software Foundation; either version 2
009: * of the License, or any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
019: *
020: */
021:
022: package org.underworldlabs.swing;
023:
024: import java.awt.Color;
025: import java.awt.Component;
026: import java.awt.Cursor;
027: import java.awt.Dimension;
028: import java.awt.Font;
029: import java.awt.Frame;
030: import java.awt.GraphicsEnvironment;
031: import java.awt.Point;
032: import java.awt.Rectangle;
033: import java.awt.Toolkit;
034: import java.lang.reflect.InvocationTargetException;
035: import java.util.Collections;
036: import java.util.Vector;
037: import javax.swing.JComponent;
038: import javax.swing.JDialog;
039: import javax.swing.JOptionPane;
040: import javax.swing.SwingUtilities;
041: import javax.swing.UIManager;
042: import org.underworldlabs.swing.plaf.UIUtils;
043: import org.underworldlabs.swing.util.SwingWorker;
044:
045: /* ----------------------------------------------------------
046: * CVS NOTE: Changes to the CVS repository prior to the
047: * release of version 3.0.0beta1 has meant a
048: * resetting of CVS revision numbers.
049: * ----------------------------------------------------------
050: */
051:
052: /**
053: * Simple of collection of GUI utility methods.
054: *
055: * @author Takis Diakoumis
056: * @version $Revision: 1.7 $
057: * @date $Date: 2006/06/12 11:21:47 $
058: */
059: public class GUIUtils {
060:
061: /** Prevent instantiation */
062: private GUIUtils() {
063: }
064:
065: /**
066: * Convenience method for consistent border colour.
067: * Actually aims to return the value from <code>
068: * UIManager.getColor("controlShadow")</code>.
069: *
070: * @return the system default border colour
071: */
072: public static Color getDefaultBorderColour() {
073: return UIManager.getColor("controlShadow");
074: }
075:
076: /**
077: * Displays the error dialog displaying the stack trace from a
078: * throws/caught exception.
079: *
080: * @param owner - the owner of the dialog
081: * @param message - the error message to display
082: * @param e - the throwable
083: */
084: public static void displayExceptionErrorDialog(Frame owner,
085: String message, Throwable e) {
086: new ExceptionErrorDialog(owner, message, e);
087: }
088:
089: /**
090: * Returns the specified component's visible bounds within the screen.
091: *
092: * @return the component's visible bounds as a <code>Rectangle</code>
093: */
094: public static Rectangle getVisibleBoundsOnScreen(
095: JComponent component) {
096: Rectangle visibleRect = component.getVisibleRect();
097: Point onScreen = visibleRect.getLocation();
098: SwingUtilities.convertPointToScreen(onScreen, component);
099: visibleRect.setLocation(onScreen);
100: return visibleRect;
101: }
102:
103: /**
104: * Calculates and returns the centered position of a dialog with
105: * the specified size to be added to the desktop area.
106: *
107: * @param the component to center to
108: * @param the size of the dialog to be added as a
109: * <code>Dimension</code> object
110: * @return the <code>Point</code> at which to add the dialog
111: */
112: public static Point getLocationForDialog(Component component,
113: Dimension dialogDim) {
114:
115: if (component == null) {
116:
117: Dimension screenSize = Toolkit.getDefaultToolkit()
118: .getScreenSize();
119:
120: if (dialogDim.height > screenSize.height) {
121: dialogDim.height = screenSize.height;
122: }
123:
124: if (dialogDim.width > screenSize.width) {
125: dialogDim.width = screenSize.width;
126: }
127:
128: return new Point((screenSize.width - dialogDim.width) / 2,
129: (screenSize.height - dialogDim.height) / 2);
130: }
131:
132: //Rectangle dRec = getVisibleBoundsOnScreen(desktop.getDesktopPane());
133: Dimension frameDim = component.getSize();
134: Rectangle dRec = new Rectangle(component.getX(), component
135: .getY(), (int) frameDim.getWidth(), (int) frameDim
136: .getHeight());
137:
138: int dialogX = dRec.x + ((dRec.width - dialogDim.width) / 2);
139: int dialogY = dRec.y + ((dRec.height - dialogDim.height) / 2);
140:
141: if (dialogX < 0 || dialogY < 0) {
142: Dimension screenSize = Toolkit.getDefaultToolkit()
143: .getScreenSize();
144:
145: if (dialogDim.height > screenSize.height) {
146: dialogDim.height = screenSize.height;
147: }
148:
149: if (dialogDim.width > screenSize.width) {
150: dialogDim.width = screenSize.width;
151: }
152:
153: dialogX = (screenSize.width - dialogDim.width) / 2;
154: dialogY = (screenSize.height - dialogDim.height) / 2;
155: }
156:
157: return new Point(dialogX, dialogY);
158: }
159:
160: /**
161: * Returns the system font names within a collection.
162: *
163: * @return the system fonts names within a <code>Vector</code> object
164: */
165: public static Vector getSystemFonts() {
166: GraphicsEnvironment gEnv = GraphicsEnvironment
167: .getLocalGraphicsEnvironment();
168: Font[] tempFonts = gEnv.getAllFonts();
169:
170: char dot = '.';
171: int dotIndex = 0;
172:
173: char[] fontNameChars = null;
174: String fontName = null;
175: Vector fontNames = new Vector();
176:
177: for (int i = 0; i < tempFonts.length; i++) {
178:
179: fontName = tempFonts[i].getFontName();
180: dotIndex = fontName.indexOf(dot);
181:
182: if (dotIndex == -1) {
183: fontNames.add(fontName);
184: } else {
185: fontNameChars = fontName.substring(0, dotIndex)
186: .toCharArray();
187: fontNameChars[0] = Character
188: .toUpperCase(fontNameChars[0]);
189:
190: fontName = new String(fontNameChars);
191:
192: if (!fontNames.contains(fontName)) {
193: fontNames.add(fontName);
194: }
195:
196: }
197:
198: }
199:
200: Collections.sort(fontNames);
201: return fontNames;
202: }
203:
204: /**
205: * Executes requestFocusInWindow on the specified component
206: * using invokeLater.
207: *
208: * @param c - the component
209: */
210: public static void requestFocusInWindow(final Component c) {
211: invokeAndWait(new Runnable() {
212: public void run() {
213: c.requestFocusInWindow();
214: }
215: });
216: }
217:
218: /**
219: * Sets the specified cursor on the primary frame.
220: *
221: * @param the cursor to set
222: */
223: private static void setCursor(Cursor cursor, Component component) {
224: if (component != null) {
225: component.setCursor(cursor);
226: }
227: }
228:
229: /**
230: * Sets the application cursor to the system normal cursor
231: * the specified component.
232: *
233: * @param component - the component to set the cursor onto
234: */
235: public static void showNormalCursor(Component component) {
236: setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR),
237: component);
238: }
239:
240: /**
241: * Executes the specified runnable using the
242: * <code>SwingWorker</code>.
243: *
244: * @param runnable - the runnable to be executed
245: */
246: public static void startWorker(final Runnable runnable) {
247: SwingWorker worker = new SwingWorker() {
248: public Object construct() {
249: try {
250: runnable.run();
251: } catch (final Exception e) {
252: invokeAndWait(new Runnable() {
253: public void run() {
254: displayExceptionErrorDialog(null,
255: "Error in EDT thread execution: "
256: + e.getMessage(), e);
257: }
258: });
259: }
260: return null;
261: }
262: };
263: worker.start();
264: }
265:
266: /**
267: * Runs the specified runnable in the EDT using
268: * <code>SwingUtilities.invokeLater(...)</code>.
269: *
270: * @param runnable - the runnable to be executed
271: */
272: public static void invokeLater(Runnable runnable) {
273: if (!SwingUtilities.isEventDispatchThread()) {
274: SwingUtilities.invokeLater(runnable);
275: } else {
276: runnable.run();
277: }
278: }
279:
280: /**
281: * Runs the specified runnable in the EDT using
282: * <code>SwingUtilities.invokeAndWait(...)</code>.
283: * Note: This method 'supresses' the method's
284: * thrown exceptions - InvocationTargetException and
285: * InterruptedException.
286: *
287: * @param runnable - the runnable to be executed
288: */
289: public static void invokeAndWait(Runnable runnable) {
290: if (!SwingUtilities.isEventDispatchThread()) {
291: try {
292: //System.err.println("Not EDT");
293: SwingUtilities.invokeAndWait(runnable);
294: } catch (InterruptedException e) {
295: } catch (InvocationTargetException e) {
296: }
297: } else {
298: runnable.run();
299: }
300: }
301:
302: /**
303: * Sets the application cursor to the system wait cursor on
304: * the specified component.
305: *
306: * @param component - the component to set the cursor onto
307: */
308: public static void showWaitCursor(Component component) {
309: setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR),
310: component);
311: }
312:
313: // -------------------------------------------------------
314: // ------ Helper methods for various option dialogs ------
315: // -------------------------------------------------------
316:
317: // These have been revised to use JDialog as the wrapper to
318: // ensure the dialog is centered within the dektop pane and not
319: // within the entire screen as you get with JOptionPane.showXXX()
320:
321: public static final void displayInformationMessage(
322: Component parent, String message) {
323: displayDialog(parent, JOptionPane.DEFAULT_OPTION,
324: JOptionPane.INFORMATION_MESSAGE, false,
325: "OptionPane.informationIcon", "Message", message);
326: }
327:
328: public static final String displayInputMessage(Component parent,
329: String title, String message) {
330: return displayDialog(parent, JOptionPane.OK_CANCEL_OPTION,
331: JOptionPane.QUESTION_MESSAGE, true,
332: "OptionPane.questionIcon", title, message).toString();
333: }
334:
335: public static final void displayWarningMessage(Component parent,
336: String message) {
337: displayDialog(parent, JOptionPane.DEFAULT_OPTION,
338: JOptionPane.WARNING_MESSAGE, false,
339: "OptionPane.warningIcon", "Warning", message);
340: }
341:
342: /** The dialog return value - where applicable */
343: private static Object dialogReturnValue;
344:
345: private static Object displayDialog(final Component parent,
346: final int optionType, final int messageType,
347: final boolean wantsInput, final String icon,
348: final String title, final String message) {
349:
350: dialogReturnValue = null;
351:
352: Runnable runnable = new Runnable() {
353: public void run() {
354: showNormalCursor(parent);
355: JOptionPane pane = new JOptionPane(message,
356: messageType, optionType, UIManager
357: .getIcon(icon));
358: pane.setWantsInput(wantsInput);
359:
360: JDialog dialog = pane.createDialog(parent, title);
361: dialog.setLocation(getLocationForDialog(parent, dialog
362: .getSize()));
363: dialog.setVisible(true);
364: dialog.dispose();
365:
366: if (wantsInput) {
367: dialogReturnValue = pane.getInputValue();
368: } else {
369: dialogReturnValue = pane.getValue();
370: }
371:
372: }
373: };
374: invokeAndWait(runnable);
375: return dialogReturnValue;
376:
377: /*
378: showNormalCursor(parent);
379: JOptionPane pane = new JOptionPane(message, messageType,
380: optionType, UIManager.getIcon(icon));
381: pane.setWantsInput(wantsInput);
382:
383: JDialog dialog = pane.createDialog(parent, title);
384: dialog.setLocation(getLocationForDialog(parent, dialog.getSize()));
385: dialog.setVisible(true);
386: dialog.dispose();
387:
388: if (wantsInput) {
389: return pane.getInputValue();
390: } else {
391: return pane.getValue();
392: }
393: */
394: }
395:
396: public static final void displayErrorMessage(Component parent,
397: String message) {
398: displayDialog(parent, JOptionPane.DEFAULT_OPTION,
399: JOptionPane.ERROR_MESSAGE, false,
400: "OptionPane.errorIcon", "Error Message", message);
401: }
402:
403: public static final int displayConfirmCancelErrorMessage(
404: Component parent, String message) {
405: return ((Integer) displayDialog(parent,
406: JOptionPane.OK_CANCEL_OPTION,
407: JOptionPane.ERROR_MESSAGE, false,
408: "OptionPane.errorIcon", "Error Message", message))
409: .intValue();
410: }
411:
412: public static final int displayYesNoDialog(Component parent,
413: String message, String title) {
414: return ((Integer) displayDialog(parent,
415: JOptionPane.YES_NO_OPTION,
416: JOptionPane.QUESTION_MESSAGE, false,
417: "OptionPane.questionIcon", title, message)).intValue();
418: }
419:
420: public static final int displayConfirmCancelDialog(
421: Component parent, String message) {
422: return ((Integer) displayDialog(parent,
423: JOptionPane.YES_NO_CANCEL_OPTION,
424: JOptionPane.QUESTION_MESSAGE, false,
425: "OptionPane.questionIcon", "Confirmation", message))
426: .intValue();
427: }
428:
429: public static final int displayConfirmDialog(Component parent,
430: String message) {
431: return ((Integer) displayDialog(parent,
432: JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
433: false, "OptionPane.questionIcon", "Confirmation",
434: message)).intValue();
435: }
436:
437: /**
438: * Schedules the garbage collector to run
439: */
440: public static void scheduleGC() {
441: SwingUtilities.invokeLater(new Runnable() {
442: public void run() {
443: System.gc();
444: }
445: });
446: }
447:
448: /**
449: * Returns whether the current applied look and feel is
450: * the EQ default look and feel (or the metal look with ocean theme).
451: *
452: * @return true | false
453: */
454: public static boolean isDefaultLookAndFeel() {
455: return UIUtils.isDefaultLookAndFeel() || UIUtils.usingOcean();
456: }
457:
458: /**
459: * Returns true if we're using the Ocean Theme under the
460: * MetalLookAndFeel.
461: */
462: public static boolean usingOcean() {
463: return UIUtils.usingOcean();
464: }
465:
466: /**
467: * Returns whether the current applied look and feel is
468: * the MetalLookAndFeel;
469: *
470: * @return true | false
471: */
472: public static boolean isMetalLookAndFeel() {
473: return UIUtils.isMetalLookAndFeel();
474: }
475:
476: }
|