001    /*
002     * $Id: WindowUtils.java 3352 2009-05-25 16:37:52Z kschaefe $
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.GraphicsConfiguration;
027    import java.awt.GraphicsDevice;
028    import java.awt.GraphicsEnvironment;
029    import java.awt.Insets;
030    import java.awt.MouseInfo;
031    import java.awt.Point;
032    import java.awt.Rectangle;
033    import java.awt.Toolkit;
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    
042    import javax.swing.JInternalFrame;
043    import javax.swing.JOptionPane;
044    import javax.swing.SwingUtilities;
045    
046    /**
047     * Encapsulates various utilities for windows (ie: <code>Frame</code> and
048     * <code>Dialog</code> objects and descendants, in particular).
049     *
050     * @author Richard Bair
051     */
052    public final class WindowUtils {
053        private static final Logger LOG = Logger.getLogger(WindowUtils.class
054                .getName());
055    
056        /**
057         * Hide the constructor - don't wan't anybody creating an instance of this
058         */
059        private WindowUtils() {
060        }
061    
062        /**
063         * <p>
064         * Returns the <code>Point</code> at which a window should be placed to
065         * center that window on the screen.
066         * </p>
067         * <p>
068         * Some thought was taken as to whether to implement a method such as this,
069         * or to simply make a method that, given a window, will center it.  It was
070         * decided that it is better to not alter an object within a method.
071         * </p>
072         *
073         * @param window The window to calculate the center point for.  This object
074         *               can not be null.
075         *
076         * @return the <code>Point</code> at which the window should be placed to
077         *         center that window on the screen.
078         */
079        public static Point getPointForCentering(Window window) {
080            Rectangle usableBounds = getUsableDeviceBounds(window);
081            int screenWidth = usableBounds.width;
082            int screenHeight = usableBounds.height;
083            int width = window.getWidth();
084            int height = window.getHeight();
085            
086            return new Point(((screenWidth - width) / 2) + usableBounds.x,
087                    ((screenHeight - height) / 2) + usableBounds.y);
088        }
089    
090        private static Rectangle getUsableDeviceBounds(Window window) {
091            Window owner = window.getOwner();
092            GraphicsConfiguration gc = null;
093            
094            if (owner == null) {
095                gc = GraphicsEnvironment.getLocalGraphicsEnvironment()
096                        .getDefaultScreenDevice().getDefaultConfiguration();
097            } else {
098                gc = owner.getGraphicsConfiguration();
099            }
100            
101            Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc);
102            Rectangle bounds = gc.getBounds();
103            bounds.x += insets.left;
104            bounds.y += insets.top;
105            bounds.width -= (insets.left + insets.right);
106            bounds.height -= (insets.top + insets.bottom);
107            
108            return bounds;
109        }
110        
111        /**
112         * <p/>
113         * Returns the <code>Point</code> at which a window should be placed to
114         * center that window on the given desktop.
115         * </p>
116         * <p/>
117         * Some thought was taken as to whether to implement a method such as this,
118         * or to simply make a method that, given a window, will center it.  It was
119         * decided that it is better to not alter an object within a method.
120         * </p>
121         *
122         * @param window  The window (JInternalFrame) to calculate the center point
123         *                for.  This object can not be null.
124         *
125         * @return the <code>Point</code> at which the window should be placed to
126         *         center that window on the given desktop
127         */
128        public static Point getPointForCentering(JInternalFrame window) {
129            try {
130                //assert window != null;
131                Point mousePoint = MouseInfo.getPointerInfo().getLocation();
132                GraphicsDevice[] devices = GraphicsEnvironment
133                        .getLocalGraphicsEnvironment().getScreenDevices();
134                for (GraphicsDevice device : devices) {
135                    Rectangle bounds = device.getDefaultConfiguration().getBounds();
136                    //check to see if the mouse cursor is within these bounds
137                    if (mousePoint.x >= bounds.x && mousePoint.y >= bounds.y
138                        && mousePoint.x <= (bounds.x + bounds.width)
139                        && mousePoint.y <= (bounds.y + bounds.height)) {
140                        //this is it
141                        int screenWidth = bounds.width;
142                        int screenHeight = bounds.height;
143                        int width = window.getWidth();
144                        int height = window.getHeight();
145                        return new Point(((screenWidth - width) / 2) + bounds.x,
146                                            ((screenHeight - height) / 2) + bounds
147                                                    .y);
148                    }
149                }
150            } catch (Exception e) {
151                LOG.log(Level.FINE, e.getLocalizedMessage() +
152                                    " - this can occur do to a Security exception in sandboxed apps");
153            }
154            return new Point(0, 0);
155        }
156    
157        /**
158         * <p/>
159         * Returns the <code>Point</code> at which a window should be placed in
160         * order to be staggered slightly from another &quot;origin&quot; window to
161         * ensure that the title areas of both windows remain visible to the user.
162         * </p>
163         *
164         * @param originWindow Window from which the staggered location will be calculated
165         *
166         * @return location staggered from the upper left location of the origin
167         *         window
168         */
169        public static Point getPointForStaggering(Window originWindow) {
170            Point origin = originWindow.getLocation();
171            Insets insets = originWindow.getInsets();
172            origin.x += insets.top;
173            origin.y += insets.top;
174            return origin;
175        }
176    
177        public static Window findWindow(Component c) {
178            if (c == null) {
179                return JOptionPane.getRootFrame();
180            } else if (c instanceof Window) {
181                return (Window) c;
182            } else {
183                return findWindow(c.getParent());
184            }
185        }
186    
187        public static List<Component> getAllComponents(final Container c) {
188            Component[] comps = c.getComponents();
189            List<Component> compList = new ArrayList<Component>();
190            for (Component comp : comps) {
191                compList.add(comp);
192                if (comp instanceof Container) {
193                    compList.addAll(getAllComponents((Container) comp));
194                }
195            }
196            return compList;
197        }
198    
199        /**
200         * Installs/resets a ComponentListener to resize the
201         * given window to minWidth/Height if needed.
202         *
203         * @param window
204         * @param minWidth
205         * @param minHeight
206         */
207        public static void setMinimumSizeManager(Window window, int minWidth,
208                                                 int minHeight) {
209            ComponentListener[] listeners = window.getComponentListeners();
210            ComponentListener listener = null;
211            for (ComponentListener l : listeners) {
212                if (l instanceof MinSizeComponentListener) {
213                    listener = l;
214                    break;
215                }
216            }
217            if (listener == null) {
218                window.addComponentListener(new MinSizeComponentListener(
219                        window, minWidth, minHeight));
220            } else {
221                ((MinSizeComponentListener) listener).resetSizes(minWidth,
222                                                                 minHeight);
223            }
224        }
225    
226        /**
227         * Resets window size to minSize if needed.
228         *
229         * @author Patrick Wright
230         */
231        public static class MinSizeComponentListener extends ComponentAdapter {
232            private Window window;
233            private int minHeight;
234            private int minWidth;
235    
236            MinSizeComponentListener(Window frame, int minWidth, int minHeight) {
237                this.window = frame;
238                resetSizes(minWidth, minHeight);
239            }
240    
241            public void resetSizes(int minWidth, int minHeight) {
242                this.minWidth = minWidth;
243                this.minHeight = minHeight;
244                adjustIfNeeded(window);
245            }
246    
247            @Override
248            public void componentResized(java.awt.event.ComponentEvent evt) {
249                adjustIfNeeded((Window) evt.getComponent());
250            }
251    
252            private void adjustIfNeeded(final Window window) {
253                boolean doSize = false;
254                int newWidth = window.getWidth();
255                int newHeight = window.getHeight();
256                if (newWidth < minWidth) {
257                    newWidth = minWidth;
258                    doSize = true;
259                }
260                if (newHeight < minHeight) {
261                    newHeight = minHeight;
262                    doSize = true;
263                }
264                if (doSize) {
265                    final int w = newWidth;
266                    final int h = newHeight;
267                    SwingUtilities.invokeLater(new Runnable() {
268                        public void run() {
269                            window.setSize(w, h);
270                        }
271                    });
272                }
273            }
274        }
275    }