Fixed GrowlPlugin for OSX10.6

!!!! No more support for Apple.Java.1.5 !!!!

git-svn-id: http://svn.igniterealtime.org/svn/repos/spark/trunk@12230 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Wolf Posdorfer
2011-04-08 13:19:44 +00:00
committed by wolf.posdorfer
parent 0e7190fab4
commit 44db6a5b26
20 changed files with 1438 additions and 593 deletions

View File

@ -141,23 +141,17 @@ public class ApplePlugin implements Plugin, NativeHandler {
}
public void flashWindow(Window window) {
_appleUtils.bounceDockIcon(true);
// statusMenu.showActiveIcon();
_appleUtils.bounceDockIcon(false);
}
public void flashWindowStopWhenFocused(Window window) {
_appleUtils.bounceDockIcon(true);
// statusMenu.showActiveIcon();
_appleUtils.bounceDockIcon(false);
}
public void stopFlashing(Window window) {
_appleUtils.resetDock();
// try {
// statusMenu.showBlackIcon();
// } catch (Exception e) {
// Log.error(e);
// }
_appleUtils.bounceDockIcon(false);
}

View File

@ -0,0 +1,103 @@
package com.jivesoftware.spark.plugin.apple;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import org.jivesoftware.resource.Res;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.spark.PresenceManager;
import org.jivesoftware.spark.SparkManager;
import com.apple.eawt.Application;
public class AppleTest implements ActionListener {
public static void main(String[] args) throws InterruptedException {
new AppleTest();
}
public AppleTest() throws InterruptedException {
for (LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
System.out.println(laf.getClassName() + " " + laf.getName());
}
System.out.println(UIManager.getLookAndFeel().getName());
//
// JFrame f = new JFrame("Test");
// JButton b = new JButton("B");
// f.add(b);
// f.setVisible(true);
//
// Application app = new Application();
// System.out.println("go to background now");
// Thread.sleep(1500);
//
// System.out.println("request attention");
// app.requestUserAttention(false);
//
// Thread.sleep(3000);
// System.out.println("bounce again");
//
// app.requestUserAttention(false);
//
}
//
// MenuItem online = new MenuItem(Res.getString("status.online"));
// online.addActionListener(this);
//
// MenuItem away = new MenuItem(Res.getString("status.away"));
// away.addActionListener(this);
//
// MenuItem extaway = new MenuItem(Res.getString("status.extended.away"));
// extaway.addActionListener(this);
// MenuItem dnd = new MenuItem(Res.getString("status.do.not.disturb"));
// dnd.addActionListener(this);
// MenuItem onpho = new MenuItem(Res.getString("status.on.phone"));
// onpho.addActionListener(this);
// MenuItem ftc = new MenuItem(Res.getString("status.free.to.chat"));
// ftc.addActionListener(this);
// statusmenu.add(online);
// statusmenu.add(away);
// statusmenu.add(extaway);
// statusmenu.add(dnd);
// statusmenu.add(onpho);
// statusmenu.add(ftc);
// menu.add(statusmenu);
//
// JFrame frame = new JFrame();
// frame.setVisible(true);
// frame.add(menu);
//
// // set dock menu
// app.setDockMenu(menu);
// }
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(e.getActionCommand());
Presence presence = null;
for (Presence p : PresenceManager.getPresences()) {
if (p.getStatus().equals(e.getActionCommand())) {
presence = p;
break;
}
}
System.out.println(presence);
}
}

View File

@ -1,7 +1,7 @@
<!-- Define your plugins -->
<plugin>
<name>Mac OSX 10.6 Plugin</name>
<version>2.0 - OSX10.6.7</version>
<version>2.0</version>
<author>Wolf Posdorfer</author>
<homePage>http://www.jivesoftware.com</homePage>
<email>9posdorf@informatik.uni-hamburg.de</email>

View File

@ -2,16 +2,20 @@
<property name="client.dir" value="../../.."/>
<property name="client.lib.dir" value="${client.dir}/target/build/lib"/>
<property name="plugin.lib.dir" value="${basedir}/build/lib"/>
<property name="client.classes.dir" value="${client.dir}/target/classes"/>
<property name="apple.plugin.classes" value="../apple/classes"/>
<property name="target.dir" value="${basedir}/target"/>
<property name="target.lib.dir" value="${basedir}/target/lib"/>
<property name="classes.dir" value="${basedir}/classes"/>
<property name="src.dir" value="${basedir}/src"/>
<property name="jar.file" value="${client.dir}/target/build/plugins/growl.jar"/>
<path id="lib.classpath">
<fileset dir="${client.lib.dir}" includes="**/*.jar"/>
<fileset dir="${plugin.lib.dir}" includes="**/*.jar"/>
<fileset dir="${plugin.lib.dir}" includes="**/*.jnilib"/>
<pathelement location="/System/Library/Java"/>
<pathelement location="${client.classes.dir}"/>
<pathelement location="${apple.plugin.classes}"/>
@ -28,22 +32,39 @@
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
classpathref="lib.classpath"
source="1.5"
source="1.6"
debug="true"
target="1.5"/>
target="1.6"/>
</target>
<target name="jar.classes" depends="compile">
<mkdir dir="${target.dir}/lib"/>
<jar basedir="${classes.dir}" file="${target.dir}/lib/growl.jar"/>
<jar basedir="${classes.dir}" file="${target.dir}/lib/growl.jar">
</jar>
</target>
<target name="jar" depends="clean,jar.classes">
<copy todir="${target.dir}">
<fileset dir="${src.dir}" includes="**/*.xml"/>
</copy>
<copy todir="${target.lib.dir}">
<fileset file="${plugin.lib.dir}/*.*"/>
</copy>
<jar basedir="${target.dir}" file="${jar.file}" update="false"/>
</target>
<target name="jni-compile">
<mkdir dir="${target.dir}"/>
<javac srcdir="src"
destdir="${target.dir}"
classpathref="lib.classpath"
source="1.6"
debug="true"
target="1.6"/>
<javah destdir="src/" class="com.jivesoftware.spark.plugin.growl.GrowlNative" classpath="${target.dir}"/>
</target>
</project>

