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 }