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 }