Binary file not shown.

View File

@ -1,474 +0,0 @@
/**
* $RCSfile: ,v $
* $Revision: $
* $Date: $
*
* Copyright (C) 2004-2010 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.spark.plugin.growl;
import com.apple.cocoa.foundation.NSDistributedNotificationCenter;
import com.apple.cocoa.foundation.NSArray;
import com.apple.cocoa.foundation.NSDictionary;
import com.apple.cocoa.foundation.NSMutableDictionary;
import com.apple.cocoa.foundation.NSData;
import com.apple.cocoa.application.NSImage;
/**
* A class that encapsulates the "work" of talking to growl
*
* @author Karl Adam
*/
public class Growl {
// defines
/** The name of the growl registration notification for DNC. */
public static final String GROWL_APP_REGISTRATION = "GrowlApplicationRegistrationNotification";
// Ticket Defines
/** Ticket key for the application name. */
public static final String GROWL_APP_NAME = "ApplicationName";
/** Ticket key for the application icon. */
public static final String GROWL_APP_ICON = "ApplicationIcon";
/** Ticket key for the default notifactions. */
public static final String GROWL_NOTIFICATIONS_DEFAULT = "DefaultNotifications";
/** Ticket key for all notifactions. */
public static final String GROWL_NOTIFICATIONS_ALL = "AllNotifications";
// Notification Defines
/** The name of the growl notification for DNC. */
public static final String GROWL_NOTIFICATION = "GrowlNotification";
/** Notification key for the name. */
public static final String GROWL_NOTIFICATION_NAME = "NotificationName";
/** Notification key for the title. */
public static final String GROWL_NOTIFICATION_TITLE = "NotificationTitle";
/** Notification key for the description. */
public static final String GROWL_NOTIFICATION_DESCRIPTION = "NotificationDescription";
/** Notification key for the icon. */
public static final String GROWL_NOTIFICATION_ICON = "NotificationIcon";
/** Notification key for the application icon. */
public static final String GROWL_NOTIFICATION_APP_ICON = "NotificationAppIcon";
/** Notification key for the sticky flag. */
public static final String GROWL_NOTIFICATION_STICKY = "NotificationSticky";
// Actual instance data
private boolean registered; // We should only register once
private String appName; // "Application" Name
private NSData appImageData; // "application" Icon
private NSArray allNotes; // All notifications
private NSArray defNotes; // Default Notifications
private NSDistributedNotificationCenter theCenter;
//************ Constructors **************//
/**
* Convenience method to contruct a growl instance, defers to Growl(String
* inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes,
* boolean registerNow) with empty arrays for your notifications.
*
*
* @param inAppName - The Name of your "application"
* @param inImage - The NSImage Icon for your Application
*
*/
public Growl(String inAppName, NSImage inImage) {
this(inAppName,
inImage.TIFFRepresentation(),
new NSArray(),
new NSArray(),
false);
}
/**
* Convenience method to contruct a growl instance, defers to Growl(String
* inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes,
* boolean registerNow) with empty arrays for your notifications.
*
* @param inAppName - The Name of your "Application"
* @param inImageData - The NSData for your NSImage
*/
public Growl(String inAppName, NSData inImageData) {
this(inAppName,
inImageData,
new NSArray(),
new NSArray(),
false);
}
/**
* Convenience method to contruct a growl instance, defers to Growl(String
* inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes,
* boolean registerNow) with empty arrays for your notifications.
*
* @param inAppName - The Name of your "Application"
* @param inImagePath - The path to your icon
*
*/
public Growl(String inAppName, String inImagePath) {
this(inAppName,
new NSImage(inImagePath, false).TIFFRepresentation(),
new NSArray(),
new NSArray(),
false);
}
/**
* Convenience method to contruct a growl instance, defers to Growl(String
* inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes,
* boolean registerNow) with the arrays passed here and empty Data for the icon.
*
* @param inAppName - The Name of your "Application"
* @param inAllNotes - A String Array with the name of all your notifications
* @param inDefNotes - A String Array with the na,es of the Notifications on
* by default
*/
public Growl(String inAppName, String [] inAllNotes, String [] inDefNotes) {
this(inAppName,
new NSData(),
new NSArray(inAllNotes),
new NSArray(inDefNotes),
false);
}
/**
* Convenience method to contruct a growl instance, defers to Growl(String
* inAppName, NSData inImageData, NSArray inAllNotes, NSArray inDefNotes,
* boolean registerNow) with empty arrays for your notifications.
*
* @param inAppName - The Name of your "Application"
* @param inImageData - The Data of your "Application"'s icon
* @param inAllNotes - The NSArray of Strings of all your Notifications
* @param inDefNotes - The NSArray of Strings of your default Notifications
* @param registerNow - Since we have all the necessary info we can go ahead
* and register
*/
public Growl(String inAppName, NSData inImageData, NSArray inAllNotes,
NSArray inDefNotes, boolean registerNow) {
appName = inAppName;
appImageData = inImageData;
allNotes = inAllNotes;
defNotes = inDefNotes;
theCenter = (NSDistributedNotificationCenter)NSDistributedNotificationCenter.defaultCenter();
if (registerNow) {
register();
}
}
//************ Commonly Used Methods **************//
/**
* Register all our notifications with Growl, this should only be called
* once.
* @return <code>true</code>.
*/
public boolean register() {
if (!registered) {
// Construct our dictionary
// Make the arrays of objects then keys
Object [] objects = { appName, allNotes, defNotes, appImageData };
String [] keys = { GROWL_APP_NAME,
GROWL_NOTIFICATIONS_ALL,
GROWL_NOTIFICATIONS_DEFAULT,
GROWL_APP_ICON};
// Make the Dictionary
NSDictionary regDict = new NSDictionary(objects, keys);
theCenter.postNotification(GROWL_APP_REGISTRATION, // notificationName
null, // anObject
regDict, // userInfoDictionary
true); // deliverImmediately
registered = true;
}
return true;
}
/**
* The fun part is actually sending those notifications we worked so hard for
* so here we let growl know about things we think the user would like, and growl
* decides if that is the case.
*
* @param inNotificationName - The name of one of the notifications we told growl
* about.
* @param inIconData - The NSData for the icon for this notification, can be null
* @param inTitle - The Title of our Notification as Growl will show it
* @param inDescription - The Description of our Notification as Growl will
* display it
* @param inExtraInfo - Growl is flexible and allows Display Plugins to do as they
* please with thier own special keys and values, you may use
* them here. These may be ignored by either the user's
* preferences or the current Display Plugin. This can be null
* @param inSticky - Whether the Growl notification should be sticky
*
* @throws Exception When a notification is not known
*/
public void notifyGrowlOf(String inNotificationName, NSData inIconData,
String inTitle, String inDescription,
NSDictionary inExtraInfo, boolean inSticky) throws Exception {
NSMutableDictionary noteDict = new NSMutableDictionary();
if (!allNotes.containsObject(inNotificationName)) {
throw new Exception("Undefined Notification attempted");
}
noteDict.setObjectForKey(inNotificationName, GROWL_NOTIFICATION_NAME);
noteDict.setObjectForKey(inTitle, GROWL_NOTIFICATION_TITLE);
noteDict.setObjectForKey(inDescription, GROWL_NOTIFICATION_DESCRIPTION);
noteDict.setObjectForKey(appName, GROWL_APP_NAME);
if (inIconData != null) {
noteDict.setObjectForKey(inIconData, GROWL_NOTIFICATION_ICON);
}
if (inSticky) {
noteDict.setObjectForKey(1, GROWL_NOTIFICATION_STICKY);
}
if (inExtraInfo != null) {
noteDict.addEntriesFromDictionary(inExtraInfo);
}
theCenter.postNotification(GROWL_NOTIFICATION,
null,
noteDict,
true);
}
/**
* Convenience method that defers to notifyGrowlOf(String inNotificationName,
* NSData inIconData, String inTitle, String inDescription,
* NSDictionary inExtraInfo, boolean inSticky)
* This is primarily for compatibility with older code
*
* @param inNotificationName - The name of one of the notifications we told growl
* about.
* @param inIconData - The NSData for the icon for this notification, can be null
* @param inTitle - The Title of our Notification as Growl will show it
* @param inDescription - The Description of our Notification as Growl will
* display it
* @param inExtraInfo - Growl is flexible and allows Display Plugins to do as
* they please with their own special keys and values, you
* may use them here. These may be ignored by either the
* user's preferences or the current Display Plugin. This
* can be null.
*
* @throws Exception When a notification is not known
*
*/
public void notifyGrowlOf(String inNotificationName, NSData inIconData,
String inTitle, String inDescription,
NSDictionary inExtraInfo) throws Exception {
notifyGrowlOf(inNotificationName, inIconData, inTitle, inDescription,
inExtraInfo, false);
}
/**
* Convenienve method that defers to notifyGrowlOf(String inNotificationName,
* NSData inIconData, String inTitle, String inDescription,
* NSDictionary inExtraInfo) with null passed for icon and extraInfo arguments
*
* @param inNotificationName - The name of one of the notifications we told growl
* about.
* @param inTitle - The Title of our Notification as Growl will show it
* @param inDescription - The Description of our Notification as Growl will
* display it
*
* @throws Exception When a notification is not known
*/
public void notifyGrowlOf(String inNotificationName, String inTitle,
String inDescription) throws Exception {
notifyGrowlOf(inNotificationName, null,
inTitle, inDescription, null, false);
}
/**
* Convenience method that defers to notifyGrowlOf(String inNotificationName,
* NSData inIconData, String inTitle, String inDescription,
* NSDictionary inExtraInfo, boolean inSticky)
* with null passed for icon and extraInfo arguments
*
* @param inNotificationName - The name of one of the notifications we told growl
* about.
* @param inTitle - The Title of our Notification as Growl will show it
* @param inDescription - The Description of our Notification as Growl will
* display it
* @param inSticky - Whether our notification should be sticky
*
* @throws Exception When a notification is not known
*
*/
public void notifyGrowlOf(String inNotificationName, String inTitle,
String inDescription, boolean inSticky) throws Exception {
notifyGrowlOf(inNotificationName, null,
inTitle, inDescription, null, inSticky);
}
/**
* Defers to notifyGrowlOf(String inNotificationName, NSData inIconData,
* String inTitle, String inDescription, NSDictionary inExtraInfo) with null
* passed for icon and extraInfo arguments
*
* @param inNotificationName - The name of one of the notifications we told growl
* about.
* @param inImage - The notification image.
* @param inTitle - The Title of our Notification as Growl will show it
* @param inDescription - The Description of our Notification as Growl will
* display it
* @param inExtraInfo - Look above for info
*
* @throws Exception When a notification is not known
*
*/
public void notifyGrowlOf(String inNotificationName, NSImage inImage,
String inTitle, String inDescription,
NSDictionary inExtraInfo) throws Exception {
notifyGrowlOf(inNotificationName, inImage.TIFFRepresentation(),
inTitle, inDescription, inExtraInfo, false);
}
/**
* Convenienve method that defers to notifyGrowlOf(String inNotificationName,
* NSData inIconData, String inTitle, String inDescription,
* NSDictionary inExtraInfo) with null passed for extraInfo
*
* @param inNotificationName - The name of one of the notifications we told growl
* about.
* @param inImagePath - Path to the image for this notification
* @param inTitle - The Title of our Notification as Growl will show it
* @param inDescription - The Description of our Notification as Growl will
* display it
*
* @throws Exception When a notification is not known
*/
public void notifyGrowlOf(String inNotificationName, String inImagePath,
String inTitle, String inDescription) throws Exception {
notifyGrowlOf(inNotificationName,
new NSImage(inImagePath, false).TIFFRepresentation(),
inTitle, inDescription, null, false);
}
//************ Accessors **************//
/**
* Accessor for The currently set "Application" Name
*
* @return String - Application Name
*/
public String applicationName() {
return appName;
}
/**
* Accessor for the Array of allowed Notifications returned an NSArray
*
* @return the array of allowed notifications.
*/
public NSArray allowedNotifications() {
return allNotes;
}
/**
* Accessor for the Array of default Notifications returned as an NSArray
*
* @return the array of default notifications.
*/
public NSArray defaultNotifications() {
return defNotes;
}
//************ Mutators **************//
/**
* Sets The name of the Application talking to growl
*
* @param inAppName - The Application Name
*/
public void setApplicationName(String inAppName) {
appName = inAppName;
}
/**
* Set the list of allowed Notifications
*
* @param inAllNotes - The array of allowed Notifications
*/
public void setAllowedNotifications(NSArray inAllNotes) {
allNotes = inAllNotes;
}
/**
* Set the list of allowed Notifications
*
* @param inAllNotes - The array of allowed Notifications
*
*/
public void setAllowedNotifications(String[] inAllNotes) {
allNotes = new NSArray(inAllNotes);
}
/**
* Set the list of Default Notfiications
*
* @param inDefNotes - The default Notifications
*
* @throws Exception when an element of the array is not in the
* allowedNotifications
*/
public void setDefaultNotifications(NSArray inDefNotes) throws Exception {
int stop = inDefNotes.count();
int i;
for(i = 0; i < stop; i++) {
if (!allNotes.containsObject(inDefNotes.objectAtIndex(i))) {
throw new Exception("Array Element not in Allowed Notifications");
}
}
defNotes = inDefNotes;
}
/**
* Set the list of Default Notfiications
*
* @param inDefNotes - The default Notifications
*
* @throws Exception when an element of the array is not in the
* allowedNotifications
*
*/
public void setDefaultNotifications(String [] inDefNotes) throws Exception {
int stop = inDefNotes.length;
int i;
for(i = 0; i < stop; i++) {
if (! allNotes.containsObject(inDefNotes[i])) {
throw new Exception("Array Element not in Allowed Notifications");
}
}
defNotes = new NSArray(inDefNotes);
}
}

