/*
Copyright (C) 2006 EBI
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the itmplied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.biomart.common.view.gui;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import org.biomart.common.resources.Log;
import org.biomart.common.resources.Resources;
import org.biomart.common.resources.Settings;
import org.biomart.common.view.gui.dialogs.AboutDialog;
import org.biomart.common.view.gui.dialogs.StackTrace;
import org.biomart.common.view.gui.dialogs.ViewTextDialog;
/**
* This abstract class provides some useful common stuff for launching any
* BioMart Java GUI appliaction.
*
* @author Richard Holland <holland@ebi.ac.uk>
* @version $Revision: 1.25 $, $Date: 2007-12-10 09:51:32 $, modified by
* $Author: rh4 $
* @since 0.5
*/
public abstract class BioMartGUI extends JFrame {
private static final long serialVersionUID = 1L;
private static boolean reallyIsMac = true;
/**
* Creates a new instance of MartBuilder. You can customise the
* look-and-feel by speciying a configuration property called
* <tt>lookandfeel</tt>, which contains the classname of the
* look-and-feel to use. Details of where this file is can be found in
* {@link Settings}.
*/
protected BioMartGUI() {
// Create the window.
super(Resources.get("GUITitle", Resources.BIOMART_VERSION));
System.out.println("..." + Settings.getApplication() + " started.");
// Set some nice Mac stuff.
if (this.isMac()) {
try {
// Set up a listener proxy.
final Class listenerClass = Class
.forName("com.apple.eawt.ApplicationListener");
final Class eventClass = Class
.forName("com.apple.eawt.ApplicationEvent");
final Method eventHandled = eventClass.getMethod("setHandled",
new Class[] { Boolean.TYPE });
final Method handleAbout = listenerClass.getMethod(
"handleAbout", new Class[] { eventClass });
final Method handleQuit = listenerClass.getMethod("handleQuit",
new Class[] { eventClass });
final Object proxy = Proxy.newProxyInstance(listenerClass
.getClassLoader(), new Class[] { listenerClass },
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
if (method.equals(handleAbout)) {
// Handle TRUE otherwise it overrides us.
eventHandled.invoke(args[0],
new Object[] { Boolean.TRUE });
BioMartGUI.this.requestShowAbout();
} else if (method.equals(handleQuit)) {
// Handle FALSE otherwise it preempts us.
eventHandled.invoke(args[0],
new Object[] { Boolean.FALSE });
BioMartGUI.this.requestExitApp();
} else
eventHandled.invoke(args[0],
new Object[] { Boolean.FALSE });
// All methods return null.
return null;
}
});
// Set up application wrapper to include handler methods.
final Object app = Class.forName("com.apple.eawt.Application")
.newInstance();
app.getClass().getMethod("addAboutMenuItem", null).invoke(app,
null);
app.getClass().getMethod("addPreferencesMenuItem", null)
.invoke(app, null);
app.getClass().getMethod("setEnabledAboutMenu",
new Class[] { Boolean.TYPE }).invoke(app,
new Object[] { Boolean.TRUE });
app.getClass().getMethod("setEnabledPreferencesMenu",
new Class[] { Boolean.TYPE }).invoke(app,
new Object[] { Boolean.FALSE });
app
.getClass()
.getMethod(
"addApplicationListener",
new Class[] { Class
.forName("com.apple.eawt.ApplicationListener") })
.invoke(app, new Object[] { proxy });
} catch (final Throwable t) {
Log.warn(t);
BioMartGUI.reallyIsMac = false;
}
// Set up properties.
System.setProperty("com.apple.macos.useScreenMenuBar", "true");
System.setProperty("com.apple.macos.use-file-dialog-packages",
"false");
System.setProperty("com.apple.macos.smallTabs", "true");
System.setProperty(
"com.apple.mrj.application.apple.menu.about.name",
Resources.get("plainGUITitle"));
System.setProperty("com.apple.mrj.application.growbox.intrudes",
"false");
System.setProperty("com.apple.mrj.application.live-resize", "true");
System.setProperty("apple.laf.useScreenMenuBar", "true");
System.setProperty("apple.awt.brushMetalRounded", "true");
System.setProperty("apple.awt.showGrowBox", "true");
System.setProperty("apple.awt.antialiasing", "on");
System.setProperty("apple.awt.textantialiasing", "on");
System.setProperty("apple.awt.rendering", "VALUE_RENDER_QUALITY");
System.setProperty("apple.awt.interpolation",
"VALUE_INTERPOLATION_BICUBIC");
System.setProperty("apple.awt.fractionalmetrics", "on");
System.setProperty("apple.awt.graphics.EnableQ2DX", "true");
System.setProperty("apple.awt.window.position.forceSafeCreation",
"true");
System
.setProperty(
"apple.awt.window.position.forceSafeProgrammaticPositioning",
"true");
}
// Attach ourselves as the main window for hourglass use.
LongProcess.setMainWindow(this);
// Load our cache of settings.
Settings.load();
// Set the look and feel to the one specified by the user, or the system
// default if not specified by the user. This may be null.
Log.info("Loading look-and-feel settings");
String lookAndFeelClass = Settings.getProperty("lookandfeel");
try {
UIManager.setLookAndFeel(lookAndFeelClass);
} catch (final Exception e) {
// Ignore, as we'll end up with the system one if this one doesn't
// work.
if (lookAndFeelClass != null)
// only worry if we were actually given one.
Log.warn("Bad look-and-feel: " + lookAndFeelClass, e);
// Use system default.
lookAndFeelClass = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel(lookAndFeelClass);
} catch (final Exception e2) {
// Ignore, as we'll end up with the cross-platform one if there
// is no system one.
Log.warn("Bad look-and-feel: " + lookAndFeelClass, e2);
}
}
// Set up window listener and use it to handle windows closing.
Log.info("Creating main GUI window");
final BioMartGUI mb = this;
this.addWindowListener(new WindowAdapter() {
public void windowClosing(final WindowEvent e) {
if (e.getWindow() == mb)
Log.debug("Main window closing");
BioMartGUI.this.requestExitApp();
}
});
this.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
// Set up our GUI components.
Log.debug("Initialising main window components");
this.initComponents();
// Pack the window.
this.pack();
// Set a sensible size.
final Dimension size = this.getToolkit().getScreenSize();
this.setSize(2*size.width/3, 2*size.height/3);
}
/**
* Starts the application.
*/
protected void launch() {
// Start the application.
Log.info("Launching GUI application");
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Centre it.
BioMartGUI.this.setLocationRelativeTo(null);
// Open it.
BioMartGUI.this.setVisible(true);
}
});
}
/**
* Adds GUI components to the window.
*/
protected abstract void initComponents();
/**
* Requests the application to exit, allowing it to ask for permission from
* the user first if necessary.
*/
public void requestExitApp() {
Log.info("Normal exit requested");
if (this.confirmExitApp()) {
Log.info("Normal exit granted");
System.exit(0);
} else
Log.info("Normal exit denied");
}
/**
* Requests the app to show an about dialog.
*/
public void requestShowAbout() {
AboutDialog.displayAbout();
}
/**
* Requests the app to show a docs dialog.
*/
public void requestShowDocs() {
// Load the docs for this app.
final StringBuffer textBuffer = new StringBuffer();
final BufferedReader reader = new BufferedReader(new InputStreamReader(
Resources.getResourceAsStream("docs.txt")));
try {
String line;
while ((line = reader.readLine()) != null) {
textBuffer.append(line);
textBuffer.append('\n');
}
ViewTextDialog.displayText(Resources.get("docsDialogTitle",
Resources.get("plainGUITitle")), textBuffer.toString());
} catch (final IOException e) {
StackTrace.showStackTrace(e);
}
}
/**
* Override this method if you wish to ask the user for confirmation.
*
* @return <tt>true</tt> if it is OK to exit, and <tt>false</tt> if the
* user asks not to.
*/
public boolean confirmExitApp() {
return true;
}
/**
* Are we on a Mac?
*
* @return <tt>true</tt> if we are.
*/
protected boolean isMac() {
return BioMartGUI.reallyIsMac
&& System.getProperty("mrj.version") != null;
}
/**
* This is the main menubar.
*/
public static abstract class BioMartMenuBar extends JMenuBar implements
ActionListener {
private static final long serialVersionUID = 1;
private JMenuItem exit;
private JMenuItem about;
private JMenuItem docs;
private BioMartGUI gui;
/**
* Constructor calls super then sets up our menu items.
*
* @param gui
* the gui to which we are attached.
*/
public BioMartMenuBar(final BioMartGUI gui) {
super();
// Remember our parent.
this.gui = gui;
if (this.gui.isMac())
this.buildMenus(null);
else {
// Exit MartBuilder menu item.
this.exit = new JMenuItem(Resources.get("exitTitle"));
this.exit.setMnemonic(Resources.get("exitMnemonic").charAt(0));
this.exit.addActionListener(this);
this.buildMenus(this.exit);
}
// Construct the help menu.
final JMenu helpMenu = new JMenu(Resources.get("helpMenuTitle"));
helpMenu.setMnemonic(Resources.get("helpMenuMnemonic").charAt(0));
// Don't do the About menu option on Macs.
if (!this.gui.isMac()) {
// About.
this.about = new JMenuItem(Resources.get("aboutTitle",
Resources.get("plainGUITitle")));
this.about
.setMnemonic(Resources.get("aboutMnemonic").charAt(0));
this.about.addActionListener(this);
helpMenu.add(this.about);
// Line to separate from rest of menu.
helpMenu.addSeparator();
}
// Add a docs page menu item.
this.docs = new JMenuItem(Resources.get("docsTitle", Resources
.get("plainGUITitle")), new ImageIcon(Resources
.getResourceAsURL("help.gif")));
this.docs.setMnemonic(Resources.get("docsMnemonic").charAt(0));
this.docs.addActionListener(this);
helpMenu.add(this.docs);
}
/**
* Override this to provide additional menu items.
*
* @param exit
* if not null then include this item in the menus somewhere.
*/
protected abstract void buildMenus(final JMenuItem exit);
/**
* Obtain the {@link BioMartGUI} instance which this menubar is attached
* to.
*
* @return the instance this is attached to.
*/
protected BioMartGUI getBioMartGUI() {
return this.gui;
}
public void actionPerformed(final ActionEvent e) {
// File menu.
if (e.getSource() == this.exit)
this.getBioMartGUI().requestExitApp();
// About menu
else if (e.getSource() == this.about)
this.getBioMartGUI().requestShowAbout();
// Docs menu
else if (e.getSource() == this.docs)
this.getBioMartGUI().requestShowDocs();
}
}
}