source: trunk/dports/java/jabref/files/OSXAdapter.java.diff @ 101150

Last change on this file since 101150 was 101150, checked in by nicos@…, 8 years ago

jabref: update to 2.9.1, adding patches to use non-deprecated Java-OSX interface

File size: 17.1 KB
  • src/osx/osxadapter/OSXAdapter.java

    old new  
    11/*
    2   File:    OSXAdapter.java
    3 
    4   Description:A single class with clear, static entry points for hooking existing preferences,
    5         about, quit functionality from an existing Java app into handlers for the Mac OS X
    6         application menu.  Useful for developers looking to support
    7         multiple platforms with a single codebase, and support Mac OS X features with
    8         minimal impact.
    9 
    10         This sample is designed for Java 1.4.1 and later on Mac OS X.
    11 
    12   Author:    mdrance
    13 
    14   Copyright:   © Copyright 2003 Apple Computer, Inc. All rights reserved.
    15 
    16   Disclaimer:  IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
    17         ("Apple") in consideration of your agreement to the following terms, and your
    18         use, installation, modification or redistribution of this Apple software
    19         constitutes acceptance of these terms.  If you do not agree with these terms,
    20         please do not use, install, modify or redistribute this Apple software.
    21 
    22         In consideration of your agreement to abide by the following terms, and subject
    23         to these terms, Apple grants you a personal, non-exclusive license, under Apple's
    24         copyrights in this original Apple software (the "Apple Software"), to use,
    25         reproduce, modify and redistribute the Apple Software, with or without
    26         modifications, in source and/or binary forms; provided that if you redistribute
    27         the Apple Software in its entirety and without modifications, you must retain
    28         this notice and the following text and disclaimers in all such redistributions of
    29         the Apple Software.  Neither the name, trademarks, service marks or logos of
    30         Apple Computer, Inc. may be used to endorse or promote products derived from the
    31         Apple Software without specific prior written permission from Apple.  Except as
    32         expressly stated in this notice, no other rights or licenses, express or implied,
    33         are granted by Apple herein, including but not limited to any patent rights that
    34         may be infringed by your derivative works or by other works in which the Apple
    35         Software may be incorporated.
    36 
    37         The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
    38         WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
    39         WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
    40         PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
    41         COMBINATION WITH YOUR PRODUCTS.
    42 
    43         IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
    44         CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
    45         GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    46         ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
    47         OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
    48         (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
    49         ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    50 
    51   Change History (most recent first):
    52     04092003  mdrance    added comments
    53 
    54 */
    55 /*package osxadapter;
    56 
    57 import net.sf.jabref.JabRefFrame;
    58 import com.apple.eawt.*;
    59 
    60 public class OSXAdapter extends ApplicationAdapter {
    61 
    62   // pseudo-singleton model; no point in making multiple instances
    63   // of the EAWT application or our adapter
    64   private static OSXAdapter            theAdapter;
    65   private static com.apple.eawt.Application    theApplication;
    66 
    67   // reference to the app where the existing quit, about, prefs code is
    68   private JabRefFrame mainApp;
    69 
    70   private OSXAdapter (JabRefFrame inApp) {
    71     mainApp = inApp;
    72   }
    73 
    74   // implemented handler methods.  These are basically hooks into existing
    75   // functionality from the main app, as if it came over from another platform.
    76   public void handleAbout(ApplicationEvent ae) {
    77     if (mainApp != null) {
    78       ae.setHandled(true);
    79       mainApp.about();
    80     } else {
    81       throw new IllegalStateException("handleAbout: MyApp instance detached from listener");
    82     }
    83   }
    84 
    85   public void handlePreferences(ApplicationEvent ae) {
    86     if (mainApp != null) {
    87       mainApp.preferences();
    88       ae.setHandled(true);
    89     } else {
    90       throw new IllegalStateException("handlePreferences: MyApp instance detached from listener");
    91     }
    92   }
    93 
    94   public void handleQuit(ApplicationEvent ae) {
    95     if (mainApp != null) {
    96       /*
    97       /  You MUST setHandled(false) if you want to delay or cancel the quit.
    98       /  This is important for cross-platform development -- have a universal quit
    99       /  routine that chooses whether or not to quit, so the functionality is identical
    100       /  on all platforms.  This example simply cancels the AppleEvent-based quit and
    101       /  defers to that universal method.
    102       *//*
    103       ae.setHandled(false);
    104       mainApp.quit();
    105     } else {
    106       throw new IllegalStateException("handleQuit: MyApp instance detached from listener");
    107     }
    108   }
    109 
    110 
    111   // The main entry-point for this functionality.  This is the only method
    112   // that needs to be called at runtime, and it can easily be done using
    113   // reflection (see MyApp.java)
    114   public static void registerMacOSXApplication(JabRefFrame inApp) {
    115     if (theApplication == null) {
    116       theApplication = new com.apple.eawt.Application();
    117     }
    118 
    119     if (theAdapter == null) {
    120       theAdapter = new OSXAdapter(inApp);
    121     }
    122     theApplication.addApplicationListener(theAdapter);
    123   }
    124 
    125   // Another static entry point for EAWT functionality.  Enables the
    126   // "Preferences..." menu item in the application menu.
    127   public static void enablePrefs(boolean enabled) {
    128     if (theApplication == null) {
    129       theApplication = new com.apple.eawt.Application();
    130     }
    131     theApplication.setEnabledPreferencesMenu(enabled);
    132   }
    133 }   */
     2 File: OSXAdapter.java
     3 
     4 Abstract: Hooks existing preferences/about/quit functionality from an
     5     existing Java app into handlers for the Mac OS X application menu.
     6     Uses a Proxy object to dynamically implement the
     7     com.apple.eawt.ApplicationListener interface and register it with the
     8     com.apple.eawt.Application object.  This allows the complete project
     9     to be both built and run on any platform without any stubs or
     10     placeholders. Useful for developers looking to implement Mac OS X
     11     features while supporting multiple platforms with minimal impact.
     12 
     13 Version: 2.0
     14 
     15 Disclaimer: IMPORTANT:  This Apple software is supplied to you by
     16 Apple Inc. ("Apple") in consideration of your agreement to the
     17 following terms, and your use, installation, modification or
     18 redistribution of this Apple software constitutes acceptance of these
     19 terms.  If you do not agree with these terms, please do not use,
     20 install, modify or redistribute this Apple software.
     21 
     22 In consideration of your agreement to abide by the following terms, and
     23 subject to these terms, Apple grants you a personal, non-exclusive
     24 license, under Apple's copyrights in this original Apple software (the
     25 "Apple Software"), to use, reproduce, modify and redistribute the Apple
     26 Software, with or without modifications, in source and/or binary forms;
     27 provided that if you redistribute the Apple Software in its entirety and
     28 without modifications, you must retain this notice and the following
     29 text and disclaimers in all such redistributions of the Apple Software.
     30 Neither the name, trademarks, service marks or logos of Apple Inc.
     31 may be used to endorse or promote products derived from the Apple
     32 Software without specific prior written permission from Apple.  Except
     33 as expressly stated in this notice, no other rights or licenses, express
     34 or implied, are granted by Apple herein, including but not limited to
     35 any patent rights that may be infringed by your derivative works or by
     36 other works in which the Apple Software may be incorporated.
     37 
     38 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
     39 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
     40 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
     41 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
     42 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
     43 
     44 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
     45 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     46 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     47 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
     48 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
     49 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
     50 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
     51 POSSIBILITY OF SUCH DAMAGE.
     52 
     53 Copyright (C) 2003-2007 Apple, Inc., All Rights Reserved
     54 
     55 */
     56
     57  package osxadapter;
     58  import java.lang.reflect.*;
     59 
     60 
     61  public class OSXAdapter implements InvocationHandler {
     62 
     63    protected Object targetObject;
     64    protected Method targetMethod;
     65    protected String proxySignature;
     66
     67    static Object macOSXApplication;
     68
     69    // Pass this method an Object and Method equipped to perform application shutdown logic
     70    // The method passed should return a boolean stating whether or not the quit should occur
     71    public static void setQuitHandler(Object target, Method quitHandler) {
     72        setHandler(new OSXAdapter("handleQuit", target, quitHandler));
     73    }
     74
     75    // Pass this method an Object and Method equipped to display application info
     76    // They will be called when the About menu item is selected from the application menu
     77    public static void setAboutHandler(Object target, Method aboutHandler) {
     78        boolean enableAboutMenu = (target != null && aboutHandler != null);
     79        if (enableAboutMenu) {
     80            setHandler(new OSXAdapter("handleAbout", target, aboutHandler));
     81        }
     82        // If we're setting a handler, enable the About menu item by calling
     83        // com.apple.eawt.Application reflectively
     84        try {
     85            Method enableAboutMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", new Class[] { boolean.class });
     86            enableAboutMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enableAboutMenu) });
     87        } catch (Exception ex) {
     88            System.err.println("OSXAdapter could not access the About Menu");
     89            ex.printStackTrace();
     90        }
     91    }
     92
     93    // Pass this method an Object and a Method equipped to display application options
     94    // They will be called when the Preferences menu item is selected from the application menu
     95    public static void setPreferencesHandler(Object target, Method prefsHandler) {
     96        boolean enablePrefsMenu = (target != null && prefsHandler != null);
     97        if (enablePrefsMenu) {
     98            setHandler(new OSXAdapter("handlePreferences", target, prefsHandler));
     99        }
     100        // If we're setting a handler, enable the Preferences menu item by calling
     101        // com.apple.eawt.Application reflectively
     102        try {
     103            Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class });
     104            enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enablePrefsMenu) });
     105        } catch (Exception ex) {
     106            System.err.println("OSXAdapter could not access the About Menu");
     107            ex.printStackTrace();
     108        }
     109    }
     110
     111    // Pass this method an Object and a Method equipped to handle document events from the Finder
     112    // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the
     113    // application bundle's Info.plist
     114    public static void setFileHandler(Object target, Method fileHandler) {
     115        setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) {
     116            // Override OSXAdapter.callTarget to send information on the
     117            // file to be opened
     118            public boolean callTarget(Object appleEvent) {
     119                if (appleEvent != null) {
     120                    try {
     121                        Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod("getFilename", (Class[])null);
     122                        String filename = (String) getFilenameMethod.invoke(appleEvent, (Object[])null);
     123                        this.targetMethod.invoke(this.targetObject, new Object[] { filename });
     124                    } catch (Exception ex) {
     125
     126                    }
     127                }
     128                return true;
     129            }
     130        });
     131    }
     132
     133    // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an ApplicationListener
     134    public static void setHandler(OSXAdapter adapter) {
     135        try {
     136            Class<?> applicationClass = Class.forName("com.apple.eawt.Application");
     137            if (macOSXApplication == null) {
     138                macOSXApplication = applicationClass.getConstructor((Class[])null).newInstance((Object[])null);
     139            }
     140            Class<?> applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
     141            Method addListenerMethod = applicationClass.getDeclaredMethod("addApplicationListener", new Class[] { applicationListenerClass });
     142            // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener
     143            Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), new Class[] { applicationListenerClass }, adapter);
     144            addListenerMethod.invoke(macOSXApplication, new Object[] { osxAdapterProxy });
     145        } catch (ClassNotFoundException cnfe) {
     146            System.err.println("This version of Mac OS X does not support the Apple EAWT.  ApplicationEvent handling has been disabled (" + cnfe + ")");
     147        } catch (Exception ex) {  // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods
     148            System.err.println("Mac OS X Adapter could not talk to EAWT:");
     149            ex.printStackTrace();
     150        }
     151    }
     152
     153    // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for example),
     154    // the Object that will ultimately perform the task, and the Method to be called on that Object
     155    protected OSXAdapter(String proxySignature, Object target, Method handler) {
     156        this.proxySignature = proxySignature;
     157        this.targetObject = target;
     158        this.targetMethod = handler;
     159    }
     160
     161    // Override this method to perform any operations on the event
     162    // that comes with the various callbacks
     163    // See setFileHandler above for an example
     164    public boolean callTarget(Object appleEvent) throws InvocationTargetException, IllegalAccessException {
     165        Object result = targetMethod.invoke(targetObject, (Object[])null);
     166        if (result == null) {
     167            return true;
     168        }
     169        return Boolean.valueOf(result.toString()).booleanValue();
     170    }
     171
     172    // InvocationHandler implementation
     173    // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked
     174    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
     175        if (isCorrectMethod(method, args)) {
     176            boolean handled = callTarget(args[0]);
     177            setApplicationEventHandled(args[0], handled);
     178        }
     179        // All of the ApplicationListener methods are void; return null regardless of what happens
     180        return null;
     181    }
     182
     183    // Compare the method that was called to the intended method when the OSXAdapter instance was created
     184    // (e.g. handleAbout, handleQuit, handleOpenFile, etc.)
     185    protected boolean isCorrectMethod(Method method, Object[] args) {
     186        return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1);
     187    }
     188
     189    // It is important to mark the ApplicationEvent as handled and cancel the default behavior
     190    // This method checks for a boolean result from the proxy method and sets the event accordingly
     191    protected void setApplicationEventHandled(Object event, boolean handled) {
     192        if (event != null) {
     193            try {
     194                Method setHandledMethod = event.getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class });
     195                // If the target method returns a boolean, use that as a hint
     196                setHandledMethod.invoke(event, new Object[] { Boolean.valueOf(handled) });
     197            } catch (Exception ex) {
     198                System.err.println("OSXAdapter was unable to handle an ApplicationEvent: " + event);
     199                ex.printStackTrace();
     200            }
     201        }
     202    }
     203}
Note: See TracBrowser for help on using the repository browser.