swing based popup notifications with tests for the PopupMessage interface.

cusax-fix
Symphorien Wanko 17 years ago
parent 65f31038bd
commit 2d81282722

@ -771,7 +771,7 @@
<target name="bundles"
depends="bundle-sc-launcher,bundle-util,bundle-configuration,bundle-configuration-slick,
bundle-history,bundle-history-slick,bundle-messagehistory, bundle-msghistory-slick,
bundle-callhistory, bundle-callhistory-slick,
bundle-callhistory, bundle-callhistory-slick, bundle-popupmessagehandler-slick,
bundle-netaddr,bundle-netaddr-slick,bundle-slickless,
bundle-slick-runner,bundle-sip,bundle-sip-slick,bundle-fileaccess,
bundle-fileaccess-slick,bundle-media,bundle-media-slick,
@ -784,7 +784,7 @@
bundle-plugin-msnaccregwizz,bundle-plugin-sipaccregwizz,
bundle-plugin-yahooaccregwizz,bundle-plugin-aimaccregwizz,
bundle-version,bundle-version-impl,bundle-shutdown,
bundle-growlnotification,bundle-sparkle,
bundle-growlnotification,bundle-swingnotification,bundle-sparkle,
bundle-audionotifier,bundle-plugin-branding,
bundle-systray,bundle-browserlauncher,bundle-gibberish,
bundle-gibberish-slick,bundle-plugin-gibberishaccregwizz,
@ -1478,6 +1478,25 @@ javax.swing.event, javax.swing.border"/>
</jar>
</target>
<!--BUNDLE-SWINGNOTIFICATION-->
<target name="bundle-swingnotification">
<!-- Creates a bundle for the swingnotification plugin.-->
<jar compress="false" destfile="${bundles.dest}/swingnotification.jar"
manifest="${src}/net/java/sip/communicator/impl/swingnotification/swingnotification.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/impl/swingnotification"
prefix="net/java/sip/communicator/impl/swingnotification" />
</jar>
</target>
<!--BUNDLE-POPUPMESSAGEHANDLER-SLICK-->
<target name="bundle-popupmessagehandler-slick">
<jar compress="false" destfile="${bundles.dest}/popupmessagehandler-slick.jar"
manifest="${testsrc}/net/java/sip/communicator/slick/popupmessagehandler/popupmessagehandler.slick.manifest.mf">
<zipfileset dir="${dest}/net/java/sip/communicator/slick/popupmessagehandler"
prefix="net/java/sip/communicator/slick/popupmessagehandler"/>
</jar>
</target>
<!--BUNDLE-SPARKLE-->
<target name="bundle-sparkle">
<!-- Creates a bundle for the sparkle activator plugin.-->

@ -127,6 +127,7 @@ felix.auto.start.60= \
felix.auto.start.66= \
reference:file:sc-bundles/swing-ui.jar \
reference:file:sc-bundles/updatechecker.jar \
reference:file:sc-bundles/swingnotification.jar \
reference:file:sc-bundles/systray.jar
felix.auto.start.67= \

@ -48,7 +48,11 @@ org.osgi.framework.system.packages.extra= org.osgi.framework; ; version=1.3.0, \
gnu.java.zrtp; \
gnu.java.zrtp.packets; \
gnu.java.zrtp.utils; \
gnu.java.zrtp.zidfile
gnu.java.zrtp.zidfile; \
com.apple.cocoa.foundation; \
org.jdesktop.jdic.tray; \
com.apple.cocoa.application; \
net.java.sip.communicator.service.audionotifier; \
#
# In case you want testing to run using oscar's graphical ui then uncomment
@ -102,7 +106,9 @@ felix.auto.start.6= \
reference:file:sc-bundles/protocol-mock.jar \
reference:file:sc-bundles/meta-cl.jar \
reference:file:sc-bundles/msghistory.jar \
reference:file:sc-bundles/callhistory.jar
reference:file:sc-bundles/callhistory.jar \
reference:file:sc-bundles/systray.jar \
reference:file:sc-bundles/notification.jar
felix.auto.start.7= \
reference:file:sc-bundles/slickless.jar \
@ -120,7 +126,8 @@ felix.auto.start.7= \
reference:file:sc-bundles/protocol-icq-slick.jar \
reference:file:sc-bundles/protocol-rss-slick.jar \
reference:file:sc-bundles/msghistory-slick.jar \
reference:file:sc-bundles/callhistory-slick.jar
reference:file:sc-bundles/callhistory-slick.jar \
reference:file:sc-bundles/popupmessagehandler-slick.jar
felix.auto.start.100= \
reference:file:sc-bundles/slick-runner.jar

@ -21,7 +21,8 @@ net.java.sip.communicator.slick.runner.TEST_LIST=ConfigurationServiceLick \
YahooProtocolProviderSlick \
MsnProtocolProviderSlick \
GibberishProtocolProviderServiceLick \
RssProtocolProviderServiceLick
RssProtocolProviderServiceLick \
PopupMessageHandlerSLick
# Note that NetworkAddressManagerServiceLick currently runs

@ -338,6 +338,9 @@ impl.systray.SET_STATUS=Set Status
impl.systray.ONLINE_STATUS=Online
impl.systray.OFFLINE_STATUS=Offline
impl.systray.FAILED_TO_OPEN_ADD_CONTACT_DIALOG=Failed to open the "Add Contact" dialog.
impl.systray.POPUP_MESSAGE_HANDLER=Systray balloon message
impl.swingnotification.POPUP_MESSAGE_HANDLER=SC likes popup
impl.growlnotification.POPUP_MESSAGE_HANDLER=Growl notifications
# account info
plugin.accountinfo.TITLE=Account Info
@ -665,6 +668,7 @@ plugin.notificationconfig.RESTORE=Restore Defaults
plugin.notificationconfig.PLAY_SOUND=Play a sound :
plugin.notificationconfig.EXEC_PROG=Execute a program :
plugin.notificationconfig.DISPLAY_POPUP=Show a message in a pop-up window
plugin.notificationconfig.POPUP_NOTIF_HANDLER=Popup notifications type
# ZRTP Securing
impl.media.security.INFO=ZRTP Security information

