/jEdit/tags/jedit-4-3-1/jars/MacOSX/macosx/OSXAdapter.java

# · Java · 187 lines · 116 code · 18 blank · 53 comment · 21 complexity · 1a2a53170ba82c5b3735ebd979ee20bf MD5 · raw file

  1. /*
  2. * :tabSize=4:indentSize=4:noTabs=false:
  3. * :folding=explicit:collapseFolds=1:
  4. *
  5. * OSXAdapter.java - An adapter which communicates with the native functions of osx
  6. * Copyright (C) 2008 Seph M. Soliman
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. */
  22. package macosx;
  23. //{{{ Imports
  24. import java.util.*;
  25. import java.io.File;
  26. import java.awt.event.*;
  27. import javax.swing.*;
  28. import java.lang.reflect.*;
  29. import org.gjt.sp.jedit.*;
  30. import org.gjt.sp.jedit.browser.*;
  31. import org.gjt.sp.jedit.gui.*;
  32. import org.gjt.sp.jedit.msg.*;
  33. import org.gjt.sp.jedit.options.GlobalOptions;
  34. import org.gjt.sp.util.Log;
  35. //}}}
  36. public class OSXAdapter implements InvocationHandler
  37. {
  38. protected Object targetObject;
  39. protected Method targetMethod;
  40. protected String proxySignature;
  41. static Object macOSXApplication;
  42. // Each OSXAdapter has the name of the EAWT method it intends to listen for (handleAbout, for example),
  43. // the Object that will ultimately perform the task, and the Method to be called on that Object
  44. protected OSXAdapter(String proxySignature, Object target, Method handler) {
  45. this.proxySignature = proxySignature;
  46. this.targetObject = target;
  47. this.targetMethod = handler;
  48. }
  49. // Pass this method an Object and Method equipped to perform application shutdown logic
  50. // The method passed should return a boolean stating whether or not the quit should occur
  51. public static void setQuitHandler(Object target, Method quitHandler) {
  52. setHandler(new OSXAdapter("handleQuit", target, quitHandler));
  53. }
  54. // Pass this method an Object and Method equipped to display application info
  55. // They will be called when the About menu item is selected from the application menu
  56. public static void setAboutHandler(Object target, Method aboutHandler) {
  57. boolean enableAboutMenu = (target != null && aboutHandler != null);
  58. if (enableAboutMenu) {
  59. setHandler(new OSXAdapter("handleAbout", target, aboutHandler));
  60. }
  61. // If we're setting a handler, enable the About menu item by calling
  62. // com.apple.eawt.Application reflectively
  63. try {
  64. Method enableAboutMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledAboutMenu", new Class[] { boolean.class });
  65. enableAboutMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enableAboutMenu) });
  66. } catch (Exception ex) {
  67. System.err.println("OSXAdapter could not access the About Menu");
  68. ex.printStackTrace();
  69. }
  70. }
  71. // Pass this method an Object and a Method equipped to display application options
  72. // They will be called when the Preferences menu item is selected from the application menu
  73. public static void setPreferencesHandler(Object target, Method prefsHandler) {
  74. boolean enablePrefsMenu = (target != null && prefsHandler != null);
  75. if (enablePrefsMenu) {
  76. setHandler(new OSXAdapter("handlePreferences", target, prefsHandler));
  77. }
  78. // If we're setting a handler, enable the Preferences menu item by calling
  79. // com.apple.eawt.Application reflectively
  80. try {
  81. Method enablePrefsMethod = macOSXApplication.getClass().getDeclaredMethod("setEnabledPreferencesMenu", new Class[] { boolean.class });
  82. enablePrefsMethod.invoke(macOSXApplication, new Object[] { Boolean.valueOf(enablePrefsMenu) });
  83. } catch (Exception ex) {
  84. System.err.println("OSXAdapter could not access the About Menu");
  85. ex.printStackTrace();
  86. }
  87. }
  88. // Pass this method an Object and a Method equipped to handle document events from the Finder
  89. // Documents are registered with the Finder via the CFBundleDocumentTypes dictionary in the
  90. // application bundle's Info.plist
  91. public static void setFileHandler(Object target, Method fileHandler) {
  92. setHandler(new OSXAdapter("handleOpenFile", target, fileHandler) {
  93. // Override OSXAdapter.callTarget to send information on the
  94. // file to be opened
  95. public boolean callTarget(Object appleEvent) {
  96. if (appleEvent != null) {
  97. try {
  98. Method getFilenameMethod = appleEvent.getClass().getDeclaredMethod("getFilename", (Class[])null);
  99. String filename = (String) getFilenameMethod.invoke(appleEvent, (Object[])null);
  100. this.targetMethod.invoke(this.targetObject, new Object[] { filename });
  101. } catch (Exception ex) {
  102. }
  103. }
  104. return true;
  105. }
  106. });
  107. }
  108. public static void setReOpenApplicationHandler(Object target, Method appHandler) {
  109. setHandler(new OSXAdapter("handleReOpenApplication", target, appHandler));
  110. }
  111. // setHandler creates a Proxy object from the passed OSXAdapter and adds it as an ApplicationListener
  112. public static void setHandler(OSXAdapter adapter) {
  113. try {
  114. Class applicationClass = Class.forName("com.apple.eawt.Application");
  115. if (macOSXApplication == null) {
  116. macOSXApplication = applicationClass.getConstructor((Class[])null).newInstance((Object[])null);
  117. }
  118. Class applicationListenerClass = Class.forName("com.apple.eawt.ApplicationListener");
  119. Method addListenerMethod = applicationClass.getDeclaredMethod("addApplicationListener", new Class[] { applicationListenerClass });
  120. // Create a proxy object around this handler that can be reflectively added as an Apple ApplicationListener
  121. Object osxAdapterProxy = Proxy.newProxyInstance(OSXAdapter.class.getClassLoader(), new Class[] { applicationListenerClass }, adapter);
  122. addListenerMethod.invoke(macOSXApplication, new Object[] { osxAdapterProxy });
  123. } catch (ClassNotFoundException cnfe) {
  124. System.err.println("This version of Mac OS X does not support the Apple EAWT. ApplicationEvent handling has been disabled (" + cnfe + ")");
  125. } catch (Exception ex) { // Likely a NoSuchMethodException or an IllegalAccessException loading/invoking eawt.Application methods
  126. System.err.println("Mac OS X Adapter could not talk to EAWT:");
  127. ex.printStackTrace();
  128. }
  129. }
  130. // Override this method to perform any operations on the event
  131. // that comes with the various callbacks
  132. // See setFileHandler above for an example
  133. public boolean callTarget(Object appleEvent) throws InvocationTargetException, IllegalAccessException {
  134. Object result = targetMethod.invoke(targetObject, (Object[])null);
  135. if (result == null) {
  136. return true;
  137. }
  138. return Boolean.valueOf(result.toString()).booleanValue();
  139. }
  140. // InvocationHandler implementation
  141. // This is the entry point for our proxy object; it is called every time an ApplicationListener method is invoked
  142. public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
  143. if (isCorrectMethod(method, args)) {
  144. boolean handled = callTarget(args[0]);
  145. setApplicationEventHandled(args[0], handled);
  146. }
  147. // All of the ApplicationListener methods are void; return null regardless of what happens
  148. return null;
  149. }
  150. // Compare the method that was called to the intended method when the OSXAdapter instance was created
  151. // (e.g. handleAbout, handleQuit, handleOpenFile, etc.)
  152. protected boolean isCorrectMethod(Method method, Object[] args) {
  153. return (targetMethod != null && proxySignature.equals(method.getName()) && args.length == 1);
  154. }
  155. // It is important to mark the ApplicationEvent as handled and cancel the default behavior
  156. // This method checks for a boolean result from the proxy method and sets the event accordingly
  157. protected void setApplicationEventHandled(Object event, boolean handled) {
  158. if (event != null) {
  159. try {
  160. Method setHandledMethod = event.getClass().getDeclaredMethod("setHandled", new Class[] { boolean.class });
  161. // If the target method returns a boolean, use that as a hint
  162. setHandledMethod.invoke(event, new Object[] { Boolean.valueOf(handled) });
  163. } catch (Exception ex) {
  164. System.err.println("OSXAdapter was unable to handle an ApplicationEvent: " + event);
  165. ex.printStackTrace();
  166. }
  167. }
  168. }
  169. }