001: package net.sourceforge.squirrel_sql.fw.gui;
002:
003: /*
004: * Copyright (C) 2001-2004 Colin Bell
005: * colbell@users.sourceforge.net
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: import java.awt.Component;
022: import java.awt.Container;
023: import java.awt.Dimension;
024: import java.awt.FontMetrics;
025: import java.awt.Frame;
026: import java.awt.GraphicsConfiguration;
027: import java.awt.GraphicsDevice;
028: import java.awt.GraphicsEnvironment;
029: import java.awt.Insets;
030: import java.awt.Point;
031: import java.awt.Rectangle;
032: import java.awt.Toolkit;
033: import java.awt.Window;
034: import java.awt.geom.Rectangle2D;
035: import java.beans.PropertyVetoException;
036: import java.lang.reflect.InvocationTargetException;
037: import java.util.ArrayList;
038: import java.util.Iterator;
039: import java.util.List;
040:
041: import javax.swing.JButton;
042: import javax.swing.JFrame;
043: import javax.swing.JInternalFrame;
044: import javax.swing.SwingUtilities;
045:
046: import net.sourceforge.squirrel_sql.fw.util.BaseRuntimeException;
047: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
048: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
049:
050: /**
051: * Common GUI utilities accessed via static methods.
052: *
053: * @author <A HREF="mailto:colbell@users.sourceforge.net">Colin Bell</A>
054: */
055: public class GUIUtils {
056: /** Logger for this class. */
057: private static final ILogger s_log = LoggerController
058: .createLogger(GUIUtils.class);
059:
060: private static JFrame _mainFrame;
061:
062: /**
063: * Centers <CODE>wind</CODE> within its parent. If it has no parent then
064: * center within the screen. If centering would cause the title bar to go
065: * above the parent (I.E. cannot see the titlebar and so cannot move the
066: * window) then move the window down.
067: *
068: * @param wind The Window to be centered.
069: *
070: * @throws IllegalArgumentException If <TT>wind</TT> is <TT>null</TT>.
071: */
072: public static void centerWithinParent(Window wind) {
073: if (wind == null) {
074: throw new IllegalArgumentException("null Window passed");
075: }
076: final Container parent = wind.getParent();
077: if (parent != null && parent.isVisible()) {
078: center(wind, new Rectangle(parent.getLocationOnScreen(),
079: parent.getSize()));
080: } else {
081: centerWithinScreen(wind);
082: }
083: }
084:
085: /**
086: * Centers passed internal frame within its desktop area. If centering
087: * would cause the title bar to go off the top of the screen then move the
088: * window down.
089: *
090: * @param frame The internal frame to be centered.
091: *
092: * @throws IllegalArgumentException If <TT>frame</TT> is <TT>null</TT>.
093: */
094: public static void centerWithinDesktop(JInternalFrame frame) {
095: if (frame == null) {
096: throw new IllegalArgumentException(
097: "null JInternalFrame passed");
098: }
099: final Container parent = frame.getDesktopPane();
100: if (parent != null && parent.isVisible()) {
101: center(frame, new Rectangle(new Point(0, 0), parent
102: .getSize()));
103: }
104: }
105:
106: /**
107: * Centers <CODE>wind</CODE> within the screen. If centering would cause the
108: * title bar to go off the top of the screen then move the window down.
109: *
110: * @param wind The Window to be centered.
111: *
112: * @throws IllegalArgumentException If <TT>wind</TT> is <TT>null</TT>.
113: */
114: public static void centerWithinScreen(Window wind) {
115: if (wind == null) {
116: throw new IllegalArgumentException("null Window passed");
117: }
118: final Toolkit toolKit = Toolkit.getDefaultToolkit();
119: final Rectangle rcScreen = new Rectangle(toolKit
120: .getScreenSize());
121: final Dimension windSize = wind.getSize();
122: final Dimension parentSize = new Dimension(rcScreen.width,
123: rcScreen.height);
124: if (windSize.height > parentSize.height) {
125: windSize.height = parentSize.height;
126: }
127: if (windSize.width > parentSize.width) {
128: windSize.width = parentSize.width;
129: }
130: center(wind, rcScreen);
131: }
132:
133: public static void moveToFront(final JInternalFrame fr) {
134: if (fr != null) {
135: processOnSwingEventThread(new Runnable() {
136: public void run() {
137: fr.moveToFront();
138: fr.setVisible(true);
139: try {
140: fr.setSelected(true);
141: } catch (PropertyVetoException ex) {
142: s_log
143: .error(
144: "Error bringing internal frame to the front",
145: ex);
146: }
147: }
148: });
149: }
150: }
151:
152: /**
153: * Return the owning <CODE>Frame</CODE> for the passed component
154: * of <CODE>null</CODE> if it doesn't have one.
155: *
156: * @throws IllegalArgumentException If <TT>wind</TT> is <TT>null</TT>.
157: */
158: public static Frame getOwningFrame(Component comp) {
159: if (comp == null) {
160: throw new IllegalArgumentException("null Component passed");
161: }
162:
163: if (comp instanceof Frame) {
164: return (Frame) comp;
165: }
166: return getOwningFrame(SwingUtilities.windowForComponent(comp));
167: }
168:
169: /**
170: * Return <TT>true</TT> if <TT>frame</TT> is a tool window. I.E. is the
171: * <TT>JInternalFrame.isPalette</TT> set to <TT>Boolean.TRUE</TT>?
172: *
173: * @param frame The <TT>JInternalFrame</TT> to be checked.
174: *
175: * @throws IllegalArgumentException If <TT>frame</TT> is <TT>null</TT>.
176: */
177: public static boolean isToolWindow(JInternalFrame frame) {
178: if (frame == null) {
179: throw new IllegalArgumentException(
180: "null JInternalFrame passed");
181: }
182:
183: final Object obj = frame
184: .getClientProperty("JInternalFrame.isPalette");
185: return obj != null && obj == Boolean.TRUE;
186: }
187:
188: /**
189: * Make the passed internal frame a Tool Window.
190: */
191: public static void makeToolWindow(JInternalFrame frame,
192: boolean isToolWindow) {
193: if (frame == null) {
194: throw new IllegalArgumentException(
195: "null JInternalFrame passed");
196: }
197: frame.putClientProperty("JInternalFrame.isPalette",
198: isToolWindow ? Boolean.TRUE : Boolean.FALSE);
199: }
200:
201: /**
202: * Change the sizes of all the passed buttons to be the size of the
203: * largest one.
204: *
205: * @param btns Array of buttons to eb resized.
206: *
207: * @throws IllegalArgumentException If <TT>btns</TT> is <TT>null</TT>.
208: */
209: public static void setJButtonSizesTheSame(JButton[] btns) {
210: if (btns == null) {
211: throw new IllegalArgumentException("null JButton[] passed");
212: }
213:
214: // Get the largest width and height
215: final Dimension maxSize = new Dimension(0, 0);
216: for (int i = 0; i < btns.length; ++i) {
217: final JButton btn = btns[i];
218: final FontMetrics fm = btn.getFontMetrics(btn.getFont());
219: Rectangle2D bounds = fm.getStringBounds(btn.getText(), btn
220: .getGraphics());
221: int boundsHeight = (int) bounds.getHeight();
222: int boundsWidth = (int) bounds.getWidth();
223: maxSize.width = boundsWidth > maxSize.width ? boundsWidth
224: : maxSize.width;
225: maxSize.height = boundsHeight > maxSize.height ? boundsHeight
226: : maxSize.height;
227: }
228:
229: Insets insets = btns[0].getInsets();
230: maxSize.width += insets.left + insets.right;
231: maxSize.height += insets.top + insets.bottom;
232:
233: for (int i = 0; i < btns.length; ++i) {
234: JButton btn = btns[i];
235: btn.setPreferredSize(maxSize);
236: }
237: }
238:
239: /**
240: * Return an array containing all <TT>JInternalFrame</TT> objects
241: * that were passed in <TT>frames</TT> that are tool windows.
242: *
243: * @param frames <TT>JInternalFrame</TT> objects to be checked.
244: */
245: public static JInternalFrame[] getOpenToolWindows(
246: JInternalFrame[] frames) {
247: if (frames == null) {
248: throw new IllegalArgumentException(
249: "null JInternalFrame[] passed");
250: }
251: List<JInternalFrame> framesList = new ArrayList<JInternalFrame>();
252: for (int i = 0; i < frames.length; ++i) {
253: JInternalFrame fr = frames[i];
254: if (isToolWindow(fr) && !fr.isClosed()) {
255: framesList.add(frames[i]);
256: }
257: }
258: return framesList
259: .toArray(new JInternalFrame[framesList.size()]);
260: }
261:
262: /**
263: * Return an array containing all <TT>JInternalFrame</TT> objects
264: * that were passed in <TT>frames</TT> that are <EM>not</EM> tool windows.
265: *
266: * @param frames <TT>JInternalFrame</TT> objects to be checked.
267: */
268: public static JInternalFrame[] getOpenNonToolWindows(
269: JInternalFrame[] frames) {
270: if (frames == null) {
271: throw new IllegalArgumentException(
272: "null JInternalFrame[] passed");
273: }
274: List<JInternalFrame> framesList = new ArrayList<JInternalFrame>();
275: for (int i = 0; i < frames.length; ++i) {
276: JInternalFrame fr = frames[i];
277: if (!isToolWindow(fr) && !fr.isClosed()) {
278: framesList.add(frames[i]);
279: }
280: }
281: return framesList
282: .toArray(new JInternalFrame[framesList.size()]);
283: }
284:
285: /**
286: * Return an array containing all <TT>JInternalFrame</TT> objects
287: * that were passed in <TT>frames</TT> that are <EM>not</EM> tool windows.
288: * and are not minimized.
289: *
290: * @param frames <TT>JInternalFrame</TT> objects to be checked.
291: */
292: public static JInternalFrame[] getNonMinimizedNonToolWindows(
293: JInternalFrame[] frames) {
294: if (frames == null) {
295: throw new IllegalArgumentException(
296: "null JInternalFrame[] passed");
297: }
298: List<JInternalFrame> framesList = new ArrayList<JInternalFrame>();
299: for (int i = 0; i < frames.length; ++i) {
300: JInternalFrame fr = frames[i];
301: if (!isToolWindow(fr) && !fr.isClosed() && !fr.isIcon()) {
302: framesList.add(frames[i]);
303: }
304: }
305: return framesList
306: .toArray(new JInternalFrame[framesList.size()]);
307: }
308:
309: public static boolean isWithinParent(Component wind) {
310: if (wind == null) {
311: throw new IllegalArgumentException("Null Component passed");
312: }
313:
314: Rectangle windowBounds = wind.getBounds();
315: Component parent = wind.getParent();
316: Rectangle parentRect = null;
317: if (parent != null) {
318: parentRect = new Rectangle(parent.getSize());
319: } else {
320: //parentRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
321: parentRect = getScreenBoundsFor(windowBounds);
322: }
323:
324: //if (windowBounds.x > (parentRect.width - 20)
325: // || windowBounds.y > (parentRect.height - 20)
326: //|| (windowBounds.x + windowBounds.width) < 20
327: //|| (windowBounds.y + windowBounds.height) < 20)
328: //{
329: //return false;
330: //}
331: if (windowBounds.x < (parentRect.x - 20)
332: || windowBounds.y < (parentRect.y - 20)) {
333: return false;
334: }
335: return true;
336: }
337:
338: public static Rectangle getScreenBoundsFor(Rectangle rc) {
339: final GraphicsDevice[] gds = GraphicsEnvironment
340: .getLocalGraphicsEnvironment().getScreenDevices();
341: final List<GraphicsConfiguration> configs = new ArrayList<GraphicsConfiguration>();
342:
343: for (int i = 0; i < gds.length; i++) {
344: GraphicsConfiguration gc = gds[i].getDefaultConfiguration();
345: if (rc.intersects(gc.getBounds())) {
346: configs.add(gc);
347: }
348: }
349:
350: GraphicsConfiguration selected = null;
351: if (configs.size() > 0) {
352: for (Iterator<GraphicsConfiguration> it = configs
353: .iterator(); it.hasNext();) {
354: GraphicsConfiguration gcc = it.next();
355: if (selected == null)
356: selected = gcc;
357: else {
358: if (gcc.getBounds().contains(rc.x + 20, rc.y + 20)) {
359: selected = gcc;
360: break;
361: }
362: }
363: }
364: } else {
365: selected = GraphicsEnvironment
366: .getLocalGraphicsEnvironment()
367: .getDefaultScreenDevice().getDefaultConfiguration();
368: }
369:
370: int x = selected.getBounds().x;
371: int y = selected.getBounds().y;
372: int w = selected.getBounds().width;
373: int h = selected.getBounds().height;
374:
375: return new Rectangle(x, y, w, h);
376: }
377:
378: public static void processOnSwingEventThread(Runnable todo) {
379: processOnSwingEventThread(todo, false);
380: }
381:
382: public static void processOnSwingEventThread(Runnable todo,
383: boolean wait) {
384: if (todo == null) {
385: throw new IllegalArgumentException("Runnable == null");
386: }
387:
388: if (wait) {
389: if (SwingUtilities.isEventDispatchThread()) {
390: todo.run();
391: } else {
392: try {
393: SwingUtilities.invokeAndWait(todo);
394: } catch (InvocationTargetException ex) {
395: throw new BaseRuntimeException(ex);
396: } catch (InterruptedException ex) {
397: throw new BaseRuntimeException(ex);
398: }
399: }
400: } else {
401: if (SwingUtilities.isEventDispatchThread()) {
402: todo.run();
403: } else {
404: SwingUtilities.invokeLater(todo);
405: }
406: }
407: }
408:
409: /**
410: * Centers <CODE>wind</CODE> within the passed rectangle.
411: *
412: * @param wind The Window to be centered.
413: * @param rect The rectangle (in screen coords) to center
414: * <CODE>wind</CODE> within.
415: *
416: * @throws IllegalArgumentException
417: * If <TT>Window</TT> or <TT>Rectangle</TT> is <TT>null</TT>.
418: */
419: private static void center(Component wind, Rectangle rect) {
420: if (wind == null || rect == null) {
421: throw new IllegalArgumentException(
422: "null Window or Rectangle passed");
423: }
424: Dimension windSize = wind.getSize();
425: int x = ((rect.width - windSize.width) / 2) + rect.x;
426: int y = ((rect.height - windSize.height) / 2) + rect.y;
427: if (y < rect.y) {
428: y = rect.y;
429: }
430: wind.setLocation(x, y);
431: }
432:
433: /**
434: * To make the main window available to fw classes.
435: *
436: * This method is called during application start by WindowManager.
437: */
438: public static void setMainFrame(JFrame mainFrame) {
439: _mainFrame = mainFrame;
440: }
441:
442: public static JFrame getMainFrame() {
443: return _mainFrame;
444: }
445:
446: /**
447: * Inserts newlines at or before lineLength at spaces or commas. If no space
448: * or comma can be found, the resultant line will not be broken up by
449: * newlines.
450: *
451: * @param line the line to word-wrap
452: * @param lineLength the maximum length any segment should be.
453: * @return a line with newlines inserted
454: */
455: public static String getWrappedLine(String line, int lineLength) {
456: if (line.length() <= lineLength) {
457: return line;
458: }
459: StringBuffer result = new StringBuffer();
460: char[] lineChars = line.toCharArray();
461: int lastBreakCharIdx = -1;
462: ArrayList<Integer> breakPoints = new ArrayList<Integer>();
463:
464: // look for places to break the string
465: for (int i = 0; i < lineChars.length; i++) {
466: char curr = lineChars[i];
467: if (curr == ' ' || curr == ',') {
468: lastBreakCharIdx = i;
469: }
470: if (i > 0 && (i % lineLength == 0)
471: && lastBreakCharIdx != -1) {
472: breakPoints.add(Integer.valueOf(lastBreakCharIdx));
473: }
474: }
475: if (lastBreakCharIdx != lineChars.length) {
476: breakPoints.add(Integer.valueOf(lineChars.length));
477: }
478: int lastBreakPointIdx = 0;
479: for (Iterator<Integer> iter = breakPoints.iterator(); iter
480: .hasNext();) {
481: int breakPointIdx = (iter.next()).intValue() + 1;
482: if (breakPointIdx > line.length()) {
483: breakPointIdx = line.length();
484: }
485: String part = line.substring(lastBreakPointIdx,
486: breakPointIdx);
487: result.append(part.trim());
488: if (!part.trim().endsWith("\\n")) {
489: result.append("\n");
490: }
491: lastBreakPointIdx = breakPointIdx;
492: }
493: return result.toString();
494: }
495: }
|