View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.log4j.chainsaw.osx;
18  
19  import java.lang.reflect.InvocationHandler;
20  import java.lang.reflect.InvocationTargetException;
21  import java.lang.reflect.Method;
22  import java.lang.reflect.Proxy;
23  
24  import org.apache.log4j.Logger;
25  import org.apache.log4j.chainsaw.LogUI;
26  
27  
28  /**
29   * This class adds dynamic hooks into OSX version of Java so that various 
30   * Mac-specific UI guidelines are adhered to.
31   * 
32   * This class uses reflection to build the necessary hooks so that there is no compile-time
33   * dependency on a Mac SDK.
34   * 
35   * @see "http://developer.apple.com/documentation/Java/index.html"
36   * @author psmith
37   *
38   */
39  public class OSXIntegration {
40      public static final boolean IS_OSX = System.getProperty("os.name").startsWith("Mac OS X");
41      private static final Logger LOG = Logger.getLogger(OSXIntegration.class);
42      private static Object applicationInstance;
43      public static final void init(final LogUI logui) {
44          LOG.info("OSXIntegration.init() called");
45          if(!IS_OSX) {
46              LOG.info("Not OSX, ignoring...");
47              return;
48          }
49          try {
50              Class applicationClazz = Class.forName("com.apple.eawt.Application");
51              Class listenerClass = Class.forName("com.apple.eawt.ApplicationListener");
52              applicationInstance = applicationClazz.newInstance();
53              
54  //            now register that we want that Preferences menu
55              Method enablePreferenceMethod = applicationClazz.getMethod("setEnabledPreferencesMenu", new Class[] {boolean.class});
56              enablePreferenceMethod.invoke(applicationInstance, new Object[] {Boolean.TRUE});
57              
58              
59              // no About menu for us for now.
60              Method enableAboutMethod = applicationClazz.getMethod("setEnabledAboutMenu", new Class[] {boolean.class});
61              enableAboutMethod.invoke(applicationInstance, new Object[] {Boolean.TRUE});
62              
63              // Need to create a Proxy object to represent an anonymous impl of the ApplicationListener class
64              Object listenerProxy = Proxy.newProxyInstance(OSXIntegration.class.getClassLoader(), 
65                          new Class[] {listenerClass}, 
66                          new InvocationHandler() {
67  
68                  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
69                      if("handlePreferences".equals(method.getName())){
70                          LOG.info("handlePreferences(...) called");
71                          logui.showApplicationPreferences();
72                      }else if("handleQuit".equals(method.getName())){
73                          setHandled(args[0], logui.exit()?Boolean.TRUE:Boolean.FALSE);
74                          
75                      }else if("handleAbout".equals(method.getName())) {
76                          logui.showAboutBox();
77                          setHandled(args[0], Boolean.TRUE);
78                      }
79  //                    TODO think about File Open/Save options
80                      return null;
81                  }
82  
83                  private void setHandled(Object event, Boolean val) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
84                      Method handleMethod =   event.getClass().getMethod("setHandled", new Class[] {boolean.class});
85                      handleMethod.invoke(event, new Object[] {val});
86                  }});           
87              // register the proxy object via the addApplicationListener method, cross fingers...
88              Method registerListenerMethod = applicationClazz.getMethod("addApplicationListener", new Class[] {listenerClass});
89              registerListenerMethod.invoke(applicationInstance, new Object[] {listenerProxy});
90          } catch (Exception e) {
91              LOG.error("Failed to setup OSXIntegration", e);
92          }
93      }
94  }