@ -6,6 +6,7 @@
*/
package net.java.sip.communicator.impl.growlnotification;
import net.java.sip.communicator.service.resources.*;
import org.osgi.framework.*;
import net.java.sip.communicator.util.*;
@ -18,16 +19,26 @@
public class GrowlNotificationActivator
implements BundleActivator
{
/**
* The bundle context in which we started
*/
public static BundleContext bundleContext;
private static final Logger logger =
Logger.getLogger(GrowlNotificationActivator.class);
/**
* A reference to the resource management service.
*/
private static ResourceManagementService resourcesService;
/**
* Initialize and start Growl Notifications Service
*
* @param bundleContext BundleContext
* @throws Exception
*/
public void start(BundleContext bundleContext) throws Exception
public void start(BundleContext bc) throws Exception
{
/* Check Java version: do not start if Java 6 */
/* Actually, this plugin uses the Growl Java bindings which
@ -47,10 +58,26 @@ public void start(BundleContext bundleContext) throws Exception
logger.info("Growl Notification Plugin ...[Started]");
}
bundleContext = bc;
}
public void stop(BundleContext bundleContext) throws Exception
{
logger.info("Growl Notification Service ...[Stopped]");
}
/**
* Returns the <tt>ResourceManagementService</tt> obtained from the bundle
* context.
* @return the <tt>ResourceManagementService</tt> obtained from the bundle
* context
*/
public static ResourceManagementService getResources()
{
if (resourcesService == null)
resourcesService =
ResourceManagementServiceUtils.getService(bundleContext);
return resourcesService;
}
}

@ -7,14 +7,15 @@
package net.java.sip.communicator.impl.growlnotification;
import java.lang.reflect.*;
import java.util.*;
import org.osgi.framework.*;
import com.growl.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.service.systray.event.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
/**
* The Growl Notification Service displays on-screen information such as
@ -23,8 +24,7 @@
* @author Romain Kuntz
*/
public class GrowlNotificationServiceImpl
implements MessageListener,
ServiceListener
implements PopupMessageHandler
{
/**
* The logger for this class.
@ -32,11 +32,6 @@ public class GrowlNotificationServiceImpl
private static Logger logger =
Logger.getLogger(GrowlNotificationServiceImpl.class);
/**
* The BundleContext that we got from the OSGI bus.
*/
private BundleContext bundleContext = null;
/**
* The Growl notifier
*/
@ -68,6 +63,10 @@ public class GrowlNotificationServiceImpl
*/
private String sipIconPath = "resources/images/logo/sc_logo_128x128.icns";
/** The list of all added popup listeners */
private final List<SystrayPopupMessageListener> popupMessageListeners =
new Vector<SystrayPopupMessageListener>();
/**
* starts the service. Creates a Growl notifier, and check the current
* registerd protocol providers which supports BasicIM and adds message
@ -80,7 +79,6 @@ public void start(BundleContext bc)
throws Exception
{
logger.debug("Starting the Growl Notification implementation.");
this.bundleContext = bc;
/* Register to Growl */
try
@ -121,38 +119,7 @@ public void start(BundleContext bc)
throw ex;
}
/* Start listening for newly register or removed protocol providers */
bc.addServiceListener(this);
ServiceReference[] protocolProviderRefs = null;
try
{
protocolProviderRefs = bc.getServiceReferences(
ProtocolProviderService.class.getName(),
null);
}
catch (InvalidSyntaxException ex)
{
// this shouldn't happen since we're providing no parameter string
// but let's log just in case.
logger.error("Error while retrieving service refs", ex);
return;
}
// in case we found any
if (protocolProviderRefs != null)
{
logger.debug("Found "
+ protocolProviderRefs.length
+ " already installed providers.");
for (int i = 0; i < protocolProviderRefs.length; i++)
{
ProtocolProviderService provider = (ProtocolProviderService) bc
.getService(protocolProviderRefs[i]);
this.handleProviderAdded(provider);
}
}
bc.registerService(PopupMessageHandler.class.getName(), this, null);
}
/**
@ -162,197 +129,6 @@ public void start(BundleContext bc)
*/
public void stop(BundleContext bc)
{
// start listening for newly register or removed protocol providers
bc.removeServiceListener(this);
ServiceReference[] protocolProviderRefs = null;
try
{
protocolProviderRefs = bc.getServiceReferences(
ProtocolProviderService.class.getName(),
null);
}
catch (InvalidSyntaxException ex)
{
// this shouldn't happen since we're providing no parameter string
// but let's log just in case.
logger.error(
"Error while retrieving service refs", ex);
return;
}
// in case we found any
if (protocolProviderRefs != null)
{
for (int i = 0; i < protocolProviderRefs.length; i++)
{
ProtocolProviderService provider = (ProtocolProviderService) bc
.getService(protocolProviderRefs[i]);
this.handleProviderRemoved(provider);
}
}
}
// ////////////////////////////////////////////////////////////////////////
// MessageListener implementation methods
/**
* Passes the newly received message to growl.
* @param evt MessageReceivedEvent the vent containing the new message.
*/
public void messageReceived(MessageReceivedEvent evt)
{
//byte[] contactImage = null;
//try
//{
// contactImage = evt.getSourceContact().getImage();
//}
//catch (Exception ex)
//{
// logger.error("Failed to load contact photo for Growl", ex);
//}
try
{
notifyGrowlOf("Message Received"
, sipIconPath
, evt.getSourceContact().getDisplayName()
, evt.getSourceMessage().getContent());
}
catch (Exception ex)
{
logger.error("Could not notify the received message to Growl", ex);
}
}
/**
* Notify growl that a message has been sent.
* @param evt the event containing the message that has just been sent.
*/
public void messageDelivered(MessageDeliveredEvent evt)
{
try
{
notifyGrowlOf("Message Sent"
, sipIconPath
, "Me"
, evt.getSourceMessage().getContent());
}
catch (Exception ex)
{
logger.error("Could not pass the sent message to Growl", ex);
}
}
/**
* Currently unused
* @param evt ignored
*/
public void messageDeliveryFailed(MessageDeliveryFailedEvent evt)
{
}
// //////////////////////////////////////////////////////////////////////////
/**
* When new protocol provider is registered we check
* does it supports BasicIM and if so add a listener to it
*
* @param serviceEvent ServiceEvent
*/
public void serviceChanged(ServiceEvent serviceEvent)
{
Object sService
= bundleContext.getService(serviceEvent.getServiceReference());
logger.trace("Received a service event for: "
+ sService.getClass().getName());
// we don't care if the source service is not a protocol provider
if (! (sService instanceof ProtocolProviderService))
{
return;
}
logger.debug("Service is a protocol provider.");
if (serviceEvent.getType() == ServiceEvent.REGISTERED)
{
logger.debug("Handling registration of a new Protocol Provider.");
this.handleProviderAdded((ProtocolProviderService)sService);
}
else if (serviceEvent.getType() == ServiceEvent.UNREGISTERING)
{
this.handleProviderRemoved( (ProtocolProviderService) sService);
}
}
/**
* Used to attach the Growl Notification Service to existing or
* just registered protocol provider. Checks if the provider has
* implementation of OperationSetBasicInstantMessaging
*
* @param provider ProtocolProviderService
*/
private void handleProviderAdded(ProtocolProviderService provider)
{
logger.debug("Adding protocol provider " + provider.getProtocolName());
// check whether the provider has a basic im operation set
OperationSetBasicInstantMessaging opSetIm =
(OperationSetBasicInstantMessaging) provider
.getOperationSet(OperationSetBasicInstantMessaging.class);
if (opSetIm != null)
{
opSetIm.addMessageListener(this);
try
{
notifyGrowlOf("Protocol events"
, sipIconPath
, "New Protocol Registered"
, provider.getProtocolName() + " registered");
}
catch (Exception ex)
{
logger.error("Could not notify the message to Growl", ex);
}
}
else
{
logger.trace("Service did not have a im op. set.");
}
}
/**
* Removes the specified provider from the list of currently known providers
* and ignores all the messages exchanged by it
*
* @param provider the ProtocolProviderService that has been unregistered.
*/
private void handleProviderRemoved(ProtocolProviderService provider)
{
OperationSetBasicInstantMessaging opSetIm =
(OperationSetBasicInstantMessaging) provider
.getOperationSet(OperationSetBasicInstantMessaging.class);
if (opSetIm != null)
{
opSetIm.removeMessageListener(this);
try
{
notifyGrowlOf("Protocol events"
, sipIconPath
, "Protocol deregistered"
, provider.getProtocolName()
+ " deregistered");
}
catch (Exception ex)
{
logger.error("Could not notify the message to Growl", ex);
}
}
}
/**
@ -408,4 +184,50 @@ public void setDefaultNotifications(String [] inDefNotes)
setDefaultNotifMethod.invoke(notifier, new Object[]{inDefNotes});
}
public void addPopupMessageListener(SystrayPopupMessageListener listener)
{
synchronized (popupMessageListeners)
{
if (!popupMessageListeners.contains(listener))
popupMessageListeners.add(listener);
}
}
public void removePopupMessageListener(SystrayPopupMessageListener listener)
{
synchronized (popupMessageListeners)
{
popupMessageListeners.remove(listener);
}
}
/**
* Implements <tt>PopupMessageHandler#showPopupMessage()</tt>
*
* @param popupMessage the message we will show
*/
public void showPopupMessage(PopupMessage popupMessage)
{
try
{
notifyGrowlOf("Message Received"
, sipIconPath
, popupMessage.getMessageTitle()
, popupMessage.getMessage());
}
catch (Exception ex)
{
logger.error("Could not notify the received message to Growl", ex);
}
}
/**
* Implements <tt>toString</tt> from <tt>PopupMessageHandler</tt>
* @return a description of this handler
*/
public String toString()
{
return GrowlNotificationActivator.getResources()
.getI18NString("impl.growlnotification.POPUP_MESSAGE_HANDLER");
}
}

@ -6,6 +6,7 @@ Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
net.java.sip.communicator.util,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.systray,
net.java.sip.communicator.service.systray.event,
com.growl

