From 65d77c46d29bb514546ea7194374cdc9390556f4 Mon Sep 17 00:00:00 2001 From: tjc <tjc@ee4ac58c-ac51-4696-9907-e4b3aa274f04> Date: Wed, 12 May 2010 16:47:21 +0000 Subject: [PATCH] additions for MacOSX about, quit git-svn-id: svn+ssh://svn.internal.sanger.ac.uk/repos/svn/pathsoft/artemis/trunk@13814 ee4ac58c-ac51-4696-9907-e4b3aa274f04 --- .../components/alignment/BamFrame.java | 79 +++++++ .../components/alignment/BamOSXAdapter.java | 209 ++++++++++++++++++ .../artemis/components/alignment/BamView.java | 17 +- 3 files changed, 301 insertions(+), 4 deletions(-) create mode 100644 uk/ac/sanger/artemis/components/alignment/BamFrame.java create mode 100644 uk/ac/sanger/artemis/components/alignment/BamOSXAdapter.java diff --git a/uk/ac/sanger/artemis/components/alignment/BamFrame.java b/uk/ac/sanger/artemis/components/alignment/BamFrame.java new file mode 100644 index 000000000..a05bada92 --- /dev/null +++ b/uk/ac/sanger/artemis/components/alignment/BamFrame.java @@ -0,0 +1,79 @@ +package uk.ac.sanger.artemis.components.alignment; + +import javax.swing.ImageIcon; +import javax.swing.JFrame; +import javax.swing.JOptionPane; + + + class BamFrame extends JFrame + { + private static final long serialVersionUID = 1L; + private String bamFile = null; + + BamFrame() + { + super(); + if(isMac()) + initMac(); + } + + private void initMac() + { + try + { + // Generate and register the OSXAdapter, passing it a hash of all the + // methods we wish to + // use as delegates for various com.apple.eawt.ApplicationListener + // methods + Class splashClass = Class.forName("uk.ac.sanger.artemis.components.alignment.BamFrame"); + BamOSXAdapter.setQuitHandler(this, splashClass.getDeclaredMethod( + "exitApp", (Class[]) null)); + BamOSXAdapter.setAboutHandler(this, splashClass.getDeclaredMethod("about", + (Class[]) null)); + // OSXAdapter.setPreferencesHandler(this, + // splashClass.getDeclaredMethod("preferences", (Class[])null)); + BamOSXAdapter.setFileHandler(this, splashClass.getDeclaredMethod( + "loadFile", new Class[] + { String.class })); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + protected void about() + { + ClassLoader cl = this.getClass().getClassLoader(); + ImageIcon icon = new ImageIcon(cl.getResource("images/icon.gif")); + + JOptionPane.showMessageDialog(this, + "BamView\nthis is free software and is distributed" + + "\nunder the terms of the GNU General Public License.", + "About", JOptionPane.INFORMATION_MESSAGE, icon); + } + + protected void loadFile(final String bamFile) + { + this.bamFile = bamFile; + } + + protected void exitApp() + { + int status = JOptionPane.showConfirmDialog(this, "Exit?", + "BamView", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); + if(status == JOptionPane.CANCEL_OPTION) + return; + System.exit(0); + } + + protected String getBamFile() + { + return bamFile; + } + + private boolean isMac() + { + return System.getProperty("mrj.version") != null; + } + } diff --git a/uk/ac/sanger/artemis/components/alignment/BamOSXAdapter.java b/uk/ac/sanger/artemis/components/alignment/BamOSXAdapter.java new file mode 100644 index 000000000..2aaf01122 --- /dev/null +++ b/uk/ac/sanger/artemis/components/alignment/BamOSXAdapter.java @@ -0,0 +1,209 @@ +package uk.ac.sanger.artemis.components.alignment; + +import java.lang.reflect.*; + +public class BamOSXAdapter implements InvocationHandler + +{ + protected Object targetObject; + protected Method targetMethod; + protected String proxySignature; + static Object macOSXApplication; + + // Each OSXAdapter has the name of the EAWT method it intends to listen for + // (handleAbout, for example), + // the Object that will ultimately perform the task, and the Method to be + // called on that Object + protected BamOSXAdapter(String proxySignature, Object target, Method handler) + { + this.proxySignature = proxySignature; + this.targetObject = target; + this.targetMethod = handler; + } + + // Pass this method an Object and Method equipped to perform application + // shutdown logic + // The method passed should return a boolean stating whether or not the quit + // should occur + public static void setQuitHandler(Object target, Method quitHandler) + { + setHandler(new BamOSXAdapter("handleQuit", target, quitHandler)); + } + + // Pass this method an Object and Method equipped to display application info + // They will be called when the About menu item is selected from the + // application menu + public static void setAboutHandler(Object target, Method aboutHandler) + { + boolean enableAboutMenu = (target != null && aboutHandler != null); + if(enableAboutMenu) + setHandler(new BamOSXAdapter("handleAbout", target, aboutHandler)); + + // If we're setting a handler, enable the About menu item by calling + // com.apple.eawt.Application reflectively + try + { + Method enableAboutMethod = macOSXApplication.getClass() + .getDeclaredMethod("setEnabledAboutMenu", + new Class[] { boolean.class }); + enableAboutMethod.invoke(macOSXApplication, new Object[] { Boolean + .valueOf(enableAboutMenu) }); + } + catch(Exception ex) + { + System.err.println("OSXAdapter could not access the About Menu"); + ex.printStackTrace(); + } + } + + // Pass this method an Object and a Method equipped to display application + // options + // They will be called when the Preferences menu item is selected from the + // application menu + public static void setPreferencesHandler(Object target, Method prefsHandler) + { + boolean enablePrefsMenu = (target != null && prefsHandler != null); + if(enablePrefsMenu) + setHandler(new BamOSXAdapter("handlePreferences", target, prefsHandler)); + + // If we're setting a handler, enable the Preferences menu item by calling + // com.apple.eawt.Application reflectively + try + { + Method enablePrefsMethod = macOSXApplication.getClass() + .getDeclaredMethod("setEnabledPreferencesMenu", + new Class[] { boolean.class }); + enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean + .valueOf(enablePrefsMenu) }); + } + catch(Exception ex) + { + System.err.println("OSXAdapter could not access the About Menu"); + ex.printStackTrace(); + } + } + + // Pass this method an Object and a Method equipped to handle document + // events from the Finder. Documents are registered with the Finder via + // the CFBundleDocumentTypes dictionary in the application Info.plist + public static void setFileHandler(Object target, Method fileHandler) + { + setHandler(new BamOSXAdapter("handleOpenFile", target, fileHandler) + { + // Override OSXAdapter.callTarget to send information on the + // file to be opened + public boolean callTarget(Object appleEvent) + { + if(appleEvent != null) + { + try + { + Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod( + "getFilename", (Class[]) null); + String filename = (String) getFilenameMethod.invoke(appleEvent, + (Object[]) null); + this.targetMethod.invoke(this.targetObject, + new Object[] { filename }); + } + catch(Exception ex) + { + ex.printStackTrace(); + } + } + return true; + } + }); + } + + // setHandler creates a Proxy object from the passed OSXAdapter and adds it as + // an ApplicationListener + public static void setHandler(BamOSXAdapter adapter) + { + try + { + Class applicationClass = Class.forName("com.apple.eawt.Application"); + if(macOSXApplication == null) + macOSXApplication = applicationClass.getConstructor((Class[]) null) + .newInstance((Object[]) null); + + Class applicationListenerClass = Class + .forName("com.apple.eawt.ApplicationListener"); + Method addListenerMethod = applicationClass.getDeclaredMethod( + "addApplicationListener", new Class[] { applicationListenerClass }); + // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener + Object osxAdapterProxy = Proxy.newProxyInstance(BamOSXAdapter.class + .getClassLoader(), new Class[] { applicationListenerClass }, adapter); + addListenerMethod.invoke(macOSXApplication, + new Object[] { osxAdapterProxy }); + } + catch(ClassNotFoundException cnfe) + { + System.err.println( + "This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" + + cnfe + ")"); + } + catch(Exception ex) + { // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods + System.err.println("Mac OS X Adapter could not talk to EAWT:"); + ex.printStackTrace(); + } + } + + // Override this method to perform any operations on the event + // that comes with the various callbacks + // See setFileHandler above for an example + public boolean callTarget(Object appleEvent) + throws InvocationTargetException, IllegalAccessException + { + Object result = targetMethod.invoke(targetObject, (Object[]) null); + if(result == null) + return true; + + return Boolean.valueOf(result.toString()).booleanValue(); + } + + // InvocationHandler implementation + // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable + { + if(isCorrectMethod(method, args)) + { + boolean handled = callTarget(args[0]); + setApplicationEventHandled(args[0], handled); + } + // All of the ApplicationListener methods are void; return null regardless of what happens + return null; + } + + // Compare the method that was called to the intended method when the OSXAdapter instance was created + // (e.g. handleAbout, handleQuit, handleOpenFile, etc.) + protected boolean isCorrectMethod(Method method, Object[] args) + { + return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1); + } + + // It is important to mark the ApplicationEvent as handled and cancel the default behavior + // This method checks for a boolean result from the proxy method and sets the event accordingly + protected void setApplicationEventHandled(Object event, boolean handled) + { + if(event != null) + { + try + { + Method setHandledMethod = event.getClass().getDeclaredMethod( + "setHandled", new Class[] { boolean.class }); + // If the target method returns a boolean, use that as a hint + setHandledMethod.invoke(event, + new Object[] { Boolean.valueOf(handled) }); + } + catch(Exception ex) + { + System.err + .println("OSXAdapter was unable to handle an ApplicationEvent: " + + event); + ex.printStackTrace(); + } + } + } +} \ No newline at end of file diff --git a/uk/ac/sanger/artemis/components/alignment/BamView.java b/uk/ac/sanger/artemis/components/alignment/BamView.java index 99c6e5a3e..0a7b21aac 100644 --- a/uk/ac/sanger/artemis/components/alignment/BamView.java +++ b/uk/ac/sanger/artemis/components/alignment/BamView.java @@ -210,6 +210,7 @@ public class BamView extends JPanel int nbasesInView) { super(); + setBackground(Color.white); this.bamList = bamList; this.nbasesInView = nbasesInView; @@ -2861,19 +2862,27 @@ public class BamView extends JPanel { SAMRecord sam1; SAMRecord sam2; - } - + } + public static void main(String[] args) { - List<String> bam = new Vector<String>();; + BamFrame frame = new BamFrame(); + if(args.length == 0 && frame.getBamFile() != null) + args = new String[]{ frame.getBamFile() }; + + List<String> bam = new Vector<String>(); String reference = null; if(args.length == 0) { + System.setProperty("default_directory", System.getProperty("user.dir")); FileSelectionDialog fileSelection = new FileSelectionDialog(null, true); bam = fileSelection.getBamFiles(); reference = fileSelection.getReferenceFile(); if(reference == null || reference.equals("")) reference = null; + + if(bam == null || bam.size() < 1) + System.exit(0); } else if(!args[0].startsWith("-")) { @@ -2916,7 +2925,7 @@ public class BamView extends JPanel } final BamView view = new BamView(bam, reference, nbasesInView); - JFrame frame = new JFrame("BamView v"+view.getVersion()); + frame.setTitle("BamView v"+view.getVersion()); // translucent //frame.getRootPane().putClientProperty("Window.alpha", new Float(0.9f)); -- GitLab