/* * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2016 Maxence Bernard * * muCommander is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * muCommander 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.mucommander.ui.notifier; import java.util.Hashtable; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.mucommander.commons.runtime.OsFamily; import com.mucommander.text.Translator; import com.mucommander.ui.macosx.AppleScript; /** * GrowlNotifier implements a notifier that uses the Growl notification system. * * <p>Growl is a third party notification system for Mac OS X, which allows Growl-enabled applications to display small, * unintrusive popup notifications to inform the user of noteworthy events. Growl can be found at: * <a href="http://growl.info">http://growl.info</a>. * * <p>This class communicates with Growl using {@link AppleScript}. More information about the AppleScript syntax can * be found <a href="http://growl.info/documentation/applescript-support.php"/>here</a>. * The Growl Java library part of the Growl SDK was previously used but it relied on the Cocoa-Java library which has * been deprecated by Apple since then.</p>. * * @author Maxence Bernard */ public class GrowlNotifier extends AbstractNotifier { private static final Logger LOGGER = LoggerFactory.getLogger(GrowlNotifier.class); /** Is this notifier enabled ? */ private static boolean isEnabled; /** Has muCommander been registered ? */ private static boolean isRegistered; /** Dictionary keys for the different notification types */ private final static Map<NotificationType, String> NOTIFICATION_KEYS; /** Name of the application to be registered with Growl, as spelled in the .app */ private final static String APP_NAME = "muCommander"; /** This AppleScript returns "true" if Growl is currently running, "false" if it isn't */ private final static String IS_GROWL_RUNNING_APPLESCRIPT = "tell application \"System Events\"\n" + "\tset isRunning to (count of (every process whose name is \"GrowlHelperApp\")) > 0\n" + "end tell"; static { NOTIFICATION_KEYS = new Hashtable<NotificationType, String>(); NOTIFICATION_KEYS.put(NotificationType.JOB_COMPLETED, "progress_dialog.job_finished"); NOTIFICATION_KEYS.put(NotificationType.JOB_ERROR, "progress_dialog.job_error"); } GrowlNotifier() { } /** * Puts the given AppleScript bit inside a <code>tell application / end tell</code> block, executes the script * and returns <code>true</code> if it was successfully executed. * * @param appleScript the AppleScript bit to execute * @return true if the script was successfully executed */ private static boolean tellGrowl(String appleScript) { return AppleScript.execute( "tell application \"GrowlHelperApp\"\n" + "\t"+appleScript+"\n" + "end tell", null); } ///////////////////////////////////// // AbstractNotifier implementation // ///////////////////////////////////// @Override public String getPrettyName() { return "Growl"; } @Override public boolean setEnabled(boolean enabled) { if(enabled) { // No need to bother if the OS is not Mac OS X if(!OsFamily.MAC_OS_X.isCurrent()) return false; // Nothing else to do if the application has already been registered if(isRegistered) return (isEnabled = true); // Test if Growl is currently running and abort if it is not StringBuilder outputBuffer = new StringBuilder(); if(!(AppleScript.execute(IS_GROWL_RUNNING_APPLESCRIPT, outputBuffer) && outputBuffer.toString().equals("true"))) { LOGGER.debug("Growl is not running, aborting"); return false; } // Register the application (muCommander) with Growl // The list of notification types muCommander uses String notificationTypes = "{"+ "\""+Translator.get(NOTIFICATION_KEYS.get(NotificationType.JOB_COMPLETED))+"\","+ "\""+Translator.get(NOTIFICATION_KEYS.get(NotificationType.JOB_ERROR))+"\""+ "}"; // Register muCommander with Growl, declare the notifications types and enable all of them by default isRegistered = tellGrowl( "register as application \""+APP_NAME+"\""+ " all notifications "+notificationTypes+ " default notifications "+notificationTypes+ " icon of application \""+APP_NAME+"\""); LOGGER.info(isRegistered? "Successfully registered "+APP_NAME+" with Growl": "Error while registering "+APP_NAME+" with Growl"); return isEnabled = isRegistered; } else { return (isEnabled = false); } } @Override public boolean isEnabled() { return isEnabled; } @Override public boolean displayNotification(NotificationType notificationType, String title, String description) { LOGGER.debug("notificationType="+notificationType+" title="+title+" description="+description); if(!isEnabled()) { LOGGER.debug("Ignoring notification, this notifier is not enabled"); return false; } boolean success = tellGrowl( "notify with"+ " name \""+Translator.get(NOTIFICATION_KEYS.get(notificationType))+"\""+ " title \""+title+"\""+ " description \""+description+"\""+ " application name \""+APP_NAME+"\""); LOGGER.debug(success? "Notification sent successfully": "Error while sending notification"); return success; } // The following commented methods are implemented using the Growl Java library that comes with the Growl SDK. This // library relies on the Cocoa-Java library which has been deprecated by Apple, which is why we're not using it anymore. // The code has been kept for the record, in case the Growl Java library is ever used again. // public boolean setEnabled(boolean enabled) { // if(enabled) { // // No need to bother if the OS is not Mac OS X // if(PlatformManager.getOsFamily()!=PlatformManager.MAC_OS_X) // return false; // // // If Growl notifier has already been initialized // if(growl!=null) { // return (isEnabled = true); // } // // try { // // Register the application (muCommander) and its icon. Growl doesn't seem to be able to retrieve the // // application's icon by itself, so we have to use some Cocoa magic to get it and feed it to Growl. // growl = new Growl("muCommander", com.apple.cocoa.application.NSApplication.sharedApplication().applicationIconImage().TIFFRepresentation()); // // String notificationTypes[] = new String[]{ // Translator.get(NOTIFICATION_KEYS[NOTIFICATION_TYPE_JOB_COMPLETED]), // Translator.get(NOTIFICATION_KEYS[NOTIFICATION_TYPE_JOB_ERROR]) // }; // // // Declare a list of available notification types // growl.setAllowedNotifications(notificationTypes); // // Declare a list of notification types enabled by default // growl.setDefaultNotifications(notificationTypes); // // // Commit everything // growl.register(); // // AppLogger.fine("Application registered OK"); // // return (isEnabled = true); // } // catch(Exception e) { // AppLogger.fine("Exception thrown while initializing Growl support (Growl not running?)", e); // } // catch(Error e) { // AppLogger.fine("Error while initializing Growl support (cocoa-java not available?)", e); // } // // growl = null; // return (isEnabled = false); // } // else { // return (isEnabled = false); // } // } // // public boolean isEnabled() { // return growl!=null && isEnabled; // } // // public boolean displayNotification(int notificationType, String title, String description) { // AppLogger.finer("notificationType="+notificationType+" title="+title+" description="+description); // // if(!isEnabled()) { // AppLogger.fine("Ignoring notification, this notifier is not enabled"); // // return false; // } // // try { // growl.notifyGrowlOf(Translator.get(NOTIFICATION_KEYS[notificationType]), title, description); // AppLogger.finer("Notification sent OK"); // // return true; // } // catch(Exception e) { // AppLogger.fine("Exception thrown while sending notification", e); // // return false; // } // } }