@ -12,6 +12,7 @@
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.service.notification.event.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.util.*;
/**
@ -394,13 +395,13 @@ public void fireNotification(String eventType, String title, String message)
NotificationActionHandler handler = action.getActionHandler();
if (!handler.isEnabled())
if ((handler == null) || !handler.isEnabled())
continue;
if (actionType.equals(NotificationService.ACTION_POPUP_MESSAGE))
{
((PopupMessageNotificationHandler) handler)
.popupMessage(title, message);
.popupMessage(new PopupMessage(title, message));
}
else if (actionType.equals(NotificationService.ACTION_LOG_MESSAGE))
{

@ -46,19 +46,17 @@ public String getDefaultMessage()
/**
* Shows a popup message through the <tt>SystrayService</tt>.
*
* @param title the title of the popup
*
* @param message the message to show in the popup
*/
public void popupMessage(String title, String message)
public void popupMessage(PopupMessage message)
{
SystrayService systray = NotificationActivator.getSystray();
if(systray == null)
return;
systray.showPopupMessage(title, message,
SystrayService.NONE_MESSAGE_TYPE);
systray.showPopupMessage(message);
}
/**

@ -0,0 +1,295 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.swingnotification;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import javax.swing.*;
import javax.swing.Timer;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.service.systray.event.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
/**
* An implementation of <tt>PopupMessageHandler</tt> using swing.
* @author Symphorien Wanko
*/
public class PopupMessageHandlerSwingImpl implements PopupMessageHandler
{
/** logger for the <tt>PopupMessageHandlerSwingImpl</tt> class */
private final Logger logger =
Logger.getLogger(PopupMessageHandlerSwingImpl.class);
/** The list of all added popup listeners */
private final List<SystrayPopupMessageListener> popupMessageListeners =
new Vector<SystrayPopupMessageListener>();
/** An icon representing the contact from which the notification comes */
private ImageIcon defaultIcon =
SwingNotificationActivator.getResources().getImage(
"service.gui.DEFAULT_USER_PHOTO");;
/**
* Adds a listerner to receive popup events
* @param listener the listener to add
*/
public void addPopupMessageListener(SystrayPopupMessageListener listener)
{
synchronized (popupMessageListeners)
{
if (!popupMessageListeners.contains(listener))
popupMessageListeners.add(listener);
}
}
/**
* Removes a listerner previously added with <tt>addPopupMessageListener</tt>
* @param listener the listener to remove
*/
public void removePopupMessageListener(SystrayPopupMessageListener listener)
{
synchronized (popupMessageListeners)
{
popupMessageListeners.remove(listener);
}
}
/**
* Implements <tt>PopupMessageHandler#showPopupMessage()</tt>
*
* @param popupMessage the message we will show
*/
public void showPopupMessage(PopupMessage popupMessage)
{
final GraphicsConfiguration graphicsConf =
GraphicsEnvironment.getLocalGraphicsEnvironment().
getDefaultScreenDevice().
getDefaultConfiguration();
final JWindow notificationWindow = new JWindow(graphicsConf);
notificationWindow.setPreferredSize(new Dimension(225, 125));
final Timer popupTimer = new Timer(10000, new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (notificationWindow.isVisible())
new Thread(new PopupDiscarder(notificationWindow)).start();
}
});
popupTimer.setRepeats(false);
notificationWindow.addMouseListener(new MouseAdapter()
{
@Override
public void mouseEntered(MouseEvent e)
{
popupTimer.stop();
}
@Override
public void mouseExited(MouseEvent e)
{
popupTimer.start();
}
@Override
public void mouseClicked(MouseEvent e)
{
firePopupMessageClicked(new SystrayPopupMessageEvent(e));
notificationWindow.dispose();
}
});
if (popupMessage.getComponent() != null)
notificationWindow.add(popupMessage.getComponent());
else
notificationWindow.add(createPopup(
popupMessage.getMessageTitle(),
popupMessage.getMessage(),
popupMessage.getIcon()));
notificationWindow.setAlwaysOnTop(true);
notificationWindow.pack();
new Thread(new PopupLauncher(notificationWindow, graphicsConf)).start();
popupTimer.start();
}
/**
* builds the popup component with given informations.
*
* @param title message title
* @param message message content
* @param icon message icon
* @return
*/
private JComponent createPopup(String title, String message,
ImageIcon icon)
{
String msg;
if (message.length() > 70)
msg = "<html><b>" + message.substring(0, 77) + "...";
else
msg = "<html><b>" + message;
JLabel msgContent = new JLabel(msg);
if (title.length() > 40)
title = title.substring(0, 28) + "...";
JLabel msgFrom = new JLabel(title);
msgFrom.setForeground(Color.DARK_GRAY);
JLabel msgIcon = (icon == null) ?
new JLabel(defaultIcon) :
new JLabel(icon);
msgIcon.setOpaque(false);
msgIcon.setPreferredSize(new Dimension(45, 45));
JPanel notificationContent = new JPanel(new BorderLayout(5, 1));
notificationContent.setBorder(
BorderFactory.createEmptyBorder(10, 10, 10, 10));
notificationContent.setOpaque(false);
notificationContent.add(msgFrom, BorderLayout.NORTH);
notificationContent.add(msgContent, BorderLayout.CENTER);
notificationContent.add(msgIcon, BorderLayout.WEST);
return new PopupNotificationPanel(notificationContent);
}
/**
* Notifies all interested listeners that a <tt>SystrayPopupMessageEvent</tt>
* occured.
*
* @param SystrayPopupMessageEvent the evt to send to listener.
*/
private void firePopupMessageClicked(SystrayPopupMessageEvent evt)
{
logger.trace("Will dispatch the following popup event: " + evt);
List<SystrayPopupMessageListener> listeners;
synchronized (popupMessageListeners)
{
listeners =
new ArrayList<SystrayPopupMessageListener>(
popupMessageListeners);
}
for (SystrayPopupMessageListener listener : listeners)
listener.popupMessageClicked(evt);
}
/**
* Implements <tt>toString</tt> from <tt>PopupMessageHandler</tt>
* @return a description of this handler
*/
public String toString()
{
return SwingNotificationActivator.getResources()
.getI18NString("impl.swingnotification.POPUP_MESSAGE_HANDLER");
}
/**
* provide animation to hide a popup. The animation could be described
* as an "inverse" of the one made by <tt>PopupLauncher</tt>.
*/
class PopupDiscarder implements Runnable
{
private JWindow notificationWindow;
PopupDiscarder(JWindow notificationWindow)
{
this.notificationWindow = notificationWindow;
}
public void run()
{
int height = notificationWindow.getY();
int x = notificationWindow.getX();
do
{
notificationWindow.setLocation(
x,
notificationWindow.getY() + 2);
try
{
Thread.sleep(10);
height -= 2;
} catch (InterruptedException ex)
{
logger.warn("exception while discarding" +
" popup notification window :", ex);
}
} while (height > 0);
notificationWindow.dispose();
}
}
/**
* provide animation to show a popup. The popup comes from the bottom of
* screen and will stay in the bottom right corner.
*/
class PopupLauncher implements Runnable
{
private final JWindow notificationWindow;
private final int x;
private final int y;
PopupLauncher(JWindow notificationWindow,
GraphicsConfiguration graphicsConf)
{
this.notificationWindow = notificationWindow;
final Rectangle rec = graphicsConf.getBounds();
final Insets ins =
Toolkit.getDefaultToolkit().getScreenInsets(graphicsConf);
x = rec.width + rec.x -
ins.right - notificationWindow.getWidth() - 1;
y = rec.height + rec.y -
ins.bottom - notificationWindow.getHeight() - 1;
notificationWindow.setLocation(x, rec.height);
notificationWindow.setVisible(true);
}
public void run()
{
int height = y - notificationWindow.getY();
do
{
notificationWindow.setLocation(
x,
notificationWindow.getY() - 2);
try
{
Thread.sleep(10);
height += 2;
} catch (InterruptedException ex)
{
logger.warn("exception while showing" +
" popup notification window :", ex);
}
} while (height < 0);
}
}
}