View File

@ -19,124 +19,80 @@
*/
package com.jivesoftware.spark.plugin.growl;
import com.apple.cocoa.application.NSImage;
import com.apple.cocoa.foundation.NSData;
import info.growl.GrowlException;
import javax.swing.SwingUtilities;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.packet.VCard;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.ui.ChatFrame;
import org.jivesoftware.spark.ui.ChatRoom;
import org.jivesoftware.spark.ui.GlobalMessageListener;
import org.jivesoftware.spark.util.log.Log;
import javax.swing.SwingUtilities;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @author Andrew Wright
* {@link GrowlMessageListener} implements the {@link GlobalMessageListener} and
* creates Growl Notifications on Message received
*
* @author Wolf.Posdorfer
*/
public class GrowlMessageListener implements GlobalMessageListener {
private Growl growl;
private GrowlTalker _growltalker;
public GrowlMessageListener() {
String[] notes = {"Message Received"};
growl = new Growl("Spark", notes, notes);
growl.register();
try {
_growltalker = new GrowlTalker();
} catch (GrowlException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void messageReceived(final ChatRoom chatRoom, final Message message) {
final ChatFrame chatFrame = SparkManager.getChatManager().getChatContainer().getChatFrame();
if (!chatFrame.isVisible() || !chatFrame.isInFocus()) {
showGrowlNotification(message);
}
SwingUtilities.invokeLater(new Runnable() {
}
@Override
public void run() {
final ChatFrame chatFrame = SparkManager.getChatManager().getChatContainer()
.getChatFrame();
private void showGrowlNotification(final Message message) {
SwingUtilities.invokeLater(new Runnable() {
if (!chatFrame.isInFocus()) {
showGrowlNotification(message);
}
}
});
public void run() {
try {
String name = SparkManager.getUserManager().getUserNicknameFromJID(message.getFrom());
// Since it looks the method can return null do this in case
if (name == null) {
name = StringUtils.parseName(message.getFrom());
}
VCard vCard = null;
try {
vCard = SparkManager.getVCardManager().getVCard(
StringUtils.parseBareAddress(message.getFrom()));
}
catch (Exception e) {
// vcard can time out so ignore
}
NSImage image = null;
if (vCard != null) {
byte[] bytes = vCard.getAvatar();
if (bytes != null) {
try {
NSData data = new NSData(bytes);
image = new NSImage(data);
}
catch (Exception e) {
// just incase there is an error i didn't intend
}
}
}
if (image == null) {
image = getImage("/images/message-32x32.png");
}
growl.notifyGrowlOf("Message Received", image, name, message.getBody(), null);
}
catch (Exception e) {
Log.error(e.getMessage(), e);
}
}
});
}
public void messageSent(ChatRoom room, Message message) {
// Ignore
}
/**
* Creates a {@link com.apple.cocoa.application.NSImage} from a string that points to an image in the class
*
* @param image classpath path of an image
* @return an cocoa image object
* Show a global Growl Notification
*
* @param message
* , {@link Message} containing Body and Sender
*/
private NSImage getImage(String image) {
InputStream in = this.getClass().getResourceAsStream(image);
ByteArrayOutputStream out = new ByteArrayOutputStream();
private void showGrowlNotification(Message message) {
try {
String name = SparkManager.getUserManager().getUserNicknameFromJID(message.getFrom());
String jid = message.getFrom();
byte[] buff = new byte[10 * 1024];
int len;
try {
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
in.close();
out.close();
}
catch (IOException e) {
Log.error(e.getMessage(), e);
}
if (name == null) {
name = StringUtils.parseName(message.getFrom());
}
_growltalker.sendNotificationWithCallback(name, message.getBody(), jid);
} catch (Exception e) {
Log.error(e.getMessage(), e);
}
NSData data = new NSData(out.toByteArray());
return new NSImage(data);
}
public void messageSent(ChatRoom room, Message message) {
}
}

View File

@ -19,37 +19,101 @@
*/
package com.jivesoftware.spark.plugin.growl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.jivesoftware.Spark;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.plugin.Plugin;
/**
* Provides support for Growl Notifications on Mac OS X. Growl can be acquired at
* http://growl.info
*
*
* @author Andrew Wright
* Provides support for Growl Notifications on Mac OS X. Growl can be acquired
* at http://growl.info
*
*
* @author Wolf.Posdorfer
*/
public class GrowlPlugin implements Plugin {
private GrowlMessageListener growlListener;
public void initialize() {
growlListener = new GrowlMessageListener();
SparkManager.getChatManager().addGlobalMessageListener(growlListener);
boolean b = placeLibs();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
if (!b) {
placeLibs();
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
}
}
GrowlPreference preference = new GrowlPreference();
// SparkManager.getPreferenceManager().addPreference(preference);
growlListener = new GrowlMessageListener();
SparkManager.getChatManager().addGlobalMessageListener(growlListener);
}
public void shutdown() {
SparkManager.getChatManager().removeGlobalMessageListener(growlListener);
SparkManager.getChatManager().removeGlobalMessageListener(growlListener);
}
public boolean canShutDown() {
return true;
return true;
}
public void uninstall() {
SparkManager.getChatManager().removeGlobalMessageListener(growlListener);
SparkManager.getChatManager().removeGlobalMessageListener(growlListener);
}
/**
* Places the libgrowl.jnilib into /Library/Java/Extensions
*
* @return
*/
private boolean placeLibs() {
boolean result = false;
File f = new File("/Library/Java/Extensions/libgrowl.jnilib");
if (f.exists()) {
return true;
}
String home = Spark.getUserHome() + "/Spark/plugins/growl/lib/";
File library = new File(home + "libgrowl.jnilib");
System.out.println(f.exists() + " " + library.exists());
try {
InputStream in = new FileInputStream(library);
OutputStream out = new FileOutputStream(f);
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
result = f.exists();
return result;
}
}

View File

@ -0,0 +1,118 @@
/**
* $RCSfile: ,v $
* $Revision: $
* $Date: $
*
* Copyright (C) 2004-2010 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.spark.plugin.growl;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.spark.preference.Preference;
/**
*
* Simple Class for GrowlPreference Panel <br>
* currently not in use
*
* @author wolf.posdorfer
*
*/
public class GrowlPreference implements Preference {
JPanel _panel;
private static final long serialVersionUID = 7485099198887907166L;
public GrowlPreference() {
}
@Override
public void commit() {
}
@Override
public Object getData() {
return "";
}
@Override
public String getErrorMessage() {
return "error with growlplugin";
}
@Override
public JComponent getGUI() {
_panel = new JPanel();
JButton button = new JButton("Test");
JButton button2 = new JButton("test2");
_panel.add(button);
_panel.add(button2);
return _panel;
}
@Override
public Icon getIcon() {
return SparkRes.getImageIcon(SparkRes.DUMMY_CONTACT_IMAGE);
}
@Override
public String getListName() {
return "growl";
}
@Override
public String getNamespace() {
return "growler";
}
@Override
public String getTitle() {
return "GROWL";
}
@Override
public String getTooltip() {
return "tooltip";
}
@Override
public boolean isDataValid() {
return true;
}
@Override
public void load() {
}
@Override
public void shutdown() {
}
}

View File

@ -0,0 +1,99 @@
/**
* $RCSfile: ,v $
* $Revision: $
* $Date: $
*
* Copyright (C) 2004-2011 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.spark.plugin.growl;
import info.growl.Growl;
import info.growl.GrowlCallbackListener;
import info.growl.GrowlException;
import info.growl.GrowlUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.ui.ChatRoom;
import org.jivesoftware.spark.util.log.Log;
/**
* GrowlTalker Class to send Messages to the GrowlInstance
*
* @author Wolf.Posdorfer
*
*/
public class GrowlTalker implements GrowlCallbackListener {
private Growl _growl;
private final String SPARK = "Spark";
public GrowlTalker() throws GrowlException {
_growl = GrowlUtils.getGrowlInstance(SPARK);
_growl.addNotification(SPARK, true);
_growl.addCallbackListener(this);
_growl.register();
}
@Override
public void notificationWasClicked(String arg0) {
String jid = StringUtils.parseBareAddress(arg0);
ChatRoom room = SparkManager.getChatManager().getChatRoom(jid);
SparkManager.getChatManager().getChatContainer().activateChatRoom(room);
SparkManager.getChatManager().getChatContainer().requestFocusInWindow();
}
/**
* Sends a simple Notification
*
* @param name
* @param title
* @param body
*/
public void sendNotification(String title, String body) {
try {
_growl.sendNotification(SPARK, title, body);
} catch (GrowlException e) {
Log.error("growl error", e);
}
}
/**
* Sends a notification with a CallBackContext
*
* @param title
* the title to display
* @param body
* the body to display
* @param callbackContext
* a callback context
*/
public void sendNotificationWithCallback(String title, String body, String callbackContext) {
try {
_growl.sendNotification(SPARK, title, body, callbackContext);
} catch (GrowlException e) {
System.out.println("growl error" + e);
}
}
}

View File

@ -0,0 +1,88 @@
/**
* $RCSfile: ,v $
* $Revision: $
* $Date: $
*
* Copyright (C) 2004-2010 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jivesoftware.spark.plugin.growl;
import info.growl.Growl;
import info.growl.GrowlCallbackListener;
import info.growl.GrowlException;
import info.growl.GrowlUtils;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
/**
* Simple Test Class to test Growl behaviour
*
* @author wolf.posdorfer
*
*/
public class GrowlTest {
public static void main(String[] args) throws GrowlException {
new GrowlTest();
}
final String appName = "Eclipse";
public GrowlTest() throws GrowlException {
JFrame f = new JFrame("test");
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Growl growl = GrowlUtils.getGrowlInstance(appName);
growl.addNotification(appName, true);
GrowlCallbackListener listener = new GrowlCallbackListener() {
public void notificationWasClicked(final String clickContext) {
System.out.println(clickContext + " was clicked");
}
};
growl.addCallbackListener(listener);
growl.register();
Action action = new AbstractAction("CLICK") {
private static final long serialVersionUID = -7415179834807796108L;
public void actionPerformed(ActionEvent ae) {
try {
Growl gu = GrowlUtils.getGrowlInstance(appName);
gu.sendNotification(appName, "title", "body", "callbackcontext");
} catch (GrowlException ge) {
ge.printStackTrace();
}
}
};
JButton button = new JButton(action);
f.setSize(200, 200);
f.add(button);
}
}

Binary file not shown.

View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 2008, Michael Stringer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Growl nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package info.growl;
import java.awt.image.RenderedImage;
/**
* Dummy implementation of the Growl API for situations where the native code
* cannot be loaded (non-Mac systems).
*
* @author Michael Stringer
* @version 0.1
*/
class DummyGrowl implements Growl {
/**
* {@inheritDoc}
*/
public void addNotification(String name, boolean enabledByDefault) {
// does nothing
}
/**
* {@inheritDoc}
*/
public void register() throws GrowlException {
// does nothing
}
/**
* {@inheritDoc}
*/
public void sendNotification(String name, String title, String body)
throws GrowlException {
// does nothing
}
/**
* {@inheritDoc}
*/
public void sendNotification(String name, String title, String body,
RenderedImage icon) throws GrowlException {
// does nothing
}
/**
* {@inheritDoc}
*/
public void setIcon(RenderedImage icon) throws GrowlException {
// does nothing
}
/**
* {@inheritDoc}
*/
public void sendNotification(String name, String title, String body,
String callbackContext) throws GrowlException {
// does nothing
}
/**
* {@inheritDoc}
*/
public void sendNotification(String name, String title, String body,
String callbackContext, RenderedImage icon) throws GrowlException {
// does nothing
}
/**
* {@inheritDoc}
*/
public void addCallbackListener(GrowlCallbackListener listener) {
// does nothing
}
}

View File

@ -0,0 +1,160 @@
/*
* Copyright (c) 2008, Michael Stringer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Growl nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package info.growl;
import java.awt.image.RenderedImage;
/**
* Interface for sending notifications to Growl.
*
* @author Michael Stringer
* @version 0.1
*/
public interface Growl {
/**
* Registers this Growl object with the Growl service.
*
* @throws GrowlException
* If an error occurs during the registration.
*/
public void register() throws GrowlException;
/**
* Sets the icon to display for notifications from this <code>Growl</code>.
*
* This <b>must</b> be called before calling {@link #register()}. If the
* icon is changed after {@link #register()} has been called then another
* call to {@link #register()} must be made.
*
* @param icon
* The icon to display.
* @throws GrowlException
* If an error occurs while setting the icon.
*/
public void setIcon(RenderedImage icon) throws GrowlException;
/**
* Adds a notification type for this <code>Growl</code>. This <b>must</b>
* be called before calling {@link #register()}. If the another
* notification type is added after {@link #register()} has been called then
* another call to {@link #register()} must be made.
*
* @param name
* The name of the notification type. This is what appears in
* the Growl settings.
* @param enabledByDefault
* <code>true</code> if this notification type should be
* enabled by default. This can be overridden by the user in
* the Growl settings.
*/
public void addNotification(String name, boolean enabledByDefault);
/**
* Adds a click callback listener.
*
* @param listener
* The callback listener to add.
*/
public void addCallbackListener(GrowlCallbackListener listener);
/**
* Sends a notification to Growl for displaying. This <b>must</b> be called
* after calling {@link #register()}.
*
* @param name
* Name of the notification type that has been registered.
* @param title
* The title of the notification.
* @param body
* The body of the notification.
* @throws GrowlException
* If the notification could not be sent.
*/
public void sendNotification(String name, String title, String body)
throws GrowlException;
/**
* Sends a notification to Growl for displaying. This <b>must</b> be called
* after calling {@link #register()}.
*
* @param name
* Name of the notification type that has been registered.
* @param title
* The title of the notification.
* @param body
* The body of the notification.
* @param icon
* The icon to display with the notification.
* @throws GrowlException
* If the notification could not be sent.
*/
public void sendNotification(String name, String title, String body,
RenderedImage icon) throws GrowlException;
/**
* Sends a notification to Growl for displaying. This <b>must</b> be called
* after calling {@link #register()}.
*
* @param name
* Name of the notification type that has been registered.
* @param title
* The title of the notification.
* @param body
* The body of the notification.
* @param callbackContext
* A unique ID that will be sent to any registered
* {@link GrowlCallbackListener}s. If this is
* <code>null</code> then clicks will be ignored.
* @throws GrowlException
* If the notification could not be sent.
*/
public void sendNotification(String name, String title, String body,
String callbackContext) throws GrowlException;
/**
* Sends a notification to Growl for displaying. This <b>must</b> be called
* after calling {@link #register()}.
*
* @param name
* Name of the notification type that has been registered.
* @param title
* The title of the notification.
* @param body
* The body of the notification.
* @param callbackContext
* A unique ID that will be sent to any registered
* {@link GrowlCallbackListener}s. If this is
* <code>null</code> then clicks will be ignored.
* @param icon
* The icon to display with the notification.
* @throws GrowlException
* If the notification could not be sent.
*/
public void sendNotification(String name, String title, String body,
String callbackContext, RenderedImage icon) throws GrowlException;
}

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 2008, Michael Stringer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Growl nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package info.growl;
/**
* Callback interface for handling users clicking on notifications.
*
* @author Michael Stringer
* @version 0.1
*/
public interface GrowlCallbackListener {
/**
* Signals that the user has clicked on a notification with an identifier of
* <code>clickContext</code>.
*
* @param clickContext
* The ID of the notification clicked.
*/
public void notificationWasClicked(String clickContext);
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2008, Michael Stringer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Growl nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package info.growl;
/**
* An exception class for handling errors while sending messages to Growl.
*
* @author Michael Stringer
* @version 0.1
*/
public class GrowlException extends Exception {
private static final long serialVersionUID = 2642457707267962686L;
/**
* Creates a new <code>GrowlException</code>.
*
* @param message
* The error message.
*/
public GrowlException(String message) {
super(message);
}
/**
* Creates a new <code>GrowlException</code>.
*
* @param message
* The error message.
* @param cause
* The underlying cause.
*/
public GrowlException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,211 @@
/*
* Copyright (c) 2008, Michael Stringer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Growl nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package info.growl;
import java.awt.image.RenderedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
/**
* Growl notification implementation. This uses JNI to send messages to Growl.
*
* @author Michael Stringer
* @version 0.1
*/
class GrowlNative implements Growl {
private String appName;
private List<NotificationType> notifications;
private List<GrowlCallbackListener> callbackListeners;
private byte[] imageData;
private native void sendNotification(String appName, String name,
String title, String message, String callbackContext, byte[] icon);
private native void registerApp(String appName, byte[] image,
List<NotificationType> notifications);
/**
* Creates a new <code>GrowlNative</code> instance for the specified
* application name.
*
* @param appName
* The name of the application sending notifications.
*/
GrowlNative(String appName) {
notifications = new ArrayList<NotificationType>();
callbackListeners = new ArrayList<GrowlCallbackListener>();
this.appName = appName;
}
void fireCallbacks(String callbackContext) {
for (GrowlCallbackListener listener : callbackListeners) {
listener.notificationWasClicked(callbackContext);
}
}
/**
* {@inheritDoc}
*/
public void register() throws GrowlException {
registerApp(appName, imageData, notifications);
}
/**
* {@inheritDoc}
*/
public void addNotification(String name, boolean enabledByDefault) {
notifications.add(new NotificationType(name, enabledByDefault));
}
/**
* {@inheritDoc}
*/
public void addCallbackListener(GrowlCallbackListener listener) {
callbackListeners.add(listener);
}
/**
* {@inheritDoc}
*/
public void setIcon(RenderedImage icon) throws GrowlException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(icon, "png", baos);
imageData = baos.toByteArray();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* {@inheritDoc}
*/
public void sendNotification(String name, String title, String body)
throws GrowlException {
if (!notifications.contains(new NotificationType(name, false))) {
System.out.println("contains: " + notifications);
throw new GrowlException("Unregistered notification name [" + name
+ "]");
}
sendNotification(appName, name, title, body, null, null);
}
/**
* {@inheritDoc}
*/
public void sendNotification(String name, String title, String body,
RenderedImage icon) throws GrowlException {
if (!notifications.contains(new NotificationType(name, false))) {
System.out.println("contains: " + notifications);
throw new GrowlException("Unregistered notification name [" + name
+ "]");
}
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(icon, "png", baos);
byte[] image = baos.toByteArray();
sendNotification(appName, name, title, body, null, image);
} catch (IOException ioe) {
throw new GrowlException("Failed to convert Image", ioe);
}
}
/**
* {@inheritDoc}
*/
public void sendNotification(String name, String title, String body,
String callbackContext) throws GrowlException {
if (!notifications.contains(new NotificationType(name, false))) {
System.out.println("contains: " + notifications);
throw new GrowlException("Unregistered notification name [" + name
+ "]");
}
sendNotification(appName, name, title, body, callbackContext, null);
}
/**
* {@inheritDoc}
*/
public void sendNotification(String name, String title, String body,
String callbackContext, RenderedImage icon) throws GrowlException {
if (!notifications.contains(new NotificationType(name, false))) {
System.out.println("contains: " + notifications);
throw new GrowlException("Unregistered notification name [" + name
+ "]");
}
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(icon, "png", baos);
byte[] image = baos.toByteArray();
sendNotification(appName, name, title, body, callbackContext, image);
} catch (IOException ioe) {
throw new GrowlException("Failed to convert Image", ioe);
}
}
private class NotificationType {
private String name;
private boolean enabledByDefault;
public NotificationType(String name, boolean enabledByDefault) {
this.name = name;
this.enabledByDefault = enabledByDefault;
}
public String getName() {
return name;
}
public boolean isEnabledByDefault() {
return enabledByDefault;
}
public boolean equals(Object other) {
if (!(other instanceof NotificationType)) {
return false;
}
NotificationType otherType = (NotificationType) other;
return name.equals(otherType.name);
}
}
}

View File

@ -0,0 +1,113 @@
/*
* Copyright (c) 2008, Michael Stringer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Growl nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package info.growl;
import java.util.HashMap;
import java.util.Map;
/**
* Utility class for sending notifications using Growl.
*
* @author Michael Stringer
* @version 0.1
*/
public final class GrowlUtils {
private static final boolean GROWL_LOADED;
private static Map<String, Growl> instances = new HashMap<String, Growl>();
// public GrowlUtils(String pathtoload)
// {
// try {
// System.load(pathtoload);
// }catch (UnsatisfiedLinkError ule) {
// System.out.println("Failed to load Growl library from "+pathtoload);
// }
// }
//
// public Growl getGrowl(String appName)
// {
//
// Growl stuff = new GrowlNative(appName);
// return stuff;
// }
static {
boolean loaded = false;
try {
System.loadLibrary("growl");
loaded = true;
} catch (UnsatisfiedLinkError ule) {
System.out.println("Failed to load Growl library");
}
GROWL_LOADED = loaded;
}
/**
* Utility method - should not be instantiated.
*/
private GrowlUtils() {
}
/**
* Gets a <code>Growl</code> instance to use for the specified application
* name. Multiple calls to this method will return the same instance.
*
* @param appName
* The name of the application.
* @return The <code>Growl</code> instance to use.
*/
public static Growl getGrowlInstance(String appName) {
Growl instance = instances.get(appName);
if (instance == null) {
if (GROWL_LOADED) {
instance = new GrowlNative(appName);
} else {
instance = new DummyGrowl();
}
instances.put(appName, instance);
}
return instance;
}
/**
* Gets whether messages can be sent to Growl. If this returns
* <code>false</code> then {@link #getGrowlInstance(String)} will return a
* dummy object.
*
* @return <code>true</code> if messages can be sent to Growl.
*/
public static boolean isGrowlLoaded() {
return GROWL_LOADED;
}
}

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2008, Michael Stringer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Growl nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY <copyright holder> ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package info.growl.test;
import info.growl.Growl;
import info.growl.GrowlCallbackListener;
import info.growl.GrowlException;
import info.growl.GrowlUtils;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
/**
* Simple test class for Growl.
*
* @author Michael Stringer
* @version 0.1
*/
public class TestGrowl extends JFrame {
private static final String APP_NAME = "Test Java App";
private static final String NOTIF_3_CALLBACK = "Notif3";
public TestGrowl() {
super("Growl for Java");
setSize(320, 290);
buildComponents();
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
private void buildComponents() {
getContentPane().setLayout(new GridLayout(6, 1));
Action action = new AbstractAction("Register") {
public void actionPerformed(ActionEvent ae) {
try {
Growl growl = GrowlUtils.getGrowlInstance(APP_NAME);
growl.addNotification("Test Notification 1", true);
growl.addNotification("Test Notification 2", false);
growl.addNotification("Test Notification 3", true);
GrowlCallbackListener listener = new GrowlCallbackListener() {
public void notificationWasClicked(
final String clickContext) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (NOTIF_3_CALLBACK.equals(clickContext)) {
JOptionPane
.showMessageDialog(
TestGrowl.this,
"User clicked on 'Test Notification 3'");
}
}
});
}
};
growl.addCallbackListener(listener);
growl.register();
} catch (GrowlException ge) {
ge.printStackTrace();
}
}
};
getContentPane().add(new JButton(action));
action = new AbstractAction("Send 'Test Notification 1'") {
public void actionPerformed(ActionEvent ae) {
try {
Growl growl = GrowlUtils.getGrowlInstance(APP_NAME);
growl.sendNotification("Test Notification 1",
"Test Notif 1", "This is a test");
} catch (GrowlException ge) {
ge.printStackTrace();
}
}
};
getContentPane().add(new JButton(action));
action = new AbstractAction("Send 'Test Notification 2'") {
public void actionPerformed(ActionEvent ae) {
try {
Growl growl = GrowlUtils.getGrowlInstance(APP_NAME);
BufferedImage image = ImageIO.read(TestGrowl.class
.getResource("/images/duke.gif"));
growl.sendNotification("Test Notification 2",
"Test Notif 2", "This is another test", image);
} catch (GrowlException ge) {
ge.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
getContentPane().add(new JButton(action));
action = new AbstractAction("Test Callback 'Notification 3'") {
public void actionPerformed(ActionEvent ae) {
try {
Growl growl = GrowlUtils.getGrowlInstance(APP_NAME);
growl.sendNotification("Test Notification 3",
"Callback Test", "Click me - I dares you!", NOTIF_3_CALLBACK);
} catch (GrowlException ge) {
ge.printStackTrace();
}
}
};
getContentPane().add(new JButton(action));
action = new AbstractAction("Reg & Test App 2") {
public void actionPerformed(ActionEvent ae) {
try {
Growl growl = GrowlUtils.getGrowlInstance("Other App");
growl.addNotification("A Notification", true);
BufferedImage image = ImageIO.read(TestGrowl.class
.getResource("/images/duke.gif"));
growl.setIcon(image);
growl.register();
growl.sendNotification("A Notification", "Testin",
"Blah de blah blah");
} catch (GrowlException ge) {
ge.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
getContentPane().add(new JButton(action));
action = new AbstractAction("Exit") {
public void actionPerformed(ActionEvent ae) {
System.exit(0);
}
};
getContentPane().add(new JButton(action));
}
public static final void main(String[] args) {
new TestGrowl();
}
}

View File

@ -1,7 +1,7 @@
<plugin>
<name>Growl Plugin</name>
<version>1.0</version>
<author>Andrew Wright</author>
<version>2.0</version>
<author>Wolf Posdorfer</author>
<homePage>http://www.jivesoftware.com</homePage>
<email>andrew@jivesoftware.com</email>
<description>Provides Growl notifications on Mac OS X.(http://growl.info)</description>