diff options
author | Yana Stamcheva <yana@jitsi.org> | 2009-06-15 15:18:29 +0000 |
---|---|---|
committer | Yana Stamcheva <yana@jitsi.org> | 2009-06-15 15:18:29 +0000 |
commit | 2f0db4d2d1ad77f058b352829a6494c7af5a16b3 (patch) | |
tree | 32ecf5f800417777fa473b8814dead041f6515c3 /src/net/java/sip/communicator/impl/osdependent | |
parent | 3563fa97f679c2f8b29f2d2eb74fc0bbcaa698ab (diff) | |
download | jitsi-2f0db4d2d1ad77f058b352829a6494c7af5a16b3.zip jitsi-2f0db4d2d1ad77f058b352829a6494c7af5a16b3.tar.gz jitsi-2f0db4d2d1ad77f058b352829a6494c7af5a16b3.tar.bz2 |
Adding support for file transfer for XMPP and graphical User Interface for file transfer (ongoing work). This first commit adds the needed gui that enables users to send and receive files, to
drag and drop files into chat windows. It displays incoming file notifications, file icons or previews (where possible, e.g. images).
This work package also contains a first file transfer implementation over the XMPP protocol (using the smack implementation of xep-0096: http://xmpp.org/extensions/xep-0096.html). Unfortunately this implementation won't work very well with GoogleTalk accounts for now, as Google servers seem to block every file bigger than 60K.
This commit contains also some improvements in the way we load the history and we manage error messages in the gui.
Diffstat (limited to 'src/net/java/sip/communicator/impl/osdependent')
17 files changed, 3753 insertions, 0 deletions
diff --git a/src/net/java/sip/communicator/impl/osdependent/Desktop.java b/src/net/java/sip/communicator/impl/osdependent/Desktop.java new file mode 100644 index 0000000..3ab5124 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/Desktop.java @@ -0,0 +1,469 @@ +/* + * 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.osdependent; + +import java.awt.*; +import java.io.*; +import java.lang.reflect.*; +import java.net.*; + +import org.jdesktop.jdic.desktop.*; + +import net.java.sip.communicator.util.*; + +/** + * The <tt>Desktop</tt> class handles desktop operations through the default + * desktop implementation. It choose which implementation to use depending on + * what is currently available (java 6 or Jdic). + * + * @author Yana Stamcheva + */ +public class Desktop +{ + private static final Logger logger = Logger.getLogger(SystemTray.class); + + private static Desktop defaultDesktop; + + /** + * Returns the default <tt>Desktop</tt> instance depending on the operating + * system and java version availability. + * + * @return the default <tt>Desktop</tt> instance + * @throws UnsupportedOperationException if the operation is not supported + * @throws HeadlessException + * @throws SecurityException + */ + public static Desktop getDefaultDesktop() + throws UnsupportedOperationException, + HeadlessException, + SecurityException + { + if (defaultDesktop != null) + return defaultDesktop; + + Class<?> awtDesktopClass = null; + try + { + awtDesktopClass = Class.forName("java.awt.Desktop"); + } + catch (ClassNotFoundException ex) + { + // We'll try org.jdesktop.jdic.desktop then. + } + DesktopPeer peer = null; + if (awtDesktopClass != null) + try + { + peer = new AWTDesktopPeer(awtDesktopClass); + } + catch (Exception ex) + { + logger.error( + "Failed to initialize the java.awt.SystemTray implementation.", + ex); + + // We'll try org.jdesktop.jdic.desktop then. + } + if (peer == null) + try + { + peer = new JdicDesktopPeer(); + } + catch (Exception ex) + { + logger.error( + "Failed to initialize the org.jdesktop.jdic.tray implementation.", + ex); + } + return (defaultDesktop = new Desktop(peer)); + } + + private final DesktopPeer peer; + + /** + * Creates a Desktop instance by specifying the underlying <tt>peer</tt> to + * use for the implementation. + * + * @param peer the implementation peer + */ + private Desktop(DesktopPeer peer) + { + this.peer = peer; + } + + /** + * Returns the currently used peer. + * + * @return the currently used peer + */ + DesktopPeer getPeer() + { + return peer; + } + + /** + * The <tt>DesktopPeer</tt> interface provides abstraction for operating + * system related desktop operations like open(file), print(file), etc. + */ + static interface DesktopPeer + { + public void open(File file) throws NullPointerException, + IllegalArgumentException, + UnsupportedOperationException, + IOException, + SecurityException; + + public void print(File file) throws NullPointerException, + IllegalArgumentException, + UnsupportedOperationException, + IOException, + SecurityException; + + public void edit(File file) throws NullPointerException, + IllegalArgumentException, + UnsupportedOperationException, + IOException, + SecurityException; + + public void browse(URI uri) throws NullPointerException, + IllegalArgumentException, + UnsupportedOperationException, + IOException, + SecurityException; + } + + /** + * A <tt>DesktopPeer</tt> implementation based on the java.awt.Desktop class + * provided in java 1.6+ + */ + private static class AWTDesktopPeer + implements DesktopPeer + { + private final Object impl; + + private final Method open; + + private final Method print; + + private final Method edit; + + private final Method browse; + + public AWTDesktopPeer(Class<?> clazz) + throws UnsupportedOperationException, + HeadlessException, + SecurityException + { + Method getDefaultDesktop; + try + { + getDefaultDesktop = + clazz.getMethod("getDesktop", (Class<?>[]) null); + + open = clazz.getMethod("open", new Class<?>[]{ File.class }); + print = clazz.getMethod("print", new Class<?>[]{ File.class }); + edit = clazz.getMethod("edit", new Class<?>[]{ File.class }); + browse = clazz.getMethod("edit", new Class<?>[]{ URI.class }); + } + catch (NoSuchMethodException ex) + { + throw new UnsupportedOperationException(ex); + } + + try + { + impl = getDefaultDesktop.invoke(null, (Object[]) null); + } + catch (IllegalAccessException ex) + { + throw new UnsupportedOperationException(ex); + } + catch (InvocationTargetException ex) + { + throw new UnsupportedOperationException(ex); + } + } + + /** + * Opens a file. + */ + public void open(File file) throws IOException + { + try + { + open.invoke(impl, new Object[]{file}); + } + catch (IllegalAccessException ex) + { + throw new UndeclaredThrowableException(ex); + } + catch (InvocationTargetException ex) + { + Throwable cause = ex.getCause(); + if (cause == null) + throw new UndeclaredThrowableException(ex); + else if (cause instanceof NullPointerException) + throw (NullPointerException) cause; + else if (cause instanceof IllegalArgumentException) + throw (IllegalArgumentException) cause; + else if (cause instanceof UnsupportedOperationException) + throw (UnsupportedOperationException) cause; + else if (cause instanceof IOException) + throw (IOException) cause; + else if (cause instanceof SecurityException) + throw (SecurityException) cause; + else + throw new UndeclaredThrowableException(cause); + } + } + + /** + * Prints a file. + */ + public void print(File file) throws IOException + { + try + { + print.invoke(impl, new Object[]{file}); + } + catch (IllegalAccessException ex) + { + throw new UndeclaredThrowableException(ex); + } + catch (InvocationTargetException ex) + { + Throwable cause = ex.getCause(); + if (cause == null) + throw new UndeclaredThrowableException(ex); + else if (cause instanceof NullPointerException) + throw (NullPointerException) cause; + else if (cause instanceof IllegalArgumentException) + throw (IllegalArgumentException) cause; + else if (cause instanceof UnsupportedOperationException) + throw (UnsupportedOperationException) cause; + else if (cause instanceof IOException) + throw (IOException) cause; + else if (cause instanceof SecurityException) + throw (SecurityException) cause; + else + throw new UndeclaredThrowableException(cause); + } + } + + /** + * Edits a file. + */ + public void edit(File file) throws IOException + { + try + { + edit.invoke(impl, new Object[]{file}); + } + catch (IllegalAccessException ex) + { + throw new UndeclaredThrowableException(ex); + } + catch (InvocationTargetException ex) + { + Throwable cause = ex.getCause(); + if (cause == null) + throw new UndeclaredThrowableException(ex); + else if (cause instanceof NullPointerException) + throw (NullPointerException) cause; + else if (cause instanceof IllegalArgumentException) + throw (IllegalArgumentException) cause; + else if (cause instanceof UnsupportedOperationException) + throw (UnsupportedOperationException) cause; + else if (cause instanceof IOException) + throw (IOException) cause; + else if (cause instanceof SecurityException) + throw (SecurityException) cause; + else + throw new UndeclaredThrowableException(cause); + } + } + + /** + * Browses a file. + */ + public void browse(URI uri) throws IOException + { + try + { + browse.invoke(impl, new Object[]{uri}); + } + catch (IllegalAccessException ex) + { + throw new UndeclaredThrowableException(ex); + } + catch (InvocationTargetException ex) + { + Throwable cause = ex.getCause(); + if (cause == null) + throw new UndeclaredThrowableException(ex); + else if (cause instanceof NullPointerException) + throw (NullPointerException) cause; + else if (cause instanceof IllegalArgumentException) + throw (IllegalArgumentException) cause; + else if (cause instanceof UnsupportedOperationException) + throw (UnsupportedOperationException) cause; + else if (cause instanceof IOException) + throw (IOException) cause; + else if (cause instanceof SecurityException) + throw (SecurityException) cause; + else + throw new UndeclaredThrowableException(cause); + } + } + } + + /** + * An implementation of <tt>DesktopPeer</tt> based on the Jdic library + * Desktop class. + */ + private static class JdicDesktopPeer + implements DesktopPeer + { + /** + * Opens a file. + */ + public void open(final File file) throws IOException + { + try + { + String osName = System.getProperty("os.name"); + + // Use browse(URL) instead of open(file) if we're on Mac OS, + // because of a Java VM crash when open(file) is invoked. + if (!osName.startsWith("Mac OS")) + { + org.jdesktop.jdic.desktop.Desktop.open(file); + } + else + { + if (!file.isDirectory()) + org.jdesktop.jdic.desktop.Desktop.browse(file.toURL()); + else + Runtime.getRuntime().exec("open " + + file.getCanonicalPath()); + } + } + catch (DesktopException ex) + { + ex.printStackTrace(); + + Throwable cause = ex.getCause(); + + if (cause == null) + throw new UndeclaredThrowableException(ex); + else if (cause instanceof NullPointerException) + throw (NullPointerException) cause; + else if (cause instanceof IllegalArgumentException) + throw (IllegalArgumentException) cause; + else if (cause instanceof UnsupportedOperationException) + throw (UnsupportedOperationException) cause; + else if (cause instanceof IOException) + throw (IOException) cause; + else if (cause instanceof SecurityException) + throw (SecurityException) cause; + else + throw new UndeclaredThrowableException(cause); + } + } + + /** + * Prints a file. + */ + public void print(File file) throws IOException + { + try + { + org.jdesktop.jdic.desktop.Desktop.print(file); + } + catch (org.jdesktop.jdic.desktop.DesktopException ex) + { + Throwable cause = ex.getCause(); + if (cause == null) + throw new UndeclaredThrowableException(ex); + else if (cause instanceof NullPointerException) + throw (NullPointerException) cause; + else if (cause instanceof IllegalArgumentException) + throw (IllegalArgumentException) cause; + else if (cause instanceof UnsupportedOperationException) + throw (UnsupportedOperationException) cause; + else if (cause instanceof IOException) + throw (IOException) cause; + else if (cause instanceof SecurityException) + throw (SecurityException) cause; + else + throw new UndeclaredThrowableException(cause); + } + } + + /** + * Edits the given file. + */ + public void edit(File file) throws IOException + { + try + { + org.jdesktop.jdic.desktop.Desktop.edit(file); + } + catch (org.jdesktop.jdic.desktop.DesktopException ex) + { + Throwable cause = ex.getCause(); + if (cause == null) + throw new UndeclaredThrowableException(ex); + else if (cause instanceof NullPointerException) + throw (NullPointerException) cause; + else if (cause instanceof IllegalArgumentException) + throw (IllegalArgumentException) cause; + else if (cause instanceof UnsupportedOperationException) + throw (UnsupportedOperationException) cause; + else if (cause instanceof IOException) + throw (IOException) cause; + else if (cause instanceof SecurityException) + throw (SecurityException) cause; + else + throw new UndeclaredThrowableException(cause); + } + } + + /** + * Opens a browser with given uri. + */ + public void browse(URI uri) throws IOException + { + try + { + org.jdesktop.jdic.desktop.Desktop.browse(uri.toURL()); + } + catch (org.jdesktop.jdic.desktop.DesktopException ex) + { + Throwable cause = ex.getCause(); + if (cause == null) + throw new UndeclaredThrowableException(ex); + else if (cause instanceof NullPointerException) + throw (NullPointerException) cause; + else if (cause instanceof IllegalArgumentException) + throw (IllegalArgumentException) cause; + else if (cause instanceof UnsupportedOperationException) + throw (UnsupportedOperationException) cause; + else if (cause instanceof IOException) + throw (IOException) cause; + else if (cause instanceof SecurityException) + throw (SecurityException) cause; + else + throw new UndeclaredThrowableException(cause); + } + catch (MalformedURLException ex) + { + throw new IllegalArgumentException(ex); + } + } + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/DesktopServiceImpl.java b/src/net/java/sip/communicator/impl/osdependent/DesktopServiceImpl.java new file mode 100644 index 0000000..e193d98 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/DesktopServiceImpl.java @@ -0,0 +1,92 @@ +/* + * 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.osdependent; + +import java.io.*; +import java.net.*; + +import net.java.sip.communicator.service.desktop.*; + +/** + * Implementation of the <tt>DesktopService</tt>. + * + * @author Yana Stamcheva + */ +public class DesktopServiceImpl + implements DesktopService +{ + private final Desktop defaultDesktop; + + /** + * Creates a <tt>DesktopServiceImpl</tt> and initializes the default + * desktop to use for all desktop operations. + */ + public DesktopServiceImpl() + { + defaultDesktop = Desktop.getDefaultDesktop(); + } + + /** + * Invokes the default desktop browse method. + * + * @see DesktopService#browse(URI) + */ + public void browse(URI uri) + throws NullPointerException, + IllegalArgumentException, + UnsupportedOperationException, + IOException, + SecurityException + { + defaultDesktop.getPeer().browse(uri); + } + + /** + * Invokes the default desktop edit method. + * + * @see DesktopService#edit(File) + */ + public void edit(File file) + throws NullPointerException, + IllegalArgumentException, + UnsupportedOperationException, + IOException, + SecurityException + { + defaultDesktop.getPeer().edit(file); + } + + /** + * Invokes the default desktop open method. + * + * @see DesktopService#open(File) + */ + public void open(File file) + throws NullPointerException, + IllegalArgumentException, + UnsupportedOperationException, + IOException, + SecurityException + { + defaultDesktop.getPeer().open(file); + } + + /** + * Invokes the default desktop print method. + * + * @see DesktopService#print(File) + */ + public void print(File file) + throws NullPointerException, + IllegalArgumentException, + UnsupportedOperationException, + IOException, + SecurityException + { + defaultDesktop.getPeer().print(file); + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/NewStatusMessageDialog.java b/src/net/java/sip/communicator/impl/osdependent/NewStatusMessageDialog.java new file mode 100644 index 0000000..fe1fb51 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/NewStatusMessageDialog.java @@ -0,0 +1,254 @@ +/* + * 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.osdependent; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.*; + +/** + * The <tt>NewStatusMessageDialog</tt> is the dialog containing the form for + * changing the status message. + * + * @author Yana Stamcheva + */ +public class NewStatusMessageDialog + extends SIPCommDialog + implements ActionListener +{ + private final Logger logger = Logger.getLogger(NewStatusMessageDialog.class); + + private final JTextField messageTextField = new JTextField(); + + private final JButton cancelButton = new JButton( + OsDependentActivator.getResources().getI18NString("service.gui.CANCEL")); + + private final ProtocolProviderService protocolProvider; + + /** + * Creates an instance of <tt>NewStatusMessageDialog</tt>. + * + * @param protocolProvider the <tt>ProtocolProviderService</tt>. + */ + public NewStatusMessageDialog (ProtocolProviderService protocolProvider) + { + this.protocolProvider = protocolProvider; + + this.init(); + pack(); + } + + /** + * Initializes the <tt>NewStatusMessageDialog</tt> by adding the buttons, + * fields, etc. + */ + private void init() + { + this.setTitle(OsDependentActivator.getResources() + .getI18NString("service.gui.NEW_STATUS_MESSAGE")); + + JButton okButton = + new JButton(OsDependentActivator.getResources() + .getI18NString("service.gui.OK")); + this.getRootPane().setDefaultButton(okButton); + + this.setPreferredSize(new Dimension(500, 200)); + + JTextArea infoArea = new JTextArea( + OsDependentActivator.getResources().getI18NString( + "service.gui.STATUS_MESSAGE_INFO")); + infoArea.setEditable(false); + infoArea.setLineWrap(true); + infoArea.setWrapStyleWord(true); + infoArea.setOpaque(false); + + JLabel messageLabel = new JLabel( + OsDependentActivator.getResources().getI18NString( + "service.gui.NEW_STATUS_MESSAGE")); + + JPanel dataPanel = new TransparentPanel(new BorderLayout(5, 5)); + dataPanel.add(messageLabel, BorderLayout.WEST); + dataPanel.add(messageTextField, BorderLayout.CENTER); + + JLabel infoTitleLabel = new JLabel( + OsDependentActivator.getResources().getI18NString( + "service.gui.NEW_STATUS_MESSAGE")); + infoTitleLabel.setHorizontalAlignment(JLabel.CENTER); + infoTitleLabel.setFont( + infoTitleLabel.getFont().deriveFont(Font.BOLD, 18.0f)); + + JPanel labelsPanel = new TransparentPanel(new GridLayout(0, 1)); + labelsPanel.add(infoTitleLabel); + labelsPanel.add(infoArea); + labelsPanel.add(dataPanel); + + JPanel messagePanel = new TransparentPanel(new GridBagLayout()); + GridBagConstraints messagePanelConstraints = new GridBagConstraints(); + messagePanelConstraints.anchor = GridBagConstraints.NORTHWEST; + messagePanelConstraints.fill = GridBagConstraints.NONE; + messagePanelConstraints.gridx = 0; + messagePanelConstraints.gridy = 0; + messagePanelConstraints.insets = new Insets(5, 0, 5, 10); + messagePanelConstraints.weightx = 0; + messagePanelConstraints.weighty = 0; + messagePanel + .add(new ImageCanvas(Resources + .getImage("service.gui.icons.RENAME_DIALOG_ICON").getImage()), + messagePanelConstraints); + messagePanelConstraints.anchor = GridBagConstraints.NORTH; + messagePanelConstraints.fill = GridBagConstraints.HORIZONTAL; + messagePanelConstraints.gridx = 1; + messagePanelConstraints.insets = new Insets(0, 0, 0, 0); + messagePanelConstraints.weightx = 1; + messagePanel.add(labelsPanel, messagePanelConstraints); + + okButton.setName("ok"); + this.cancelButton.setName("cancel"); + + okButton.setMnemonic( + OsDependentActivator.getResources() + .getI18nMnemonic("service.gui.OK")); + this.cancelButton.setMnemonic( + OsDependentActivator.getResources() + .getI18nMnemonic("service.gui.CANCEL")); + + okButton.addActionListener(this); + this.cancelButton.addActionListener(this); + + JPanel buttonsPanel = + new TransparentPanel(new FlowLayout(FlowLayout.RIGHT)); + buttonsPanel.add(okButton); + buttonsPanel.add(cancelButton); + + JPanel mainPanel = new TransparentPanel(new GridBagLayout()); + mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 10, 0, 10)); + + GridBagConstraints mainPanelConstraints = new GridBagConstraints(); + mainPanelConstraints.anchor = GridBagConstraints.NORTH; + mainPanelConstraints.fill = GridBagConstraints.BOTH; + mainPanelConstraints.gridx = 0; + mainPanelConstraints.gridy = 0; + mainPanelConstraints.weightx = 1; + mainPanelConstraints.weighty = 1; + mainPanel.add(messagePanel, mainPanelConstraints); + mainPanelConstraints.anchor = GridBagConstraints.SOUTHEAST; + mainPanelConstraints.fill = GridBagConstraints.NONE; + mainPanelConstraints.gridy = 1; + mainPanelConstraints.weightx = 0; + mainPanelConstraints.weighty = 0; + mainPanel.add(buttonsPanel, mainPanelConstraints); + + this.getContentPane().add(mainPanel); + } + + /** + * Handles the <tt>ActionEvent</tt>. In order to change the status message + * with the new one calls the <tt>PublishStatusMessageThread</tt>. + */ + public void actionPerformed(ActionEvent e) + { + JButton button = (JButton)e.getSource(); + String name = button.getName(); + + if (name.equals("ok")) + { + new PublishStatusMessageThread(messageTextField.getText()).start(); + } + + this.dispose(); + } + + /** + * Requests the focus in the text field contained in this + * dialog. + */ + public void requestFocusInFiled() + { + this.messageTextField.requestFocus(); + } + + /** + * This class allow to use a thread to change the presence status message. + */ + private class PublishStatusMessageThread extends Thread + { + private String message; + + private PresenceStatus currentStatus; + + private OperationSetPresence presenceOpSet; + + public PublishStatusMessageThread(String message) + { + this.message = message; + + presenceOpSet + = (OperationSetPersistentPresence) protocolProvider + .getOperationSet(OperationSetPresence.class); + + this.currentStatus = presenceOpSet.getPresenceStatus(); + } + + public void run() + { + try + { + presenceOpSet.publishPresenceStatus(currentStatus, message); + } + catch (IllegalArgumentException e1) + { + + logger.error("Error - changing status", e1); + } + catch (IllegalStateException e1) + { + + logger.error("Error - changing status", e1); + } + catch (OperationFailedException e1) + { + + if (e1.getErrorCode() + == OperationFailedException.GENERAL_ERROR) + { + logger.error( + "General error occured while " + + "publishing presence status.", + e1); + } + else if (e1.getErrorCode() + == OperationFailedException + .NETWORK_FAILURE) + { + logger.error( + "Network failure occured while " + + "publishing presence status.", + e1); + } + else if (e1.getErrorCode() + == OperationFailedException + .PROVIDER_NOT_REGISTERED) + { + logger.error( + "Protocol provider must be" + + "registered in order to change status.", + e1); + } + } + } + } + + protected void close(boolean isEscaped) + { + cancelButton.doClick(); + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/OsDependentActivator.java b/src/net/java/sip/communicator/impl/osdependent/OsDependentActivator.java new file mode 100644 index 0000000..8f548c9 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/OsDependentActivator.java @@ -0,0 +1,153 @@ +/* + * 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.osdependent; + +import net.java.sip.communicator.impl.osdependent.jdic.*; +import net.java.sip.communicator.service.configuration.*; +import net.java.sip.communicator.service.desktop.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.resources.*; +import net.java.sip.communicator.service.systray.*; +import net.java.sip.communicator.util.*; + +import org.osgi.framework.*; + +/** + * Registers the <tt>Systray</tt> in the UI Service. + * + * @author Nicolas Chamouard + */ +public class OsDependentActivator + implements BundleActivator +{ + /** + * A currently valid bundle context. + */ + public static BundleContext bundleContext; + + public static UIService uiService; + + private static ConfigurationService configService; + + private static ResourceManagementService resourcesService; + + private static final Logger logger = + Logger.getLogger(OsDependentActivator.class); + + /** + * Called when this bundle is started. + * + * @param bc The execution context of the bundle being started. + * @throws Exception If + */ + public void start(BundleContext bc) + throws Exception + { + bundleContext = bc; + + try { + // Create the notification service implementation + SystrayService systrayService = new SystrayServiceJdicImpl(); + + logger.info("Systray Service...[ STARTED ]"); + + bundleContext.registerService( + SystrayService.class.getName(), + systrayService, + null); + + logger.info("Systray Service ...[REGISTERED]"); + + // Create the desktop service implementation + DesktopService desktopService = new DesktopServiceImpl(); + + logger.info("Desktop Service...[ STARTED ]"); + + bundleContext.registerService( + DesktopService.class.getName(), + desktopService, + null); + + logger.info("Desktop Service ...[REGISTERED]"); + + logger.logEntry(); + } + finally { + logger.logExit(); + } + } + + /** + * Called when this bundle is stopped so the Framework can perform the + * bundle-specific activities necessary to stop the bundle. + * + * @param bc The execution context of the bundle being stopped. + * @throws Exception If this method throws an exception, the bundle is + * still marked as stopped, and the Framework will remove the bundle's + * listeners, unregister all services registered by the bundle, and + * release all services used by the bundle. + */ + public void stop(BundleContext bc) + 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>UIService</tt> obtained from the bundle + * context. + * @return the <tt>UIService</tt> obtained from the bundle + * context + */ + public static UIService getUIService() + { + if(uiService == null) + { + ServiceReference serviceRef = bundleContext + .getServiceReference(UIService.class.getName()); + + if (serviceRef != null) + uiService = (UIService) bundleContext.getService(serviceRef); + } + + return uiService; + } + + /** + * Returns the <tt>ResourceManagementService</tt>, through which we will + * access all resources. + * + * @return the <tt>ResourceManagementService</tt>, through which we will + * access all resources. + */ + public static ResourceManagementService getResources() + { + if (resourcesService == null) + resourcesService = + ResourceManagementServiceUtils.getService(bundleContext); + return resourcesService; + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/PopupMessageHandlerTrayIconImpl.java b/src/net/java/sip/communicator/impl/osdependent/PopupMessageHandlerTrayIconImpl.java new file mode 100644 index 0000000..55211db --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/PopupMessageHandlerTrayIconImpl.java @@ -0,0 +1,130 @@ +/* + * 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.osdependent; + +import java.awt.event.*; +import java.util.*; + +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 OsDependentActivator.getResources() + .getI18NString("impl.systray.POPUP_MESSAGE_HANDLER"); + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/Resources.java b/src/net/java/sip/communicator/impl/osdependent/Resources.java new file mode 100644 index 0000000..ec63890 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/Resources.java @@ -0,0 +1,88 @@ +/* + * 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.osdependent; + +import java.net.*; + +import javax.swing.*; + +import net.java.sip.communicator.service.resources.*; + +/** + * The Messages class manages the access to the internationalization + * properties files. + * + * @author Nicolas Chamouard + */ +public class Resources +{ + private static ResourceManagementService resourcesService; + + /** + * Returns an internationalized string corresponding to the given key. + * + * @param key The key of the string. + * @return An internationalized string corresponding to the given key. + */ + public static String getString(String key) + { + return getResources().getI18NString(key); + } + + /** + * Returns an internationalized string corresponding to the given key. + * + * @param key The key of the string. + * @return An internationalized string corresponding to the given key. + */ + public static char getMnemonic(String key) + { + return getResources().getI18nMnemonic(key); + } + + /** + * Loads an image from a given image identifier. + * + * @param imageID The identifier of the image. + * @return The image for the given identifier. + */ + public static ImageIcon getImage(String imageID) + { + return getResources().getImage(imageID); + } + + /** + * Loads an image url from a given image identifier. + * + * @param imageID The identifier of the image. + * @return The image url for the given identifier. + */ + public static URL getImageURL(String imageID) + { + return getResources().getImageURL(imageID); + } + + /** + * Returns the application property string corresponding to the given key. + * + * @param key The key of the string. + * @return the application property string corresponding to the given key + */ + public static String getApplicationString(String key) + { + return getResources().getSettingsString(key); + } + + public static ResourceManagementService getResources() + { + if (resourcesService == null) + resourcesService = + ResourceManagementServiceUtils + .getService(OsDependentActivator.bundleContext); + return resourcesService; + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/StatusMessageMenu.java b/src/net/java/sip/communicator/impl/osdependent/StatusMessageMenu.java new file mode 100644 index 0000000..44b2a26 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/StatusMessageMenu.java @@ -0,0 +1,191 @@ +/* + * 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.osdependent; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +public class StatusMessageMenu + implements ActionListener +{ + private final Logger logger = Logger.getLogger(StatusMessageMenu.class); + + private static final String BRB_MESSAGE + = Resources.getString("service.gui.BRB_MESSAGE"); + + private static final String BUSY_MESSAGE + = Resources.getString("service.gui.BUSY_MESSAGE"); + + private final Object newMessageItem; + + private final Object busyMessageItem; + + private final Object brbMessageItem; + + private final ProtocolProviderService protocolProvider; + + private final Object menu; + + public StatusMessageMenu(ProtocolProviderService protocolProvider, + boolean swing) + { + this.protocolProvider = protocolProvider; + + String text = Resources.getString("service.gui.SET_STATUS_MESSAGE"); + if (swing) + menu = new JMenu(text); + else + menu = new Menu(text); + + createMenuItem(Resources.getString("service.gui.NO_MESSAGE")); + newMessageItem = + createMenuItem(Resources.getString("service.gui.NEW_MESSAGE")); + + addSeparator(); + + busyMessageItem = createMenuItem(BUSY_MESSAGE); + brbMessageItem = createMenuItem(BRB_MESSAGE); + } + + private Object createMenuItem(String text) + { + if (menu instanceof Container) + { + JMenuItem menuItem = new JMenuItem(text); + menuItem.addActionListener(this); + ((Container) menu).add(menuItem); + return menuItem; + } + else + { + MenuItem menuItem = new MenuItem(text); + menuItem.addActionListener(this); + ((Menu) menu).add(menuItem); + return menuItem; + } + } + + private void addSeparator() + { + if (menu instanceof JMenu) + ((JMenu) menu).addSeparator(); + else + ((Menu) menu).addSeparator(); + } + + public Object getMenu() + { + return menu; + } + + public void actionPerformed(ActionEvent e) + { + Object menuItem = e.getSource(); + + String statusMessage = ""; + + if (menuItem.equals(newMessageItem)) + { + NewStatusMessageDialog dialog = + new NewStatusMessageDialog(protocolProvider); + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + + dialog.setLocation(screenSize.width / 2 - dialog.getWidth() / 2, + screenSize.height / 2 - dialog.getHeight() / 2); + + dialog.setVisible(true); + + dialog.requestFocusInFiled(); + } + else if (menuItem.equals(busyMessageItem)) + { + statusMessage = BUSY_MESSAGE; + } + else if (menuItem.equals(brbMessageItem)) + { + statusMessage = BRB_MESSAGE; + } + + new PublishStatusMessageThread(statusMessage).start(); + } + + /** + * This class allow to use a thread to change the presence status. + */ + private class PublishStatusMessageThread extends Thread + { + private String message; + + private PresenceStatus currentStatus; + + private OperationSetPresence presenceOpSet; + + public PublishStatusMessageThread(String message) + { + this.message = message; + + presenceOpSet + = (OperationSetPersistentPresence) protocolProvider + .getOperationSet(OperationSetPresence.class); + + this.currentStatus = presenceOpSet.getPresenceStatus(); + } + + public void run() + { + try + { + presenceOpSet.publishPresenceStatus(currentStatus, message); + } + catch (IllegalArgumentException e1) + { + + logger.error("Error - changing status", e1); + } + catch (IllegalStateException e1) + { + + logger.error("Error - changing status", e1); + } + catch (OperationFailedException e1) + { + + if (e1.getErrorCode() + == OperationFailedException.GENERAL_ERROR) + { + logger.error( + "General error occured while " + + "publishing presence status.", + e1); + } + else if (e1.getErrorCode() + == OperationFailedException + .NETWORK_FAILURE) + { + logger.error( + "Network failure occured while " + + "publishing presence status.", + e1); + } + else if (e1.getErrorCode() + == OperationFailedException + .PROVIDER_NOT_REGISTERED) + { + logger.error( + "Protocol provider must be" + + "registered in order to change status.", + e1); + } + } + } + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/SystemTray.java b/src/net/java/sip/communicator/impl/osdependent/SystemTray.java new file mode 100644 index 0000000..7e98385 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/SystemTray.java @@ -0,0 +1,230 @@ +/*
+ * 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.osdependent;
+
+import java.awt.*;
+import java.lang.reflect.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.osdependent.TrayIcon.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class SystemTray
+{
+ private static final Logger logger = Logger.getLogger(SystemTray.class);
+
+ private static SystemTray defaultSystemTray;
+
+ public static SystemTray getDefaultSystemTray()
+ throws UnsupportedOperationException,
+ HeadlessException,
+ SecurityException
+ {
+ if (defaultSystemTray != null)
+ return defaultSystemTray;
+
+ Class<?> awtSystemTrayClass = null;
+ try
+ {
+ awtSystemTrayClass = Class.forName("java.awt.SystemTray");
+ }
+ catch (ClassNotFoundException ex)
+ {
+ // We'll try org.jdesktop.jdic.tray then.
+ }
+ SystemTrayPeer peer = null;
+ if (awtSystemTrayClass != null)
+ try
+ {
+ peer = new AWTSystemTrayPeer(awtSystemTrayClass);
+ }
+ catch (Exception ex)
+ {
+ logger.error(
+ "Failed to initialize the java.awt.SystemTray implementation.",
+ ex);
+
+ // We'll try org.jdesktop.jdic.tray then.
+ }
+ if (peer == null)
+ try
+ {
+ peer = new JdicSystemTrayPeer();
+ }
+ catch (Exception ex)
+ {
+ logger.error(
+ "Failed to initialize the org.jdesktop.jdic.tray implementation.",
+ ex);
+ }
+ return (defaultSystemTray = new SystemTray(peer));
+ }
+
+ private final SystemTrayPeer peer;
+
+ private SystemTray(SystemTrayPeer peer)
+ {
+ this.peer = peer;
+ }
+
+ public void addTrayIcon(TrayIcon trayIcon)
+ throws NullPointerException,
+ IllegalArgumentException
+ {
+ if (peer != null)
+ peer.addTrayIcon(trayIcon.getPeer());
+ }
+
+ SystemTrayPeer getPeer()
+ {
+ return peer;
+ }
+
+ public boolean isSwing()
+ {
+ if (peer != null)
+ return getPeer().isSwing();
+ return false;
+ }
+
+ static interface SystemTrayPeer
+ {
+ void addTrayIcon(TrayIconPeer trayIconPeer)
+ throws NullPointerException,
+ IllegalArgumentException;
+
+ TrayIconPeer createTrayIcon(ImageIcon icon,
+ String tooltip,
+ Object popup)
+ throws IllegalArgumentException,
+ UnsupportedOperationException,
+ HeadlessException,
+ SecurityException;
+
+ boolean isSwing();
+ }
+
+ private static class AWTSystemTrayPeer
+ implements SystemTrayPeer
+ {
+ private final Method addTrayIcon;
+
+ private final Object impl;
+
+ private final Class<?> trayIconClass;
+
+ public AWTSystemTrayPeer(Class<?> clazz)
+ throws UnsupportedOperationException,
+ HeadlessException,
+ SecurityException
+ {
+ Method getDefaultSystemTray;
+ try
+ {
+ getDefaultSystemTray =
+ clazz.getMethod("getSystemTray", (Class<?>[]) null);
+ trayIconClass = Class.forName("java.awt.TrayIcon");
+ addTrayIcon = clazz.getMethod("add", new Class<?>[]
+ { trayIconClass });
+ }
+ catch (ClassNotFoundException ex)
+ {
+ throw new UnsupportedOperationException(ex);
+ }
+ catch (NoSuchMethodException ex)
+ {
+ throw new UnsupportedOperationException(ex);
+ }
+
+ try
+ {
+ impl = getDefaultSystemTray.invoke(null, (Object[]) null);
+ }
+ catch (IllegalAccessException ex)
+ {
+ throw new UnsupportedOperationException(ex);
+ }
+ catch (InvocationTargetException ex)
+ {
+ throw new UnsupportedOperationException(ex);
+ }
+ }
+
+ public void addTrayIcon(TrayIconPeer trayIconPeer)
+ throws NullPointerException,
+ IllegalArgumentException
+ {
+ try
+ {
+ addTrayIcon.invoke(impl, new Object[]
+ { ((AWTTrayIconPeer) trayIconPeer).getImpl() });
+ }
+ catch (IllegalAccessException ex)
+ {
+ throw new UndeclaredThrowableException(ex);
+ }
+ catch (InvocationTargetException ex)
+ {
+ Throwable cause = ex.getCause();
+ if (cause == null)
+ throw new UndeclaredThrowableException(ex);
+ if (cause instanceof NullPointerException)
+ throw (NullPointerException) cause;
+ if (cause instanceof IllegalArgumentException)
+ throw (IllegalArgumentException) cause;
+ throw new UndeclaredThrowableException(cause);
+ }
+ }
+
+ public TrayIconPeer createTrayIcon(ImageIcon icon, String tooltip,
+ Object popup)
+ throws IllegalArgumentException,
+ UnsupportedOperationException,
+ HeadlessException,
+ SecurityException
+ {
+ return new AWTTrayIconPeer(trayIconClass, (icon == null) ? null
+ : icon.getImage(), tooltip, popup);
+ }
+
+ public boolean isSwing()
+ {
+ return false;
+ }
+ }
+
+ private static class JdicSystemTrayPeer
+ implements SystemTrayPeer
+ {
+ private final org.jdesktop.jdic.tray.SystemTray impl;
+
+ public JdicSystemTrayPeer()
+ {
+ impl = org.jdesktop.jdic.tray.SystemTray.getDefaultSystemTray();
+ }
+
+ public void addTrayIcon(TrayIconPeer trayIconPeer)
+ {
+ impl.addTrayIcon(((JdicTrayIconPeer) trayIconPeer).getImpl());
+ }
+
+ public TrayIconPeer createTrayIcon(ImageIcon icon, String tooltip,
+ Object popup)
+ {
+ return new JdicTrayIconPeer(icon, tooltip, (JPopupMenu) popup);
+ }
+
+ public boolean isSwing()
+ {
+ return true;
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/osdependent/TrayIcon.java b/src/net/java/sip/communicator/impl/osdependent/TrayIcon.java new file mode 100644 index 0000000..f18b015 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/TrayIcon.java @@ -0,0 +1,445 @@ +/*
+ * 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.osdependent;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.lang.reflect.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+import net.java.sip.communicator.impl.osdependent.SystemTray.*;
+
+/**
+ * @author Lubomir Marinov
+ */
+public class TrayIcon
+{
+ public static final int ERROR_MESSAGE_TYPE =
+ org.jdesktop.jdic.tray.TrayIcon.ERROR_MESSAGE_TYPE;
+
+ public static final int INFO_MESSAGE_TYPE =
+ org.jdesktop.jdic.tray.TrayIcon.INFO_MESSAGE_TYPE;
+
+ public static final int NONE_MESSAGE_TYPE =
+ org.jdesktop.jdic.tray.TrayIcon.NONE_MESSAGE_TYPE;
+
+ public static final int WARNING_MESSAGE_TYPE =
+ org.jdesktop.jdic.tray.TrayIcon.WARNING_MESSAGE_TYPE;
+
+ private final TrayIconPeer peer;
+
+ public TrayIcon(ImageIcon icon, String tooltip, Object popup)
+ throws IllegalArgumentException,
+ UnsupportedOperationException,
+ HeadlessException,
+ SecurityException
+ {
+ SystemTrayPeer systemTrayPeer =
+ SystemTray.getDefaultSystemTray().getPeer();
+ if (systemTrayPeer != null)
+ peer = systemTrayPeer.createTrayIcon(icon, tooltip, popup);
+ else
+ peer = null;
+ }
+
+ public void addActionListener(ActionListener listener)
+ {
+ if (peer != null)
+ peer.addActionListener(listener);
+ }
+
+ public void addBalloonActionListener(ActionListener listener)
+ {
+ if (peer != null)
+ peer.addBalloonActionListener(listener);
+ }
+
+ public void displayMessage(String caption, String text, int messageType)
+ throws NullPointerException
+ {
+ if (peer != null)
+ peer.displayMessage(caption, text, messageType);
+ }
+
+ TrayIconPeer getPeer()
+ {
+ return peer;
+ }
+
+ public void setIcon(ImageIcon icon) throws NullPointerException
+ {
+ if (peer != null)
+ peer.setIcon(icon);
+ }
+
+ public void setIconAutoSize(boolean autoSize)
+ {
+ if (peer != null)
+ peer.setIconAutoSize(autoSize);
+ }
+
+ static interface TrayIconPeer
+ {
+ void addActionListener(ActionListener listener);
+
+ void addBalloonActionListener(ActionListener listener);
+
+ void displayMessage(String caption, String text, int messageType)
+ throws NullPointerException;
+
+ void setIcon(ImageIcon icon) throws NullPointerException;
+
+ void setIconAutoSize(boolean autoSize);
+ }
+
+ static class AWTTrayIconPeer
+ implements TrayIconPeer
+ {
+ private final Method addActionListener;
+
+ private final Method addMouseListener;
+
+ private final Method displayMessage;
+
+ private final Object impl;
+
+ private final Class<?> messageTypeClass;
+
+ private final Method setIcon;
+
+ private final Method setIconAutoSize;
+
+ public AWTTrayIconPeer(Class<?> clazz, Image image, String tooltip,
+ Object popup)
+ throws IllegalArgumentException,
+ UnsupportedOperationException,
+ HeadlessException,
+ SecurityException
+ {
+ Constructor<?> constructor;
+ try
+ {
+ if (popup instanceof JPopupMenu)
+ {
+ constructor = clazz.getConstructor(new Class<?>[]
+ { Image.class, String.class });
+ }
+ else
+ {
+ constructor = clazz.getConstructor(new Class<?>[]
+ { Image.class, String.class, PopupMenu.class });
+ }
+ addActionListener =
+ clazz.getMethod("addActionListener", new Class<?>[]
+ { ActionListener.class });
+ addMouseListener =
+ clazz.getMethod("addMouseListener", new Class<?>[]
+ { MouseListener.class });
+ messageTypeClass =
+ Class.forName("java.awt.TrayIcon$MessageType");
+ displayMessage =
+ clazz.getMethod("displayMessage", new Class<?>[]
+ { String.class, String.class, messageTypeClass });
+ setIcon = clazz.getMethod("setImage", new Class<?>[]
+ { Image.class });
+ setIconAutoSize =
+ clazz.getMethod("setImageAutoSize", new Class<?>[]
+ { boolean.class });
+ }
+ catch (ClassNotFoundException ex)
+ {
+ throw new UnsupportedOperationException(ex);
+ }
+ catch (NoSuchMethodException ex)
+ {
+ throw new UnsupportedOperationException(ex);
+ }
+
+ try
+ {
+ if (popup instanceof JPopupMenu)
+ {
+ impl = constructor.newInstance(
+ new Object[] { image, tooltip });
+ addMouseListener(new AWTMouseAdapter((JPopupMenu) popup));
+ }
+ else
+ {
+ impl = constructor.newInstance(
+ new Object[] { image, tooltip, popup });
+ }
+ }
+ catch (IllegalAccessException ex)
+ {
+ throw new UnsupportedOperationException(ex);
+ }
+ catch (InstantiationException ex)
+ {
+ throw new UnsupportedOperationException(ex);
+ }
+ catch (InvocationTargetException ex)
+ {
+ Throwable cause = ex.getCause();
+ if (cause == null)
+ throw new UnsupportedOperationException(ex);
+ if (cause instanceof IllegalArgumentException)
+ throw (IllegalArgumentException) cause;
+ if (cause instanceof UnsupportedOperationException)
+ throw (UnsupportedOperationException) cause;
+ if (cause instanceof HeadlessException)
+ throw (HeadlessException) cause;
+ if (cause instanceof SecurityException)
+ throw (SecurityException) cause;
+ throw new UnsupportedOperationException(cause);
+ }
+ }
+
+ public void addActionListener(ActionListener listener)
+ {
+ try
+ {
+ addActionListener.invoke(getImpl(), new Object[]
+ { listener });
+ }
+ catch (IllegalAccessException ex)
+ {
+ throw new UndeclaredThrowableException(ex);
+ }
+ catch (InvocationTargetException ex)
+ {
+ Throwable cause = ex.getCause();
+ throw new UndeclaredThrowableException((cause == null) ? ex
+ : cause);
+ }
+ }
+
+ public void addMouseListener(MouseListener listener)
+ {
+ try
+ {
+ addMouseListener.invoke(getImpl(), new Object[] { listener });
+ }
+ catch (IllegalAccessException ex)
+ {
+ throw new UndeclaredThrowableException(ex);
+ }
+ catch (InvocationTargetException ex)
+ {
+ Throwable cause = ex.getCause();
+ throw new UndeclaredThrowableException((cause == null) ? ex
+ : cause);
+ }
+ }
+
+ public void addBalloonActionListener(ActionListener listener)
+ {
+ // java.awt.TrayIcon doesn't support addBalloonActionListener()
+ }
+
+ public void displayMessage(String caption, String text, int messageType)
+ throws NullPointerException
+ {
+ try
+ {
+ displayMessage.invoke(getImpl(), new Object[]
+ { caption, text, getMessageType(messageType) });
+ }
+ catch (IllegalAccessException ex)
+ {
+ throw new UndeclaredThrowableException(ex);
+ }
+ catch (InvocationTargetException ex)
+ {
+ Throwable cause = ex.getCause();
+ if (cause instanceof NullPointerException)
+ throw (NullPointerException) cause;
+ throw new UndeclaredThrowableException((cause == null) ? ex
+ : cause);
+ }
+ }
+
+ public Object getImpl()
+ {
+ return impl;
+ }
+
+ private Object getMessageType(int messageType)
+ {
+ Object[] constants = messageTypeClass.getEnumConstants();
+ String name;
+ switch (messageType)
+ {
+ case ERROR_MESSAGE_TYPE:
+ name = "ERROR";
+ break;
+ case INFO_MESSAGE_TYPE:
+ name = "INFO";
+ break;
+ case NONE_MESSAGE_TYPE:
+ name = "NONE";
+ break;
+ case WARNING_MESSAGE_TYPE:
+ name = "WARNING";
+ break;
+ default:
+ throw new IllegalArgumentException("messageType");
+ }
+ for (int i = 0; i < constants.length; i++)
+ {
+ Object constant = constants[i];
+ if (name.equals(constant.toString()))
+ return constant;
+ }
+ throw new IllegalArgumentException("messageType");
+ }
+
+ public void setIcon(ImageIcon icon) throws NullPointerException
+ {
+ try
+ {
+ setIcon.invoke(getImpl(), new Object[]
+ { (icon == null) ? null : icon.getImage() });
+ }
+ catch (IllegalAccessException ex)
+ {
+ throw new UndeclaredThrowableException(ex);
+ }
+ catch (InvocationTargetException ex)
+ {
+ Throwable cause = ex.getCause();
+ if (cause instanceof NullPointerException)
+ throw (NullPointerException) cause;
+ throw new UndeclaredThrowableException((cause == null) ? ex
+ : cause);
+ }
+ }
+
+ public void setIconAutoSize(boolean autoSize)
+ {
+ try
+ {
+ setIconAutoSize.invoke(getImpl(), new Object[]
+ { autoSize });
+ }
+ catch (IllegalAccessException ex)
+ {
+ throw new UndeclaredThrowableException(ex);
+ }
+ catch (InvocationTargetException ex)
+ {
+ Throwable cause = ex.getCause();
+ throw new UndeclaredThrowableException((cause == null) ? ex
+ : cause);
+ }
+ }
+ }
+
+ static class JdicTrayIconPeer
+ implements TrayIconPeer
+ {
+ private final org.jdesktop.jdic.tray.TrayIcon impl;
+
+ public JdicTrayIconPeer(ImageIcon icon, String tooltip, JPopupMenu popup)
+ {
+ impl = new org.jdesktop.jdic.tray.TrayIcon(icon, tooltip, popup);
+ }
+
+ public void addActionListener(ActionListener listener)
+ {
+ getImpl().addActionListener(listener);
+ }
+
+ public void addBalloonActionListener(ActionListener listener)
+ {
+ getImpl().addBalloonActionListener(listener);
+ }
+
+ public void displayMessage(String caption, String text, int messageType)
+ throws NullPointerException
+ {
+ getImpl().displayMessage(caption, text, messageType);
+ }
+
+ org.jdesktop.jdic.tray.TrayIcon getImpl()
+ {
+ return impl;
+ }
+
+ public void setIcon(ImageIcon icon)
+ {
+ getImpl().setIcon(icon);
+ }
+
+ public void setIconAutoSize(boolean autoSize)
+ {
+ getImpl().setIconAutoSize(autoSize);
+ }
+ }
+
+ /**
+ * Extended mouse adapter to show the JpopupMenu in java 6
+ * Based on : http://weblogs.java.net/blog/ixmal/archive/2006/05/using_jpopupmen.html
+ *
+ * Use a JWindow as a parent to manage the JPopupMenu
+ *
+ * @author Damien Roth
+ */
+ private static class AWTMouseAdapter
+ extends MouseAdapter
+ {
+ private final JPopupMenu popup;
+ private static boolean popupVisible = false;
+ private static JWindow hiddenWindow;
+
+ public AWTMouseAdapter(JPopupMenu p)
+ {
+ hiddenWindow = new JWindow();
+ hiddenWindow.setAlwaysOnTop(true);
+
+ this.popup = p;
+ this.popup.addPopupMenuListener(new PopupMenuListener()
+ {
+ public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
+ }
+
+ public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
+ hiddenWindow.setVisible(false);
+ popupVisible = false;
+ }
+
+ public void popupMenuCanceled(PopupMenuEvent e) {
+ hiddenWindow.setVisible(false);
+ popupVisible = false;
+ }
+ });
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ // Trick used here, the isVisible function always return false
+ // So we manage this manually
+ if (e.getButton() == MouseEvent.BUTTON3 && !popupVisible)
+ {
+ int x = e.getX(), y = e.getY();
+
+ hiddenWindow.setLocation(x, y);
+ hiddenWindow.setVisible(true);
+ this.popup.show(hiddenWindow, 0, 0);
+ hiddenWindow.toFront();
+
+ popupVisible = true;
+ }
+ else
+ {
+ popup.setVisible(false);
+ popupVisible = false;
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderRegistration.java b/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderRegistration.java new file mode 100644 index 0000000..b5f7630 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderRegistration.java @@ -0,0 +1,88 @@ +/* + * 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.osdependent.jdic; + +import net.java.sip.communicator.impl.osdependent.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +/** + * The <tt>ProviderRegistration</tt> is used by the systray plugin + * to make the registration to a protocol provider. This operation + * is implemented within a thread, so that sip-communicator can + * continue its execution during this operation. + * + * @author Nicolas Chamouard + * @author Emil Ivov + */ + +public class ProviderRegistration + extends Thread +{ + /** + * The protocol provider to whom we want to register + */ + private ProtocolProviderService protocolProvider; + + /** + * The logger for this class. + */ + private Logger logger + = Logger.getLogger(ProviderRegistration.class.getName()); + + /** + * Creates an instance of <tt>ProviderRegistration</tt>. + * + * @param protocolProvider the provider we want to register + */ + public ProviderRegistration(ProtocolProviderService protocolProvider) + { + this.protocolProvider = protocolProvider; + } + + /** + * Start the thread which will register to the provider + */ + public void run() + { + try + { + protocolProvider.register(OsDependentActivator.getUIService() + .getDefaultSecurityAuthority(protocolProvider)); + } + catch (OperationFailedException ex) + { + int errorCode = ex.getErrorCode(); + if (errorCode == OperationFailedException.GENERAL_ERROR) + { + logger.error("Provider could not be registered" + + " due to the following general error: ", ex); + } + else if (errorCode == OperationFailedException.INTERNAL_ERROR) + { + logger.error("Provider could not be registered" + + " due to the following internal error: ", ex); + } + else if (errorCode == OperationFailedException.NETWORK_FAILURE) + { + logger.error("Provider could not be registered" + + " due to a network failure: " + ex); + } + else if (errorCode == OperationFailedException + .INVALID_ACCOUNT_PROPERTIES) + { + logger.error("Provider could not be registered" + + " due to an invalid account property: ", ex); + } + else + { + logger.error("Provider could not be registered.", ex); + } + } + } + } diff --git a/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderUnRegistration.java b/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderUnRegistration.java new file mode 100644 index 0000000..11d30fd --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderUnRegistration.java @@ -0,0 +1,82 @@ +/* + * 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.osdependent.jdic; + +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +/** + * The <tt>ProviderUnRegistration</tt> is used by the systray plugin + * to make the unregistration to a protocol provider. This operation + * is implemented within a thread, so that sip-communicator can + * continue its execution smoothly. + * + * @author Nicolas Chamouard + */ +public class ProviderUnRegistration + extends Thread +{ + /** + * The protocol provider to whom we want to unregister + */ + ProtocolProviderService protocolProvider; + /** + * The logger for this class. + */ + private Logger logger + = Logger.getLogger(ProviderUnRegistration.class.getName()); + + /** + * Creates an instance of <tt>ProviderUnRegistration</tt>. + * @param protocolProvider the provider we want to unregister + */ + ProviderUnRegistration(ProtocolProviderService protocolProvider) + { + this.protocolProvider = protocolProvider; + } + + /** + * Start the thread which will unregister to the provider + */ + public void run() + { + try + { + protocolProvider.unregister(); + } + catch (OperationFailedException ex) + { + int errorCode = ex.getErrorCode(); + if (errorCode == OperationFailedException.GENERAL_ERROR) + { + logger.error("Provider could not be unregistered" + + " due to the following general error: ", ex); + } + else if (errorCode == OperationFailedException.INTERNAL_ERROR) + { + logger.error("Provider could not be unregistered" + + " due to the following internal error: ", ex); + } + else if (errorCode == OperationFailedException.NETWORK_FAILURE) + { + logger.error("Provider could not be unregistered" + + " due to a network failure: " + ex); + } + else if (errorCode == OperationFailedException + .INVALID_ACCOUNT_PROPERTIES) + { + logger.error("Provider could not be unregistered" + + " due to an invalid account property: ", ex); + } + else + { + logger.error("Provider could not be unregistered.", ex); + } + } + } + }
\ No newline at end of file diff --git a/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSelector.java b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSelector.java new file mode 100644 index 0000000..879f509 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSelector.java @@ -0,0 +1,254 @@ +/* + * 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.osdependent.jdic; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; + +import javax.swing.*; + +import net.java.sip.communicator.impl.osdependent.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; + +/** + * The <tt>StatusSelector</tt> is a submenu which allows to select a status for + * a protocol provider which supports the OperationSetPresence. + * + * @author Nicolas Chamouard + * @author Lubomir Marinov + */ +public class StatusSelector + implements ActionListener +{ + /** + * A reference of <tt>Systray</tt> + */ + private final SystrayServiceJdicImpl parentSystray; + /** + * The protocol provider + */ + private final ProtocolProviderService provider; + /** + * The presence status + */ + private final OperationSetPresence presence; + + /** + * The logger for this class. + */ + private final Logger logger = Logger.getLogger(StatusSelector.class); + + private final Object menu; + + /** + * Creates an instance of StatusSelector + * + * @param jdicSystray a reference of the parent <tt>Systray</tt> + * @param provider the protocol provider + * @param presence the presence status + */ + public StatusSelector(SystrayServiceJdicImpl jdicSystray, + ProtocolProviderService provider, OperationSetPresence presence, + boolean swing) + { + this.parentSystray = jdicSystray; + this.provider = provider; + this.presence = presence; + + /* the parent item */ + { + String text = provider.getAccountID().getUserID(); + if (swing) + { + JMenu menu = new JMenu(text); + menu.setIcon(new ImageIcon(presence.getPresenceStatus() + .getStatusIcon())); + + this.menu = menu; + } + else + { + this.menu = new Menu(text); + } + } + + /* the submenu itself */ + + Iterator<PresenceStatus> statusIterator + = this.presence.getSupportedStatusSet(); + + while (statusIterator.hasNext()) + { + PresenceStatus status = statusIterator.next(); + String text = status.getStatusName(); + + if (menu instanceof Container) + { + ImageIcon icon = new ImageIcon(status.getStatusIcon()); + JMenuItem item = new JMenuItem(text, icon); + + item.addActionListener(this); + + ((Container) menu).add(item); + } + else + { + MenuItem item = new MenuItem(text); + item.addActionListener(this); + ((Menu) menu).add(item); + } + } + + addSeparator(); + + StatusSubMenu.addMenuItem(menu, new StatusMessageMenu(provider, swing) + .getMenu()); + } + + private void addSeparator() + { + if (menu instanceof JMenu) + ((JMenu) menu).addSeparator(); + else + ((Menu) menu).addSeparator(); + } + + public Object getMenu() + { + return menu; + } + + /** + * Change the status of the protocol according to the menu item selected + * + * @param evt the event containing the menu item name + */ + public void actionPerformed(ActionEvent evt) + { + Object source = evt.getSource(); + String menuItemText; + if (source instanceof AbstractButton) + menuItemText = ((AbstractButton) source).getText(); + else + menuItemText = ((MenuItem) source).getLabel(); + + Iterator<PresenceStatus> statusSet = presence.getSupportedStatusSet(); + + while (statusSet.hasNext()) + { + PresenceStatus status = statusSet.next(); + + if (status.getStatusName().equals(menuItemText)) + { + RegistrationState registrationState = + provider.getRegistrationState(); + + if (registrationState == RegistrationState.REGISTERED + && !presence.getPresenceStatus().equals(status)) + { + if (status.isOnline()) + new PublishPresenceStatusThread(status).start(); + else + new ProviderUnRegistration(this.provider).start(); + } + else if (registrationState != RegistrationState.REGISTERED + && registrationState != RegistrationState.REGISTERING + && registrationState != RegistrationState.AUTHENTICATING + && status.isOnline()) + { + new ProviderRegistration(provider).start(); + } + else if (!status.isOnline() + && !(registrationState == RegistrationState.UNREGISTERING)) + { + new ProviderUnRegistration(this.provider).start(); + } + + parentSystray.saveStatusInformation(provider, status + .getStatusName()); + + break; + } + } + } + + /** + * Stops the timer that manages the connecting animated icon. + */ + public void updateStatus(PresenceStatus presenceStatus) + { + logger.trace("Systray update status for provider: " + + provider.getAccountID().getAccountAddress() + + ". The new status will be: " + presenceStatus.getStatusName()); + + if (menu instanceof AbstractButton) + ((AbstractButton) menu).setIcon(new ImageIcon(presenceStatus + .getStatusIcon())); + } + + /** + * This class allow to use a thread to change the presence status. + */ + private class PublishPresenceStatusThread extends Thread + { + PresenceStatus status; + + public PublishPresenceStatusThread(PresenceStatus status) + { + this.status = status; + } + + public void run() + { + try { + presence.publishPresenceStatus(status, ""); + } + catch (IllegalArgumentException e1) + { + + logger.error("Error - changing status", e1); + } + catch (IllegalStateException e1) + { + + logger.error("Error - changing status", e1); + } + catch (OperationFailedException e1) + { + + if (e1.getErrorCode() + == OperationFailedException.GENERAL_ERROR) + { + logger.error( + "General error occured while " + + "publishing presence status.", + e1); + } + else if (e1.getErrorCode() + == OperationFailedException + .NETWORK_FAILURE) + { + logger.error( + "Network failure occured while " + + "publishing presence status.", + e1); + } + else if (e1.getErrorCode() + == OperationFailedException + .PROVIDER_NOT_REGISTERED) + { + logger.error( + "Protocol provider must be" + + "registered in order to change status.", + e1); + } + } + } + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSimpleSelector.java b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSimpleSelector.java new file mode 100644 index 0000000..fe2b061 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSimpleSelector.java @@ -0,0 +1,151 @@ +/* + * 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.osdependent.jdic; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +import net.java.sip.communicator.impl.osdependent.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.*; + +/** + * The <tt>StatusSimpleSelector</tt> is a submenu which allow to select a status + * for a protocol provider which does not support the OperationSetPresence + * + * @author Nicolas Chamouard + * @author Lubomir Marinov + */ +public class StatusSimpleSelector + implements ActionListener +{ + + /** + * The protocol provider + */ + private final ProtocolProviderService provider; + + /** + * The logger for this class. + */ + private final Logger logger = Logger.getLogger(StatusSimpleSelector.class); + + private final Object menu; + + /** + * Creates an instance of <tt>StatusSimpleSelector</tt> + * + * @param protocolProvider the protocol provider + */ + public StatusSimpleSelector(ProtocolProviderService protocolProvider, + boolean swing) + { + this.provider = protocolProvider; + + /* the parent item */ + String text = provider.getAccountID().getUserID(); + if (swing) + { + JMenu menu = new JMenu(text); + + ImageIcon icon = + new ImageIcon(protocolProvider.getProtocolIcon().getIcon( + ProtocolIcon.ICON_SIZE_16x16)); + if (!provider.isRegistered()) + { + icon = + new ImageIcon(LightGrayFilter.createDisabledImage(icon + .getImage())); + } + menu.setIcon(icon); + + this.menu = menu; + } + else + { + this.menu = new Menu(text); + } + + /* the menu itself */ + createMenuItem("impl.systray.ONLINE_STATUS", "online"); + createMenuItem("impl.systray.OFFLINE_STATUS", "offline"); + } + + private void createMenuItem(String textKey, String name) + { + String text = Resources.getString(textKey); + if (menu instanceof JMenu) + { + JMenuItem menuItem = new JMenuItem(text); + menuItem.setName(name); + menuItem.addActionListener(this); + ((JMenu) menu).add(menuItem); + } + else + { + MenuItem menuItem = new MenuItem(text); + menuItem.setName(name); + menuItem.addActionListener(this); + ((Menu) menu).add(menuItem); + } + } + + public Object getMenu() + { + return menu; + } + + /** + * Change the status of the protocol according to + * the menu item selected + * @param evt the event containing the menu item name + */ + public void actionPerformed(ActionEvent evt) + { + Object source = evt.getSource(); + String itemName; + if (source instanceof Component) + itemName = ((Component) source).getName(); + else + itemName = ((MenuComponent) source).getName(); + + if(itemName.equals("online")) + { + if(!this.provider.isRegistered()) + { + new ProviderRegistration(provider).start(); + } + } + else + { + if( !this.provider.getRegistrationState() + .equals(RegistrationState.UNREGISTERED) + && !this.provider.getRegistrationState() + .equals(RegistrationState.UNREGISTERING)) + { + new ProviderUnRegistration(this.provider).start(); + } + } + } + + /** + * Stops the timer that manages the connecting animated icon. + */ + public void updateStatus(PresenceStatus presenceStatus) + { + logger.trace("Systray update status for provider: " + + provider.getAccountID().getAccountAddress() + + ". The new status will be: " + presenceStatus.getStatusName()); + + if (menu instanceof AbstractButton) + ((AbstractButton) menu).setIcon(new ImageIcon(presenceStatus + .getStatusIcon())); + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSubMenu.java b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSubMenu.java new file mode 100644 index 0000000..fc3ae09 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSubMenu.java @@ -0,0 +1,271 @@ +/* + * 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.osdependent.jdic; + +import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.util.*; + +import javax.swing.*; + +import net.java.sip.communicator.impl.osdependent.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.protocol.event.*; +import net.java.sip.communicator.util.*; + +import org.osgi.framework.*; + +/** + * The <tt>StatusSubMenu</tt> provides a menu which allow to select the status + * for each of the protocol providers registered when the menu appears + * + * @author Nicolas Chamouard + * @author Lubomir Marinov + */ +public class StatusSubMenu +{ + /** + * A reference of <tt>Systray</tt> + */ + private final SystrayServiceJdicImpl parentSystray; + + /** + * Contains all accounts and corresponding menus. + */ + private final Map<AccountID, Object> accountSelectors = + new Hashtable<AccountID, Object>(); + + private final Logger logger = Logger.getLogger(StatusSubMenu.class); + + private final Object menu; + + /** + * Creates an instance of <tt>StatusSubMenu</tt>. + * + * @param tray a reference of the parent <tt>Systray</tt> + * @param swing <tt>true</tt> to represent this instance with a Swing + * <code>JMenu</code>; <tt>false</tt> to use an AWT + * <code>Menu</code> + */ + public StatusSubMenu(SystrayServiceJdicImpl tray, boolean swing) + { + parentSystray = tray; + + String text = Resources.getString("impl.systray.SET_STATUS"); + if (swing) + { + JMenu menu = new JMenu(text); + menu + .setIcon(Resources.getImage("service.systray.STATUS_MENU_ICON")); + + /* makes the menu look better */ + menu.setPreferredSize(new java.awt.Dimension(28, 24)); + + this.menu = menu; + } + else + { + this.menu = new Menu(text); + } + + this.init(); + } + + public Object getMenu() + { + return menu; + } + + /** + * Adds the account corresponding to the given protocol provider to this + * menu. + * + * @param protocolProvider the protocol provider corresponding to the + * account to add + */ + private void addAccount(ProtocolProviderService protocolProvider) + { + OperationSetPresence presence = + (OperationSetPresence) protocolProvider + .getOperationSet(OperationSetPresence.class); + boolean swing = (menu instanceof JComponent); + + if (presence == null) + { + StatusSimpleSelector simpleSelector = + new StatusSimpleSelector(protocolProvider, swing); + + this.accountSelectors.put(protocolProvider.getAccountID(), + simpleSelector); + addMenuItem(menu, simpleSelector.getMenu()); + } + else + { + StatusSelector statusSelector = + new StatusSelector(parentSystray, protocolProvider, presence, + swing); + + this.accountSelectors.put(protocolProvider.getAccountID(), + statusSelector); + addMenuItem(menu, statusSelector.getMenu()); + + presence + .addProviderPresenceStatusListener(new SystrayProviderPresenceStatusListener()); + } + } + + static void addMenuItem(Object menu, Object menuItem) + { + if (menu instanceof Container) + ((Container) menu).add((Component) menuItem); + else + ((Menu) menu).add((MenuItem) menuItem); + } + + /** + * Removes the account corresponding to the given protocol provider from + * this menu. + * + * @param protocolProvider the protocol provider corresponding to the + * account to remove. + */ + private void removeAccount(ProtocolProviderService protocolProvider) + { + Object selector = + this.accountSelectors.get(protocolProvider.getAccountID()); + Object selectorMenu; + if (selector instanceof StatusSimpleSelector) + selectorMenu = ((StatusSimpleSelector) selector).getMenu(); + else + selectorMenu = ((StatusSelector) selector).getMenu(); + + if (menu instanceof Container) + ((Container) menu).remove((Component) selectorMenu); + else + ((MenuContainer) menu).remove((MenuComponent) selectorMenu); + } + + /** + * We fill the protocolProviderTable with all + * running protocol providers at the start of + * the bundle. + */ + private void init() + { + OsDependentActivator.bundleContext + .addServiceListener(new ProtocolProviderServiceListener()); + + ServiceReference[] protocolProviderRefs = null; + try + { + protocolProviderRefs + = OsDependentActivator.bundleContext.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) OsDependentActivator.bundleContext + .getService(protocolProviderRefs[i]); + + boolean isHidden = + provider.getAccountID().getAccountProperty( + ProtocolProviderFactory.IS_PROTOCOL_HIDDEN) != null; + + if(!isHidden) + this.addAccount(provider); + } + } + } + + /** + * Listens for <tt>ServiceEvent</tt>s indicating that a + * <tt>ProtocolProviderService</tt> has been registered and completes the + * account status menu. + */ + private class ProtocolProviderServiceListener implements ServiceListener + { + /** + * When a service is registered or unregistered, we update + * the provider tables and add/remove listeners (if it supports + * BasicInstantMessenging implementation) + * + * @param event ServiceEvent + */ + public void serviceChanged(ServiceEvent event) + { + //if the event is caused by a bundle being stopped, we don't want to + //know + if(event.getServiceReference().getBundle().getState() + == Bundle.STOPPING) + { + return; + } + + Object service = OsDependentActivator.bundleContext + .getService( event.getServiceReference()); + + if (! (service instanceof ProtocolProviderService)) + return; + + ProtocolProviderService provider = (ProtocolProviderService)service; + + switch (event.getType()) + { + case ServiceEvent.REGISTERED: + addAccount(provider); + break; + + case ServiceEvent.UNREGISTERING: + removeAccount(provider); + break; + } + } + } + + /** + * Listens for all providerStatusChanged and providerStatusMessageChanged + * events in order to refresh the account status panel, when a status is + * changed. + */ + private class SystrayProviderPresenceStatusListener + implements ProviderPresenceStatusListener + { + /** + * Fired when an account has changed its status. We update the icon + * in the menu. + */ + public void providerStatusChanged(ProviderPresenceStatusChangeEvent evt) + { + ProtocolProviderService pps = evt.getProvider(); + + StatusSelector selectorBox + = (StatusSelector) accountSelectors.get(pps.getAccountID()); + + if(selectorBox == null) + return; + + selectorBox.updateStatus(evt.getNewStatus()); + } + + public void providerStatusMessageChanged(PropertyChangeEvent evt) + { + } + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java b/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java new file mode 100644 index 0000000..06dd90f --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java @@ -0,0 +1,661 @@ +/* + * 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.osdependent.jdic; + +import org.osgi.framework.*; + +import java.awt.event.*; +import java.net.*; +import java.util.*; + +import javax.swing.*; +import javax.swing.event.*; + +import net.java.sip.communicator.impl.osdependent.*; +import net.java.sip.communicator.impl.systray.mac.*; +import net.java.sip.communicator.service.configuration.*; +import net.java.sip.communicator.service.gui.*; +import net.java.sip.communicator.service.protocol.*; +import net.java.sip.communicator.service.systray.*; +import net.java.sip.communicator.service.systray.event.*; +import net.java.sip.communicator.util.*; + +/** + * The <tt>Systray</tt> provides a Icon and the associated <tt>TrayMenu</tt> + * in the system tray using the Jdic library. + * + * @author Nicolas Chamouard + * @author Yana Stamcheva + * @author Lubomir Marinov + * @author Symphorien Wanko + */ +public class SystrayServiceJdicImpl + implements SystrayService +{ + + /** + * The systray. + */ + private SystemTray systray; + + /** + * The icon in the system tray. + */ + private TrayIcon trayIcon; + + /** + * The menu that spring with a right click. + */ + private Object menu; + + /** + * The popup handler currently used to show popup messages + */ + private PopupMessageHandler activePopupHandler; + + /** + * A set of usable <tt>PopupMessageHandler</tt> + */ + private final Hashtable<String, PopupMessageHandler> popupHandlerSet = + new Hashtable<String, PopupMessageHandler>(); + + /** + * A reference of the <tt>ConfigurationService</tt> obtained from the + * <tt>SystrayServiceActivator</tt> + */ + private final ConfigurationService configService = OsDependentActivator. + getConfigurationService(); + + /** + * The logger for this class. + */ + private static final Logger logger = + Logger.getLogger(SystrayServiceJdicImpl.class); + + /** + * The various icons used on the systray + */ + private ImageIcon currentIcon; + + private ImageIcon logoIcon; + + private ImageIcon logoIconOffline; + + private ImageIcon logoIconAway; + + private ImageIcon logoIconFFC; + + private ImageIcon logoIconWhite; + + private ImageIcon envelopeIcon; + + private ImageIcon envelopeIconWhite; + + /** + * The dock Icons used only in Mac version + */ + private URL dockIconOffline; + + private URL dockIconAway; + + private URL dockIconFFC; + + 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>. + */ + public SystrayServiceJdicImpl() + { + try + { + systray = SystemTray.getDefaultSystemTray(); + } catch (Throwable e) + { + logger.error("Failed to create a systray!", e); + } + + if (systray != null) + { + this.initSystray(); + + UIService ui = OsDependentActivator.getUIService(); + if (ui != null) + ui.setExitOnMainWindowClose(false); + } + } + + /** + * Initializes the systray icon and related listeners. + */ + private void initSystray() + { + menu = TrayMenuFactory.createTrayMenu(this, systray.isSwing()); + + String osName = System.getProperty("os.name"); + // If we're running under Windows, we use a special icon without + // background. + if (osName.startsWith("Windows")) + { + logoIcon = Resources.getImage("service.systray.TRAY_ICON_WINDOWS"); + logoIconOffline = Resources.getImage( + "service.systray.TRAY_ICON_WINDOWS_OFFLINE"); + logoIconAway = Resources.getImage( + "service.systray.TRAY_ICON_WINDOWS_AWAY"); + logoIconFFC = Resources.getImage( + "service.systray.TRAY_ICON_WINDOWS_FFC"); + envelopeIcon = Resources.getImage( + "service.systray.MESSAGE_ICON_WINDOWS"); + } // If we're running under MacOSX, we use a special black and + // white icons without background. + else if (osName.startsWith("Mac OS X")) + { + logoIcon = Resources.getImage("service.systray.TRAY_ICON_MACOSX"); + logoIconWhite = Resources.getImage( + "service.systray.TRAY_ICON_MACOSX_WHITE"); + envelopeIcon = Resources.getImage( + "service.systray.MESSAGE_ICON_MACOSX"); + envelopeIconWhite = Resources.getImage( + "service.systray.MESSAGE_ICON_MACOSX_WHITE"); + } else + { + logoIcon = Resources.getImage("service.systray.TRAY_ICON"); + logoIconOffline = Resources.getImage( + "service.systray.TRAY_ICON_OFFLINE"); + logoIconAway = Resources.getImage("service.systray.TRAY_ICON_AWAY"); + logoIconFFC = Resources.getImage("service.systray.TRAY_ICON_FFC"); + envelopeIcon = Resources.getImage("service.systray.MESSAGE_ICON"); + } + + if (!osName.startsWith("Mac OS X")) + { + // default to set offline , if any protocols become + // online will set it to online + currentIcon = logoIconOffline; + } else + { + currentIcon = logoIcon; + } + + trayIcon = new TrayIcon( + currentIcon, + Resources.getApplicationString("service.gui.APPLICATION_NAME"), + menu); + + trayIcon.setIconAutoSize(true); + + if (osName.startsWith("Mac OS X")) + { + // init dock Icons + dockIconOffline = Resources.getImageURL( + "service.systray.DOCK_ICON_OFFLINE"); + dockIconAway = Resources.getImageURL( + "service.systray.DOCK_ICON_AWAY"); + dockIconFFC = Resources.getImageURL("service.systray.DOCK_ICON_FFC"); + } + + //Show/hide the contact list when user clicks on the systray. + trayIcon.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + UIService uiService = OsDependentActivator.getUIService(); + ExportedWindow win = + uiService.getExportedWindow(ExportedWindow.MAIN_WINDOW); + boolean setIsVisible = !win.isVisible(); + + win.setVisible(setIsVisible); + configService.setProperty( + "net.java.sip.communicator.impl.systray.showApplication", + Boolean.toString(setIsVisible)); + + if(win.isVisible()) + { + win.bringToFront(); + } + } + }); + + // Change the MacOSX icon with the white one when the popup + // menu appears + if (osName.startsWith("Mac OS X")) + { + TrayMenuFactory.addPopupMenuListener(menu, new PopupMenuListener() + { + + public void popupMenuWillBecomeVisible(PopupMenuEvent e) + { + if (currentIcon == envelopeIcon) + { + trayIcon.setIcon(envelopeIconWhite); + currentIcon = envelopeIconWhite; + } else + { + trayIcon.setIcon(logoIconWhite); + currentIcon = logoIconWhite; + } + } + + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) + { + if (currentIcon == envelopeIconWhite) + { + trayIcon.setIcon(envelopeIcon); + currentIcon = envelopeIcon; + } else + { + getTrayIcon().setIcon(logoIcon); + currentIcon = logoIcon; + } + } + + public void popupMenuCanceled(PopupMenuEvent e) + { + popupMenuWillBecomeInvisible(e); + } + }); + } + + PopupMessageHandler pph = null; + if (!osName.startsWith("Mac OS X")) + { + pph = new PopupMessageHandlerTrayIconImpl(trayIcon); + popupHandlerSet.put(pph.getClass().getName(), pph); + OsDependentActivator.bundleContext.registerService( + PopupMessageHandler.class.getName(), + pph, null); + } + try + { + OsDependentActivator.bundleContext.addServiceListener( + new ServiceListenerImpl(), + "(objectclass=" + PopupMessageHandler.class.getName() + ")"); + } catch (Exception e) + { + logger.warn(e); + } + + // now we look if some handler has been registered before we start + // to listen + ServiceReference[] handlerRefs = null; + try + { + handlerRefs = OsDependentActivator.bundleContext.getServiceReferences( + PopupMessageHandler.class.getName(), + null); + } catch (InvalidSyntaxException ex) + { + logger.error("Error while retrieving service refs", ex); + } + if (handlerRefs != null) + { + String configuredHandler = (String) configService.getProperty( + "systray.POPUP_HANDLER"); + for (int i = 0; i < handlerRefs.length; i++) + { + PopupMessageHandler handler = + (PopupMessageHandler) OsDependentActivator.bundleContext. + getService(handlerRefs[i]); + String handlerName = handler.getClass().getName(); + if (!popupHandlerSet.containsKey(handlerName)) + { + popupHandlerSet.put(handlerName, handler); + logger.info("added the following popup handler : " + + 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); + + initialized = true; + } + + /** + * Saves the last status for all accounts. This information is used + * on logging. Each time user logs in he's logged with the same status + * as he was the last time before closing the application. + * + * @param protocolProvider the protocol provider for which we save the + * last selected status + * @param statusName the status name to save + */ + public void saveStatusInformation( + ProtocolProviderService protocolProvider, + String statusName) + { + if (configService != null) + { + String prefix = "net.java.sip.communicator.impl.gui.accounts"; + + List<String> accounts = configService.getPropertyNamesByPrefix( + prefix, true); + + boolean savedAccount = false; + + for (String accountRootPropName : accounts) + { + String accountUID = configService.getString(accountRootPropName); + + if (accountUID.equals(protocolProvider.getAccountID(). + getAccountUniqueID())) + { + + configService.setProperty( + accountRootPropName + ".lastAccountStatus", + statusName); + + savedAccount = true; + } + } + + if (!savedAccount) + { + String accNodeName = "acc" + Long.toString(System. + currentTimeMillis()); + + String accountPackage = + "net.java.sip.communicator.impl.gui.accounts." + accNodeName; + + configService.setProperty(accountPackage, + protocolProvider.getAccountID().getAccountUniqueID()); + + configService.setProperty( + accountPackage + ".lastAccountStatus", + statusName); + } + } + } + + /** + * Implements <tt>SystraService#showPopupMessage()</tt> + * + * @param popupMessage the message we will show + */ + public void showPopupMessage(PopupMessage popupMessage) + { + // 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); + } + } + + /** + * Implements the <tt>SystrayService.addPopupMessageListener</tt> method. + * + * @param listener the listener to add + */ + public void addPopupMessageListener(SystrayPopupMessageListener listener) + { + if (activePopupHandler != null) + { + activePopupHandler.addPopupMessageListener(listener); + } + } + + /** + * Implements the <tt>SystrayService.removePopupMessageListener</tt> method. + * + * @param listener the listener to remove + */ + public void removePopupMessageListener(SystrayPopupMessageListener listener) + { + if (activePopupHandler != null) + { + activePopupHandler.removePopupMessageListener(listener); + } + } + + /** + * Sets a new Systray icon. + * + * @param imageType the type of the image to set. + */ + public void setSystrayIcon(int imageType) + { + if (!checkInitialized()) + { + return; + } + + String osName = System.getProperty("os.name"); + + ImageIcon toChangeSystrayIcon = null; + + if (imageType == SystrayService.SC_IMG_TYPE) + { + if (osName.startsWith("Mac OS X") && TrayMenuFactory.isVisible(menu)) + { + toChangeSystrayIcon = logoIconWhite; + } else + { + toChangeSystrayIcon = logoIcon; + } + } else if (imageType == SystrayService.SC_IMG_OFFLINE_TYPE) + { + if (!osName.startsWith("Mac OS X")) + { + toChangeSystrayIcon = logoIconOffline; + } + } else if (imageType == SystrayService.SC_IMG_AWAY_TYPE) + { + if (!osName.startsWith("Mac OS X")) + { + toChangeSystrayIcon = logoIconAway; + } + } else if (imageType == SystrayService.SC_IMG_FFC_TYPE) + { + if (!osName.startsWith("Mac OS X")) + { + toChangeSystrayIcon = logoIconFFC; + } + } else if (imageType == SystrayService.ENVELOPE_IMG_TYPE) + { + if (osName.startsWith("Mac OS X") && TrayMenuFactory.isVisible(menu)) + { + toChangeSystrayIcon = envelopeIconWhite; + } else + { + toChangeSystrayIcon = envelopeIcon; + } + } + + if (toChangeSystrayIcon != null) + { + this.trayIcon.setIcon(toChangeSystrayIcon); + this.currentIcon = toChangeSystrayIcon; + } + + if (osName.startsWith("Mac OS X")) + { + URL toChangeDockIcon = null; + switch (imageType) + { + case SystrayService.SC_IMG_TYPE: + // online will restore the original image + break; + case SystrayService.SC_IMG_OFFLINE_TYPE: + toChangeDockIcon = dockIconOffline; + break; + case SystrayService.SC_IMG_AWAY_TYPE: + toChangeDockIcon = dockIconAway; + break; + case SystrayService.SC_IMG_FFC_TYPE: + toChangeDockIcon = dockIconFFC; + break; + } + + try + { + if (toChangeDockIcon != null) + { + Dock.setDockTileImage(toChangeDockIcon); + } else + { + Dock.restoreDockTileImage(); + } + } catch (Exception e) + { + logger.error("failed to change dock icon", e); + } + } + } + + private boolean checkInitialized() + { + if (!initialized) + { + logger.error("Systray not init"); + return false; + } else + { + return true; + } + } + + /** + * @return the trayIcon + */ + public TrayIcon getTrayIcon() + { + return trayIcon; + } + + /** + * 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 + */ + public PopupMessageHandler setActivePopupMessageHandler( + PopupMessageHandler newHandler) + { + PopupMessageHandler oldHandler = activePopupHandler; + if (oldHandler != null) + { + oldHandler.removePopupMessageListener(popupMessageListener); + } + + if (newHandler != null) + { + newHandler.addPopupMessageListener(popupMessageListener); + } + activePopupHandler = newHandler; + + return oldHandler; + } + + /** + * Get the handler currently used by this implementation to popup message + * @return the current handler + */ + public PopupMessageHandler getActivePopupMessageHandler() + { + return activePopupHandler; + } + + /** our listener for popup message click */ + private static class SystrayPopupMessageListenerImpl + implements SystrayPopupMessageListener + { + + /** + * Handles a user click on a systray popup message. If the + * popup notification was the result of an incoming message from a + * contact, the chat window with that contact will be opened if not already, + * and brought to front. + * + * @param evt the event triggered when user clicks on a systray popup + * message + */ + public void popupMessageClicked(SystrayPopupMessageEvent evt) + { + Object o = evt.getTag(); + + if (o instanceof Contact) + OsDependentActivator.getUIService(). + getChat((Contact) o).setChatVisible(true); + } + } + + /** an implementation of <tt>ServiceListener</tt> we will use */ + private class ServiceListenerImpl implements ServiceListener + { + + /** implements <tt>ServiceListener.serviceChanged</tt> */ + public void serviceChanged(ServiceEvent serviceEvent) + { + try + { + PopupMessageHandler handler = + (PopupMessageHandler) OsDependentActivator.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.equals(handler.getClass().getName())) + setActivePopupMessageHandler(handler); + } else if (serviceEvent.getType() == ServiceEvent.UNREGISTERING) + { + popupHandlerSet.remove(handler.getClass().getName()); + if (activePopupHandler == handler) + { + activePopupHandler.removePopupMessageListener( + popupMessageListener); + activePopupHandler = null; + //we just lost our default handler, we replace it + //with the first one we find + if (!popupHandlerSet.isEmpty()) + setActivePopupMessageHandler( + popupHandlerSet.get( + popupHandlerSet.keys().nextElement())); + } + } + } catch (IllegalStateException e) + { + logger.debug(e); + } + } + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/jdic/TrayMenuFactory.java b/src/net/java/sip/communicator/impl/osdependent/jdic/TrayMenuFactory.java new file mode 100644 index 0000000..6f32c48 --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/jdic/TrayMenuFactory.java @@ -0,0 +1,156 @@ +/* + * 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.osdependent.jdic; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.event.*; + +import net.java.sip.communicator.impl.osdependent.*; +import net.java.sip.communicator.service.gui.*; + +/** + * The <tt>TrayMenu</tt> is the menu that appears when the user right-click + * on the Systray icon. + * + * @author Nicolas Chamouard + * @author Lubomir Marinov + */ +public final class TrayMenuFactory +{ + + /** + * Handles the <tt>ActionEvent</tt> when one of the menu items is selected. + * + * @param evt the event containing the menu item name + */ + private static void actionPerformed(ActionEvent evt) + { + Object source = evt.getSource(); + String itemName; + if (source instanceof JMenuItem) + { + JMenuItem menuItem = (JMenuItem) source; + itemName = menuItem.getName(); + } + else + { + MenuItem menuItem = (MenuItem) source; + itemName = menuItem.getName(); + } + + if (itemName.equals("settings")) + { + OsDependentActivator.getUIService().setConfigurationWindowVisible(true); + } + else if (itemName.equals("service.gui.CLOSE")) + { + OsDependentActivator.getUIService().beginShutdown(); + } + else if (itemName.equals("addContact")) + { + ExportedWindow dialog = + OsDependentActivator.getUIService().getExportedWindow( + ExportedWindow.ADD_CONTACT_WINDOW); + + if (dialog != null) + dialog.setVisible(true); + else + OsDependentActivator.getUIService().getPopupDialog() + .showMessagePopupDialog(Resources.getString( + "impl.systray.FAILED_TO_OPEN_ADD_CONTACT_DIALOG")); + } + } + + private static void add(Object trayMenu, Object trayMenuItem) + { + if (trayMenu instanceof JPopupMenu) + ((JPopupMenu) trayMenu).add((JMenuItem) trayMenuItem); + else + ((PopupMenu) trayMenu).add((MenuItem) trayMenuItem); + } + + public static void addPopupMenuListener(Object trayMenu, + PopupMenuListener listener) + { + if (trayMenu instanceof JPopupMenu) + ((JPopupMenu) trayMenu).addPopupMenuListener(listener); + } + + private static void addSeparator(Object trayMenu) + { + if (trayMenu instanceof JPopupMenu) + ((JPopupMenu) trayMenu).addSeparator(); + else + ((PopupMenu) trayMenu).addSeparator(); + } + + public static Object createTrayMenu(SystrayServiceJdicImpl tray, + boolean swing) + { + // Enable swing for java 1.6 except for the mac version + if (!swing && !System.getProperty("os.name").startsWith("Mac")) + swing = true; + + Object trayMenu = swing ? new JPopupMenu() : new PopupMenu(); + ActionListener listener = new ActionListener() + { + public void actionPerformed(ActionEvent event) + { + TrayMenuFactory.actionPerformed(event); + } + }; + + add(trayMenu, createTrayMenuItem("settings", "service.gui.SETTINGS", + "service.systray.CONFIGURE_ICON", listener, swing)); + add(trayMenu, createTrayMenuItem("addContact", + "service.gui.ADD_CONTACT", + "service.gui.icons.ADD_CONTACT_16x16_ICON", listener, swing)); + addSeparator(trayMenu); + add(trayMenu, new StatusSubMenu(tray, swing).getMenu()); + addSeparator(trayMenu); + add(trayMenu, createTrayMenuItem("service.gui.CLOSE", + "service.gui.CLOSE", "service.systray.CLOSE_MENU_ICON", listener, + swing)); + + return trayMenu; + } + + private static Object createTrayMenuItem( String name, + String textID, + String iconID, + ActionListener listener, + boolean swing) + { + String text = Resources.getString(textID); + Object trayMenuItem; + if (swing) + { + JMenuItem menuItem = new JMenuItem(text, Resources.getImage(iconID)); + menuItem.setName(name); + menuItem.addActionListener(listener); + trayMenuItem = menuItem; + } + else + { + MenuItem menuItem = new MenuItem(text); + menuItem.setName(name); + menuItem.addActionListener(listener); + trayMenuItem = menuItem; + } + return trayMenuItem; + } + + public static boolean isVisible(Object trayMenu) + { + if (trayMenu instanceof JPopupMenu) + return ((JPopupMenu) trayMenu).isVisible(); + return false; + } +} diff --git a/src/net/java/sip/communicator/impl/osdependent/osdependent.manifest.mf b/src/net/java/sip/communicator/impl/osdependent/osdependent.manifest.mf new file mode 100644 index 0000000..3a0a1ff --- /dev/null +++ b/src/net/java/sip/communicator/impl/osdependent/osdependent.manifest.mf @@ -0,0 +1,38 @@ +Bundle-Activator: net.java.sip.communicator.impl.osdependent.OsDependentActivator
+Bundle-Name: OS dependent
+Bundle-Description: OS dependent.
+Bundle-Vendor: sip-communicator.org
+Bundle-Version: 0.0.1
+System-Bundle: yes
+Export-Package: net.java.sip.communicator.service.systray,
+ net.java.sip.communicator.service.systray.event, + net.java.sip.communicator.service.desktop
+Import-Package: org.osgi.framework,
+ org.jdesktop.jdic.tray, + org.jdesktop.jdic.desktop,
+ com.apple.cocoa.application,
+ com.apple.cocoa.foundation,
+ net.java.sip.communicator.service.configuration,
+ net.java.sip.communicator.service.gui,
+ net.java.sip.communicator.service.gui.event,
+ 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,
+ net.java.sip.communicator.util,
+ net.java.sip.communicator.util.swing,
+ javax.swing,
+ javax.swing.event,
+ javax.swing.table,
+ javax.swing.text,
+ javax.swing.text.html,
+ javax.accessibility,
+ javax.swing.plaf,
+ javax.swing.plaf.metal,
+ javax.swing.plaf.basic,
+ javax.imageio,
+ javax.swing.filechooser,
+ javax.swing.tree,
+ javax.swing.undo,
+ javax.swing.border
|