View Javadoc

1   /**
2    * This program is free software: you can redistribute it and/or modify
3    * it under the terms of the GNU General Public License as published by
4    * the Free Software Foundation, version 3.
5    *
6    * This program is distributed in the hope that it will be useful,
7    * but WITHOUT ANY WARRANTY; without even the implied warranty of
8    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9    * GNU General Public License for more details.
10   *
11   * You should have received a copy of the GNU General Public License
12   * along with this program. If not, see <http://www.gnu.org/licenses/>.
13   */
14  
15  package net.curre.prefcount.util.mac;
16  
17  import java.util.logging.Logger;
18  import java.util.logging.Level;
19  import java.lang.reflect.Method;
20  import java.lang.reflect.InvocationHandler;
21  
22  import net.curre.prefcount.PrefCountRegistry;
23  
24  /**
25   * This is a Mac OS helper class to assist with handling
26   * of MAC OS events using the <code>com.apple.eawt.Application</code>
27   * class. This class will not work on a platform other than Mac OS.
28   * <p/>
29   * It's important to note, that in this class, we use classes
30   * from the <code>com.apple.eawt</code> package, but since no such
31   * package exist on a non-Mac platform, we must use reflection API
32   * to create objects and invoke methods of those Mac-specific classes.
33   * <p/>
34   * Created date: Jan 22, 2008
35   *
36   * @author Yevgeny Nyden
37   */
38  public class MacOsHandler {
39  
40    /** Private class logger. */
41    private static Logger log = Logger.getLogger(MacOsHandler.class.toString());
42  
43    /** Flag to indicate that this handler has been initialized. */
44    private static boolean isInitialized = false;
45  
46    /**
47     * Method to initialized Mac OS application handler, which functionality
48     * is based upone the <code>com.apple.eawt.Application</code> class. Here
49     * we add custom "about" and "quit" handlers to the Mac application menu bar.
50     * <br /><br />
51     * This method should be called once per application run - successive calls
52     * will have no effect.
53     */
54    public static synchronized void initializeMacOsHandler() {
55      if (isInitialized) {
56        return;
57      }
58      try {
59        // creating an Application object
60        Class appClass = Class.forName("com.apple.eawt.Application");
61        Object application = appClass.newInstance();
62  
63        // geting the Application#addApplicationListener() method
64        Class listClass = Class.forName("com.apple.eawt.ApplicationListener");
65        Method addAppListmethod = appClass.getDeclaredMethod("addApplicationListener", listClass);
66  
67        // creating and adding a custom adapter/listener to the Application
68        Class adapterClass = Class.forName("com.apple.eawt.ApplicationAdapter");
69        Object listener = ListenerProxy.newInstance(adapterClass.newInstance());
70        addAppListmethod.invoke(application, listener);
71  
72        isInitialized = true;
73  
74      } catch (Exception e) {
75        log.log(Level.WARNING, "Exception is thrown when using reflection API on the classes " +
76                               "of the com.apple.eawt package! Are we on Mac OS? Exception: ", e);
77      }
78    }
79  
80  }
81  
82  /**
83   * Class to assist with intercepting calls to
84   * the handleAbout() and handleQuit() methods of the
85   * <code>com.apple.eawt.ApplicationAdapter</code> class and
86   * triggering appropriate 'about' and 'quit' actions for
87   * these events.
88   */
89  class ListenerProxy implements InvocationHandler {
90  
91    /** Private class logger. */
92    private static Logger log = Logger.getLogger(MacOsHandler.class.toString());
93  
94    /** Reference to the proxied object. */
95    private Object object;
96  
97    /**
98     * Method to create a new proxy for the given object.
99     *
100    * @param obj Object to proxy.
101    * @return Reference to the new proxy.
102    */
103   public static Object newInstance(Object obj) {
104     return java.lang.reflect.Proxy.newProxyInstance(
105         obj.getClass().getClassLoader(),
106         obj.getClass().getInterfaces(),
107         new ListenerProxy(obj));
108   }
109 
110   /**
111    * Constructor that sets the reference to the proxied object.
112    *
113    * @param obj Reference to the proxied object to set.
114    */
115   private ListenerProxy(Object obj) {
116     this.object = obj;
117   }
118 
119   /**
120    * <p/>
121    * Triggers appropriate events for the "handleAbout" and "handleQuit"
122    * methods. Executes default (proxied) code for other methods.
123    * </p>
124    * {@inheritDoc}
125    */
126   public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
127     Object result = null;
128     try {
129       if ("handleAbout".equals(m.getName())) {
130         // handling about action
131         log.fine("Processing handleAbout() method...");
132         PrefCountRegistry.getInstance().getMainWindow().showAboutInfo();
133         Object event = args[0];
134         Method eventSetter = Class.forName("com.apple.eawt.ApplicationEvent").
135             getDeclaredMethod("setHandled", Boolean.TYPE);
136         eventSetter.invoke(event, true);
137 
138       } else if ("handleQuit".equals(m.getName())) {
139         // handling quit action
140         log.fine("Processing handleQuit() method...");
141         PrefCountRegistry.getInstance().doQuit();
142 
143       } else {
144         // for now, we don't care about other methods
145         result = m.invoke(object, args);
146       }
147     } catch (Exception e) {
148       log.log(Level.WARNING, "Unexpected invocation exception!", e);
149     }
150     return result;
151   }
152 
153 }