/* * Copyright 2008-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package griffon.swing.support; import griffon.core.GriffonApplication; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.swing.JDesktopPane; import javax.swing.JFrame; import javax.swing.JInternalFrame; import javax.swing.WindowConstants; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Point; import java.awt.Toolkit; import java.awt.Window; import java.awt.image.BufferedImage; import java.util.Map; import static griffon.util.GriffonClassUtils.setPropertiesNoException; import static griffon.util.GriffonNameUtils.isBlank; import static griffon.util.GriffonNameUtils.requireNonBlank; import static java.util.Objects.requireNonNull; /** * Additional utilities for Swing based applications. * * @author Andres Almiray * @since 2.0.0 */ public class SwingUtils { private static final String ERROR_WINDOW_NULL = "Argument 'window' must not be null"; /** * Centers a Window on the screen<p> * Sets the window on the top left corner if the window's * dimensions are bigger than the screen's. * * @param window a Window object */ public static void centerOnScreen(@Nonnull Window window) { requireNonNull(window, ERROR_WINDOW_NULL); Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint(); Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); double w = Math.min(window.getWidth(), screen.width); double h = Math.min(window.getHeight(), screen.height); int x = (int) (center.x - (w / 2)); int y = (int) (center.y - (h / 2)); Point corner = new Point( (x >= 0 ? x : 0), (y >= 0 ? y : 0) ); window.setLocation(corner); } /** * Centers a JInternalFrame on the screen<p> * Sets the internal frame on the top left corner if the frame's * dimensions are bigger than the desktop's. * * @param internalFrame a JInternalFrame object */ public static void centerOnScreen(@Nonnull JInternalFrame internalFrame) { requireNonNull(internalFrame, "Argument 'internalFrame' must not be null"); JDesktopPane desktop = internalFrame.getDesktopPane(); if (desktop == null) return; Dimension screen = desktop.getSize(); Point center = new Point(screen.width / 2, screen.height / 2); double w = Math.min(internalFrame.getWidth(), screen.width); double h = Math.min(internalFrame.getHeight(), screen.height); int x = (int) (center.x - (w / 2)); int y = (int) (center.y - (h / 2)); Point corner = new Point( (x >= 0 ? x : 0), (y >= 0 ? y : 0) ); internalFrame.setLocation(corner); } /** * Returns the window's current opacity value. * * @param window the window on which the opacity will be queried * @return the window's opacity value */ public static float getWindowOpacity(@Nonnull Window window) { requireNonNull(window, ERROR_WINDOW_NULL); return window.getOpacity(); } /** * Sets the value for the window's opacity. * * @param window the window on which the opacity will be set * @param opacity the new opacity value */ public static void setWindowOpacity(@Nonnull Window window, float opacity) { requireNonNull(window, ERROR_WINDOW_NULL); window.setOpacity(opacity); } /** * Searches a component by name in a particular component hierarchy.<p> * A component must have a value for its <tt>name</tt> property if it's * to be found with this method.<br/> * This method performs a depth-first search. * * @param name the value of the component's <tt>name</tt> property * @param root the root of the component hierarchy from where searching * searching should start * @return the component reference if found, null otherwise */ @Nullable public static Component findComponentByName(@Nonnull String name, @Nonnull Container root) { requireNonNull(root, "Argument 'root' must not be null"); requireNonBlank(name, "Argument 'name' must not be blank"); if (name.equals(root.getName())) { return root; } for (Component comp : root.getComponents()) { if (name.equals(comp.getName())) { return comp; } if (comp instanceof Container) { Component found = findComponentByName(name, (Container) comp); if (found != null) { return found; } } } return null; } /** * Takes a snapshot of the target component. * * @param component the component to draw * @return a Graphics compatible image of the component */ @Nonnull public static Image takeSnapshot(@Nonnull Component component) { return takeSnapshot(component, false); } /** * Takes a snapshot of the target component. * * @param component the component to draw * @param usePrint whether <tt>print()</tt> or <tt>paint()</tt> is used to grab the snapshot * @return a Graphics compatible image of the component */ @Nonnull public static Image takeSnapshot(@Nonnull Component component, boolean usePrint) { requireNonNull(component, "Argument 'component' must not be null"); BufferedImage image = null; GraphicsEnvironment genv = GraphicsEnvironment.getLocalGraphicsEnvironment(); GraphicsDevice gd = genv.getDefaultScreenDevice(); GraphicsConfiguration gc = gd.getDefaultConfiguration(); if (gc.getColorModel().hasAlpha()) { image = gc.createCompatibleImage( (int) component.getSize().getWidth(), (int) component.getSize().getHeight()); } else { image = new BufferedImage( (int) component.getSize().getWidth(), (int) component.getSize().getHeight(), BufferedImage.TYPE_INT_ARGB); } Graphics g = image.getGraphics(); if (usePrint) { component.print(g); } else { component.paint(g); } g.dispose(); return image; } private static Class<?> loadClass(String className) { try { return Class.forName(className); } catch (ClassNotFoundException e) { throw new IllegalArgumentException(e); } } /** * Creates a Window based on the application's configuration.<p> * Class lookup order is<ol> * <li>value in app.config.application.frameClass</li> * <li>'org.jdesktop.swingx.JXFrame' if SwingX is in the classpath</li> * <li>'javax.swing.JFrame'</li> * * * @param application the current running application * @param attributes window attributes * @return a newly instantiated window according to the application's * preferences */ @Nonnull public static Window createApplicationFrame(@Nonnull GriffonApplication application, @Nonnull Map<String, Object> attributes) { requireNonNull(application, "Argument 'application' must not be null"); JFrame frame = null; // try config specified first String frameClass = application.getConfiguration().getAsString("application.frameClass", JFrame.class.getName()); if (!isBlank(frameClass)) { try { ClassLoader cl = SwingUtils.class.getClassLoader(); if (cl != null) { frame = (JFrame) cl.loadClass(frameClass).newInstance(); } else { frame = (JFrame) Class.forName(frameClass).newInstance(); } } catch (Throwable ignored) { // ignore } } if (frame == null) { // JXFrame, it's nice. Try it! try { ClassLoader cl = SwingUtils.class.getClassLoader(); if (cl != null) { frame = (JFrame) cl.loadClass("org.jdesktop.swingx.JXFrame").newInstance(); } else { frame = (JFrame) Class.forName("org.jdesktop.swingx.JXFrame").newInstance(); } } catch (Throwable ignored) { // ignore } // this will work for sure if (frame == null) { frame = new JFrame(); } // do some standard tweaking frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); } setPropertiesNoException(frame, attributes); return frame; } }