/*
* Copyright (C) 2009 Illya Yalovyy (yalovoy@gmail.com). All rights reserved.
* Copyright (C) 2011 Peransin Nicolas. All rights reserved.
* Use is subject to license terms.
*/
package org.mypsycho.swing.app.utils;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.net.URL;
import java.util.Locale;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.JRootPane;
import javax.swing.RootPaneContainer;
import org.mypsycho.beans.converter.TypeConverter;
import org.mypsycho.swing.app.Application;
/**
* Utility class for Swing Application Framework (BSAF)
*
* @author Illya Yalovyy
* @author Eric Heumann
* @author Peransin Nicolas
*/
public class Swings {
private static final String WINDOW_STATE_NORMAL_BOUNDS = "WindowState.normalBounds";
public static boolean isSwing(Component comp) {
return (comp instanceof JComponent) || (comp instanceof RootPaneContainer);
}
/**
* Calculates virtual graphic bounds.
* On multiscreen systems all screens are united into one virtual screen.
* @return the graphic bounds
*/
public static Rectangle computeVirtualGraphicsBounds() {
Rectangle virtualBounds = new Rectangle();
GraphicsEnvironment ge = GraphicsEnvironment
.getLocalGraphicsEnvironment();
GraphicsDevice[] gs = ge.getScreenDevices();
for (GraphicsDevice gd : gs) {
GraphicsConfiguration gc = gd.getDefaultConfiguration();
virtualBounds = virtualBounds.union(gc.getBounds());
}
return virtualBounds;
}
/**
* Checks whether the window supports resizing
* @param window the {@code Window} to be checked
* @return true if the window supports resizing
*/
public static boolean isResizable(Window window) {
if (window instanceof Frame) {
return ((Frame) window).isResizable();
}
if (window instanceof Dialog) {
return ((Dialog) window).isResizable();
}
return true;
}
/**
* Calculates default location for the specified window.
* @return default location for the window
* @param window the window location is calculated for.
* It should not be null.
*/
public static Point defaultLocation(Window window) {
GraphicsConfiguration gc = window.getGraphicsConfiguration();
Rectangle bounds = gc.getBounds();
Insets insets = window.getToolkit().getScreenInsets(gc);
int x = bounds.x + insets.left;
int y = bounds.y + insets.top;
return new Point(x, y);
}
/**
* Finds the nearest RootPaneContainer of the provided Component.
* Primarily, if a JPopupMenu (such as used by JMenus when they are visible) has no parent,
* the search continues with the JPopupMenu's invoker instead. Fixes BSAF-77
*
* @return a RootPaneContainer for the provided component
* @param root the Component
*/
public static RootPaneContainer findRootPaneContainer(Component root) {
while (root != null) {
if (root instanceof RootPaneContainer) {
return (RootPaneContainer) root;
} else if (root instanceof JPopupMenu && root.getParent() == null) {
root = ((JPopupMenu) root).getInvoker();
} else {
root = root.getParent();
}
}
return null;
}
/**
* Gets {@code Window} bounds from the client property
* @param window the source {@code Window}
* @return bounds from the client property
*/
public static Rectangle getWindowNormalBounds(Window window) {
if (!(window instanceof RootPaneContainer)) {
return null;
}
JRootPane root = ((RootPaneContainer) window).getRootPane();
Object res = root.getClientProperty(WINDOW_STATE_NORMAL_BOUNDS);
return (res instanceof Rectangle) ? (Rectangle) res : null;
}
/**
* Puts {@code Window} bounds to client property.
* @param window the target {@code Window}
* @param bounds bounds
*/
public static void putWindowNormalBounds(Window window, Rectangle bounds) {
if (!(window instanceof RootPaneContainer)) {
return;
}
JRootPane root = ((RootPaneContainer) window).getRootPane();
root.putClientProperty(WINDOW_STATE_NORMAL_BOUNDS, bounds);
}
public static boolean isVisibleWindow(Window w) {
return w.isVisible() && (w instanceof RootPaneContainer);
}
private static final String[] EXT_FILES_FALLBACK = { ".html", ".txt", "" };
public static URL getDefaultResource(Application app, String prop) {
// English is the common technical language.
// Here locale is about resource id, not application content.
return getDefaultResource(app, prop, prop.toUpperCase(Locale.ENGLISH));
}
public static URL getDefaultResource(Application app, String prop, String defaultValue) {
TypeConverter converter = app.getContext().getResourceManager().getConverter();
String value = app.getProperty("Application." + prop);
URL text = (value != null) ? (URL) converter.convert(URL.class, value, app) : null;
for (String ext : EXT_FILES_FALLBACK) {
value = defaultValue.toUpperCase() + ext;
if (text != null) {
break;
}
text = (URL) converter.convert(URL.class, value, app);
}
return text;
}
public static final void assertNotNull(String name, Object value) {
if (value == null) {
throw new IllegalArgumentException("null " + null);
}
}
public static final ComponentListener FRAME_BOUND_LISTENER = new ComponentAdapter() {
private void maybeSaveFrameSize(ComponentEvent e) {
if (e.getComponent() instanceof JFrame) {
JFrame f = (JFrame) e.getComponent();
if ((f.getExtendedState() & Frame.MAXIMIZED_BOTH) == 0) {
SwingHelper.putWindowNormalBounds(f, f.getBounds());
}
}
}
@Override
public void componentResized(ComponentEvent e) {
maybeSaveFrameSize(e);
}
// @Override
// public void componentMoved(ComponentEvent e) { /* maybeSaveFrameSize(e); */ }
};
}