001    /*
002     * $Id: WindowUtils.java,v 1.11 2006/04/20 00:20:41 gfx Exp $
003     *
004     * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005     * Santa Clara, California 95054, U.S.A. All rights reserved.
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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
020     */
021    
022    package org.jdesktop.swingx.util;
023    
024    import java.awt.Component;
025    import java.awt.Container;
026    import java.awt.Font;
027    import java.awt.GraphicsDevice;
028    import java.awt.GraphicsEnvironment;
029    import java.awt.GridBagConstraints;
030    import java.awt.Insets;
031    import java.awt.MouseInfo;
032    import java.awt.Point;
033    import java.awt.Rectangle;
034    import java.awt.Window;
035    import java.awt.event.ComponentAdapter;
036    import java.awt.event.ComponentListener;
037    import java.util.ArrayList;
038    import java.util.List;
039    import java.util.logging.Level;
040    import java.util.logging.Logger;
041    import javax.swing.JComponent;
042    import javax.swing.JDialog;
043    import javax.swing.JFrame;
044    import javax.swing.JInternalFrame;
045    import javax.swing.JOptionPane;
046    import javax.swing.RootPaneContainer;
047    import javax.swing.SwingUtilities;
048    
049    /**
050     * Encapsulates various utilities for windows (ie: <code>Frame</code> and
051     * <code>Dialog</code> objects and descendants, in particular).
052     *
053     * @author Richard Bair
054     */
055    public final class WindowUtils {
056        private static final Logger LOG = Logger.getLogger(WindowUtils.class
057                .getName());
058    
059        /**
060         * Hide the constructor - don't wan't anybody creating an instance of this
061         */
062        private WindowUtils() {
063        }
064    
065        /**
066         * <p/>
067         * Returns the <code>Point</code> at which a window should be placed to
068         * center that window on the screen.
069         * </p>
070         * <p/>
071         * Some thought was taken as to whether to implement a method such as this,
072         * or to simply make a method that, given a window, will center it.  It was
073         * decided that it is better to not alter an object within a method.
074         * </p>
075         *
076         * @param window The window to calculate the center point for.  This object
077         *               can not be null.
078         *
079         * @return the <code>Point</code> at which the window should be placed to
080         *         center that window on the screen.
081         */
082        public static Point getPointForCentering(Window window) {
083            //assert window != null;
084            try {
085                Point mousePoint = MouseInfo.getPointerInfo().getLocation();
086                GraphicsDevice[] devices = GraphicsEnvironment
087                        .getLocalGraphicsEnvironment().getScreenDevices();
088                for (GraphicsDevice device : devices) {
089                    Rectangle bounds = device.getDefaultConfiguration().getBounds();
090                    //check to see if the mouse cursor is within these bounds
091                    if (mousePoint.x >= bounds.x && mousePoint.y >= bounds.y
092                        && mousePoint.x <= (bounds.x + bounds.width)
093                        && mousePoint.y <= (bounds.y + bounds.height)) {
094                        //this is it
095                        int screenWidth = bounds.width;
096                        int screenHeight = bounds.height;
097                        int width = window.getWidth();
098                        int height = window.getHeight();
099                        Point p = new Point(((screenWidth - width) / 2) + bounds.x,
100                                            ((screenHeight - height) / 2) + bounds
101                                                    .y);
102                        return p;
103                    }
104                }
105            } catch (Exception e) {
106                LOG.log(Level.FINE, e.getLocalizedMessage() +
107                                    " - this can occur do to a Security exception in sandboxed apps");
108            }
109            return new Point(0, 0);
110        }
111    
112        /**
113         * <p/>
114         * Returns the <code>Point</code> at which a window should be placed to
115         * center that window on the given desktop.
116         * </p>
117         * <p/>
118         * Some thought was taken as to whether to implement a method such as this,
119         * or to simply make a method that, given a window, will center it.  It was
120         * decided that it is better to not alter an object within a method.
121         * </p>
122         *
123         * @param window  The window (JInternalFrame) to calculate the center point
124         *                for.  This object can not be null.
125         *
126         * @return the <code>Point</code> at which the window should be placed to
127         *         center that window on the given desktop
128         */
129        public static Point getPointForCentering(JInternalFrame window) {
130            try {
131                //assert window != null;
132                Point mousePoint = MouseInfo.getPointerInfo().getLocation();
133                GraphicsDevice[] devices = GraphicsEnvironment
134                        .getLocalGraphicsEnvironment().getScreenDevices();
135                for (GraphicsDevice device : devices) {
136                    Rectangle bounds = device.getDefaultConfiguration().getBounds();
137                    //check to see if the mouse cursor is within these bounds
138                    if (mousePoint.x >= bounds.x && mousePoint.y >= bounds.y
139                        && mousePoint.x <= (bounds.x + bounds.width)
140                        && mousePoint.y <= (bounds.y + bounds.height)) {
141                        //this is it
142                        int screenWidth = bounds.width;
143                        int screenHeight = bounds.height;
144                        int width = window.getWidth();
145                        int height = window.getHeight();
146                        Point p = new Point(((screenWidth - width) / 2) + bounds.x,
147                                            ((screenHeight - height) / 2) + bounds
148                                                    .y);
149                        return p;
150                    }
151                }
152            } catch (Exception e) {
153                LOG.log(Level.FINE, e.getLocalizedMessage() +
154                                    " - this can occur do to a Security exception in sandboxed apps");
155            }
156            return new Point(0, 0);
157        }
158    
159        /**
160         * <p/>
161         * Returns the <code>Point</code> at which a window should be placed in
162         * order to be staggered slightly from another &quot;origin&quot; window to
163         * ensure that the title areas of both windows remain visible to the user.
164         * </p>
165         *
166         * @param originWindow Window from which the staggered location will be calculated
167         *
168         * @return location staggered from the upper left location of the origin
169         *         window
170         */
171        public static Point getPointForStaggering(Window originWindow) {
172            Point origin = originWindow.getLocation();
173            Insets insets = originWindow.getInsets();
174            origin.x += insets.top;
175            origin.y += insets.top;
176            return origin;
177        }
178    
179        /**
180         * Utility method used to load a GridBagConstraints object (param gbc) with the
181         * data in the other parameters.  This method saves code space over doing the
182         * assignments by hand, and also allows you to reuse the same GridBagConstraints
183         * object reducing temporary object creating (at the expense of a method call.
184         * Go figure).
185         */
186        public static void setConstraints(GridBagConstraints gbc, int gridx,
187                                          int gridy, int gridwidth, int gridheight,
188                                          double weightx, double weighty,
189                                          int anchor, int fill, int top, int left,
190                                          int bottom, int right) {
191            gbc.gridx = gridx;
192            gbc.gridy = gridy;
193            gbc.gridwidth = gridwidth;
194            gbc.gridheight = gridheight;
195            gbc.weightx = weightx;
196            gbc.weighty = weighty;
197            gbc.anchor = anchor;
198            gbc.fill = fill;
199            gbc.insets = new Insets(top, left, bottom, right);
200        }
201    
202        /**
203         * Get a <code>Rectangle</code> object representing the given window's position and
204         * magnitude in space.
205         *
206         * @param win The window to get a Rectangle object for
207         *
208         * @return a Rectangle object.  @see com.jgui.Rectangle
209         */
210        public static Rectangle getRectangle(Window win) {
211            Rectangle Rectangle = new Rectangle(win.getY(), win.getX(),
212                                                win.getWidth(), win.getHeight());
213            return Rectangle;
214        }
215    
216        /**
217         * Get a <code>Rectangle</code> object representing the given JComponent's position and
218         * magnitude in space.
219         *
220         * @param comp The JComponent to get a Rectangle object for
221         *
222         * @return a Rectangle object.  @see com.jgui.Rectangle
223         */
224        public static Rectangle getRectangle(JComponent comp) {
225            Rectangle Rectangle = new Rectangle(comp.getY(), comp.getX(),
226                                                comp.getWidth(), comp.getHeight());
227            return Rectangle;
228        }
229    
230        /**
231         * Locates the RootPaneContainer for the given component
232         *
233         * @param c
234         *
235         * @return the RootPaneContainer to which the component belongs to
236         */
237        public static RootPaneContainer findRootPaneContainer(Component c) {
238            if (c == null) {
239                return null;
240            } else if (c instanceof RootPaneContainer) {
241                return (RootPaneContainer) c;
242            } else {
243                return findRootPaneContainer(c.getParent());
244            }
245        }
246    
247        /**
248         * Locates the JFrame for the given component
249         *
250         * @param c
251         *
252         * @return the JFrame to which the component belongs to
253         */
254        public static JFrame findJFrame(Component c) {
255            if (c == null) {
256                return null;
257            } else if (c instanceof RootPaneContainer) {
258                return (JFrame) c;
259            } else {
260                return findJFrame(c.getParent());
261            }
262        }
263    
264        /**
265         * Locates the JDialog for the given component
266         *
267         * @param c
268         *
269         * @return the JDialog to which the component belongs to
270         */
271        public static JDialog findJDialog(Component c) {
272            if (c == null) {
273                return null;
274            } else if (c instanceof JDialog) {
275                return (JDialog) c;
276            } else {
277                return findJDialog(c.getParent());
278            }
279        }
280    
281        public static Window findWindow(Component c) {
282            if (c == null) {
283                return JOptionPane.getRootFrame();
284            } else if (c instanceof Window) {
285                return (Window) c;
286            } else {
287                return findWindow(c.getParent());
288            }
289        }
290    
291        public static List<Component> getAllComponents(final Container c) {
292            Component[] comps = c.getComponents();
293            List<Component> compList = new ArrayList<Component>();
294            for (Component comp : comps) {
295                compList.add(comp);
296                if (comp instanceof Container) {
297                    compList.addAll(getAllComponents((Container) comp));
298                }
299            }
300            return compList;
301        }
302    
303        public static void setFontRecursively(Container c, Font font) {
304            for (Component comp : getAllComponents(c)) {
305                comp.setFont(font);
306            }
307        }
308    
309        /**
310         * Installs/resets a ComponentListener to resize the
311         * given window to minWidth/Height if needed.
312         *
313         * @param window
314         * @param minWidth
315         * @param minHeight
316         */
317        public static void setMinimumSizeManager(Window window, int minWidth,
318                                                 int minHeight) {
319            ComponentListener[] listeners = window.getComponentListeners();
320            ComponentListener listener = null;
321            for (ComponentListener l : listeners) {
322                if (l instanceof MinSizeComponentListener) {
323                    listener = l;
324                    break;
325                }
326            }
327            if (listener == null) {
328                window.addComponentListener(new MinSizeComponentListener(
329                        window, minWidth, minHeight));
330            } else {
331                ((MinSizeComponentListener) listener).resetSizes(minWidth,
332                                                                 minHeight);
333            }
334        }
335    
336        /**
337         * Resets window size to minSize if needed.
338         *
339         * @author Patrick Wright
340         */
341        public static class MinSizeComponentListener extends ComponentAdapter {
342            private Window window;
343            private int minHeight;
344            private int minWidth;
345    
346            MinSizeComponentListener(Window frame, int minWidth, int minHeight) {
347                this.window = frame;
348                resetSizes(minWidth, minHeight);
349            }
350    
351            public void resetSizes(int minWidth, int minHeight) {
352                this.minWidth = minWidth;
353                this.minHeight = minHeight;
354                adjustIfNeeded(window);
355            }
356    
357            @Override
358            public void componentResized(java.awt.event.ComponentEvent evt) {
359                adjustIfNeeded((Window) evt.getComponent());
360            }
361    
362            private void adjustIfNeeded(final Window window) {
363                boolean doSize = false;
364                int newWidth = window.getWidth();
365                int newHeight = window.getHeight();
366                if (newWidth < minWidth) {
367                    newWidth = minWidth;
368                    doSize = true;
369                }
370                if (newHeight < minHeight) {
371                    newHeight = minHeight;
372                    doSize = true;
373                }
374                if (doSize) {
375                    final int w = newWidth;
376                    final int h = newHeight;
377                    SwingUtilities.invokeLater(new Runnable() {
378                        public void run() {
379                            window.setSize(w, h);
380                        }
381                    });
382                }
383            }
384        }
385    }