/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package org.pentaho.reporting.libraries.designtime.swing; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.swing.*; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; public class MacOSXIntegration { private static final Log logger = LogFactory.getLog( MacOSXIntegration.class ); public static final boolean MAC_OS_X; public static class ApplicationEventSupport { private Object event; private boolean handled; public ApplicationEventSupport( final Object event ) { this.event = event; } public String getFileName() { if ( event == null ) { return null; } try { final Method isHandledMethod = event.getClass().getDeclaredMethod( "getFilename" ); // If the target method returns a boolean, use that as a hint final Object o = isHandledMethod.invoke( event ); if ( o == null ) { return null; } return String.valueOf( o ); } catch ( Exception ex ) { logger.debug( "OSXAdapter was unable to handle an ApplicationEvent: " + event, ex ); } return null; } public boolean isHandled() { if ( event == null ) { return handled; } try { final Method isHandledMethod = event.getClass().getDeclaredMethod( "isHandled" ); // If the target method returns a boolean, use that as a hint final Object o = isHandledMethod.invoke( event ); return Boolean.TRUE.equals( o ); } catch ( Exception ex ) { logger.debug( "OSXAdapter was unable to handle an ApplicationEvent: " + event, ex ); } return false; } public void setHandled( final boolean handled ) { if ( event == null ) { this.handled = handled; return; } try { final Method setHandledMethod = event.getClass().getDeclaredMethod( "setHandled", boolean.class ); // If the target method returns a boolean, use that as a hint setHandledMethod.invoke( event, handled ); } catch ( Exception ex ) { logger.debug( "OSXAdapter was unable to handle an ApplicationEvent: " + event, ex ); } } } private static class MacOSApplicationListener implements InvocationHandler { private Object application; private MacOSApplicationListener() throws Exception { final Class applicationClass = Class.forName( "com.apple.eawt.Application" ); final Method getApplicationMethod = applicationClass.getDeclaredMethod( "getApplication" ); // If the target method returns a boolean, use that as a hint application = getApplicationMethod.invoke( null ); final Class applicationListenerClass = Class.forName( "com.apple.eawt.ApplicationListener" ); final Method addListenerMethod = applicationClass.getDeclaredMethod( "addApplicationListener", applicationListenerClass ); final Object osxAdapterProxy = Proxy .newProxyInstance( MacOSXIntegration.class.getClassLoader(), new Class[] { applicationListenerClass }, this ); addListenerMethod.invoke( application, osxAdapterProxy ); } public Object invoke( final Object proxy, final Method method, final Object[] args ) throws Throwable { logger.info( "Receiving event from Apple-System: " + method ); if ( isMatch( "handleQuit", method, args ) ) { if ( handleAction( args[ 0 ], quitAction, "handleQuit" ) ) { initialized = false; } } else if ( isMatch( "handleReOpenApplication", method, args ) ) { handleAction( args[ 0 ], reOpenApplicationAction, "handleReOpenApplication" ); } else if ( isMatch( "handleAbout", method, args ) ) { handleAction( args[ 0 ], aboutAction, "handleAbout" ); } else if ( isMatch( "handleOpenApplication", method, args ) ) { handleAction( args[ 0 ], openApplicationAction, "handleOpenApplication" ); } else if ( isMatch( "handleOpenFile", method, args ) ) { if ( handleAction( args[ 0 ], openFileAction, "handleOpenFile" ) == false ) { final ApplicationEventSupport eventSupport = new ApplicationEventSupport( args ); if ( initialized == false && queueOpenFiles.size() < 100 ) { queueOpenFiles.add( eventSupport.getFileName() ); } } } else if ( isMatch( "handlePreferences", method, args ) ) { handleAction( args[ 0 ], preferencesAction, "handlePreferences" ); } else if ( isMatch( "handlePrintFile", method, args ) ) { if ( handleAction( args[ 0 ], printFileAction, "handlePrintFile" ) == false ) { final ApplicationEventSupport eventSupport = new ApplicationEventSupport( args ); if ( initialized == false && queuePrintedFiles.size() < 100 ) { queuePrintedFiles.add( eventSupport.getFileName() ); } } } return null; } private boolean handleAction( final Object args, final Action action, final String method ) { final ApplicationEventSupport eventSupport = new ApplicationEventSupport( args ); if ( action == null ) { eventSupport.setHandled( false ); return false; } final ConsumableActionEvent actionEvent = new ConsumableActionEvent( eventSupport, 0, method ); action.actionPerformed( actionEvent ); if ( actionEvent.isConsumed() ) { eventSupport.setHandled( true ); return true; } else { eventSupport.setHandled( false ); return false; } } private boolean isMatch( final String proxySignature, final Method method, final Object[] args ) { return ( proxySignature.equals( method.getName() ) && args.length == 1 ); } } static { boolean result; try { result = ( System.getProperty( "os.name" ).toLowerCase().startsWith( "mac os x" ) ); } catch ( Exception e ) { // ignore all errors. result = false; } MAC_OS_X = result; } private static MacOSApplicationListener integration; private static Action preferencesAction; private static Action openFileAction; private static Action openApplicationAction; private static Action reOpenApplicationAction; private static Action printFileAction; private static Action aboutAction; private static Action quitAction; private static ArrayList queueOpenFiles; private static ArrayList queuePrintedFiles; private static boolean initialized; protected MacOSXIntegration() { } private static void init() { if ( MAC_OS_X == false ) { return; } try { if ( integration == null ) { logger.warn( "Installing MacOS integration support." ); integration = new MacOSApplicationListener(); queueOpenFiles = new ArrayList(); queuePrintedFiles = new ArrayList(); } } catch ( Throwable t ) { logger.warn( "Unable to install the Mac-OS support.", t ); } } public static Action getPreferencesAction() { return preferencesAction; } public static void setPreferencesAction( final Action preferencesAction ) { MacOSXIntegration.preferencesAction = preferencesAction; init(); } public static Action getOpenFileAction() { return openFileAction; } public static void setOpenFileAction( final Action openFileAction ) { MacOSXIntegration.openFileAction = openFileAction; init(); if ( queueOpenFiles.isEmpty() == false ) { final String[] fileNames = (String[]) queueOpenFiles.toArray( new String[ queueOpenFiles.size() ] ); for ( int i = 0; i < fileNames.length; i++ ) { final String fileName = fileNames[ i ]; logger.warn( "Would like to work with File: " + fileName ); } queueOpenFiles.clear(); } } public static Action getOpenApplicationAction() { return openApplicationAction; } public static void setOpenApplicationAction( final Action openApplicationAction ) { MacOSXIntegration.openApplicationAction = openApplicationAction; init(); } public static Action getReOpenApplicationAction() { return reOpenApplicationAction; } public static void setReOpenApplicationAction( final Action reOpenApplicationAction ) { MacOSXIntegration.reOpenApplicationAction = reOpenApplicationAction; init(); } public static Action getPrintFileAction() { return printFileAction; } public static void setPrintFileAction( final Action printFileAction ) { MacOSXIntegration.printFileAction = printFileAction; init(); if ( queuePrintedFiles.isEmpty() == false ) { final String[] fileNames = (String[]) queuePrintedFiles.toArray( new String[ queuePrintedFiles.size() ] ); for ( int i = 0; i < fileNames.length; i++ ) { final String fileName = fileNames[ i ]; logger.warn( "Would like to print File: " + fileName ); } queuePrintedFiles.clear(); } } public static Action getAboutAction() { return aboutAction; } public static void setAboutAction( final Action aboutAction ) { MacOSXIntegration.aboutAction = aboutAction; init(); } public static Action getQuitAction() { return quitAction; } public static void setQuitAction( final Action quitAction ) { MacOSXIntegration.quitAction = quitAction; init(); } }