From 2d812827220778a947e1577f4018fd022ba36a0a Mon Sep 17 00:00:00 2001 From: Symphorien Wanko Date: Tue, 17 Feb 2009 02:06:44 +0000 Subject: [PATCH] swing based popup notifications with tests for the PopupMessage interface. --- build.xml | 23 +- lib/felix.client.run.properties | 1 + lib/felix.unit.test.properties | 13 +- lib/testing.properties | 3 +- resources/languages/resources.properties | 4 + .../GrowlNotificationActivator.java | 29 +- .../GrowlNotificationServiceImpl.java | 288 +++--------- .../growlnotification.manifest.mf | 5 +- .../notification/NotificationServiceImpl.java | 5 +- .../PopupMessageNotificationHandlerImpl.java | 12 +- .../PopupMessageHandlerSwingImpl.java | 295 ++++++++++++ .../SwingNotificationActivator.java | 113 +++++ .../swingnotification.manifest.mf | 14 + .../PopupMessageHandlerTrayIconImpl.java | 131 ++++++ .../impl/systray/SystrayActivator.java | 4 +- .../systray/jdic/SystrayServiceJdicImpl.java | 433 ++++++++---------- .../generalconfig/ConfigurationManager.java | 22 +- .../GeneralConfigPluginActivator.java | 24 +- .../GeneralConfigurationPanel.java | 75 +++ .../generalconfig/generalconfig.manifest.mf | 1 + .../PopupMessageNotificationHandler.java | 8 +- .../service/systray/PopupMessage.java | 192 ++++++++ .../service/systray/PopupMessageHandler.java | 55 +++ .../service/systray/SystrayService.java | 25 +- .../util/swing/PopupNotificationPanel.java | 98 ++++ .../communicator/util/swing/SIPCommFrame.java | 2 +- .../PopupMessageHandlerSLick.java | 52 +++ .../TestPopupMessageHandler.java | 164 +++++++ .../popupmessagehandler.slick.manifest.mf | 13 + 29 files changed, 1588 insertions(+), 516 deletions(-) create mode 100644 src/net/java/sip/communicator/impl/swingnotification/PopupMessageHandlerSwingImpl.java create mode 100644 src/net/java/sip/communicator/impl/swingnotification/SwingNotificationActivator.java create mode 100644 src/net/java/sip/communicator/impl/swingnotification/swingnotification.manifest.mf create mode 100644 src/net/java/sip/communicator/impl/systray/PopupMessageHandlerTrayIconImpl.java create mode 100644 src/net/java/sip/communicator/service/systray/PopupMessage.java create mode 100644 src/net/java/sip/communicator/service/systray/PopupMessageHandler.java create mode 100644 src/net/java/sip/communicator/util/swing/PopupNotificationPanel.java create mode 100644 test/net/java/sip/communicator/slick/popupmessagehandler/PopupMessageHandlerSLick.java create mode 100644 test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java create mode 100644 test/net/java/sip/communicator/slick/popupmessagehandler/popupmessagehandler.slick.manifest.mf diff --git a/build.xml b/build.xml index fdd178d8a..c03eec5ca 100644 --- a/build.xml +++ b/build.xml @@ -771,7 +771,7 @@ + + + + + + + + + + + + + + + diff --git a/lib/felix.client.run.properties b/lib/felix.client.run.properties index 168fc21e6..bd444342c 100644 --- a/lib/felix.client.run.properties +++ b/lib/felix.client.run.properties @@ -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= \ diff --git a/lib/felix.unit.test.properties b/lib/felix.unit.test.properties index 6b6baa902..1f1f79950 100644 --- a/lib/felix.unit.test.properties +++ b/lib/felix.unit.test.properties @@ -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 diff --git a/lib/testing.properties b/lib/testing.properties index f77226049..8ac06de39 100644 --- a/lib/testing.properties +++ b/lib/testing.properties @@ -21,7 +21,8 @@ net.java.sip.communicator.slick.runner.TEST_LIST=ConfigurationServiceLick \ YahooProtocolProviderSlick \ MsnProtocolProviderSlick \ GibberishProtocolProviderServiceLick \ - RssProtocolProviderServiceLick + RssProtocolProviderServiceLick \ + PopupMessageHandlerSLick # Note that NetworkAddressManagerServiceLick currently runs diff --git a/resources/languages/resources.properties b/resources/languages/resources.properties index b3cef5787..b309e35af 100644 --- a/resources/languages/resources.properties +++ b/resources/languages/resources.properties @@ -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 diff --git a/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationActivator.java b/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationActivator.java index ba5d49520..bab65396c 100644 --- a/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationActivator.java +++ b/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationActivator.java @@ -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 ResourceManagementService obtained from the bundle + * context. + * @return the ResourceManagementService obtained from the bundle + * context + */ + public static ResourceManagementService getResources() + { + if (resourcesService == null) + resourcesService = + ResourceManagementServiceUtils.getService(bundleContext); + return resourcesService; + + } } diff --git a/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationServiceImpl.java b/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationServiceImpl.java index 225a45ef6..8751393ad 100644 --- a/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationServiceImpl.java +++ b/src/net/java/sip/communicator/impl/growlnotification/GrowlNotificationServiceImpl.java @@ -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 popupMessageListeners = + new Vector(); + /** * 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 PopupMessageHandler#showPopupMessage() + * + * @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 toString from PopupMessageHandler + * @return a description of this handler + */ + public String toString() + { + return GrowlNotificationActivator.getResources() + .getI18NString("impl.growlnotification.POPUP_MESSAGE_HANDLER"); + } } diff --git a/src/net/java/sip/communicator/impl/growlnotification/growlnotification.manifest.mf b/src/net/java/sip/communicator/impl/growlnotification/growlnotification.manifest.mf index c8b5a5301..fb78f334b 100644 --- a/src/net/java/sip/communicator/impl/growlnotification/growlnotification.manifest.mf +++ b/src/net/java/sip/communicator/impl/growlnotification/growlnotification.manifest.mf @@ -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 diff --git a/src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java b/src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java index 9e89f1f3e..cd635fef3 100644 --- a/src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java +++ b/src/net/java/sip/communicator/impl/notification/NotificationServiceImpl.java @@ -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)) { diff --git a/src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java b/src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java index 05349b94a..b3352179d 100644 --- a/src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java +++ b/src/net/java/sip/communicator/impl/notification/PopupMessageNotificationHandlerImpl.java @@ -46,19 +46,17 @@ public String getDefaultMessage() /** * Shows a popup message through the SystrayService. - * - * @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); } /** diff --git a/src/net/java/sip/communicator/impl/swingnotification/PopupMessageHandlerSwingImpl.java b/src/net/java/sip/communicator/impl/swingnotification/PopupMessageHandlerSwingImpl.java new file mode 100644 index 000000000..79748e173 --- /dev/null +++ b/src/net/java/sip/communicator/impl/swingnotification/PopupMessageHandlerSwingImpl.java @@ -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 PopupMessageHandler using swing. + * @author Symphorien Wanko + */ +public class PopupMessageHandlerSwingImpl implements PopupMessageHandler +{ + + /** logger for the PopupMessageHandlerSwingImpl class */ + private final Logger logger = + Logger.getLogger(PopupMessageHandlerSwingImpl.class); + + /** The list of all added popup listeners */ + private final List popupMessageListeners = + new Vector(); + + /** 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 addPopupMessageListener + * @param listener the listener to remove + */ + public void removePopupMessageListener(SystrayPopupMessageListener listener) + { + synchronized (popupMessageListeners) + { + popupMessageListeners.remove(listener); + } + } + + /** + * Implements PopupMessageHandler#showPopupMessage() + * + * @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 = "" + message.substring(0, 77) + "..."; + else + msg = "" + 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 SystrayPopupMessageEvent + * occured. + * + * @param SystrayPopupMessageEvent the evt to send to listener. + */ + private void firePopupMessageClicked(SystrayPopupMessageEvent evt) + { + logger.trace("Will dispatch the following popup event: " + evt); + + List listeners; + synchronized (popupMessageListeners) + { + listeners = + new ArrayList( + popupMessageListeners); + } + + for (SystrayPopupMessageListener listener : listeners) + listener.popupMessageClicked(evt); + } + + /** + * Implements toString from PopupMessageHandler + * @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 PopupLauncher. + */ + 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); + } + } +} diff --git a/src/net/java/sip/communicator/impl/swingnotification/SwingNotificationActivator.java b/src/net/java/sip/communicator/impl/swingnotification/SwingNotificationActivator.java new file mode 100644 index 000000000..d9e61d333 --- /dev/null +++ b/src/net/java/sip/communicator/impl/swingnotification/SwingNotificationActivator.java @@ -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 ConfigurationService obtained from the bundle + * context. + * @return the ConfigurationService 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 ResourceManagementService obtained from the bundle + * context. + * @return the ResourceManagementService obtained from the bundle + * context + */ + public static ResourceManagementService getResources() + { + if (resourcesService == null) + resourcesService = + ResourceManagementServiceUtils.getService(bundleContext); + return resourcesService; + + } +} diff --git a/src/net/java/sip/communicator/impl/swingnotification/swingnotification.manifest.mf b/src/net/java/sip/communicator/impl/swingnotification/swingnotification.manifest.mf new file mode 100644 index 000000000..edaf035df --- /dev/null +++ b/src/net/java/sip/communicator/impl/swingnotification/swingnotification.manifest.mf @@ -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 diff --git a/src/net/java/sip/communicator/impl/systray/PopupMessageHandlerTrayIconImpl.java b/src/net/java/sip/communicator/impl/systray/PopupMessageHandlerTrayIconImpl.java new file mode 100644 index 000000000..1cbe32780 --- /dev/null +++ b/src/net/java/sip/communicator/impl/systray/PopupMessageHandlerTrayIconImpl.java @@ -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 PopupMsystrayessageHandler 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 PopupMessageListener = + new Vector(); + + /** the tray icon we will use to popup messages */ + private TrayIcon trayIcon; + + + /** + * Creates a new PopupMessageHandlerTrayIconImpl which will uses + * the provided TrayIcon 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 PopupMessageHandler.addPopupMessageListener + * @param listener the listener to add + */ + public void addPopupMessageListener(SystrayPopupMessageListener listener) + { + synchronized (PopupMessageListener) + { + if (!PopupMessageListener.contains(listener)) + PopupMessageListener.add(listener); + } + } + + /** + * Implementation of PopupMessageHandler.removePopupMessageListener + * @param listener the listener to remove + */ + public void removePopupMessageListener(SystrayPopupMessageListener listener) + { + synchronized (PopupMessageListener) + { + PopupMessageListener.remove(listener); + } + } + + /** + * Implements PopupMessageHandler#showPopupMessage() + * + * @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("]*+>", ""); + String messageTitle = popupMessage.getMessageTitle() + .replaceAll("]*+>", ""); + + if(messageContent.length() > 40) + messageContent = messageContent.substring(0, 40).concat("..."); + trayIcon.displayMessage( + messageTitle, + messageContent, + TrayIcon.NONE_MESSAGE_TYPE); + } + + /** + * Notifies all interested listeners that a SystrayPopupMessageEvent + * 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 listeners; + synchronized (PopupMessageListener) + { + listeners = + new ArrayList( + PopupMessageListener); + } + + for (SystrayPopupMessageListener listener : listeners) + listener.popupMessageClicked(evt); + } + + /** + * Implements toString from PopupMessageHandler + * @return a description of this handler + */ + public String toString() + { + return SystrayActivator.getResources() + .getI18NString("impl.systray.POPUP_MESSAGE_HANDLER"); + } +} diff --git a/src/net/java/sip/communicator/impl/systray/SystrayActivator.java b/src/net/java/sip/communicator/impl/systray/SystrayActivator.java index d0f312827..82511a072 100644 --- a/src/net/java/sip/communicator/impl/systray/SystrayActivator.java +++ b/src/net/java/sip/communicator/impl/systray/SystrayActivator.java @@ -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; diff --git a/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java b/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java index b59a2270b..ed6c42fa9 100644 --- a/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java +++ b/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java @@ -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 popupMessageListeners = - new Vector(); + private PopupMessageHandler activePopupHandler; /** - * List of all messages waiting to be shown. + * A set of usable PopupMessageHandler */ - private final List messageQueue = - new ArrayList(); - - private Timer popupTimer = new Timer(); + private final Hashtable popupHandlerSet + = new Hashtable(); /** - * 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 ConfigurationService obtained from the + * SystrayServiceActivator */ - 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 Systray. */ @@ -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 SystratService.showPopupMessage method. Shows - * a pop up message, above the Systray icon, which has the given title, - * message content and message type. + * Implements SystraService#showPopupMessage() * - * @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("]*+>", ""); - - 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 SystrayPopupMessageEvent - * 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 listeners; - synchronized (popupMessageListeners) - { - listeners = - new ArrayList( - 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 SystrayMessage by specifying the - * message title, 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 SystrayMessage by specifying the - * message title, 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 SystrayPopupMessageListener.popupMessageClicked() */ + 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 ServiceListener we will use */ + private class ServiceListenerImpl implements ServiceListener + { + /** implements ServiceListener.serviceChanged */ + 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); + } } } } diff --git a/src/net/java/sip/communicator/plugin/generalconfig/ConfigurationManager.java b/src/net/java/sip/communicator/plugin/generalconfig/ConfigurationManager.java index 8b5e7f0f9..606903142 100644 --- a/src/net/java/sip/communicator/plugin/generalconfig/ConfigurationManager.java +++ b/src/net/java/sip/communicator/plugin/generalconfig/ConfigurationManager.java @@ -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 true if transparent windows are enabled, * false otherwise. diff --git a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java index 94f870a82..d2fe80852 100644 --- a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java +++ b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigPluginActivator.java @@ -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 SystrayService obtained from the bundle + * context. + * @return the SystrayService 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 UIService. * diff --git a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java index 31c4e10fd..72ff0cbf0 100644 --- a/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java +++ b/src/net/java/sip/communicator/plugin/generalconfig/GeneralConfigurationPanel.java @@ -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 diff --git a/src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf b/src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf index 3bdd7f83e..e12d62e83 100644 --- a/src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf +++ b/src/net/java/sip/communicator/plugin/generalconfig/generalconfig.manifest.mf @@ -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, diff --git a/src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java b/src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java index 2aa519de5..281bb683b 100644 --- a/src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java +++ b/src/net/java/sip/communicator/service/notification/PopupMessageNotificationHandler.java @@ -6,6 +6,8 @@ */ package net.java.sip.communicator.service.notification; +import net.java.sip.communicator.service.systray.*; + /** * The PopupMessageNotificationHandler 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 message content and the given - * title. + * Shows the given PopupMessage * - * @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); } diff --git a/src/net/java/sip/communicator/service/systray/PopupMessage.java b/src/net/java/sip/communicator/service/systray/PopupMessage.java new file mode 100644 index 000000000..3f8232411 --- /dev/null +++ b/src/net/java/sip/communicator/service/systray/PopupMessage.java @@ -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 PopupMessage 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 PopupMessageHandler 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 JComponet for this PopupMessage */ + 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 PopupMessage 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 SystrayService + */ + public PopupMessage(String title, String content, int messageType) + { + this(title, content); + this.messageType = messageType; + } + + /** + * Creates a new PopupMessage 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 PopupMessage with the given + * JComponent 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 PopupMessage + * @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; + } +} diff --git a/src/net/java/sip/communicator/service/systray/PopupMessageHandler.java b/src/net/java/sip/communicator/service/systray/PopupMessageHandler.java new file mode 100644 index 000000000..0198a64bf --- /dev/null +++ b/src/net/java/sip/communicator/service/systray/PopupMessageHandler.java @@ -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 PopupMessageHandler role is to give differents methods to + * display PopupMessage 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 addPopupMessageListener. + * + * @param listener the listener to remove + */ + public void removePopupMessageListener(SystrayPopupMessageListener listener); + + /** + * Shows the given PopupMessage. Any given PopupMessage + * will provides a minimum of two values : a message title and + * a message body. thoose two values are respectively available via + * PopupMessage#getMessageTitle() and + * PopupMessage#getMessage() + * + * @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(); +} diff --git a/src/net/java/sip/communicator/service/systray/SystrayService.java b/src/net/java/sip/communicator/service/systray/SystrayService.java index 951bcafb9..7123f2e84 100644 --- a/src/net/java/sip/communicator/service/systray/SystrayService.java +++ b/src/net/java/sip/communicator/service/systray/SystrayService.java @@ -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 PopupMessage * - * @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 SystrayPopupMessageEvents 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. * diff --git a/src/net/java/sip/communicator/util/swing/PopupNotificationPanel.java b/src/net/java/sip/communicator/util/swing/PopupNotificationPanel.java new file mode 100644 index 000000000..7933b5158 --- /dev/null +++ b/src/net/java/sip/communicator/util/swing/PopupNotificationPanel.java @@ -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 PopupNotificationPanel 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 notificationContent as + * the component to put in that panel + * + * @param notificationContent content to add in the new created + * PopupNotificationPanel + */ + public PopupNotificationPanel(JPanel notificationContent) + { + this(); + add(notificationContent, BorderLayout.CENTER); + } +} diff --git a/src/net/java/sip/communicator/util/swing/SIPCommFrame.java b/src/net/java/sip/communicator/util/swing/SIPCommFrame.java index 716eeb4e7..db14b4220 100644 --- a/src/net/java/sip/communicator/util/swing/SIPCommFrame.java +++ b/src/net/java/sip/communicator/util/swing/SIPCommFrame.java @@ -395,7 +395,7 @@ public void update(Observable obs, Object arg) } } - static class MainContentPane + public static class MainContentPane extends JPanel { private final boolean isColorBgEnabled; diff --git a/test/net/java/sip/communicator/slick/popupmessagehandler/PopupMessageHandlerSLick.java b/test/net/java/sip/communicator/slick/popupmessagehandler/PopupMessageHandlerSLick.java new file mode 100644 index 000000000..b9ba24f4a --- /dev/null +++ b/test/net/java/sip/communicator/slick/popupmessagehandler/PopupMessageHandlerSLick.java @@ -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 + {} + +} diff --git a/test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java b/test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java new file mode 100644 index 000000000..2a0e9eea0 --- /dev/null +++ b/test/net/java/sip/communicator/slick/popupmessagehandler/TestPopupMessageHandler.java @@ -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 SystrayService 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 NotificationService 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 TestSuite 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 PopupMessageHandler */ + private class MockPopupMessageHandler implements PopupMessageHandler + { + + /** + * implements PopupMessageHandler.addPopupMessageListener() + */ + public void addPopupMessageListener(SystrayPopupMessageListener listener) + {} + + /** + * implements PopupMessageHandler.removePopupMessageListener() + */ + public void removePopupMessageListener(SystrayPopupMessageListener listener) + {} + + /** + * implements PopupMessageHandler#showPopupMessage() + */ + 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); + } + + } +} diff --git a/test/net/java/sip/communicator/slick/popupmessagehandler/popupmessagehandler.slick.manifest.mf b/test/net/java/sip/communicator/slick/popupmessagehandler/popupmessagehandler.slick.manifest.mf new file mode 100644 index 000000000..6424a68fc --- /dev/null +++ b/test/net/java/sip/communicator/slick/popupmessagehandler/popupmessagehandler.slick.manifest.mf @@ -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,