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