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