@ -0,0 +1,113 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.swingnotification;
import org.osgi.framework.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.resources.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.util.*;
/**
* Activator for the swing notification service.
* @author Symphorien Wanko
*/
public class SwingNotificationActivator implements BundleActivator
{
/**
* The bundle context in which we started
*/
public static BundleContext bundleContext;
/**
* A reference to the configuration service.
*/
private static ConfigurationService configService;
/**
* Logger for this class.
*/
private static final Logger logger =
Logger.getLogger(SwingNotificationActivator.class);
/**
* A reference to the resource management service.
*/
private static ResourceManagementService resourcesService;
/**
* start the swing notification service and set the swing popup handler as
* the default if there is no default popup handler.
* @param bc
* @throws java.lang.Exception
*/
public void start(BundleContext bc) throws Exception
{
logger.info("Swing Notification ...[ STARTING ]");
bundleContext = bc;
PopupMessageHandler handler = null;
handler = new PopupMessageHandlerSwingImpl();
getConfigurationService();
String defaultHandler =
(String) configService.getProperty("systray.POPUP_HANDLER");
if (defaultHandler == null)
{
configService.setProperty(
"systray.POPUP_HANDLER", handler.getClass().getName());
}
bc.registerService(
PopupMessageHandler.class.getName()
, handler
, null);
logger.info("Swing Notification ...[REGISTERED]");
}
public void stop(BundleContext arg0) throws Exception
{
}
/**
* Returns the <tt>ConfigurationService</tt> obtained from the bundle
* context.
* @return the <tt>ConfigurationService</tt> obtained from the bundle
* context
*/
public static ConfigurationService getConfigurationService()
{
if(configService == null) {
ServiceReference configReference = bundleContext
.getServiceReference(ConfigurationService.class.getName());
configService = (ConfigurationService) bundleContext
.getService(configReference);
}
return configService;
}
/**
* Returns the <tt>ResourceManagementService</tt> obtained from the bundle
* context.
* @return the <tt>ResourceManagementService</tt> obtained from the bundle
* context
*/
public static ResourceManagementService getResources()
{
if (resourcesService == null)
resourcesService =
ResourceManagementServiceUtils.getService(bundleContext);
return resourcesService;
}
}

@ -0,0 +1,14 @@
Bundle-Activator: net.java.sip.communicator.impl.swingnotification.SwingNotificationActivator
Bundle-Name: Swing Notification Service Provider
Bundle-Description: A bundle that implements swing notification.
Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: org.osgi.framework,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.systray,
net.java.sip.communicator.service.systray.event,
net.java.sip.communicator.util,
net.java.sip.communicator.util.swing,
javax.swing

@ -0,0 +1,131 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.systray;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import net.java.sip.communicator.impl.systray.jdic.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.service.systray.event.*;
import net.java.sip.communicator.util.*;
/**
* An implementation of the <tt>PopupMsystrayessageHandler</tt> using the tray icon.
*/
public class PopupMessageHandlerTrayIconImpl implements PopupMessageHandler
{
/**
* The logger for this class.
*/
private static Logger logger =
Logger.getLogger(PopupMessageHandlerTrayIconImpl.class);
/** The list of all added systray popup listeners */
private final List<SystrayPopupMessageListener> PopupMessageListener =
new Vector<SystrayPopupMessageListener>();
/** the tray icon we will use to popup messages */
private TrayIcon trayIcon;
/**
* Creates a new <tt>PopupMessageHandlerTrayIconImpl</tt> which will uses
* the provided <tt>TrayIcon</tt> to show message.
* @param icon the icon we will use to show popup message.
*/
public PopupMessageHandlerTrayIconImpl(TrayIcon icon)
{
trayIcon = icon;
icon.addBalloonActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
firePopupMessageClicked(new SystrayPopupMessageEvent(e));
}
});
}
/**
* Implementation of <tt>PopupMessageHandler.addPopupMessageListener</tt>
* @param listener the listener to add
*/
public void addPopupMessageListener(SystrayPopupMessageListener listener)
{
synchronized (PopupMessageListener)
{
if (!PopupMessageListener.contains(listener))
PopupMessageListener.add(listener);
}
}
/**
* Implementation of <tt>PopupMessageHandler.removePopupMessageListener</tt>
* @param listener the listener to remove
*/
public void removePopupMessageListener(SystrayPopupMessageListener listener)
{
synchronized (PopupMessageListener)
{
PopupMessageListener.remove(listener);
}
}
/**
* Implements <tt>PopupMessageHandler#showPopupMessage()</tt>
*
* @param popupMessage the message we will show
*/
public void showPopupMessage(PopupMessage popupMessage)
{
// remove eventual html code before showing the popup message
String messageContent = popupMessage.getMessage()
.replaceAll("</?\\w++[^>]*+>", "");
String messageTitle = popupMessage.getMessageTitle()
.replaceAll("</?\\w++[^>]*+>", "");
if(messageContent.length() > 40)
messageContent = messageContent.substring(0, 40).concat("...");
trayIcon.displayMessage(
messageTitle,
messageContent,
TrayIcon.NONE_MESSAGE_TYPE);
}
/**
* Notifies all interested listeners that a <tt>SystrayPopupMessageEvent</tt>
* has occured.
*
* @param SystrayPopupMessageEvent the evt to send to listener.
*/
private void firePopupMessageClicked(SystrayPopupMessageEvent evt)
{
logger.trace("Will dispatch the following systray popup event: " + evt);
List<SystrayPopupMessageListener> listeners;
synchronized (PopupMessageListener)
{
listeners =
new ArrayList<SystrayPopupMessageListener>(
PopupMessageListener);
}
for (SystrayPopupMessageListener listener : listeners)
listener.popupMessageClicked(evt);
}
/**
* Implements <tt>toString</tt> from <tt>PopupMessageHandler</tt>
* @return a description of this handler
*/
public String toString()
{
return SystrayActivator.getResources()
.getI18NString("impl.systray.POPUP_MESSAGE_HANDLER");
}
}

@ -116,8 +116,8 @@ public static UIService getUIService()
ServiceReference serviceRef = bundleContext
.getServiceReference(UIService.class.getName());
uiService = (UIService) bundleContext
.getService(serviceRef);
if (serviceRef != null)
uiService = (UIService) bundleContext.getService(serviceRef);
}
return uiService;

