// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program 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 2 of the License, or (at your option) any later version.
//
// 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id $
//
package com.salas.bb.utils.notification;
import com.salas.bb.utils.i18n.Strings;
import java.awt.*;
import java.awt.event.ActionListener;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Native Java6 notification handler.
*/
class Java6NotificationHandler implements INotificationHandler
{
private static final Logger LOG = Logger.getLogger(Java6NotificationHandler.class.getName());
/** Application name. */
private final String appName;
/** System tray icon image. */
private final Image smallImage;
private ActionListener listener;
private boolean initOK;
private final Object iconLock = new Object();
private Object icon;
private Method mSystemTray_getSystemTray;
private Method mSystemTray_add;
private Method mSystemTray_remove;
private Method mTrayIcon_addActionListener;
private Method methodTrayIcon_displayMessage;
private Method methodTrayIcon_setToolTip;
private Method methodTrayIcon_setPopupMenu;
private Method mTrayIcon_setImageAutoSize;
private Class classTrayIcon;
private Object enumInfo;
private PopupMenu appIconMenu;
/**
* Creates handler.
*
* @param appName application name.
* @param smallImage image for system tray.
*
* @throws NotificationsNotSupported if notifications aren't supported.
*/
public Java6NotificationHandler(String appName, Image smallImage)
throws NotificationsNotSupported
{
this.appName = appName;
this.smallImage = smallImage;
initOK = false;
try
{
// Get classes
Class classSystemTray = Class.forName("java.awt.SystemTray");
classTrayIcon = Class.forName("java.awt.TrayIcon");
Class classTrayIconMessageType = Class.forName("java.awt.TrayIcon$MessageType");
// Get methods
Method methodSystemTray_isSupported = classSystemTray.getMethod("isSupported");
Object result = methodSystemTray_isSupported.invoke(null);
if ((Boolean)result)
{
mSystemTray_getSystemTray = classSystemTray.getMethod("getSystemTray");
mSystemTray_add = classSystemTray.getMethod("add", classTrayIcon);
mSystemTray_remove = classSystemTray.getMethod("remove", classTrayIcon);
mTrayIcon_addActionListener = classTrayIcon.getMethod("addActionListener", ActionListener.class);
mTrayIcon_setImageAutoSize = classTrayIcon.getMethod("setImageAutoSize", Boolean.TYPE);
methodTrayIcon_displayMessage = classTrayIcon.getMethod("displayMessage",
String.class, String.class, classTrayIconMessageType);
methodTrayIcon_setToolTip = classTrayIcon.getMethod("setToolTip", String.class);
methodTrayIcon_setPopupMenu = classTrayIcon.getMethod("setPopupMenu", PopupMenu.class);
Method methodClass_getEnumConstants = Class.class.getMethod("getEnumConstants");
enumInfo = ((Object[])methodClass_getEnumConstants.invoke(classTrayIconMessageType))[2];
initOK = true;
}
} catch (Throwable e)
{
LOG.log(Level.SEVERE, Strings.error("notify.initialization.failed"), e);
}
if (!initOK) throw new NotificationsNotSupported();
}
/**
* Shows application icon with the menu.
*
* @param appIconMenu menu or <code>NULL</code> if menu isn't required.
*/
public void showAppIcon(PopupMenu appIconMenu)
{
if (!initOK) return;
synchronized (iconLock)
{
if (icon != null) return;
this.appIconMenu = appIconMenu;
try
{
Constructor constructor = classTrayIcon.getConstructor(new Class[] {
Image.class, String.class,PopupMenu.class });
icon = constructor.newInstance(smallImage, appName, appIconMenu);
// Set auto-sizing for an image
mTrayIcon_setImageAutoSize.invoke(icon, true);
addIcon(icon);
if (listener != null) addIconActionListener(icon, listener);
} catch (Exception e)
{
LOG.log(Level.SEVERE, Strings.error("notify.failed.to.show.icon"), e);
}
}
}
/**
* Hides application icon.
*/
public void hideAppIcon()
{
if (!initOK || icon == null) return;
try
{
synchronized (iconLock)
{
// Unregister menu from other icon
removeIcon(icon);
resetPopupMenu(icon);
icon = null;
}
} catch (Exception e)
{
LOG.log(Level.SEVERE, Strings.error("notify.failed.to.remove.icon"), e);
}
}
/**
* Shows blogbridge icon (if applicable) in notification area and
* shows balloon with the given text. If balloon is already visible,
* its text gets updated.
*
* @param event event name.
* @param message message text.
*/
public void showMessage(String event, String message)
{
if (!initOK) return;
Object icn = getIcon();
displayMessage(icn, event, message);
setToolTip(icn, message);
}
/**
* Returns or creates icon when necessary.
*
* @return tray icon.
*/
private Object getIcon()
{
synchronized (iconLock)
{
if (icon == null) showAppIcon(appIconMenu);
}
return icon;
}
/**
* Sets an action listener which will be notified when a user clicks over the
* balloon.
*
* @param l listener.
*/
public void setAppIconActionListener(ActionListener l)
{
listener = l;
}
/**
* Sets the URL of an image to use in balloon (if applicable).
*
* @param imageURL image URL.
*/
public void setBalloonImageURL(URL imageURL)
{
// Not applicable
}
// -----------------------------------------------------------------------------------------------------------------
/**
* Adds an icon to the system tray.
*
* @param icon icon to add.
*
* @throws IllegalAccessException in case of access violation.
* @throws InvocationTargetException in case of invocation problems.
*/
private void addIcon(Object icon)
throws IllegalAccessException, InvocationTargetException
{
Object systray = mSystemTray_getSystemTray.invoke(null);
mSystemTray_add.invoke(systray, icon);
}
/**
* Removes an icon from the system tray.
*
* @param icon icon.
*
* @throws IllegalAccessException in case of access violation.
* @throws InvocationTargetException in case of invocation problems.
*/
private void removeIcon(Object icon)
throws IllegalAccessException, InvocationTargetException
{
Object systray = mSystemTray_getSystemTray.invoke(null);
mSystemTray_remove.invoke(systray, icon);
}
/**
* Adds an action listener to the icon.
*
* @param icon icon.
* @param l listener.
*
* @throws IllegalAccessException in case of access violation.
* @throws InvocationTargetException in case of invocation problems.
*/
private void addIconActionListener(Object icon, ActionListener l)
throws IllegalAccessException, InvocationTargetException
{
mTrayIcon_addActionListener.invoke(icon, l);
}
/**
* Sets icon tooltip.
*
* @param icn icon.
* @param message message.
*/
private void setToolTip(Object icn, String message)
{
try
{
methodTrayIcon_setToolTip.invoke(icn, message);
} catch (Exception e)
{
LOG.log(Level.SEVERE, Strings.error("notify.failed.to.set.tool.tip"), e);
}
}
/**
* Resets popup menu of an icon releasing it for other icons.
*
* @param icn icon.
*/
private void resetPopupMenu(Object icn)
{
try
{
methodTrayIcon_setPopupMenu.invoke(icn, new Object[] { null });
} catch (Exception e)
{
LOG.log(Level.SEVERE, "Failed to reset popup menu.", e);
}
}
/**
* Displays message.
*
* @param icn system tray icon.
* @param caption caption.
* @param message message.
*/
private void displayMessage(Object icn, String caption, String message)
{
try
{
methodTrayIcon_displayMessage.invoke(icn, caption, message, enumInfo);
} catch (Exception e)
{
LOG.log(Level.SEVERE, Strings.error("notify.failed.to.display.the.message"), e);
}
}
}