SwingUtils.java
001 /*
002  * Copyright 2008-2014 the original author or authors.
003  *
004  * Licensed under the Apache License, Version 2.0 (the "License");
005  * you may not use this file except in compliance with the License.
006  * You may obtain a copy of the License at
007  *
008  *     http://www.apache.org/licenses/LICENSE-2.0
009  *
010  * Unless required by applicable law or agreed to in writing, software
011  * distributed under the License is distributed on an "AS IS" BASIS,
012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013  * See the License for the specific language governing permissions and
014  * limitations under the License.
015  */
016 package griffon.swing.support;
017 
018 import griffon.core.GriffonApplication;
019 
020 import javax.annotation.Nonnull;
021 import javax.annotation.Nullable;
022 import javax.swing.JDesktopPane;
023 import javax.swing.JFrame;
024 import javax.swing.JInternalFrame;
025 import javax.swing.WindowConstants;
026 import java.awt.*;
027 import java.awt.image.BufferedImage;
028 import java.util.Map;
029 
030 import static griffon.util.GriffonClassUtils.setPropertiesNoException;
031 import static griffon.util.GriffonNameUtils.isBlank;
032 import static griffon.util.GriffonNameUtils.requireNonBlank;
033 import static java.util.Objects.requireNonNull;
034 
035 /**
036  * Additional utilities for Swing based applications.
037  *
038  @author Andres Almiray
039  @since 2.0.0
040  */
041 public class SwingUtils {
042     private static final String ERROR_WINDOW_NULL = "Argument 'window' must not be null";
043 
044     /**
045      * Centers a Window on the screen<p>
046      * Sets the window on the top left corner if the window's
047      * dimensions are bigger than the screen's.
048      *
049      @param window a Window object
050      */
051     public static void centerOnScreen(@Nonnull Window window) {
052         requireNonNull(window, ERROR_WINDOW_NULL);
053 
054         Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
055         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
056 
057         double w = Math.min(window.getWidth(), screen.width);
058         double h = Math.min(window.getHeight(), screen.height);
059         int x = (int) (center.x - (w / 2));
060         int y = (int) (center.y - (h / 2));
061 
062         Point corner = new Point(
063             (x >= ? x : 0),
064             (y >= ? y : 0)
065         );
066 
067         window.setLocation(corner);
068     }
069 
070     /**
071      * Centers a JInternalFrame on the screen<p>
072      * Sets the internal frame on the top left corner if the frame's
073      * dimensions are bigger than the desktop's.
074      *
075      @param internalFrame a JInternalFrame object
076      */
077     public static void centerOnScreen(@Nonnull JInternalFrame internalFrame) {
078         requireNonNull(internalFrame, "Argument 'internalFrame' must not be null");
079 
080         JDesktopPane desktop = internalFrame.getDesktopPane();
081         if (desktop == nullreturn;
082         Dimension screen = desktop.getSize();
083         Point center = new Point(screen.width / 2, screen.height / 2);
084 
085         double w = Math.min(internalFrame.getWidth(), screen.width);
086         double h = Math.min(internalFrame.getHeight(), screen.height);
087         int x = (int) (center.x - (w / 2));
088         int y = (int) (center.y - (h / 2));
089 
090         Point corner = new Point(
091             (x >= ? x : 0),
092             (y >= ? y : 0)
093         );
094 
095         internalFrame.setLocation(corner);
096     }
097 
098     /**
099      * Returns the window's current opacity value.
100      *
101      @param window the window on which the opacity will be queried
102      @return the window's opacity value
103      */
104     public static float getWindowOpacity(@Nonnull Window window) {
105         requireNonNull(window, ERROR_WINDOW_NULL);
106         return window.getOpacity();
107     }
108 
109     /**
110      * Sets the value for the window's opacity.
111      *
112      @param window  the window on which the opacity will be set
113      @param opacity the new opacity value
114      */
115     public static void setWindowOpacity(@Nonnull Window window, float opacity) {
116         requireNonNull(window, ERROR_WINDOW_NULL);
117         window.setOpacity(opacity);
118     }
119 
120     /**
121      * Searches a component by name in a particular component hierarchy.<p>
122      * A component must have a value for its <tt>name</tt> property if it's
123      * to be found with this method.<br/>
124      * This method performs a depth-first search.
125      *
126      @param name the value of the component's <tt>name</tt> property
127      @param root the root of the component hierarchy from where searching
128      *             searching should start
129      @return the component reference if found, null otherwise
130      */
131     @Nullable
132     public static Component findComponentByName(@Nonnull String name, @Nonnull Container root) {
133         requireNonNull(root, "Argument 'root' must not be null");
134         requireNonBlank(name, "Argument 'name' must not be blank");
135         if (name.equals(root.getName())) {
136             return root;
137         }
138 
139         for (Component comp : root.getComponents()) {
140             if (name.equals(comp.getName())) {
141                 return comp;
142             }
143             if (comp instanceof Container) {
144                 Component found = findComponentByName(name, (Containercomp);
145                 if (found != null) {
146                     return found;
147                 }
148             }
149         }
150         return null;
151     }
152 
153     /**
154      * Takes a snapshot of the target component.
155      *
156      @param component the component to draw
157      @return a Graphics compatible image of the component
158      */
159     @Nonnull
160     public static Image takeSnapshot(@Nonnull Component component) {
161         return takeSnapshot(component, false);
162     }
163 
164     /**
165      * Takes a snapshot of the target component.
166      *
167      @param component the component to draw
168      @param usePrint  whether <tt>print()</tt> or <tt>paint()</tt> is used to grab the snapshot
169      @return a Graphics compatible image of the component
170      */
171     @Nonnull
172     public static Image takeSnapshot(@Nonnull Component component, boolean usePrint) {
173         requireNonNull(component, "Argument 'component' must not be null");
174 
175         BufferedImage image = null;
176         GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
177         GraphicsDevice gd = genv.getDefaultScreenDevice();
178         GraphicsConfiguration gc = gd.getDefaultConfiguration();
179 
180         if (gc.getColorModel().hasAlpha()) {
181             image = gc.createCompatibleImage(
182                 (intcomponent.getSize().getWidth(),
183                 (intcomponent.getSize().getHeight());
184         else {
185             image = new BufferedImage(
186                 (intcomponent.getSize().getWidth(),
187                 (intcomponent.getSize().getHeight(),
188                 BufferedImage.TYPE_INT_ARGB);
189         }
190 
191         Graphics g = image.getGraphics();
192         if (usePrint) {
193             component.print(g);
194         else {
195             component.paint(g);
196         }
197         g.dispose();
198 
199         return image;
200     }
201 
202     private static Class<?> loadClass(String className) {
203         try {
204             return Class.forName(className);
205         catch (ClassNotFoundException e) {
206             throw new IllegalArgumentException(e);
207         }
208     }
209 
210     /**
211      * Creates a Window based on the application's configuration.<p>
212      * Class lookup order is<ol>
213      <li>value in app.config.application.frameClass</li>
214      <li>'org.jdesktop.swingx.JXFrame' if SwingX is in the classpath</li>
215      <li>'javax.swing.JFrame'</li>
216      *
217      *
218      @param application the current running application
219      @param attributes window attributes
220      @return a newly instantiated window according to the application's
221      *         preferences
222      */
223     @Nonnull
224     public static Window createApplicationFrame(@Nonnull GriffonApplication application, @Nonnull Map<String, Object> attributes) {
225         requireNonNull(application, "Argument 'application' must not be null");
226         JFrame frame = null;
227         // try config specified first
228         String frameClass = application.getConfiguration().getAsString("application.frameClass", JFrame.class.getName());
229         if (!isBlank(frameClass)) {
230             try {
231                 ClassLoader cl = SwingUtils.class.getClassLoader();
232                 if (cl != null) {
233                     frame = (JFramecl.loadClass(frameClass).newInstance();
234                 else {
235                     frame = (JFrameClass.forName(frameClass).newInstance();
236                 }
237             catch (Throwable ignored) {
238                 // ignore
239             }
240         }
241         if (frame == null) {
242             // JXFrame, it's nice.  Try it!
243             try {
244                 ClassLoader cl = SwingUtils.class.getClassLoader();
245                 if (cl != null) {
246                     frame = (JFramecl.loadClass("org.jdesktop.swingx.JXFrame").newInstance();
247                 else {
248                     frame = (JFrameClass.forName("org.jdesktop.swingx.JXFrame").newInstance();
249                 }
250             catch (Throwable ignored) {
251                 // ignore
252             }
253             // this will work for sure
254             if (frame == null) {
255                 frame = new JFrame();
256             }
257 
258             // do some standard tweaking
259             frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
260         }
261 
262         setPropertiesNoException(frame, attributes);
263 
264         return frame;
265     }
266 }