@ -6,11 +6,12 @@
*/
package net.java.sip.communicator.impl.systray.jdic;
import org.osgi.framework.*;
import java.awt.Toolkit;
import java.awt.event.*;
import java.net.*;
import java.util.*;
import java.util.Timer;
import javax.swing.*;
import javax.swing.event.*;
@ -31,6 +32,7 @@
* @author Nicolas Chamouard
* @author Yana Stamcheva
* @author Lubomir Marinov
* @author Symphorien Wanko
*/
public class SystrayServiceJdicImpl
implements SystrayService
@ -51,38 +53,33 @@ public class SystrayServiceJdicImpl
private Object menu;
/**
* The list of all added popup message listeners.
* The popup handler currently used to show popup messages
*/
private final List<SystrayPopupMessageListener> popupMessageListeners =
new Vector<SystrayPopupMessageListener>();
private PopupMessageHandler activePopupHandler;
/**
* List of all messages waiting to be shown.
* A set of usable <tt>PopupMessageHandler</tt>
*/
private final List<SystrayMessage> messageQueue =
new ArrayList<SystrayMessage>();
private Timer popupTimer = new Timer();
private final Hashtable<String, PopupMessageHandler> popupHandlerSet
= new Hashtable<String, PopupMessageHandler>();
/**
* The delay between the message pop ups.
* Stores the system time, when the main window was restored the last time
*/
private int messageDelay = 1000;
private int maxMessageNumber = 3;
private SystrayMessage aggregatedMessage;
private long setVisibleTime = 0;
/**
* Stores the system time, when the main window was restored the last time
* A reference of the <tt>ConfigurationService</tt> obtained from the
* <tt>SystrayServiceActivator</tt>
*/
private long setVisibleTime = 0;
private final ConfigurationService configService
= SystrayActivator.getConfigurationService();
/**
* The logger for this class.
*/
private static Logger logger =
Logger.getLogger(SystrayServiceJdicImpl.class.getName());
private static final Logger logger =
Logger.getLogger(SystrayServiceJdicImpl.class);
/**
* The various icons used on the systray
@ -105,6 +102,12 @@ public class SystrayServiceJdicImpl
private boolean initialized = false;
/**
* the listener we will use for popup message event (clicks on the popup)
*/
private final SystrayPopupMessageListener popupMessageListener =
new SystrayPopupMessageListenerImpl();
/**
* Creates an instance of <tt>Systray</tt>.
*/
@ -123,7 +126,9 @@ public SystrayServiceJdicImpl()
{
this.initSystray();
SystrayActivator.getUIService().setExitOnMainWindowClose(false);
UIService ui = SystrayActivator.getUIService();
if (ui != null)
ui.setExitOnMainWindowClose(false);
}
}
@ -132,7 +137,6 @@ public SystrayServiceJdicImpl()
*/
private void initSystray()
{
popupTimer.scheduleAtFixedRate(new ShowPopupTask(), 0, messageDelay);
// Get the system's double click speed
Object o = Toolkit.getDefaultToolkit().getDesktopProperty(
@ -215,10 +219,8 @@ public void actionPerformed(ActionEvent e)
{
long currentTime = System.currentTimeMillis();
UIService uiService = SystrayActivator.getUIService();
boolean isVisible = !uiService.isVisible();
boolean isVisible;
isVisible = ! uiService.isVisible();
if (isVisible) {
setVisibleTime = currentTime;
}
@ -232,9 +234,6 @@ else if (currentTime < (setVisibleTime + doubleClickSpeed))
uiService.setVisible(isVisible);
ConfigurationService configService
= SystrayActivator.getConfigurationService();
configService.setProperty(
"net.java.sip.communicator.impl.systray.showApplication",
Boolean.toString(isVisible));
@ -270,7 +269,7 @@ public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
}
else
{
trayIcon.setIcon(logoIcon);
getTrayIcon().setIcon(logoIcon);
currentIcon = logoIcon;
}
}
@ -282,25 +281,67 @@ public void popupMenuCanceled(PopupMenuEvent e)
});
}
//Notify all interested listener that user has clicked on the systray
//popup message.
trayIcon.addBalloonActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
UIService uiService = SystrayActivator.getUIService();
firePopupMessageEvent(e.getSource());
PopupMessageHandler pph = new PopupMessageHandlerTrayIconImpl(trayIcon);
popupHandlerSet.put(pph.getClass().getName(), pph);
SystrayActivator.bundleContext.registerService(
PopupMessageHandler.class.getName(),
pph, null);
ExportedWindow chatWindow
= uiService.getExportedWindow(ExportedWindow.CHAT_WINDOW);
try
{
SystrayActivator.bundleContext.addServiceListener(
new ServiceListenerImpl(),
"(objectclass=" + PopupMessageHandler.class.getName() + ")");
} catch (Exception e)
{
logger.warn(e);
}
if(chatWindow != null && chatWindow.isVisible())
// now we look if some handler has been registered before we start
// to listen
ServiceReference[] handlerRefs = null;
try
{
handlerRefs = SystrayActivator.bundleContext.getServiceReferences(
PopupMessageHandler.class.getName(),
null);
}
catch (InvalidSyntaxException ex)
{
logger.error("Error while retrieving service refs", ex);
}
if (handlerRefs != null)
{
for (int i = 0; i < handlerRefs.length; i++)
{
PopupMessageHandler handler =
(PopupMessageHandler) SystrayActivator.
bundleContext.getService(handlerRefs[i]);
String handlerName = handler.getClass().getName();
if (!popupHandlerSet.containsKey(handlerName))
{
chatWindow.bringToFront();
popupHandlerSet
.put(handlerName, handler);
logger.info("added the following popup handler : " +
handler);
String configuredHandler =(String) configService.
getProperty("systray.POPUP_HANDLER");
if (configuredHandler.equals(handler.getClass().getName()))
setActivePopupMessageHandler(handler);
}
}
});
}
// either we have an incorrect config value or the default popup handler
// is not yet available. we use the available popup handler and will
// auto switch to the configured one when it will be available.
// we will be aware of it since we listen for new registerred
// service in the bundle context.
if (activePopupHandler == null)
{
setActivePopupMessageHandler(pph);
}
systray.addTrayIcon(trayIcon);
@ -320,9 +361,6 @@ public void saveStatusInformation(
ProtocolProviderService protocolProvider,
String statusName)
{
ConfigurationService configService
= SystrayActivator.getConfigurationService();
if(configService != null)
{
String prefix = "net.java.sip.communicator.impl.gui.accounts";
@ -366,37 +404,16 @@ public void saveStatusInformation(
}
/**
* Implements the <tt>SystratService.showPopupMessage</tt> method. Shows
* a pop up message, above the Systray icon, which has the given title,
* message content and message type.
* Implements <tt>SystraService#showPopupMessage()</tt>
*
* @param title the title of the message
* @param messageContent the content text
* @param messageType the type of the message
* @param popupMessage the message we will show
*/
public void showPopupMessage( String title,
String messageContent,
int messageType)
public void showPopupMessage(PopupMessage popupMessage)
{
if(!checkInitialized())
return;
int trayMsgType = TrayIcon.NONE_MESSAGE_TYPE;
if (messageType == SystrayService.ERROR_MESSAGE_TYPE)
trayMsgType = TrayIcon.ERROR_MESSAGE_TYPE;
else if (messageType == SystrayService.INFORMATION_MESSAGE_TYPE)
trayMsgType = TrayIcon.INFO_MESSAGE_TYPE;
else if (messageType == SystrayService.WARNING_MESSAGE_TYPE)
trayMsgType = TrayIcon.WARNING_MESSAGE_TYPE;
// remove eventual html code before showing the popup message
messageContent = messageContent.replaceAll("</?\\w++[^>]*+>", "");
if(messageContent.length() > 40)
messageContent = messageContent.substring(0, 40).concat("...");
messageQueue.add(new SystrayMessage(title, messageContent, trayMsgType));
// since popup handler could be loaded and unloader on the fly,
// we have to check if we currently have a valid one.
if (activePopupHandler != null)
activePopupHandler.showPopupMessage(popupMessage);
}
/**
@ -406,10 +423,8 @@ else if (messageType == SystrayService.WARNING_MESSAGE_TYPE)
*/
public void addPopupMessageListener(SystrayPopupMessageListener listener)
{
synchronized (popupMessageListeners)
{
this.popupMessageListeners.add(listener);
}
if (activePopupHandler != null)
activePopupHandler.addPopupMessageListener(listener);
}
/**
@ -419,37 +434,8 @@ public void addPopupMessageListener(SystrayPopupMessageListener listener)
*/
public void removePopupMessageListener(SystrayPopupMessageListener listener)
{
synchronized (popupMessageListeners)
{
this.popupMessageListeners.remove(listener);
}
}
/**
* Notifies all interested listeners that a <tt>SystrayPopupMessageEvent</tt>
* has occured.
*
* @param sourceObject the source of this event
*/
private void firePopupMessageEvent(Object sourceObject)
{
SystrayPopupMessageEvent evt
= new SystrayPopupMessageEvent(sourceObject);
logger.trace("Will dispatch the following systray msg event: " + evt);
List<SystrayPopupMessageListener> listeners;
synchronized (popupMessageListeners)
{
listeners =
new ArrayList<SystrayPopupMessageListener>(
popupMessageListeners);
}
for (SystrayPopupMessageListener listener : listeners)
{
listener.popupMessageClicked(evt);
}
if (activePopupHandler != null)
activePopupHandler.removePopupMessageListener(listener);
}
/**
@ -562,161 +548,112 @@ private boolean checkInitialized()
}
/**
* Shows the oldest message in the message queue and then removes it from
* the queue.
* @return the trayIcon
*/
private class ShowPopupTask extends TimerTask
public TrayIcon getTrayIcon()
{
public void run()
{
if(messageQueue.isEmpty())
return;
int messageNumber = messageQueue.size();
SystrayMessage msg = messageQueue.get(0);
if(messageNumber > maxMessageNumber)
{
messageQueue.clear();
if(aggregatedMessage != null)
{
aggregatedMessage
.addAggregatedMessageNumber(messageNumber);
}
else
{
String messageContent = msg.getMessageContent();
if(!messageContent.endsWith("..."))
messageContent.concat("...");
aggregatedMessage = new SystrayMessage(
"Messages start by: " + messageContent,
messageNumber);
}
messageQueue.add(aggregatedMessage);
}
else
{
trayIcon.displayMessage(msg.getTitle(),
msg.getMessageContent(),
msg.getMessageType());
messageQueue.remove(0);
if(msg.equals(aggregatedMessage))
aggregatedMessage = null;
}
}
return trayIcon;
}
/**
* Represents a systray message.
* Set the handler which will be used for popup message
* @param newHandler the handler to set. providing a null handler is like
* disabling popup.
* @return the previously used popup handler
*/
private class SystrayMessage
public PopupMessageHandler setActivePopupMessageHandler(
PopupMessageHandler newHandler)
{
private String title;
private String messageContent;
private int messageType;
private int aggregatedMessageNumber;
/**
* Creates an instance of <tt>SystrayMessage</tt> by specifying the
* message <tt>title</tt>, the content of the message and the type of
* the message.
*
* @param title the title of the message
* @param messageContent the content of the message
* @param messageType the type of the message
*/
public SystrayMessage( String title,
String messageContent,
int messageType)
{
this.title = title;
this.messageContent = messageContent;
this.messageType = messageType;
}
/**
* Creates an instance of <tt>SystrayMessage</tt> by specifying the
* message <tt>title</tt>, the content of the message, the type of
* the message and the number of messages that this message has
* aggregated.
*
* @param messageContent the content of the message
* @param aggregatedMessageNumber the number of messages that this
* message has aggregated
*/
public SystrayMessage( String messageContent,
int aggregatedMessageNumber)
{
this.aggregatedMessageNumber = aggregatedMessageNumber;
PopupMessageHandler oldHandler = activePopupHandler;
if (oldHandler != null)
oldHandler.removePopupMessageListener(popupMessageListener);
this.title = "You have received "
+ aggregatedMessageNumber
+ " new messages.";
if (newHandler != null)
newHandler.addPopupMessageListener(popupMessageListener);
activePopupHandler = newHandler;
this.messageContent = messageContent;
this.messageType = TrayIcon.INFO_MESSAGE_TYPE;
}
/**
* Returns the title of the message.
*
* @return the title of the message
*/
public String getTitle()
{
return title;
}
/**
* Returns the message content.
*
* @return the message content
*/
public String getMessageContent()
{
return messageContent;
}
return oldHandler;
}
/**
* Returns the message type.
*
* @return the message type
*/
public int getMessageType()
{
return messageType;
}
/**
* Get the handler currently used by this implementation to popup message
* @return the current handler
*/
public PopupMessageHandler getActivePopupMessageHandler()
{
return activePopupHandler;
}
/**
* Returns the number of aggregated messages this message represents.
*
* @return the number of aggregated messages this message represents.
*/
public int getAggregatedMessageNumber()
/** our listener for popup message click */
private static class SystrayPopupMessageListenerImpl
implements SystrayPopupMessageListener
{
/** implements <tt>SystrayPopupMessageListener.popupMessageClicked()</tt> */
public void popupMessageClicked(SystrayPopupMessageEvent evt)
{
return aggregatedMessageNumber;
UIService uiService = SystrayActivator.getUIService();
ExportedWindow chatWindow
= uiService.getExportedWindow(ExportedWindow.CHAT_WINDOW);
if (chatWindow != null && chatWindow.isVisible())
{
chatWindow.bringToFront();
}
}
}
/**
* Adds the given number of messages to the number of aggregated
* messages contained in this message.
*
* @param messageNumber the number of messages to add to the number of
* aggregated messages contained in this message
*/
public void addAggregatedMessageNumber(int messageNumber)
/** an implementation of <tt>ServiceListener</tt> we will use */
private class ServiceListenerImpl implements ServiceListener
{
/** implements <tt>ServiceListener.serviceChanged</tt> */
public void serviceChanged(ServiceEvent serviceEvent)
{
this.aggregatedMessageNumber += messageNumber;
this.title = "You have received " + aggregatedMessageNumber
+ " new messages.";
try
{
PopupMessageHandler handler =
(PopupMessageHandler) SystrayActivator.bundleContext
.getService(serviceEvent.getServiceReference());
if (serviceEvent.getType() == ServiceEvent.REGISTERED)
{
if (!popupHandlerSet.containsKey(handler.getClass().getName()))
{
logger.info(
"adding the following popup handler : " + handler);
popupHandlerSet.put(
handler.getClass().getName(), handler);
}
else
{
logger.warn("the following popup handler has not " +
"been added since it is already known : " + handler);
}
String configuredHandler = (String) configService.
getProperty("systray.POPUP_HANDLER");
if (configuredHandler.compareTo(
handler.getClass().getName()) == 0)
{
setActivePopupMessageHandler(handler);
}
}
else if (serviceEvent.getType() == ServiceEvent.UNREGISTERING)
{
popupHandlerSet.remove(handler.getClass().getName());
if (activePopupHandler == handler)
{
activePopupHandler.removePopupMessageListener(
popupMessageListener);
activePopupHandler = null;
if (!popupHandlerSet.isEmpty())
{
setActivePopupMessageHandler(popupHandlerSet.get(
popupHandlerSet.keys().nextElement()));
}
}
}
}
catch (IllegalStateException e)
{
logger.debug(e);
}
}
}
}

@ -34,7 +34,7 @@ public class ConfigurationManager
private static int windowTransparency;
private static boolean isTransparentWindowEnabled;
private static ConfigurationService configService
= GeneralConfigPluginActivator.getConfigurationService();
@ -283,6 +283,26 @@ public static String getSendMessageCommand()
return sendMessageCommand;
}
/**
* Gets the configuration handler which is currently in use.
*
* @return the configuration handler which is currently in use
*/
public static String getPopupHandlerConfig()
{
return (String) configService.getProperty("systray.POPUP_HANDLER");
}
/**
* Saves the popup handler choice made by the user.
*
* @param handler the handler which will be used
*/
public static void setPopupHandlerConfig(String handler)
{
configService.setProperty("systray.POPUP_HANDLER", handler);
}
/**
* Returns <code>true</code> if transparent windows are enabled,
* <code>false</code> otherwise.

@ -8,6 +8,7 @@
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.util.*;
import org.osgi.framework.*;
@ -18,6 +19,8 @@ public class GeneralConfigPluginActivator implements BundleActivator
private static ConfigurationService configService;
private static SystrayService systrayService;
protected static BundleContext bundleContext;
private static UIService uiService;
@ -66,7 +69,26 @@ public static ConfigurationService getConfigurationService() {
return configService;
}
/**
* Returns the <tt>SystrayService</tt> obtained from the bundle
* context.
* @return the <tt>SystrayService</tt> obtained from the bundle
* context
*/
public static SystrayService getSystrayService()
{
if(systrayService == null) {
ServiceReference configReference = bundleContext
.getServiceReference(SystrayService.class.getName());
systrayService = (SystrayService) bundleContext
.getService(configReference);
}
return systrayService;
}
/**
* Returns the <tt>UIService</tt>.
*

@ -11,13 +11,16 @@
import java.io.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.swing.*;
import com.izforge.izpack.util.os.*;
import org.osgi.framework.*;
/**
* @author Yana Stamcheva
@ -41,6 +44,9 @@ public class GeneralConfigurationPanel
private JCheckBox enableTypingNotifiCheckBox;
private JCheckBox showHistoryCheckBox;
private JPanel logHistoryPanel;
private JPanel notifConfigPanel;
private JLabel notifConfigLabel;
private JComboBox notifConfigComboBox;
public GeneralConfigurationPanel()
{
@ -218,6 +224,75 @@ public void itemStateChanged(ItemEvent arg0)
Resources.getString("plugin.generalconfig.BRING_WINDOW_TO_FRONT"));
bringToFrontCheckBox.addActionListener(this);
}
{
ServiceReference[] handlerRefs = null;
BundleContext bc = GeneralConfigPluginActivator.bundleContext;
try
{
handlerRefs = bc.getServiceReferences(
PopupMessageHandler.class.getName(),
null);
}
catch (InvalidSyntaxException ex)
{
logger.warn("Error while retrieving service refs", ex);
}
// user has choice only if there is more than one handler
if ((handlerRefs != null) && (handlerRefs.length > 1))
{
notifConfigPanel = new JPanel();
notifConfigPanel.setOpaque(false);
notifConfigPanel.setLayout(new BorderLayout(10, 10));
notifConfigPanel.setAlignmentX(0.0f);
notifConfigPanel.setPreferredSize(
new java.awt.Dimension(380, 22));
mainPanel.add(notifConfigPanel);
mainPanel.add(Box.createVerticalStrut(10));
{
notifConfigLabel = new JLabel(
Resources.getString(
"plugin.notificationconfig.POPUP_NOTIF_HANDLER"));
notifConfigPanel.add(
notifConfigLabel, BorderLayout.WEST);
}
{
notifConfigComboBox = new JComboBox();
String currentConfig =
ConfigurationManager.getPopupHandlerConfig();
for (int i = 0; i < handlerRefs.length; i++)
{
PopupMessageHandler handler =
(PopupMessageHandler) bc.getService(
handlerRefs[i]);
notifConfigComboBox.addItem(handler);
String handlerName = handler.getClass().getName();
if (handlerName.equals(currentConfig))
notifConfigComboBox.setSelectedItem(handler);
}
notifConfigComboBox.addItemListener(new ItemListener()
{
public void itemStateChanged(ItemEvent evt)
{
PopupMessageHandler handler =
(PopupMessageHandler)
notifConfigComboBox.getSelectedItem();
ConfigurationManager.setPopupHandlerConfig(
handler.getClass().getName());
GeneralConfigPluginActivator.getSystrayService()
.setActivePopupMessageHandler(handler);
}
});
notifConfigPanel.add(
notifConfigComboBox, BorderLayout.CENTER);
}
}
}
// {
// JPanel transparencyPanel = new JPanel();
// BorderLayout transparencyPanelLayout

@ -11,6 +11,7 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.gui,
net.java.sip.communicator.service.gui.event,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.systray,
net.java.sip.communicator.util,
net.java.sip.communicator.util.swing,
javax.swing,

@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.service.notification;
import net.java.sip.communicator.service.systray.*;
/**
* The <tt>PopupMessageNotificationHandler</tt> interface is meant to be
* implemented by the notification bundle in order to provide handling of
@ -26,11 +28,9 @@ public interface PopupMessageNotificationHandler
public String getDefaultMessage();
/**
* Pops up a message with the given <tt>message</tt> content and the given
* <tt>title</tt>.
* Shows the given <tt>PopupMessage</tt>
*
* @param title the title of the popup
* @param message the message to show in the popup
*/
public void popupMessage(String title, String message);
public void popupMessage(PopupMessage message);
}

