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