/* This file is part of RouteConverter. RouteConverter is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. RouteConverter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with RouteConverter; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Copyright (C) 2007 Christian Pesch. All Rights Reserved. */ package slash.navigation.gui; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowStateListener; import java.net.URL; import java.util.logging.Logger; import java.util.prefs.Preferences; import static java.awt.Frame.MAXIMIZED_HORIZ; import static java.awt.Frame.MAXIMIZED_VERT; import static java.awt.Frame.NORMAL; import static java.awt.event.KeyEvent.VK_ESCAPE; import static java.lang.Integer.MAX_VALUE; import static java.util.logging.Logger.getLogger; import static java.util.prefs.Preferences.userNodeForPackage; import static javax.swing.JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT; import static javax.swing.KeyStroke.getKeyStroke; import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE; /** * The base of all single frame graphical user interfaces. * * @author Christian Pesch */ public abstract class SingleFrameApplication extends Application { private static final Logger log = getLogger(SingleFrameApplication.class.getName()); private final Preferences preferences = userNodeForPackage(getClass()); static final String X_PREFERENCE = "x"; static final String Y_PREFERENCE = "y"; static final String WIDTH_PREFERENCE = "width"; static final String HEIGHT_PREFERENCE = "height"; private static final String STATE_PREFERENCE = "state"; private static final String DEVICE_PREFERENCE = "device"; protected JFrame frame; public JFrame getFrame() { return frame; } protected void createFrame(String frameTitle, String iconName, JPanel contentPane, JButton defaultButton, JMenuBar menuBar) { GraphicsConfiguration gc = null; String deviceId = preferences.get(DEVICE_PREFERENCE, null); if (deviceId != null) { GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices(); for (GraphicsDevice device : devices) { if (deviceId.equals(device.getIDstring())) { gc = device.getDefaultConfiguration(); log.info("Graphics device is " + deviceId); break; } } } frame = new JFrame(frameTitle, gc); frame.setIconImage(loadImage(iconName)); frame.setContentPane(contentPane); if (defaultButton != null) frame.getRootPane().setDefaultButton(defaultButton); if (menuBar != null) { frame.getRootPane().setJMenuBar(menuBar); getContext().setMenuBar(menuBar); } } private Image loadImage(String name) { URL iconURL = SingleFrameApplication.class.getResource(name); return new ImageIcon(iconURL).getImage(); } protected void openFrame(JPanel contentPane) { frame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { Application.getInstance().getContext().getActionManager().run("exit"); } }); contentPane.registerKeyboardAction(new ActionListener() { public void actionPerformed(ActionEvent e) { Application.getInstance().getContext().getActionManager().run("exit"); } }, getKeyStroke(VK_ESCAPE, 0), WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); frame.pack(); frame.setLocationRelativeTo(null); Rectangle bounds = frame.getGraphicsConfiguration().getBounds(); Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(frame.getGraphicsConfiguration()); log.info("Screen size is " + bounds + ", insets are " + insets); int state = getPreferencesState(); int width = crop("width", getPreferenceWidth(), (int) bounds.getX() - (insets.left + insets.right), (int) bounds.getWidth() - (insets.left + insets.right)); int height = crop("height", getPreferenceHeight(), (int) bounds.getY() - (insets.top + insets.bottom), (int) bounds.getHeight() - (insets.top + insets.bottom)); if((state & MAXIMIZED_HORIZ) == MAXIMIZED_HORIZ) width = (int)bounds.getWidth() - (insets.left + insets.right); if((state & MAXIMIZED_VERT) == MAXIMIZED_VERT) height = (int)bounds.getHeight() - (insets.top + insets.bottom); if (width != -1 && height != -1) frame.setSize(width, height); log.info("Frame size is " + frame.getSize()); int x = crop("x", getPreferencesX(), (int) bounds.getX() + insets.left, (int) bounds.getX() + insets.left + (int) bounds.getWidth() - insets.right - width); int y = crop("y", getPreferencesY(), (int) bounds.getY() + insets.top, (int) bounds.getY() + insets.top + (int) bounds.getHeight() - insets.bottom - height); if ((state & MAXIMIZED_HORIZ) == MAXIMIZED_HORIZ) x = insets.left; if ((state & MAXIMIZED_VERT) == MAXIMIZED_VERT) y = insets.top; if (x != -1 && y != -1) frame.setLocation(x, y); log.info("Frame location is " + frame.getLocation()); frame.setExtendedState(state); log.info("Frame state is " + frame.getExtendedState()); frame.setVisible(true); frame.toFront(); frame.addComponentListener(new ComponentAdapter() { public void componentMoved(ComponentEvent e) { putPreferencesLocation(); } public void componentResized(ComponentEvent e) { putPreferencesSize(); } }); frame.addWindowStateListener(new WindowStateListener() { public void windowStateChanged(WindowEvent e) { putPreferencesState(); } }); } private int getPreferencesX() { return preferences.getInt(X_PREFERENCE, -1); } private int getPreferencesY() { return preferences.getInt(Y_PREFERENCE, -1); } private int getPreferenceHeight() { return crop("preferencesHeight", preferences.getInt(HEIGHT_PREFERENCE, -1), 0, MAX_VALUE); } private int getPreferenceWidth() { return crop("preferenceWidth", preferences.getInt(WIDTH_PREFERENCE, -1), 0, MAX_VALUE); } private int getPreferencesState() { return preferences.getInt(STATE_PREFERENCE, NORMAL); } static int crop(String name, int position, int minimum, int maximum) { int result = position < minimum ? (position == -1 ? -1 : minimum) : position > maximum ? (position == -1 ? -1 : maximum) : position; log.finer("Cropping value " + position + " for " + name + " to [" + minimum + ";" + maximum + "] gives " + result); return result; } private void putPreferencesLocation() { int x = frame.getLocation().x; int y = frame.getLocation().y; if(getPreferencesX() == x && getPreferencesY() == y) return; preferences.putInt(X_PREFERENCE, x); preferences.putInt(Y_PREFERENCE, y); log.info("Storing frame location as " + frame.getLocation()); String deviceId = frame.getGraphicsConfiguration().getDevice().getIDstring(); preferences.put(DEVICE_PREFERENCE, deviceId); log.info("Storing graphics device as " + deviceId); } private void putPreferencesSize() { int width = frame.getSize().width; int height = frame.getSize().height; if(getPreferenceWidth() == width && getPreferenceHeight() == height) return; preferences.putInt(WIDTH_PREFERENCE, width); preferences.putInt(HEIGHT_PREFERENCE, height); log.info("Storing frame size as " + frame.getSize()); } private void putPreferencesState() { int state = frame.getExtendedState(); if(getPreferencesState() == state) return; preferences.putInt(STATE_PREFERENCE, state); log.info("Storing frame state as " + state); } void closeFrame() { putPreferencesLocation(); putPreferencesSize(); putPreferencesState(); frame.dispose(); } protected void shutdown() { super.shutdown(); closeFrame(); } }