@ -0,0 +1,192 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.systray;
import javax.swing.*;
import net.java.sip.communicator.service.protocol.*;
/**
* The <tt>PopupMessage</tt> class encloses informations to show in a popup.
* While a message title and a message body are mandatory informations,
* a popup message could provides more stuffs like a component or an image which
* may be used by a <tt>PopupMessageHandler</tt> capable to handle it.
*
* @author Symphorien Wanko
*/
public class PopupMessage
{
/** message to show in the popup */
private String message;
/** title of the message */
private String messageTitle;
/** An icon representing the contact from which the notification comes */
private ImageIcon imageIcon;
/** A ready to show <tt>JComponet</tt> for this <tt>PopupMessage</tt> */
private JComponent component;
/** type of the message */
private int messageType;
/** the contact which is the cause of this popup message */
private Contact contact;
/**
* Creates a <tt>PopupMessage</tt> with the given title and message inside
*
* @param messageTitle title of the message
* @param message message to show in the systray
*/
public PopupMessage(String messageTitle, String message)
{
this.messageTitle = messageTitle;
this.message = message;
}
/**
* Creates a system tray message with the given title and message content. The
* message type will affect the icon used to present the message.
*
* @param title the title, which will be shown
* @param content the content of the message to display
* @param messageType the message type; one of XXX_MESSAGE_TYPE constants
* declared in <tt>SystrayService
*/
public PopupMessage(String title, String content, int messageType)
{
this(title, content);
this.messageType = messageType;
}
/**
* Creates a new <tt>PopupMessage</tt> with the given title, message and
* icon.
*
* @param messageTitle title of the message
* @param message message to show in the systray
* @param imageIcon an incon to show in the popup message.
*/
public PopupMessage(String title, String message, ImageIcon imageIcon)
{
this(title, message);
this.imageIcon = imageIcon;
}
/**
* Creates a new <tt>PopupMessage</tt> with the given
* <tt>JComponent</tt> as its content. This constructor also takes a title
* and a message as replacements in cases the component is not usable.
*
* @param component the component to put in the <tt>PopupMessage</tt>
* @param title of the message
* @param message message to use in place of the component
*/
public PopupMessage(JComponent component, String title, String message)
{
this(title, message);
this.component = component;
}
/**
* @return the message
*/
public String getMessage()
{
return message;
}
/**
* @param message the message to set
*/
public void setMessage(String message)
{
this.message = message;
}
/**
* @return the messageTitle
*/
public String getMessageTitle()
{
return messageTitle;
}
/**
* @param messageTitle the messageTitle to set
*/
public void setMessageTitle(String messageTitle)
{
this.messageTitle = messageTitle;
}
/**
* @return the component
*/
public JComponent getComponent()
{
return component;
}
/**
* @param component the component to set
*/
public void setComponent(JComponent component)
{
this.component = component;
}
/**
* @return the imageIcon
*/
public ImageIcon getIcon()
{
return imageIcon;
}
/**
* @param imageIcon the imageIcon to set
*/
public void setIcon(ImageIcon imageIcon)
{
this.imageIcon = imageIcon;
}
/**
* @return the messageType
*/
public int getMessageType()
{
return messageType;
}
/**
* @param messageType the messageType to set
*/
public void setMessageType(int messageType)
{
this.messageType = messageType;
}
/**
* @return the contact
*/
public Contact getContact()
{
return contact;
}
/**
* @param contact the contact to set
*/
public void setContact(Contact contact)
{
this.contact = contact;
}
}

