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 >= 0 ? x : 0),
080 (y >= 0 ? 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 >= 0 ? x : 0),
108 (y >= 0 ? 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, (Container) comp);
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 (int) component.getSize().getWidth(),
203 (int) component.getSize().getHeight());
204 } else {
205 image = new BufferedImage(
206 (int) component.getSize().getWidth(),
207 (int) component.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 = (JFrame) cl.loadClass(frameClass).newInstance();
246 } else {
247 frame = (JFrame) Class.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 = (JFrame) cl.loadClass("org.jdesktop.swingx.JXFrame").newInstance();
259 } else {
260 frame = (JFrame) Class.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 }
|