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 >= 0 ? x : 0),
074 (y >= 0 ? 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 == null) return;
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 >= 0 ? x : 0),
102 (y >= 0 ? 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, (Container) comp);
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 (int) component.getSize().getWidth(),
193 (int) component.getSize().getHeight());
194 } else {
195 image = new BufferedImage(
196 (int) component.getSize().getWidth(),
197 (int) component.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 = (JFrame) cl.loadClass(frameClass).newInstance();
244 } else {
245 frame = (JFrame) Class.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 = (JFrame) cl.loadClass("org.jdesktop.swingx.JXFrame").newInstance();
257 } else {
258 frame = (JFrame) Class.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 }
|