@ -0,0 +1,55 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.systray;
import net.java.sip.communicator.service.systray.event.*;
/**
* The <tt>PopupMessageHandler</tt> role is to give differents methods to
* display <tt>PopupMessage</tt> and listen for events (user click)
* coming from that popup.
*
* @author Symphorien Wanko
*/
public interface PopupMessageHandler
{
/**
* Register a listener to be informed of systray popup events.
*
* @param listener the listened which will be informed of systray popup
* events
*/
public void addPopupMessageListener(SystrayPopupMessageListener listener);
/**
* Removes a listener previously added with <tt>addPopupMessageListener</tt>.
*
* @param listener the listener to remove
*/
public void removePopupMessageListener(SystrayPopupMessageListener listener);
/**
* Shows the given <tt>PopupMessage</tt>. Any given <tt>PopupMessage</tt>
* will provides a minimum of two values : a message title and
* a message body. thoose two values are respectively available via
* <tt>PopupMessage#getMessageTitle()</tt> and
* <tt>PopupMessage#getMessage()</tt>
*
* @param popupMessage the message to show
*/
public void showPopupMessage(PopupMessage popupMessage);
/**
* Returns a readable description of this popup handler. It is expected
* to be a localized string.
*
* @returns a string describing this popup handler
*/
@Override
public String toString();
}

