SwingUtils.java
001 /*
002  * Copyright 2008-2017 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     private SwingUtils() {
055         // prevent instantiation
056     }
057 
058     /**
059      * Centers a Window on the screen<p>
060      * Sets the window on the top left corner if the window's
061      * dimensions are bigger than the screen's.
062      *
063      @param window a Window object
064      */
065     public static void centerOnScreen(@Nonnull Window window) {
066         requireNonNull(window, ERROR_WINDOW_NULL);
067 
068         Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
069         Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
070 
071         double w = Math.min(window.getWidth(), screen.width);
072         double h = Math.min(window.getHeight(), screen.height);
073         int x = (int) (center.x - (w / 2));
074         int y = (int) (center.y - (h / 2));
075 
076         Point corner = new Point(
077             (x >= ? x : 0),
078             (y >= ? y : 0)
079         );
080 
081         window.setLocation(corner);
082     }
083 
084     /**
085      * Centers a JInternalFrame on the screen<p>
086      * Sets the internal frame on the top left corner if the frame's
087      * dimensions are bigger than the desktop's.
088      *
089      @param internalFrame a JInternalFrame object
090      */
091     public static void centerOnScreen(@Nonnull JInternalFrame internalFrame) {
092         requireNonNull(internalFrame, "Argument 'internalFrame' must not be null");
093 
094         JDesktopPane desktop = internalFrame.getDesktopPane();
095         if (desktop == null) { return}
096         Dimension screen = desktop.getSize();
097         Point center = new Point(screen.width / 2, screen.height / 2);
098 
099         double w = Math.min(internalFrame.getWidth(), screen.width);
100         double h = Math.min(internalFrame.getHeight(), screen.height);
101         int x = (int) (center.x - (w / 2));
102         int y = (int) (center.y - (h / 2));
103 
104         Point corner = new Point(
105             (x >= ? x : 0),
106             (y >= ? y : 0)
107         );
108 
109         internalFrame.setLocation(corner);
110     }
111 
112     /**
113      * Returns the window's current opacity value.
114      *
115      @param window the window on which the opacity will be queried
116      *
117      @return the window's opacity value
118      */
119     public static float getWindowOpacity(@Nonnull Window window) {
120         requireNonNull(window, ERROR_WINDOW_NULL);
121         return window.getOpacity();
122     }
123 
124     /**
125      * Sets the value for the window's opacity.
126      *
127      @param window  the window on which the opacity will be set
128      @param opacity the new opacity value
129      */
130     public static void setWindowOpacity(@Nonnull Window window, float opacity) {
131         requireNonNull(window, ERROR_WINDOW_NULL);
132         window.setOpacity(opacity);
133     }
134 
135     /**
136      * Searches a component by name in a particular component hierarchy.<p>
137      * A component must have a value for its <tt>name</tt> property if it's
138      * to be found with this method.<br/>
139      * This method performs a depth-first search.
140      *
141      @param name the value of the component's <tt>name</tt> property
142      @param root the root of the component hierarchy from where searching
143      *             searching should start
144      *
145      @return the component reference if found, null otherwise
146      */
147     @Nullable
148     public static Component findComponentByName(@Nonnull String name, @Nonnull Container root) {
149         requireNonNull(root, "Argument 'root' must not be null");
150         requireNonBlank(name, "Argument 'name' must not be blank");
151         if (name.equals(root.getName())) {
152             return root;
153         }
154 
155         for (Component comp : root.getComponents()) {
156             if (name.equals(comp.getName())) {
157                 return comp;
158             }
159             if (comp instanceof Container) {
160                 Component found = findComponentByName(name, (Containercomp);
161                 if (found != null) {
162                     return found;
163                 }
164             }
165         }
166         return null;
167     }
168 
169     /**
170      * Takes a snapshot of the target component.
171      *
172      @param component the component to draw
173      *
174      @return a Graphics compatible image of the component
175      */
176     @Nonnull
177     public static Image takeSnapshot(@Nonnull Component component) {
178         return takeSnapshot(component, false);
179     }
180 
181     /**
182      * Takes a snapshot of the target component.
183      *
184      @param component the component to draw
185      @param usePrint  whether <tt>print()</tt> or <tt>paint()</tt> is used to grab the snapshot
186      *
187      @return a Graphics compatible image of the component
188      */
189     @Nonnull
190     public static Image takeSnapshot(@Nonnull Component component, boolean usePrint) {
191         requireNonNull(component, "Argument 'component' must not be null");
192 
193         BufferedImage image = null;
194         GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment();
195         GraphicsDevice gd = genv.getDefaultScreenDevice();
196         GraphicsConfiguration gc = gd.getDefaultConfiguration();
197 
198         if (gc.getColorModel().hasAlpha()) {
199             image = gc.createCompatibleImage(
200                 (intcomponent.getSize().getWidth(),
201                 (intcomponent.getSize().getHeight());
202         else {
203             image = new BufferedImage(
204                 (intcomponent.getSize().getWidth(),
205                 (intcomponent.getSize().getHeight(),
206                 BufferedImage.TYPE_INT_ARGB);
207         }
208 
209         Graphics g = image.getGraphics();
210         if (usePrint) {
211             component.print(g);
212         else {
213             component.paint(g);
214         }
215         g.dispose();
216 
217         return image;
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      @param application the current running application
228      @param attributes  window attributes
229      *
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 }