@ -62,16 +62,11 @@ public interface SystrayService
public static final int ENVELOPE_IMG_TYPE = 1;
/**
* Shows a system tray message with the given title and message content. The
* message type will affect the icon used to present the message.
* Shows the given <tt>PopupMessage</tt>
*
* @param title the title, which will be shown
* @param messageContent the content of the message to display
* @param messageType the message type; one of XXX_MESSAGE_TYPE constants
* declared in this class
* @param popupMessage the message to show
*/
public void showPopupMessage(String title,
String messageContent, int messageType);
public void showPopupMessage(PopupMessage popupMessage);
/**
* Adds a listener for <tt>SystrayPopupMessageEvent</tt>s posted when user
@ -88,6 +83,20 @@ public void showPopupMessage(String title,
*/
public void removePopupMessageListener(SystrayPopupMessageListener listener);
/**
* Set the handler which will be used for popup message
* @param popupHandler the handler to use
* @return the previously used popup handler
*/
public PopupMessageHandler setActivePopupMessageHandler(
PopupMessageHandler popupHandler);
/**
* Get the handler currently used by the systray service for popup message
* @return the handler used by the systray service
*/
public PopupMessageHandler getActivePopupMessageHandler();
/**
* Sets a new icon to the systray.
*

@ -0,0 +1,98 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.util.swing;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import net.java.sip.communicator.util.*;
/**
* A custom panel to handle systray popup notification
*
* @author Symphorien Wanko
*/
public class PopupNotificationPanel extends SIPCommFrame.MainContentPane
{
/** logger for this class */
private final Logger logger = Logger.getLogger(SIPCommFrame.class);
/**
* Creates a new <tt>PopupNotificationPanel</tt> with a customized panel title
*/
private PopupNotificationPanel()
{
JLabel notifTitle = new JLabel(
UtilActivator.getResources().getSettingsString(
"service.gui.APPLICATION_NAME"),
UtilActivator.getResources().getImage(
"service.gui.SIP_COMMUNICATOR_LOGO"),
SwingConstants.LEFT);
final JLabel notifClose = new JLabel(
UtilActivator.getResources()
.getImage("service.gui.lookandfeel.CLOSE_TAB_ICON"));
notifClose.setToolTipText(UtilActivator.getResources()
.getI18NString("service.gui.CLOSE"));
notifClose.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
try
{
// TODO : that is pretty ugly. It will be nice if
// it is possible to reach the top window in a better way
JWindow jw = (JWindow) notifClose
.getParent().getParent().getParent()
.getParent().getParent().getParent();
jw.dispose();
}
catch (Exception ex)
{
// should never happens : if the user clicks on the close
// icon, it means that the popup window were visible
logger.warn("error while getting the popup window :"
, ex);
}
}
});
BorderLayout borderLayout = new BorderLayout();
borderLayout.setVgap(5);
JPanel notificationWindowTitle = new JPanel(borderLayout);
notificationWindowTitle
.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
notificationWindowTitle.setOpaque(false);
notificationWindowTitle.add(notifTitle, BorderLayout.WEST);
notificationWindowTitle.add(notifClose, BorderLayout.EAST);
JSeparator jSep = new JSeparator();
notificationWindowTitle.add(jSep, BorderLayout.SOUTH);
add(notificationWindowTitle, BorderLayout.NORTH);
setBorder(BorderFactory.createLineBorder(Color.GRAY));
}
/**
* Creates a new notifcation panel with <tt>notificationContent</tt> as
* the component to put in that panel
*
* @param notificationContent content to add in the new created
* <tt>PopupNotificationPanel</tt>
*/
public PopupNotificationPanel(JPanel notificationContent)
{
this();
add(notificationContent, BorderLayout.CENTER);
}
}

@ -395,7 +395,7 @@ public void update(Observable obs, Object arg)
}
}
static class MainContentPane
public static class MainContentPane
extends JPanel
{
private final boolean isColorBgEnabled;

@ -0,0 +1,52 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.slick.popupmessagehandler;
import java.util.*;
import junit.framework.*;
import org.osgi.framework.*;
import net.java.sip.communicator.util.*;
/**
*
* @author Symphorien Wanko
*/
public class PopupMessageHandlerSLick extends TestSuite implements BundleActivator
{
/** Logger for this class */
private static Logger logger =
Logger.getLogger(PopupMessageHandlerSLick.class);
/** our bundle context */
protected static BundleContext bundleContext = null;
/** implements BundleActivator.start() */
public void start(BundleContext bc) throws Exception
{
logger.info("starting popup message test ");
bundleContext = bc;
setName("PopupMessageHandlerSLick");
Hashtable properties = new Hashtable();
properties.put("service.pid", getName());
addTest(TestPopupMessageHandler.suite());
bundleContext.registerService(getClass().getName(), this, properties);
}
/** implements BundleActivator.stop() */
public void stop(BundleContext bc) throws Exception
{}
}

@ -0,0 +1,164 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.slick.popupmessagehandler;
import junit.framework.*;
import org.osgi.framework.*;
import net.java.sip.communicator.service.notification.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.service.systray.event.*;
import net.java.sip.communicator.util.*;
/**
* Test suite for the popup message handler interface.
* @author Symphorien Wanko
*/
public class TestPopupMessageHandler
extends TestCase
{
/** Logger for this class */
private static final Logger logger
= Logger.getLogger(TestPopupMessageHandler.class);
/**
* the <tt>SystrayService</tt> reference we will get from bundle
* context to register ours handlers
*/
private static SystrayService systrayService = null;
/**
* reference to services we will retrive from bundle context
*/
private static ServiceReference serviceReference = null;
/**
* the <tt>NotificationService</tt> reference we will get from bundle
* context to send notifications to our handlers
*/
private static NotificationService notificationService = null;
/**
* a trivial message we will send via the nofification service.
*/
private String messageStart = "Lorem ipsum dolor sit amet.";
/**
* the first handler we will use.
*/
private PopupMessageHandler handler1 = new MockPopupMessageHandler();
/**
* the second handler we will use.
*/
private PopupMessageHandler handler2 = new MockPopupMessageHandler();
/**
* A reference to the bundle context in which we are runing.
*/
private BundleContext bc = PopupMessageHandlerSLick.bundleContext;
/**
* Create an instance to launch tests.
* @param name name of the test case
*/
public TestPopupMessageHandler(String name)
{
super(name);
}
/**
* Creates the test suite
* @return the <tt>TestSuite</tt> created
*/
public static Test suite()
{
TestSuite suite = new TestSuite();
suite.addTest(
new TestPopupMessageHandler("testHandlerModification"));
suite.addTest(
new TestPopupMessageHandler("testNotificationHandling"));
return suite;
}
/**
* here we will test (get/set)ActivePopupMesssageHandler()
*/
public void testHandlerModification()
{
serviceReference = bc.getServiceReference(
SystrayService.class.getName());
systrayService = (SystrayService) bc.getService(serviceReference);
systrayService.setActivePopupMessageHandler(handler1);
// do we have our handler as expected ?
assertEquals(handler1, systrayService.getActivePopupMessageHandler());
// was handler1 the previous handler as returned by the set method ?
assertEquals(
handler1,
systrayService.setActivePopupMessageHandler(handler2));
// and now handler2 is our curretn hander
assertEquals(handler2, systrayService.getActivePopupMessageHandler());
}
/**
* we will fire a notification then see if it was handled by the right handler
* which received the right message.
*/
public void testNotificationHandling()
{
serviceReference = bc.getServiceReference(
NotificationService.class.getName());
notificationService = (NotificationService) bc.getService(serviceReference);
notificationService.fireNotification(
NotificationService.ACTION_POPUP_MESSAGE,
messageStart,
messageStart);
}
/** A trivial handler implementing <tt>PopupMessageHandler</tt> */
private class MockPopupMessageHandler implements PopupMessageHandler
{
/**
* implements <tt>PopupMessageHandler.addPopupMessageListener()</tt>
*/
public void addPopupMessageListener(SystrayPopupMessageListener listener)
{}
/**
* implements <tt>PopupMessageHandler.removePopupMessageListener()</tt>
*/
public void removePopupMessageListener(SystrayPopupMessageListener listener)
{}
/**
* implements <tt>PopupMessageHandler#showPopupMessage()</tt>
*/
public void showPopupMessage(PopupMessage popupMsg)
{
// is it the expected message and title ?
assertEquals(messageStart, popupMsg.getMessage());
assertEquals(messageStart, popupMsg.getMessageTitle());
// is it the expected handler which is handling it ?
assertEquals(handler2, this);
}
}
}

@ -0,0 +1,13 @@
Bundle-Activator: net.java.sip.communicator.slick.popupmessagehandler.PopupMessageHandlerSLick
Bundle-Name: PopupMessageHandler Test
Bundle-Description: PopupMessageHandler Test
Bundle-Vendor: sip-communicator.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: junit.framework,
org.osgi.framework,
net.java.sip.communicator.service.notification,
net.java.sip.communicator.service.systray,
net.java.sip.communicator.service.systray.event,
net.java.sip.communicator.util,
Export-Package: net.java.sip.communicator.slick.popupmessagehandler,
Loading…
Cancel
Save