aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip
diff options
context:
space:
mode:
authorYana Stamcheva <yana@jitsi.org>2009-06-15 15:18:29 +0000
committerYana Stamcheva <yana@jitsi.org>2009-06-15 15:18:29 +0000
commit2f0db4d2d1ad77f058b352829a6494c7af5a16b3 (patch)
tree32ecf5f800417777fa473b8814dead041f6515c3 /src/net/java/sip
parent3563fa97f679c2f8b29f2d2eb74fc0bbcaa698ab (diff)
downloadjitsi-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')
-rw-r--r--src/net/java/sip/communicator/impl/fileaccess/FileAccessServiceImpl.java40
-rw-r--r--src/net/java/sip/communicator/impl/gui/GuiActivator.java53
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/MainFrame.java33
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationComponent.java150
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationContainer.java20
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java113
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java123
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java372
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionRenderer.java11
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java293
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java10
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/chat/ChatWindow.java29
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java8
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanelTransferHandler.java208
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java64
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/SendSmsDialog.java18
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java12
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java16
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java587
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/SendFileConversationComponent.java317
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java167
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java70
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java51
-rw-r--r--src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf2
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/utils/Constants.java8
-rw-r--r--src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java6
-rw-r--r--src/net/java/sip/communicator/impl/gui/utils/SIPCommHTMLEditorKit.java25
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/Desktop.java469
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/DesktopServiceImpl.java92
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/NewStatusMessageDialog.java (renamed from src/net/java/sip/communicator/impl/systray/NewStatusMessageDialog.java)21
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/OsDependentActivator.java (renamed from src/net/java/sip/communicator/impl/systray/SystrayActivator.java)25
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/PopupMessageHandlerTrayIconImpl.java (renamed from src/net/java/sip/communicator/impl/systray/PopupMessageHandlerTrayIconImpl.java)9
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/Resources.java (renamed from src/net/java/sip/communicator/impl/systray/Resources.java)4
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/StatusMessageMenu.java (renamed from src/net/java/sip/communicator/impl/systray/StatusMessageMenu.java)2
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/SystemTray.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/SystemTray.java)22
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/TrayIcon.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/TrayIcon.java)10
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/jdic/ProviderRegistration.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/ProviderRegistration.java)6
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/jdic/ProviderUnRegistration.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/ProviderUnRegistration.java)2
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/jdic/StatusSelector.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/StatusSelector.java)4
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/jdic/StatusSimpleSelector.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/StatusSimpleSelector.java)4
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/jdic/StatusSubMenu.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/StatusSubMenu.java)12
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java)22
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/jdic/TrayMenuFactory.java (renamed from src/net/java/sip/communicator/impl/systray/jdic/TrayMenuFactory.java)12
-rw-r--r--src/net/java/sip/communicator/impl/osdependent/osdependent.manifest.mf (renamed from src/net/java/sip/communicator/impl/systray/systray.manifest.mf)12
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/IncomingFileTransferJabberImpl.java48
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/IncomingFileTransferRequestJabberImpl.java143
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetFileTransferJabberImpl.java392
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java55
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java8
-rwxr-xr-xsrc/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf1
-rw-r--r--src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/FileTransferSSHImpl.java50
-rw-r--r--src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java63
-rw-r--r--src/net/java/sip/communicator/service/desktop/DesktopService.java111
-rw-r--r--src/net/java/sip/communicator/service/fileaccess/FileAccessService.java9
-rw-r--r--src/net/java/sip/communicator/service/protocol/AbstractFileTransfer.java180
-rw-r--r--src/net/java/sip/communicator/service/protocol/FileTransfer.java109
-rw-r--r--src/net/java/sip/communicator/service/protocol/IncomingFileTransferRequest.java67
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java75
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/FileListener.java20
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/FileTransferProgressEvent.java63
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/FileTransferProgressListener.java24
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/FileTransferRequestEvent.java65
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/FileTransferRequestListener.java28
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/FileTransferStatusChangeEvent.java80
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/FileTransferStatusListener.java24
-rw-r--r--src/net/java/sip/communicator/util/ByteFormat.java101
-rw-r--r--src/net/java/sip/communicator/util/FileUtils.java84
-rw-r--r--src/net/java/sip/communicator/util/swing/FileDragLabel.java194
-rw-r--r--src/net/java/sip/communicator/util/swing/SwingWorker.java219
70 files changed, 5111 insertions, 638 deletions
diff --git a/src/net/java/sip/communicator/impl/fileaccess/FileAccessServiceImpl.java b/src/net/java/sip/communicator/impl/fileaccess/FileAccessServiceImpl.java
index 8378002..c7a8342 100644
--- a/src/net/java/sip/communicator/impl/fileaccess/FileAccessServiceImpl.java
+++ b/src/net/java/sip/communicator/impl/fileaccess/FileAccessServiceImpl.java
@@ -354,7 +354,37 @@ public class FileAccessServiceImpl implements FileAccessService {
return file;
}
-
+
+ /**
+ * Returns the default download directory.
+ *
+ * @return the default download directory
+ */
+ public File getDefaultDownloadDirectory()
+ throws IOException
+ {
+ String defaultLocation = getSystemProperty("user.home")
+ + File.separatorChar + "Downloads";
+
+ File downloadDir = new File(defaultLocation);
+
+ if (!downloadDir.exists())
+ {
+ if (!downloadDir.mkdirs())
+ {
+ String message = "Could not create the download directory : "
+ + downloadDir.getAbsolutePath();
+
+ logger.debug(message);
+ throw new IOException(message);
+ }
+ logger.debug("Download directory created : "
+ + downloadDir.getAbsolutePath());
+ }
+
+ return downloadDir;
+ }
+
/**
* Creates a failsafe transaction which can be used to safely store
* informations into a file.
@@ -363,11 +393,13 @@ public class FileAccessServiceImpl implements FileAccessService {
*
* @return A new failsafe transaction related to the given file.
*/
- public FailSafeTransaction createFailSafeTransaction(File file) {
- if (file == null) {
+ public FailSafeTransaction createFailSafeTransaction(File file)
+ {
+ if (file == null)
+ {
return null;
}
-
+
return new FailSafeTransactionImpl(file);
}
diff --git a/src/net/java/sip/communicator/impl/gui/GuiActivator.java b/src/net/java/sip/communicator/impl/gui/GuiActivator.java
index 1bc6de6..127d5b9 100644
--- a/src/net/java/sip/communicator/impl/gui/GuiActivator.java
+++ b/src/net/java/sip/communicator/impl/gui/GuiActivator.java
@@ -14,6 +14,8 @@ import net.java.sip.communicator.service.browserlauncher.*;
import net.java.sip.communicator.service.callhistory.*;
import net.java.sip.communicator.service.configuration.*;
import net.java.sip.communicator.service.contactlist.*;
+import net.java.sip.communicator.service.desktop.*;
+import net.java.sip.communicator.service.fileaccess.*;
import net.java.sip.communicator.service.gui.*;
import net.java.sip.communicator.service.keybindings.*;
import net.java.sip.communicator.service.msghistory.*;
@@ -59,8 +61,12 @@ public class GuiActivator implements BundleActivator
private static KeybindingsService keybindingsService;
- private static final Map<Object, ProtocolProviderFactory> providerFactoriesMap =
- new Hashtable<Object, ProtocolProviderFactory>();
+ private static FileAccessService fileAccessService;
+
+ private static DesktopService desktopService;
+
+ private static final Map<Object, ProtocolProviderFactory>
+ providerFactoriesMap = new Hashtable<Object, ProtocolProviderFactory>();
public static boolean isStarted = false;
@@ -157,7 +163,8 @@ public class GuiActivator implements BundleActivator
for (int i = 0; i < serRefs.length; i++)
{
- ProtocolProviderFactory providerFactory = (ProtocolProviderFactory) bundleContext
+ ProtocolProviderFactory providerFactory
+ = (ProtocolProviderFactory) bundleContext
.getService(serRefs[i]);
providerFactoriesMap.put(serRefs[i]
@@ -399,9 +406,47 @@ public class GuiActivator implements BundleActivator
}
/**
+ * Returns the <tt>FileAccessService</tt> obtained from the bundle context.
+ *
+ * @return the <tt>FileAccessService</tt> obtained from the bundle context
+ */
+ public static FileAccessService getFileAccessService()
+ {
+ if (fileAccessService == null)
+ {
+ ServiceReference serviceReference = bundleContext
+ .getServiceReference(FileAccessService.class.getName());
+
+ fileAccessService = (FileAccessService) bundleContext
+ .getService(serviceReference);
+ }
+
+ return fileAccessService;
+ }
+
+ /**
+ * Returns the <tt>DesktopService</tt> obtained from the bundle context.
+ *
+ * @return the <tt>DesktopService</tt> obtained from the bundle context
+ */
+ public static DesktopService getDesktopService()
+ {
+ if (desktopService == null)
+ {
+ ServiceReference serviceReference = bundleContext
+ .getServiceReference(DesktopService.class.getName());
+
+ desktopService = (DesktopService) bundleContext
+ .getService(serviceReference);
+ }
+
+ return desktopService;
+ }
+
+ /**
* Implements the <tt>ServiceListener</tt>. Verifies whether the
* passed event concerns a <tt>NotificationService</tt> and if so
- * intiates the gui NotificationManager.
+ * initiates the user interface NotificationManager.
*/
private static class NotificationServiceListener implements ServiceListener
{
diff --git a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
index 1ef04c9..d86d3c9 100755
--- a/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
+++ b/src/net/java/sip/communicator/impl/gui/main/MainFrame.java
@@ -314,8 +314,8 @@ public class MainFrame
// Obtain the presence operation set.
if (supportedOperationSets.containsKey(ppOpSetClassName)
- || supportedOperationSets.containsKey(pOpSetClassName)) {
-
+ || supportedOperationSets.containsKey(pOpSetClassName))
+ {
OperationSetPresence presence = (OperationSetPresence)
supportedOperationSets.get(ppOpSetClassName);
@@ -334,8 +334,8 @@ public class MainFrame
String imOpSetClassName = OperationSetBasicInstantMessaging
.class.getName();
- if (supportedOperationSets.containsKey(imOpSetClassName)) {
-
+ if (supportedOperationSets.containsKey(imOpSetClassName))
+ {
OperationSetBasicInstantMessaging im
= (OperationSetBasicInstantMessaging)
supportedOperationSets.get(imOpSetClassName);
@@ -350,8 +350,8 @@ public class MainFrame
String tnOpSetClassName = OperationSetTypingNotifications
.class.getName();
- if (supportedOperationSets.containsKey(tnOpSetClassName)) {
-
+ if (supportedOperationSets.containsKey(tnOpSetClassName))
+ {
OperationSetTypingNotifications tn
= (OperationSetTypingNotifications)
supportedOperationSets.get(tnOpSetClassName);
@@ -365,8 +365,8 @@ public class MainFrame
// Obtain the basic telephony operation set.
String telOpSetClassName = OperationSetBasicTelephony.class.getName();
- if (supportedOperationSets.containsKey(telOpSetClassName)) {
-
+ if (supportedOperationSets.containsKey(telOpSetClassName))
+ {
OperationSetBasicTelephony telephony
= (OperationSetBasicTelephony)
supportedOperationSets.get(telOpSetClassName);
@@ -390,6 +390,17 @@ public class MainFrame
multiUserChat.addInvitationRejectionListener(conferenceManager);
multiUserChat.addPresenceListener(conferenceManager);
}
+
+ // Obtain file transfer operation set.
+ OperationSetFileTransfer fileTransferOpSet
+ = (OperationSetFileTransfer) protocolProvider
+ .getOperationSet(OperationSetFileTransfer.class);
+
+ if (fileTransferOpSet != null)
+ {
+ fileTransferOpSet.addFileTransferRequestListener(
+ getContactListPanel());
+ }
}
/**
@@ -531,7 +542,8 @@ public class MainFrame
OperationSet opSet
= protocolProvider.getOperationSet(OperationSetPresence.class);
- return (opSet instanceof OperationSetPresence) ? (OperationSetPresence) opSet
+ return (opSet instanceof OperationSetPresence)
+ ? (OperationSetPresence) opSet
: null;
}
@@ -588,7 +600,8 @@ public class MainFrame
OperationSet opSet
= protocolProvider.getOperationSet(OperationSetMultiUserChat.class);
- return (opSet instanceof OperationSetMultiUserChat) ? (OperationSetMultiUserChat) opSet
+ return (opSet instanceof OperationSetMultiUserChat)
+ ? (OperationSetMultiUserChat) opSet
: null;
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationComponent.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationComponent.java
new file mode 100644
index 0000000..f08dd23
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationComponent.java
@@ -0,0 +1,150 @@
+/*
+ * 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.gui.main.chat;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.util.swing.*;
+
+/**
+ * The <tt>ChatConversationComponent</tt> is a component that can be added to
+ * the conversation area of the chat window in order to display any special
+ * events.
+ *
+ * @author Yana Stamcheva
+ */
+public class ChatConversationComponent
+ extends JPanel
+{
+ protected final GridBagConstraints constraints = new GridBagConstraints();
+
+ private static final Color defaultColor
+ = new Color(GuiActivator.getResources()
+ .getColor("service.gui.CHAT_CONVERSATION_COMPONENT"));
+
+ private static final Color warningColor
+ = new Color(GuiActivator.getResources()
+ .getColor("service.gui.CHAT_CONVERSATION_WARNING_COMPONENT"));
+
+ private Color backgroundColor = defaultColor;
+
+ /**
+ * Creates a <tt>ChatConversationComponent</tt>.
+ */
+ public ChatConversationComponent()
+ {
+ this.setLayout(new GridBagLayout());
+ this.setOpaque(false);
+ }
+
+ /**
+ * A specially customized button to fit better chat conversation component
+ * look and feel.
+ */
+ protected class ChatConversationButton extends JButton
+ {
+ public ChatConversationButton()
+ {
+ init();
+ }
+
+ /**
+ * Create a new RolloverButton.
+ *
+ * @param text the button text.
+ * @param icon the button icon.
+ */
+ public ChatConversationButton(String text, Icon icon)
+ {
+ super(text, icon);
+ init();
+ }
+
+ /**
+ * Decorates the button with the appropriate UI configurations.
+ */
+ private void init()
+ {
+ int color = GuiActivator.getResources()
+ .getColor("service.gui.CHAT_LINK_COLOR");
+
+ setForeground(new Color(color));
+ setFont(getFont().deriveFont(Font.BOLD, 11f));
+ setBorder(BorderFactory.createEmptyBorder());
+ setBorderPainted(false);
+ setOpaque(true);
+
+ setContentAreaFilled(false);
+
+ this.addMouseListener(new MouseAdapter()
+ {
+ public void mouseEntered(MouseEvent e)
+ {
+ setCursor(new Cursor(Cursor.HAND_CURSOR));
+ }
+
+ public void mouseExited(MouseEvent e)
+ {
+ setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
+ }
+ });
+ }
+ }
+
+ /**
+ * Updates the background color to catch user attention if anything
+ * unexpected has happened.
+ *
+ * @param isWarningStyle <code>true</code> to indicate that the warning
+ * style should be set, <code>false</code> - otherwise.
+ */
+ protected void setWarningStyle(boolean isWarningStyle)
+ {
+ if (isWarningStyle)
+ backgroundColor = warningColor;
+ else
+ backgroundColor = defaultColor;
+ }
+
+ /**
+ * Call a custom internal paint.
+ */
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ g = g.create();
+ try
+ {
+ internalPaintComponent(g);
+ }
+ finally
+ {
+ g.dispose();
+ }
+ }
+
+ /**
+ * Paints a round background for this component.
+ *
+ * @param g the Graphics object
+ */
+ private void internalPaintComponent(Graphics g)
+ {
+ AntialiasingManager.activateAntialiasing(g);
+
+ Graphics2D g2 = (Graphics2D) g;
+
+ g2.setColor(backgroundColor);
+ g2.fillRoundRect(
+ 1, 1, this.getWidth() - 1, this.getHeight() -1, 15, 15);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationContainer.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationContainer.java
index 60b0511..a744c68 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationContainer.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationContainer.java
@@ -8,9 +8,27 @@ package net.java.sip.communicator.impl.gui.main.chat;
import java.awt.*;
+/**
+ * The <tt>ChatConversationContainer</tt> is used as an abstraction of the
+ * conversation area, which is included in both the chat window and the history
+ * window.
+ *
+ * @author Yana Stamcheva
+ */
public interface ChatConversationContainer
{
+ /**
+ * Returns the window, where this chat conversation container is contained.
+ * (the chat window, the history window, etc)
+ *
+ * @return the window, where this chat conversation container is contained.
+ */
public Window getConversationContainerWindow();
-
+
+ /**
+ * Sets the given status message to this conversation container.
+ *
+ * @param statusMessage the status message to set
+ */
public void setStatusMessage(String statusMessage);
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
index 3efe7bf..e01d2fc 100755
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
@@ -43,7 +43,7 @@ public class ChatConversationPanel
private static final Logger logger =
Logger.getLogger(ChatConversationPanel.class);
- private final JEditorPane chatEditorPane = new MyEditorPane();
+ private final JTextPane chatTextPane = new MyTextPane();
private final HTMLEditorKit editorKit = new SIPCommHTMLEditorKit();
@@ -84,33 +84,30 @@ public class ChatConversationPanel
this.document = (HTMLDocument) editorKit.createDefaultDocument();
- this.chatEditorPane.setContentType("text/html");
+ this.chatTextPane.setEditorKitForContentType("text/html", editorKit);
+ this.chatTextPane.setEditorKit(editorKit);
+ this.chatTextPane.setEditable(false);
+ this.chatTextPane.setDocument(document);
+ this.chatTextPane.setDragEnabled(true);
- this.chatEditorPane.setEditable(false);
-
- this.chatEditorPane.setEditorKitForContentType("text/html", editorKit);
- this.chatEditorPane.setEditorKit(editorKit);
-
- this.chatEditorPane.setDocument(document);
-
- chatEditorPane.putClientProperty(
+ chatTextPane.putClientProperty(
JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
Constants.loadSimpleStyle(
- document.getStyleSheet(), chatEditorPane.getFont());
+ document.getStyleSheet(), chatTextPane.getFont());
- this.chatEditorPane.addHyperlinkListener(this);
- this.chatEditorPane.addMouseListener(this);
- this.chatEditorPane.setCursor(
+ this.chatTextPane.addHyperlinkListener(this);
+ this.chatTextPane.addMouseListener(this);
+ this.chatTextPane.setCursor(
Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
this.setWheelScrollingEnabled(true);
- this.setViewportView(chatEditorPane);
+ this.setViewportView(chatTextPane);
this.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
- ToolTipManager.sharedInstance().registerComponent(chatEditorPane);
+ ToolTipManager.sharedInstance().registerComponent(chatTextPane);
String copyLinkString
= GuiActivator.getResources().getI18NString("service.gui.COPY_LINK");
@@ -194,9 +191,14 @@ public class ChatConversationPanel
* @param message The message text.
* @return the formatted message
*/
- public String processMessage(String contactName, long date,
- String messageType, String message, String contentType)
+ public String processMessage(ChatMessage chatMessage)
{
+ String contactName = chatMessage.getContactName();
+ String contentType = chatMessage.getContentType();
+ long date = chatMessage.getDate();
+ String messageType = chatMessage.getMessageType();
+ String message = chatMessage.getMessage();
+
String msgID = "message";
String msgHeaderID = "messageHeader";
String chatString = "";
@@ -371,17 +373,20 @@ public class ChatConversationPanel
* INCOMING_MESSAGE.
* @param message The message text.
*/
- public String processMessage(String contactName, long date,
- String messageType, String message, String contentType, String keyword)
+ public String processMessage(ChatMessage chatMessage, String keyword)
{
- String formattedMessage = message;
+ String formattedMessage = chatMessage.getMessage();
if (keyword != null && keyword.length() != 0)
{
- formattedMessage = processKeyword(message, contentType, keyword);
+ formattedMessage = processKeyword( chatMessage.getMessage(),
+ chatMessage.getContentType(),
+ keyword);
}
- return this.processMessage(contactName, date, messageType,
- formattedMessage, contentType);
+
+ chatMessage.setMessage(formattedMessage);
+
+ return this.processMessage(chatMessage);
}
/**
@@ -761,7 +766,7 @@ public class ChatConversationPanel
*/
public JEditorPane getChatEditorPane()
{
- return chatEditorPane;
+ return chatTextPane;
}
/**
@@ -779,10 +784,10 @@ public class ChatConversationPanel
*/
public void setCarretToEnd()
{
- if (this.chatEditorPane.getDocument().getLength()
+ if (this.chatTextPane.getDocument().getLength()
== this.document.getLength())
{
- this.chatEditorPane.setCaretPosition(this.document.getLength());
+ this.chatTextPane.setCaretPosition(this.document.getLength());
}
}
@@ -830,7 +835,7 @@ public class ChatConversationPanel
rightButtonMenu.remove(copyLinkSeparator);
}
- if (chatEditorPane.getSelectedText() != null)
+ if (chatTextPane.getSelectedText() != null)
{
rightButtonMenu.enableCopy();
}
@@ -838,7 +843,7 @@ public class ChatConversationPanel
{
rightButtonMenu.disableCopy();
}
- rightButtonMenu.setInvoker(chatEditorPane);
+ rightButtonMenu.setInvoker(chatTextPane);
rightButtonMenu.setLocation(p.x, p.y);
rightButtonMenu.setVisible(true);
}
@@ -878,7 +883,7 @@ public class ChatConversationPanel
*/
public void copyConversation()
{
- this.chatEditorPane.copy();
+ this.chatTextPane.copy();
}
/**
@@ -889,7 +894,7 @@ public class ChatConversationPanel
{
this.document = (HTMLDocument) editorKit.createDefaultDocument();
Constants.loadSimpleStyle(
- document.getStyleSheet(), chatEditorPane.getFont());
+ document.getStyleSheet(), chatTextPane.getFont());
}
/**
@@ -900,7 +905,7 @@ public class ChatConversationPanel
public void setContent(HTMLDocument doc)
{
this.document = doc;
- this.chatEditorPane.setDocument(doc);
+ this.chatTextPane.setDocument(doc);
}
/**
@@ -909,7 +914,7 @@ public class ChatConversationPanel
*/
public void setDefaultContent()
{
- this.chatEditorPane.setDocument(document);
+ this.chatTextPane.setDocument(document);
}
/**
@@ -919,7 +924,7 @@ public class ChatConversationPanel
*/
public HTMLDocument getContent()
{
- return (HTMLDocument) this.chatEditorPane.getDocument();
+ return (HTMLDocument) this.chatTextPane.getDocument();
}
/**
@@ -1105,8 +1110,8 @@ public class ChatConversationPanel
/**
* Extend Editor pane to add url tooltips.
*/
- private class MyEditorPane
- extends JEditorPane
+ private class MyTextPane
+ extends JTextPane
{
/**
* Returns the string to be used as the tooltip for <i>event</i>.
@@ -1121,4 +1126,40 @@ public class ChatConversationPanel
return null;
}
}
+
+ /**
+ * Adds a custom component at the end of the conversation.
+ *
+ * @param component the component to add at the end of the conversation.
+ */
+ public void addComponent(Component component)
+ {
+ Style style = document.getStyleSheet().addStyle(
+ StyleConstants.ComponentElementName,
+ document.getStyleSheet().getStyle("body"));
+
+ // The image must first be wrapped in a style
+ style.addAttribute(
+ AbstractDocument.ElementNameAttribute,
+ StyleConstants.ComponentElementName);
+
+ style.addAttribute(
+ StyleConstants.ComponentAttribute,
+ component);
+
+ // Insert the component style at the end of the text
+ try
+ {
+ document.insertString( document.getLength(),
+ "ignored text", style);
+ document.insertString(document.getLength(),
+ "\n", document.getStyle("body"));
+ }
+ catch (BadLocationException e)
+ {
+ logger.error("Insert in the HTMLDocument failed.", e);
+ }
+
+ this.setCarretToEnd();
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java
new file mode 100644
index 0000000..21c07bd
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java
@@ -0,0 +1,123 @@
+/*
+ * 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.gui.main.chat;
+
+/**
+ * The <tt>ChatMessage</tt> class encapsulates message information in order to
+ * provide a single object containing all data needed to display a chat message.
+ *
+ * @author Yana Stamcheva
+ */
+public class ChatMessage
+{
+ /**
+ * The name of the contact sending the message.
+ */
+ private final String contactName;
+
+ /**
+ * The date and time of the message.
+ */
+ private final long date;
+
+ /**
+ * The type of the message.
+ */
+ private final String messageType;
+
+ /**
+ * The content of the message.
+ */
+ private String message;
+
+ /**
+ * The content type of the message.
+ */
+ private final String contentType;
+
+ /**
+ * Creates a <tt>ChatMessage</tt> by specifying all parameters of the
+ * message.
+ * @param contactName the name of the contact
+ * @param date the date and time
+ * @param messageType the type (INCOMING or OUTGOING)
+ * @param message the content
+ * @param contentType the content type (e.g. "text", "text/html", etc.)
+ */
+ public ChatMessage( String contactName,
+ long date,
+ String messageType,
+ String message,
+ String contentType)
+ {
+ this.contactName = contactName;
+ this.date = date;
+ this.messageType = messageType;
+ this.message = message;
+ this.contentType = contentType;
+ }
+
+ /**
+ * Returns the name of the contact sending the message.
+ *
+ * @return the name of the contact sending the message.
+ */
+ public String getContactName()
+ {
+ return contactName;
+ }
+
+ /**
+ * Returns the date and time of the message.
+ *
+ * @return the date and time of the message.
+ */
+ public long getDate()
+ {
+ return date;
+ }
+
+ /**
+ * Returns the type of the message.
+ *
+ * @return the type of the message.
+ */
+ public String getMessageType()
+ {
+ return messageType;
+ }
+
+ /**
+ * Returns the content of the message.
+ *
+ * @return the content of the message.
+ */
+ public String getMessage()
+ {
+ return message;
+ }
+
+ /**
+ * Sets the content of the message.
+ *
+ * @param message the new content
+ */
+ public void setMessage(String message)
+ {
+ this.message = message;
+ }
+
+ /**
+ * Returns the content type (e.g. "text", "text/html", etc.).
+ *
+ * @return the content type
+ */
+ public String getContentType()
+ {
+ return contentType;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
index dc4ff17..3e1244d 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
@@ -20,6 +20,7 @@ import javax.swing.text.html.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.chat.conference.*;
+import net.java.sip.communicator.impl.gui.main.chat.filetransfer.*;
import net.java.sip.communicator.impl.gui.utils.*;
import net.java.sip.communicator.service.contactlist.*;
import net.java.sip.communicator.service.gui.*;
@@ -50,7 +51,8 @@ public class ChatPanel
{
private static final Logger logger = Logger.getLogger(ChatPanel.class);
- private final JSplitPane messagePane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+ private final JSplitPane messagePane
+ = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
private final JCheckBox sendSmsCheckBox = new SIPCommCheckBox(
GuiActivator.getResources().getI18NString("service.gui.SEND_AS_SMS"));
@@ -98,6 +100,10 @@ public class ChatPanel
private final java.util.List<ChatFocusListener> focusListeners =
new Vector<ChatFocusListener>();
+ private final Vector<Object> incomingEventBuffer = new Vector<Object>();
+
+ private boolean isHistoryLoaded;
+
/**
* Creates a <tt>ChatPanel</tt> which is added to the given chat window.
*
@@ -111,6 +117,8 @@ public class ChatPanel
this.conversationPanel = new ChatConversationPanel(this);
this.conversationPanel.setPreferredSize(new Dimension(400, 200));
+ this.conversationPanel.getChatEditorPane()
+ .setTransferHandler(new ChatTransferHandler(this));
this.sendPanel = new ChatSendPanel(this);
@@ -299,7 +307,8 @@ public class ChatPanel
* @return ChatWindow The chat window, where this
* chat panel is located.
*/
- public Window getConversationContainerWindow() {
+ public Window getConversationContainerWindow()
+ {
return chatWindow;
}
@@ -444,7 +453,7 @@ public class ChatPanel
* @param escapedMessageID The incoming message needed to be ignored if
* contained in history.
*/
- public void processHistory( Collection<EventObject> historyList,
+ private void processHistory( Collection<EventObject> historyList,
String escapedMessageID)
{
Iterator<EventObject> iterator = historyList.iterator();
@@ -532,10 +541,10 @@ public class ChatPanel
evt.getMessage().getContentType());
}
}
-
conversationPanel.appendMessageToEnd(historyString);
}
+ isHistoryLoaded = true;
getChatWindow().getMainToolBar()
.changeHistoryButtonsState(this);
@@ -552,19 +561,56 @@ public class ChatPanel
* or INCOMING_MESSAGE.
* @param message The message text.
*/
- public void processMessage(String contactName, long date,
+ public void addMessage(String contactName, long date,
String messageType, String message, String contentType)
{
- String processedMessage
- = this.conversationPanel.processMessage(contactName, date,
- messageType, message, contentType);
- this.conversationPanel.appendMessageToEnd(processedMessage);
+ ChatMessage chatMessage = new ChatMessage(contactName, date,
+ messageType, message, contentType);
+
+ if (!isHistoryLoaded)
+ {
+ synchronized (incomingEventBuffer)
+ {
+ incomingEventBuffer.add(chatMessage);
+ }
+ }
+ else
+ {
+ appendChatMessage(chatMessage);
+ }
// change the last history message timestamp after we add one.
this.lastHistoryMsgTimestamp = date;
}
/**
+ * Adds the given error message to the chat window conversation area.
+ *
+ * @param contactName the name of the contact, for which the error occured
+ * @param message the error message
+ */
+ public void addErrorMessage(String contactName, String message)
+ {
+ this.addMessage(contactName, System.currentTimeMillis(),
+ Constants.ERROR_MESSAGE, message, "text");
+ }
+
+ /**
+ * Passes the message to the contained <code>ChatConversationPanel</code>
+ * for processing and appends it at the end of the conversationPanel
+ * document.
+ *
+ * @param chatMessage the message to append
+ */
+ private void appendChatMessage(ChatMessage chatMessage)
+ {
+ String processedMessage
+ = this.conversationPanel.processMessage(chatMessage);
+
+ this.conversationPanel.appendMessageToEnd(processedMessage);
+ }
+
+ /**
* Passes the message to the contained <code>ChatConversationPanel</code>
* for processing.
*
@@ -577,14 +623,16 @@ public class ChatPanel
*
* @return a string containing the processed message.
*/
- public String processHistoryMessage(String contactName,
+ private String processHistoryMessage(String contactName,
long date,
String messageType,
String message,
String contentType)
{
- return this.conversationPanel.processMessage(contactName, date,
- messageType, message, contentType);
+ ChatMessage chatMessage = new ChatMessage(contactName, date,
+ messageType, message, contentType);
+
+ return this.conversationPanel.processMessage(chatMessage);
}
/**
@@ -803,6 +851,91 @@ public class ChatPanel
return isProtocolHidden && isGreyHistoryDisabled;
}
+ /**
+ * Sends the given file through the currently selected chat transport by
+ * using the given fileComponent to visualize the transfer process in the
+ * chat conversation panel.
+ *
+ * @param file the file to send
+ * @param fileComponent the file component to use for visualization
+ */
+ public void sendFile( final File file,
+ final SendFileConversationComponent fileComponent)
+ {
+ final ChatTransport currentChatTransport
+ = chatSession.getCurrentChatTransport();
+
+ SwingWorker worker = new SwingWorker()
+ {
+ public Object construct()
+ throws Exception
+ {
+ final FileTransfer fileTransfer
+ = currentChatTransport.sendFile(file);
+
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ fileComponent.setProtocolFileTransfer(fileTransfer);
+ }
+ });
+
+ return "";
+ }
+
+ public void catchException(Throwable ex)
+ {
+ logger.error("Failed to send message.", ex);
+
+ refreshWriteArea();
+
+ if (ex instanceof IllegalStateException)
+ {
+ addErrorMessage(
+ chatSession.getCurrentChatTransport().getName(),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_SEND_CONNECTION_PROBLEM"));
+ }
+ else
+ {
+ addErrorMessage(
+ chatSession.getCurrentChatTransport().getName(),
+ GuiActivator.getResources().getI18NString(
+ "service.gui.MSG_DELIVERY_UNKNOWN_ERROR",
+ new String[]{ex.getMessage()}));
+ }
+ }
+ };
+
+ worker.start();
+ }
+
+ /**
+ * Sends the given file through the currently selected chat transport.
+ *
+ * @param file the file to send
+ */
+ public void sendFile(final File file)
+ {
+ final ChatTransport fileTransferTransport
+ = findFileTransferChatTransport();
+
+ final SendFileConversationComponent fileComponent
+ = new SendFileConversationComponent(
+ this,
+ fileTransferTransport.getDisplayName(),
+ file);
+
+ getChatConversationPanel().addComponent(fileComponent);
+
+ this.sendFile(file, fileComponent);
+ }
+
+ /**
+ * Sends the text contained in the write area as an SMS message or an
+ * instance message depending on the "send SMS" check box.
+ */
protected void sendMessage()
{
if (sendSmsCheckBox.isSelected())
@@ -815,6 +948,9 @@ public class ChatPanel
}
}
+ /**
+ * Sends the text contained in the write area as an SMS message.
+ */
public void sendSmsMessage()
{
String messageText = getTextFromWriteArea(
@@ -846,20 +982,17 @@ public class ChatPanel
this.refreshWriteArea();
- this.processMessage(
+ this.addMessage(
smsChatTransport.getName(),
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
messageText,
"plain/text");
- this.processMessage(
+ this.addErrorMessage(
smsChatTransport.getName(),
- System.currentTimeMillis(),
- Constants.ERROR_MESSAGE,
GuiActivator.getResources().getI18NString(
- "service.gui.SEND_SMS_NOT_SUPPORTED"),
- "plain/text");
+ "service.gui.SEND_SMS_NOT_SUPPORTED"));
return;
}
@@ -911,20 +1044,17 @@ public class ChatPanel
{
logger.error("Failed to send message.", ex);
- this.processMessage(
+ this.addMessage(
chatSession.getCurrentChatTransport().getName(),
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
messageText,
mimeType);
- this.processMessage(
+ this.addErrorMessage(
chatSession.getCurrentChatTransport().getName(),
- System.currentTimeMillis(),
- Constants.ERROR_MESSAGE,
GuiActivator.getResources().getI18NString(
- "service.gui.MSG_SEND_CONNECTION_PROBLEM"),
- "text");
+ "service.gui.MSG_SEND_CONNECTION_PROBLEM"));
}
catch (Exception ex)
{
@@ -932,21 +1062,18 @@ public class ChatPanel
this.refreshWriteArea();
- this.processMessage(
+ this.addMessage(
chatSession.getCurrentChatTransport().getName(),
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
messageText,
mimeType);
- this.processMessage(
+ this.addErrorMessage(
chatSession.getCurrentChatTransport().getName(),
- System.currentTimeMillis(),
- Constants.ERROR_MESSAGE,
GuiActivator.getResources().getI18NString(
"service.gui.MSG_DELIVERY_UNKNOWN_ERROR",
- new String[]{ex.getMessage()}),
- "text");
+ new String[]{ex.getMessage()}));
}
if (chatSession.getCurrentChatTransport().allowsTypingNotifications())
@@ -1014,9 +1141,11 @@ public class ChatPanel
this.repaint();
}
+ /**
+ * Listens for SMS messages and shows them in the chat.
+ */
private class SmsMessageListener implements MessageListener
{
-
/**
* @param chatTransport Currently unused
*/
@@ -1030,13 +1159,13 @@ public class ChatPanel
Contact contact = evt.getDestinationContact();
- processMessage(
+ addMessage(
contact.getDisplayName(),
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
msg.getContent(), msg.getContentType());
- processMessage(
+ addMessage(
contact.getDisplayName(),
System.currentTimeMillis(),
Constants.ACTION_MESSAGE,
@@ -1087,19 +1216,16 @@ public class ChatPanel
"service.gui.MSG_DELIVERY_UNKNOWN_ERROR");
}
- processMessage(
+ addMessage(
metaContact.getDisplayName(),
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
sourceMessage.getContent(),
sourceMessage.getContentType());
- processMessage(
+ addErrorMessage(
metaContact.getDisplayName(),
- System.currentTimeMillis(),
- Constants.ERROR_MESSAGE,
- errorMsg,
- "text");
+ errorMsg);
}
public void messageReceived(MessageReceivedEvent evt)
@@ -1127,14 +1253,19 @@ public class ChatPanel
}
/**
- * Loads history for the chat meta contact in a separate thread. Implements
- * the <tt>ChatPanel.loadHistory</tt> method.
+ * Loads history messages ignoring the message given by the
+ * escapedMessageID. Implements the
+ * <tt>ChatPanel.loadHistory(String)</tt> method.
+ *
+ * @param escapedMessageID The id of the message that should be ignored.
*/
- public void loadHistory()
+ public void loadHistory(final String escapedMessageID)
{
- new Thread()
+ SwingWorker historyWorker = new SwingWorker()
{
- public void run()
+ private Collection<EventObject> historyList;
+
+ public Object construct() throws Exception
{
// Load the history period, which initializes the
// firstMessageTimestamp and the lastMessageTimeStamp variables.
@@ -1143,49 +1274,39 @@ public class ChatPanel
loadHistoryPeriod();
// Load the last N=CHAT_HISTORY_SIZE messages from history.
- Collection<EventObject> historyList = chatSession.getHistory(
+ historyList = chatSession.getHistory(
ConfigurationManager.getChatHistorySize());
- if(historyList.size() > 0) {
- class ProcessHistory implements Runnable
- {
- Collection<EventObject> historyList;
-
- ProcessHistory(Collection<EventObject> historyList)
- {
- this.historyList = historyList;
- }
+ return historyList;
+ }
- public void run()
- {
- processHistory(historyList, null);
- }
- }
- SwingUtilities.invokeLater(new ProcessHistory(historyList));
+ /**
+ * Called on the event dispatching thread (not on the worker thread)
+ * after the <code>construct</code> method has returned.
+ */
+ public void finished()
+ {
+ if(historyList != null && historyList.size() > 0)
+ {
+ processHistory(historyList, escapedMessageID);
}
+
+ // Add incoming events accumulated while the history was loading
+ // at the end of the chat.
+ addIncomingEvents();
}
- }.start();
+ };
+
+ historyWorker.start();
}
/**
- * Loads history messages ignoring the message given by the
- * escapedMessageID. Implements the
- * <tt>ChatPanel.loadHistory(String)</tt> method.
- *
- * @param escapedMessageID The id of the message that should be ignored.
+ * Loads history for the chat meta contact in a separate thread. Implements
+ * the <tt>ChatPanel.loadHistory</tt> method.
*/
- public void loadHistory(final String escapedMessageID)
+ public void loadHistory()
{
- // Load the history period, which initializes the
- // firstMessageTimestamp and the lastMessageTimeStamp variables.
- // Used to disable/enable history flash buttons in the chat
- // window tool bar.
- loadHistoryPeriod();
-
- Collection<EventObject> historyList = chatSession.getHistory(
- ConfigurationManager.getChatHistorySize());
-
- processHistory(historyList, escapedMessageID);
+ this.loadHistory(null);
}
/**
@@ -1265,7 +1386,7 @@ public class ChatPanel
transportSelectorBox.updateTransportStatus(chatTransport);
// Show a status message to the user.
- String message = getChatConversationPanel().processMessage(
+ this.addMessage(
chatTransport.getName(),
System.currentTimeMillis(),
Constants.STATUS_MESSAGE,
@@ -1274,8 +1395,6 @@ public class ChatPanel
new String[]{chatTransport.getStatus().getStatusName()}),
"text/plain");
- getChatConversationPanel().appendMessageToEnd(message);
-
if(ConfigurationManager.isMultiChatWindowEnabled())
{
if (getChatWindow().getChatTabCount() > 0) {
@@ -1402,7 +1521,7 @@ public class ChatPanel
public void updateChatContactStatus(ChatContact chatContact,
String statusMessage)
{
- this.processMessage(
+ this.addMessage(
chatContact.getName(),
System.currentTimeMillis(),
Constants.STATUS_MESSAGE,
@@ -1416,7 +1535,7 @@ public class ChatPanel
{
subjectPanel.setSubject(subject);
- this.processMessage(
+ this.addMessage(
chatSession.getChatName(),
System.currentTimeMillis(),
Constants.STATUS_MESSAGE,
@@ -1429,6 +1548,29 @@ public class ChatPanel
}
/**
+ * Adds the given <tt>IncomingFileTransferRequest</tt> to the conversation
+ * panel in order to notify the user of the incoming file.
+ *
+ * @param request the request to display in the conversation panel
+ */
+ public void addIncomingFileTransferRequest(
+ IncomingFileTransferRequest request)
+ {
+ ReceiveFileConversationComponent component
+ = new ReceiveFileConversationComponent(request);
+
+ if (!isHistoryLoaded)
+ {
+ synchronized (incomingEventBuffer)
+ {
+ incomingEventBuffer.add(component);
+ }
+ }
+ else
+ this.getChatConversationPanel().addComponent(component);
+ }
+
+ /**
* Implements <tt>Chat.addChatFocusListener</tt> method. Adds the given
* <tt>ChatFocusListener</tt> to the list of listeners.
*
@@ -1459,6 +1601,44 @@ public class ChatPanel
/**
* Returns the first chat transport for the current chat session that
+ * supports file transfer.
+ *
+ * @return the first chat transport for the current chat session that
+ * supports file transfer.
+ */
+ public ChatTransport findFileTransferChatTransport()
+ {
+ ChatTransport currentChatTransport
+ = chatSession.getCurrentChatTransport();
+
+ if (currentChatTransport.getProtocolProvider()
+ .getOperationSet(OperationSetFileTransfer.class) != null)
+ {
+ return currentChatTransport;
+ }
+ else
+ {
+ Iterator<ChatTransport> chatTransportsIter
+ = chatSession.getChatTransports();
+
+ while (chatTransportsIter.hasNext())
+ {
+ ChatTransport chatTransport = chatTransportsIter.next();
+
+ Object fileTransferOpSet
+ = chatTransport.getProtocolProvider()
+ .getOperationSet(OperationSetFileTransfer.class);
+
+ if (fileTransferOpSet != null)
+ return chatTransport;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the first chat transport for the current chat session that
* supports group chat.
*
* @return the first chat transport for the current chat session that
@@ -1595,4 +1775,32 @@ public class ChatPanel
}
}
}
+
+ /**
+ * Adds all events accumulated in the incoming event buffer to the
+ * chat conversation panel.
+ */
+ private void addIncomingEvents()
+ {
+ synchronized (incomingEventBuffer)
+ {
+ Iterator<Object> eventBufferIter = incomingEventBuffer.iterator();
+
+ while(eventBufferIter.hasNext())
+ {
+ Object incomingEvent = eventBufferIter.next();
+
+ if (incomingEvent instanceof ChatMessage)
+ {
+ this.appendChatMessage((ChatMessage) incomingEvent);
+ }
+ else if (incomingEvent instanceof Component)
+ {
+ this.getChatConversationPanel()
+ .addComponent((Component) incomingEvent);
+ }
+ }
+ }
+ }
+
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionRenderer.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionRenderer.java
index 5c54315..7b72500 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionRenderer.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatSessionRenderer.java
@@ -6,6 +6,8 @@
*/
package net.java.sip.communicator.impl.gui.main.chat;
+import net.java.sip.communicator.service.protocol.*;
+
/**
* The <tt>ChatSessionRenderer</tt> is the connector between the
* <tt>ChatSession</tt> and the <tt>ChatPanel</tt>, which represents the UI
@@ -73,4 +75,13 @@ public interface ChatSessionRenderer
* @param subject the new subject to set.
*/
public void setChatSubject(String subject);
+
+ /**
+ * Adds the given <tt>IncomingFileTransferRequest</tt> to the conversation
+ * panel in order to notify the user of the incoming file.
+ *
+ * @param request the request to display in the conversation panel
+ */
+ public void addIncomingFileTransferRequest(
+ IncomingFileTransferRequest request);
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java
new file mode 100644
index 0000000..a56fe03
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java
@@ -0,0 +1,293 @@
+/*
+ * 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.gui.main.chat;
+
+import java.awt.datatransfer.*;
+import java.awt.im.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.text.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * A TransferHandler that we use to handle copying, pasting and DnD operations
+ * in our <tt>ChatPanel</tt>. The string handler is heavily inspired
+ * by Sun's <tt>DefaultTransferHandler</tt> with the main difference being that
+ * we only accept pasting of plain text. We do this in order to avoid html
+ * support problems that appear when pasting formatted text into our editable
+ * area.
+ *
+ * @author Emil Ivov
+ * @author Yana Stamcheva
+ */
+public class ChatTransferHandler
+ extends TransferHandler
+{
+ /**
+ * This class logger.
+ */
+ private final static Logger logger
+ = Logger.getLogger(ChatTransferHandler.class);
+
+ /**
+ * The chat panel involved in the copy/paste/DnD operation.
+ */
+ private final ChatPanel chatPanel;
+
+ /**
+ * Constructs the <tt>ChatTransferHandler</tt> by specifying the
+ * <tt>ChatPanel</tt> we're currently dealing with.
+ *
+ * @param chatPanel the <tt>ChatPanel</tt> we're currently dealing with
+ */
+ public ChatTransferHandler(ChatPanel chatPanel)
+ {
+ this.chatPanel = chatPanel;
+ }
+
+ /**
+ * Returns the type of transfer actions supported by the source;
+ * any bitwise-OR combination of <tt>COPY</tt>, <tt>MOVE</tt>
+ * and <tt>LINK</tt>.
+ * <p>
+ * Some models are not mutable, so a transfer operation of <tt>MOVE</tt>
+ * should not be advertised in that case. Returning <tt>NONE</tt>
+ * disables transfers from the component.
+ *
+ * @param c the component holding the data to be transferred;
+ * provided to enable sharing of <code>TransferHandler</code>s
+ * @return {@code COPY} if the transfer property can be found,
+ * otherwise returns <code>NONE</code>
+ */
+ public int getSourceActions(JComponent c)
+ {
+ return TransferHandler.COPY_OR_MOVE;
+ }
+
+ /** Indicates whether a component will accept an import of the given
+ * set of data flavors prior to actually attempting to import it. We return
+ * <tt>true</tt> to indicate that the transfer with at least one of the
+ * given flavors would work and <tt>false</tt> to reject the transfer.
+ * <p>
+ * @param support the object containing the details of the transfer, not
+ * <code>null</code>.
+ * @param transferFlavors the data formats available
+ * @return true if the data can be inserted into the component, false
+ * otherwise
+ * @throws NullPointerException if <code>support</code> is {@code null}
+ */
+ public boolean canImport(JComponent comp, DataFlavor flavor[])
+ {
+ JTextComponent c = (JTextComponent)comp;
+
+ if (!(c.isEditable() && c.isEnabled()))
+ {
+ return false;
+ }
+
+ for (int i = 0, n = flavor.length; i < n; i++)
+ {
+ if (flavor[i].equals(DataFlavor.javaFileListFlavor)
+ || flavor[i].equals(DataFlavor.stringFlavor))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Creates a transferable for text pane components in order to enable drag
+ * and drop of text.
+ */
+ public Transferable createTransferable(JComponent comp)
+ {
+ if (comp instanceof JTextPane)
+ {
+ return new SelectedTextTransferable((JTextPane) comp);
+ }
+
+ return null;
+ }
+
+ /**
+ * Handles transfers to the chat panel from the clip board or a
+ * DND drop operation. The <tt>Transferable</tt> parameter contains the
+ * data that needs to be imported.
+ * <p>
+ * @param comp the component to receive the transfer;
+ * @param transferable the data to import
+ * @return true if the data was inserted into the component and false
+ * otherwise
+ * @see #importData(TransferHandler.TransferSupport)
+ */
+ public boolean importData(JComponent comp, Transferable t)
+ {
+ if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
+ {
+ try
+ {
+ Object o = t.getTransferData(DataFlavor.javaFileListFlavor);
+
+ if (o instanceof java.util.Collection)
+ {
+ Collection<File> files = (Collection<File>) o;
+
+ for(File file: files)
+ {
+ chatPanel.sendFile(file);
+ }
+
+ // Otherwise fire files dropped event.
+ return true;
+ }
+ }
+ catch (UnsupportedFlavorException e)
+ {
+ logger.debug("Failed to drop files.", e);
+ }
+ catch (IOException e)
+ {
+ logger.debug("Failed to drop files.", e);
+ }
+ }
+ else if (t.isDataFlavorSupported(DataFlavor.stringFlavor))
+ {
+ InputContext inputContext = comp.getInputContext();
+ if (inputContext != null)
+ {
+ inputContext.endComposition();
+ }
+ try
+ {
+ BufferedReader reader = new BufferedReader(
+ DataFlavor.stringFlavor.getReaderForText(t));
+
+ StringBuffer buffToPaste = new StringBuffer();
+ String line = reader.readLine();
+
+ while(line != null)
+ {
+ buffToPaste.append(line);
+
+ //read next line
+ line = reader.readLine();
+ if(line != null)
+ buffToPaste.append("\n");
+ }
+
+ ((JTextComponent)comp)
+ .replaceSelection(buffToPaste.toString());
+ return true;
+ }
+ catch (UnsupportedFlavorException ufe)
+ {
+ //ignore
+ }
+ catch (IOException ioe)
+ {
+ //ignore
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Handles transport (cut and copy) from the chat panel to
+ * <tt>clipboard</tt>. This method will only transfer plain text and would
+ * explicitly ignore any formatting.
+ * <p>
+ * @param comp the component holding the data to be transferred;
+ * provided to enable sharing of <code>TransferHandler</code>s
+ * @param clip the clipboard to transfer the data into
+ * @param action the transfer action requested; this should
+ * be a value of either <code>COPY</code> or <code>MOVE</code>;
+ * the operation performed is the intersection of the transfer
+ * capabilities given by getSourceActions and the requested action;
+ * the intersection may result in an action of <code>NONE</code>
+ * if the requested action isn't supported
+ * @throws IllegalStateException if the clipboard is currently unavailable
+ * @see Clipboard#setContents(Transferable, ClipboardOwner)
+ */
+ public void exportToClipboard(JComponent comp,
+ Clipboard clipboard,
+ int action)
+ throws IllegalStateException
+ {
+ if (comp instanceof JTextComponent)
+ {
+ JTextComponent textComponent = (JTextComponent)comp;
+ int startIndex = textComponent.getSelectionStart();
+ int endIndex = textComponent.getSelectionEnd();
+ if (startIndex != endIndex)
+ {
+ try
+ {
+ Document doc = textComponent.getDocument();
+ String srcData = doc.getText(startIndex,
+ endIndex - startIndex);
+ StringSelection contents =new StringSelection(srcData);
+
+ // this may throw an IllegalStateException,
+ // but it will be caught and handled in the
+ // action that invoked this method
+ clipboard.setContents(contents, null);
+
+ if (action == TransferHandler.MOVE)
+ {
+ doc.remove(startIndex, endIndex - startIndex);
+ }
+ }
+ catch (BadLocationException ble)
+ {
+ //we simply ignore
+ }
+ }
+ }
+ }
+
+ /**
+ * Transferable for text pane components that enables drag and drop of text.
+ */
+ public class SelectedTextTransferable implements Transferable
+ {
+ private JTextPane textPane;
+
+ public SelectedTextTransferable(JTextPane textPane)
+ {
+ this.textPane = textPane;
+ }
+
+ // Returns supported flavors
+ public DataFlavor[] getTransferDataFlavors()
+ {
+ return new DataFlavor[]{DataFlavor.stringFlavor};
+ }
+
+ // Returns true if flavor is supported
+ public boolean isDataFlavorSupported(DataFlavor flavor)
+ {
+ return DataFlavor.stringFlavor.equals(flavor);
+ }
+
+ // Returns Selected Text
+ public Object getTransferData(DataFlavor flavor)
+ throws UnsupportedFlavorException, IOException
+ {
+ if (!DataFlavor.stringFlavor.equals(flavor))
+ {
+ throw new UnsupportedFlavorException(flavor);
+ }
+
+ return textPane.getSelectedText();
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java
index 75ec902..8d2dc04 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java
@@ -7,6 +7,8 @@
package net.java.sip.communicator.impl.gui.main.chat;
+import java.io.*;
+
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
@@ -117,6 +119,14 @@ public interface ChatTransport
public int sendTypingNotification(int typingState);
/**
+ * Sends the given file trough this chat transport.
+ *
+ * @param file the file to send
+ */
+ public FileTransfer sendFile(File file)
+ throws Exception;
+
+ /**
* Invites a contact to join this chat.
*
* @param contactAddress the address of the contact we invite
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWindow.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWindow.java
index 6179adb..50f2db8 100755
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWindow.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWindow.java
@@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.gui.main.chat;
import java.awt.*;
import java.awt.event.*;
+import java.io.*;
import java.util.*;
import javax.swing.*;
@@ -434,10 +435,12 @@ public class ChatWindow
ChatTransport inviteChatTransport = chatPanel.findInviteChatTransport();
- if (inviteChatTransport != null)
- mainToolBar.enableInviteButton(true);
- else
- mainToolBar.enableInviteButton(false);
+ mainToolBar.enableInviteButton(inviteChatTransport != null);
+
+ ChatTransport sendFileTransport
+ = chatPanel.findFileTransferChatTransport();
+
+ mainToolBar.enableSendFileButton(sendFileTransport != null);
mainToolBar.changeHistoryButtonsState(chatPanel);
@@ -1213,4 +1216,22 @@ public class ChatWindow
}
}
}
+
+ /**
+ *
+ */
+ public void directoryDropped(File file, Point point)
+ {
+
+ }
+
+ /**
+ *
+ */
+ public void fileDropped(File file, Point point)
+ {
+ ChatPanel chatPanel = getCurrentChatPanel();
+
+ chatPanel.sendFile(file);
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
index 149e21b..4a26bbc 100755
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
@@ -82,12 +82,12 @@ public class ChatWritePanel
this.editorPane.addMouseListener(this);
this.editorPane.setCursor(
Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
-
- //set our own transfer (i.e. copy/paste) handler
- this.editorPane.setTransferHandler(new ChatWritePanelTransferHandler());
+ this.editorPane.setDragEnabled(true);
+ this.editorPane.setTransferHandler(new ChatTransferHandler(chatPanel));
this.editTextToolBar = new EditTextToolBar(this);
- this.editTextToolBar.setVisible(ConfigurationManager.isChatStylebarVisible());
+ this.editTextToolBar.setVisible(
+ ConfigurationManager.isChatStylebarVisible());
this.add(editTextToolBar, BorderLayout.NORTH);
this.add(scrollPane, BorderLayout.CENTER);
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanelTransferHandler.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanelTransferHandler.java
deleted file mode 100644
index 77f2bae..0000000
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanelTransferHandler.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * 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.gui.main.chat;
-
-import java.awt.datatransfer.*;
-import java.awt.im.*;
-import java.io.*;
-
-import javax.swing.*;
-import javax.swing.text.*;
-
-/**
- * A TransferHandler that we use to handle copying and pasting in our chat write
- * panel. The handler is heavily inspired by Sun's
- * <tt>DefaultTransferHandler</tt> with the main difference being that we only
- * accept pasting of plain text. We do this in order to avoid html support
- * problems that appear when pasting formatted text into our editable area.
- */
-public class ChatWritePanelTransferHandler
- extends TransferHandler
-{
-
- /**
- * Handles transport (cut and copy) from the chat panel to
- * <tt>clipboard</tt>. This method will only transfer plain text and would
- * explicitly ignore any formatting.
- * <p>
- * @param comp the component holding the data to be transferred;
- * provided to enable sharing of <code>TransferHandler</code>s
- * @param clip the clipboard to transfer the data into
- * @param action the transfer action requested; this should
- * be a value of either <code>COPY</code> or <code>MOVE</code>;
- * the operation performed is the intersection of the transfer
- * capabilities given by getSourceActions and the requested action;
- * the intersection may result in an action of <code>NONE</code>
- * if the requested action isn't supported
- * @throws IllegalStateException if the clipboard is currently unavailable
- * @see Clipboard#setContents(Transferable, ClipboardOwner)
- */
- public void exportToClipboard(JComponent comp,
- Clipboard clipboard,
- int action)
- throws IllegalStateException
- {
- if (comp instanceof JTextComponent)
- {
- JTextComponent textComponent = (JTextComponent)comp;
- int startIndex = textComponent.getSelectionStart();
- int endIndex = textComponent.getSelectionEnd();
- if (startIndex != endIndex)
- {
- try
- {
- Document doc = textComponent.getDocument();
- String srcData = doc.getText(startIndex,
- endIndex - startIndex);
- StringSelection contents =new StringSelection(srcData);
-
- // this may throw an IllegalStateException,
- // but it will be caught and handled in the
- // action that invoked this method
- clipboard.setContents(contents, null);
-
- if (action == TransferHandler.MOVE)
- {
- doc.remove(startIndex, endIndex - startIndex);
- }
- }
- catch (BadLocationException ble)
- {
- //we simply ignore
- }
- }
- }
- }
-
- /**
- * Handles transfers to the chat panel write area from the clip board or a
- * DND drop operation. The <tt>Transferable</tt> parameter contains the
- * data that needs to be imported.
- * <p>
- * @param comp the component to receive the transfer;
- * @param transferable the data to import
- * @return true if the data was inserted into the component and false
- * otherwise
- * @see #importData(TransferHandler.TransferSupport)
- */
- public boolean importData(JComponent comp, Transferable transferable)
- {
- if (comp instanceof JTextComponent)
- {
- DataFlavor flavor
- = getFlavor(transferable.getTransferDataFlavors());
-
- if (flavor != null)
- {
- InputContext inputContext = comp.getInputContext();
- if (inputContext != null)
- {
- inputContext.endComposition();
- }
- try
- {
- BufferedReader reader = new BufferedReader(
- flavor.getReaderForText(transferable));
-
- StringBuffer buffToPaste = new StringBuffer();
- String line = reader.readLine();
-
- while(line != null)
- {
- buffToPaste.append(line);
-
- //read next line
- line = reader.readLine();
- if(line != null)
- buffToPaste.append("\n");
- }
-
- ((JTextComponent)comp)
- .replaceSelection(buffToPaste.toString());
- return true;
- }
- catch (UnsupportedFlavorException ufe)
- {
- //ignore
- }
- catch (IOException ioe)
- {
- //ignore
- }
- }
- }
- return false;
- }
-
- /** Indicates whether a component will accept an import of the given
- * set of data flavors prior to actually attempting to import it. We return
- * <tt>true</tt> to indicate that the transfer with at least one of the
- * given flavors would work and <tt>false</tt> to reject the transfer.
- * <p>
- * @param support the object containing the details of
- * the transfer, not <code>null</code>.
- * @param transferFlavors the data formats available
- * @return true if the data can be inserted into the component, false otherwise
- * @throws NullPointerException if <code>support</code> is {@code null}
- */
- public boolean canImport(JComponent comp,
- DataFlavor[] transferFlavors)
- {
- JTextComponent c = (JTextComponent)comp;
-
- if (!(c.isEditable() && c.isEnabled()))
- {
- return false;
- }
- return (getFlavor(transferFlavors) != null);
- }
-
- /**
- * Returns the type of transfer actions supported by the source;
- * any bitwise-OR combination of <tt>COPY</tt>, <tt>MOVE</tt>
- * and <tt>LINK</tt>.
- * <p>
- * Some models are not mutable, so a transfer operation of <tt>MOVE</tt>
- * should not be advertised in that case. Returning <tt>NONE</tt>
- * disables transfers from the component.
- *
- * @param c the component holding the data to be transferred;
- * provided to enable sharing of <code>TransferHandler</code>s
- * @return {@code COPY} if the transfer property can be found,
- * otherwise returns <code>NONE</code>
- */
- public int getSourceActions(JComponent c)
- {
- //we always return null here since we don't need to do anything with
- //the source component at this stage/
- return NONE;
- }
-
- /**
- * Locates and returns a string flavor.
- *
- * @param flavors the haystack containing all supported flavors.
- *
- * @return a string flavor if one exists in the <tt>flavors</tt> array and
- * false otherwise.
- */
- private DataFlavor getFlavor(DataFlavor[] flavors)
- {
- if (flavors != null)
- {
- for (int counter = 0; counter < flavors.length; counter++)
- {
- if (flavors[counter].equals(DataFlavor.stringFlavor))
- {
- return flavors[counter];
- }
- }
- }
-
- return null;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java
index a6e6784..48c9930 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java
@@ -7,11 +7,15 @@
package net.java.sip.communicator.impl.gui.main.chat;
+import java.io.*;
+
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/**
+ * The single chat implementation of the <tt>ChatTransport</tt> interface that
+ * provides abstraction to protocol provider access.
*
* @author Yana Stamcheva
*/
@@ -19,13 +23,14 @@ public class MetaContactChatTransport
implements ChatTransport,
ContactPresenceStatusListener
{
- private Logger logger = Logger.getLogger(MetaContactChatTransport.class);
+ private static final Logger logger
+ = Logger.getLogger(MetaContactChatTransport.class);
- private ChatSession parentChatSession;
+ private final ChatSession parentChatSession;
- private Contact contact;
+ private final Contact contact;
- private OperationSetPresence presenceOpSet;
+ private final OperationSetPresence presenceOpSet;
public MetaContactChatTransport(ChatSession chatSession,
Contact contact)
@@ -37,7 +42,8 @@ public class MetaContactChatTransport
(OperationSetPresence) contact.getProtocolProvider()
.getOperationSet(OperationSetPresence.class);
- presenceOpSet.addContactPresenceStatusListener(this);
+ if (presenceOpSet != null)
+ presenceOpSet.addContactPresenceStatusListener(this);
}
public Contact getContact()
@@ -142,6 +148,24 @@ public class MetaContactChatTransport
}
/**
+ * Returns <code>true</code> if this chat transport supports file transfer,
+ * otherwise returns <code>false</code>.
+ *
+ * @return <code>true</code> if this chat transport supports file transfer,
+ * otherwise returns <code>false</code>.
+ */
+ public boolean allowsFileTransfer()
+ {
+ Object ftOpSet = contact.getProtocolProvider()
+ .getOperationSet(OperationSetFileTransfer.class);
+
+ if (ftOpSet != null)
+ return true;
+ else
+ return false;
+ }
+
+ /**
* Sends the given instant message trough this chat transport, by specifying
* the mime type (html or plain text).
*
@@ -239,9 +263,29 @@ public class MetaContactChatTransport
return ChatPanel.TYPING_NOTIFICATION_SEND_FAILED;
}
+ /**
+ * Sends the given file through this chat transport file transfer operation
+ * set.
+ * @param file the file to send
+ * @throws Exception if anything goes wrong
+ */
+ public FileTransfer sendFile(File file)
+ throws Exception
+ {
+ // If this chat transport does not support instant messaging we do
+ // nothing here.
+ if (!allowsFileTransfer())
+ return null;
+
+ OperationSetFileTransfer ftOpSet
+ = (OperationSetFileTransfer) contact.getProtocolProvider()
+ .getOperationSet(OperationSetFileTransfer.class);
+
+ return ftOpSet.sendFile(contact, file);
+ }
+
public void inviteChatContact(String contactAddress, String reason)
{
-
}
/**
@@ -369,9 +413,15 @@ public class MetaContactChatTransport
*/
public void dispose()
{
- presenceOpSet.removeContactPresenceStatusListener(this);
+ if (presenceOpSet != null)
+ presenceOpSet.removeContactPresenceStatusListener(this);
}
+ /**
+ * Returns the descriptor of this chat transport.
+ *
+ * @return the descriptor of this chat transport
+ */
public Object getDescriptor()
{
return contact;
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/SendSmsDialog.java b/src/net/java/sip/communicator/impl/gui/main/chat/SendSmsDialog.java
index 5a386f2..c920dad 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/SendSmsDialog.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/SendSmsDialog.java
@@ -131,20 +131,17 @@ public class SendSmsDialog
chatPanel.refreshWriteArea();
- chatPanel.processMessage(
+ chatPanel.addMessage(
phoneNumber,
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
message,
"text/plain");
- chatPanel.processMessage(
+ chatPanel.addErrorMessage(
phoneNumber,
- System.currentTimeMillis(),
- Constants.ERROR_MESSAGE,
GuiActivator.getResources()
- .getI18NString("service.gui.SMS_SEND_CONNECTION_PROBLEM"),
- "text");
+ .getI18NString("service.gui.SMS_SEND_CONNECTION_PROBLEM"));
}
catch (Exception ex)
{
@@ -152,21 +149,18 @@ public class SendSmsDialog
chatPanel.refreshWriteArea();
- chatPanel.processMessage(
+ chatPanel.addMessage(
phoneNumber,
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
message,
"text/plain");
- chatPanel.processMessage(
+ chatPanel.addErrorMessage(
phoneNumber,
- System.currentTimeMillis(),
- Constants.ERROR_MESSAGE,
GuiActivator.getResources()
.getI18NString("service.gui.MSG_DELIVERY_UNKNOWN_ERROR",
- new String[]{ex.getMessage()}),
- "text");
+ new String[]{ex.getMessage()}));
}
this.dispose();
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
index 92b71e8..9676385 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatManager.java
@@ -141,7 +141,7 @@ public class ConferenceChatManager
if(chatPanel != null)
{
- chatPanel.processMessage(sourceChatRoom.getParentProvider()
+ chatPanel.addMessage(sourceChatRoom.getParentProvider()
.getAccountID().getUserID(),
evt.getTimestamp(),
messageType,
@@ -205,7 +205,7 @@ public class ConferenceChatManager
String messageContent = message.getContent();
- chatPanel.processMessage(
+ chatPanel.addMessage(
sourceMember.getName(),
evt.getTimestamp(),
messageType,
@@ -333,18 +333,16 @@ public class ConferenceChatManager
ChatPanel chatPanel
= chatWindowManager.getMultiChat(sourceChatRoom);
- chatPanel.processMessage(
+ chatPanel.addMessage(
destMember.getName(),
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
sourceMessage.getContent(),
sourceMessage.getContentType());
- chatPanel.processMessage(
+ chatPanel.addErrorMessage(
destMember.getName(),
- System.currentTimeMillis(),
- Constants.ERROR_MESSAGE,
- errorMsg, "text");
+ errorMsg);
chatWindowManager.openChat(chatPanel, false);
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java
index e9034c4..8debb9f 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java
@@ -7,11 +7,15 @@
package net.java.sip.communicator.impl.gui.main.chat.conference;
+import java.io.*;
+
import net.java.sip.communicator.impl.gui.main.chat.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
/**
+ * The conference implementation of the <tt>ChatTransport</tt> interface that
+ * provides abstraction to access to protocol providers.
*
* @author Yana Stamcheva
*/
@@ -165,7 +169,17 @@ public class ConferenceChatTransport
}
/**
- * Invites the given contact in this chat conferenece.
+ * Sending files through a chat room is not yet supported by this chat
+ * transport implementation.
+ */
+ public FileTransfer sendFile(File file)
+ throws Exception
+ {
+ return null;
+ }
+
+ /**
+ * Invites the given contact in this chat conference.
*
* @param contactAddress the address of the contact to invite
* @param reason the reason for the invitation
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java b/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java
new file mode 100644
index 0000000..f3b142a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/ReceiveFileConversationComponent.java
@@ -0,0 +1,587 @@
+/*
+ * 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.gui.main.chat.filetransfer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.chat.*;
+import net.java.sip.communicator.impl.gui.utils.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.*;
+import net.java.sip.communicator.util.swing.*;
+
+/**
+ * The <tt>ReceiveFileConversationComponent</tt> is the component shown in the
+ * conversation area of the chat window to display a incoming file transfer.
+ *
+ * @author Yana Stamcheva
+ */
+public class ReceiveFileConversationComponent
+ extends ChatConversationComponent
+ implements ActionListener,
+ FileTransferStatusListener,
+ FileTransferProgressListener
+{
+ private final Logger logger
+ = Logger.getLogger(SendFileConversationComponent.class);
+
+ private final FileDragLabel imageLabel = new FileDragLabel();
+ private final JLabel titleLabel = new JLabel();
+ private final JLabel fileLabel = new JLabel();
+ private final JTextArea errorArea = new JTextArea();
+ private final JLabel errorIconLabel = new JLabel(
+ new ImageIcon(ImageLoader.getImage(ImageLoader.EXCLAMATION_MARK)));
+
+ private ChatConversationButton acceptButton = new ChatConversationButton();
+ private ChatConversationButton rejectButton = new ChatConversationButton();
+ private ChatConversationButton cancelButton = new ChatConversationButton();
+
+ private ChatConversationButton openFileButton
+ = new ChatConversationButton();
+ private ChatConversationButton openFolderButton
+ = new ChatConversationButton();
+
+ private JProgressBar progressBar = new JProgressBar();
+
+ private static final ResourceManagementService resources
+ = GuiActivator.getResources();
+
+ private IncomingFileTransferRequest fileTransferRequest;
+
+ private FileTransfer fileTransfer;
+
+ private File downloadFile;
+
+ /**
+ * Creates a <tt>ReceiveFileConversationComponent</tt>.
+ *
+ * @param fileTransferRequest the <tt>IncomingFileTransferRequest</tt>
+ * associated with this component
+ */
+ public ReceiveFileConversationComponent(
+ IncomingFileTransferRequest fileTransferRequest)
+ {
+ this.fileTransferRequest = fileTransferRequest;
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 4;
+ constraints.anchor = GridBagConstraints.NORTHWEST;
+ constraints.insets = new Insets(5, 5, 5, 5);
+
+ add(imageLabel, constraints);
+ imageLabel.setIcon(new ImageIcon(
+ ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON)));
+
+ constraints.gridx = 1;
+ constraints.gridy = 0;
+ constraints.gridwidth = 2;
+ constraints.gridheight = 1;
+ constraints.fill=GridBagConstraints.HORIZONTAL;
+ constraints.weightx = 1.0;
+ constraints.anchor = GridBagConstraints.NORTHWEST;
+ constraints.insets = new Insets(5, 5, 5, 5);
+
+ add(titleLabel, constraints);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_TRANSFER_REQUEST_RECIEVED",
+ new String[]{fileTransferRequest.getSender().getDisplayName()}));
+ titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 11f));
+
+ constraints.gridx = 1;
+ constraints.gridy = 1;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 5, 5);
+
+ add(fileLabel, constraints);
+ fileLabel.setText(fileTransferRequest.getFileName());
+
+ constraints.gridx = 1;
+ constraints.gridy = 2;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+ constraints.fill = GridBagConstraints.NONE;
+
+ add(errorIconLabel, constraints);
+ errorIconLabel.setVisible(false);
+
+ constraints.gridx = 2;
+ constraints.gridy = 2;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+ constraints.fill = GridBagConstraints.HORIZONTAL;
+
+ add(errorArea, constraints);
+ errorArea.setForeground(
+ new Color(resources.getColor("service.gui.ERROR_FOREGROUND")));
+ setTextAreaStyle(errorArea);
+ errorArea.setVisible(false);
+
+ constraints.gridx = 1;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = 0.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+ constraints.fill = GridBagConstraints.NONE;
+
+ add(acceptButton, constraints);
+ acceptButton.setText(
+ GuiActivator.getResources().getI18NString("service.gui.ACCEPT"));
+ acceptButton.addActionListener(this);
+
+ constraints.gridx = 2;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = 0.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+
+ add(rejectButton, constraints);
+ rejectButton.setText(
+ GuiActivator.getResources().getI18NString("service.gui.REJECT"));
+ rejectButton.addActionListener(this);
+
+ constraints.gridx = 1;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = 0.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+
+ add(cancelButton, constraints);
+ cancelButton.setText(
+ GuiActivator.getResources().getI18NString("service.gui.CANCEL"));
+ cancelButton.addActionListener(this);
+ cancelButton.setVisible(false);
+
+ constraints.gridx = 1;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = 0.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+
+ add(openFileButton, constraints);
+ openFileButton.setText(
+ GuiActivator.getResources().getI18NString("service.gui.OPEN"));
+ openFileButton.setVisible(false);
+ openFileButton.addActionListener(this);
+
+ constraints.gridx = 2;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = 0.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+
+ add(openFolderButton, constraints);
+ openFolderButton.setText(
+ GuiActivator.getResources().getI18NString(
+ "service.gui.OPEN_FOLDER"));
+ openFolderButton.setVisible(false);
+ openFolderButton.addActionListener(this);
+
+ constraints.gridx = 1;
+ constraints.gridy = 2;
+ constraints.gridwidth = 2;
+ constraints.gridheight = 1;
+ constraints.weightx = 1.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+ constraints.ipadx = 150;
+
+ add(progressBar, constraints);
+ progressBar.setVisible(false);
+ progressBar.setStringPainted(true);
+ progressBar.setMaximum((int)fileTransferRequest.getFileSize());
+ }
+
+ /**
+ * Handles button actions.
+ */
+ public void actionPerformed(ActionEvent evt)
+ {
+ JButton sourceButton = (JButton) evt.getSource();
+
+ if (sourceButton.equals(acceptButton))
+ {
+ titleLabel.setText(resources
+ .getI18NString("service.gui.FILE_TRANSFER_PREPARING",
+ new String[]{fileTransferRequest.getSender()
+ .getDisplayName()}));
+ acceptButton.setVisible(false);
+ rejectButton.setVisible(false);
+ cancelButton.setVisible(true);
+ progressBar.setVisible(true);
+
+ downloadFile = createFile();
+
+ new AcceptFile().start();
+ }
+ else if (sourceButton.equals(rejectButton))
+ {
+ fileTransferRequest.rejectFile();
+
+ acceptButton.setVisible(false);
+ rejectButton.setVisible(false);
+ fileLabel.setText("");
+ titleLabel.setText(
+ resources.getI18NString("service.gui.FILE_TRANSFER_CANCELED"));
+ }
+ else if (sourceButton.equals(cancelButton))
+ {
+ fileTransfer.cancel();
+ }
+ else if (sourceButton.equals(openFileButton))
+ {
+ this.openFile(downloadFile);
+ }
+ else if (sourceButton.equals(openFolderButton))
+ {
+ try
+ {
+ File downloadDir = GuiActivator.getFileAccessService()
+ .getDefaultDownloadDirectory();
+
+ GuiActivator.getDesktopService().open(downloadDir);
+ }
+ catch (IllegalArgumentException e)
+ {
+ logger.debug("Unable to open folder.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FOLDER_DOES_NOT_EXIST"));
+ }
+ catch (NullPointerException e)
+ {
+ logger.debug("Unable to open folder.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FOLDER_DOES_NOT_EXIST"));
+ }
+ catch (UnsupportedOperationException e)
+ {
+ logger.debug("Unable to open folder.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FILE_OPEN_NOT_SUPPORTED"));
+ }
+ catch (SecurityException e)
+ {
+ logger.debug("Unable to open folder.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FOLDER_OPEN_NO_PERMISSION"));
+ }
+ catch (IOException e)
+ {
+ logger.debug("Unable to open folder.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FOLDER_OPEN_NO_APPLICATION"));
+ }
+ catch (Exception e)
+ {
+ logger.debug("Unable to open file.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FOLDER_OPEN_FAILED"));
+ }
+ }
+ }
+
+ /**
+ * Creates the file to download.
+ *
+ * @return the file to download.
+ */
+ private File createFile()
+ {
+ File downloadFile = null;
+ File downloadDir = null;
+ try
+ {
+ downloadDir = GuiActivator.getFileAccessService()
+ .getDefaultDownloadDirectory();
+ }
+ catch (IOException e)
+ {
+ logger.debug("Unable to find download directory.");
+ }
+
+ if (downloadDir != null)
+ downloadFile = new File(downloadDir,
+ fileTransferRequest.getFileName());
+
+ return downloadFile;
+ }
+
+ /**
+ * Handles status changes in file transfer.
+ */
+ public void statusChanged(FileTransferStatusChangeEvent event)
+ {
+ int status = event.getNewStatus();
+ String fromContactName
+ = fileTransferRequest.getSender().getDisplayName();
+
+ if (status == FileTransfer.PREPARING)
+ {
+ progressBar.setVisible(false);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_TRANSFER_PREPARING",
+ new String[]{fromContactName}));
+ }
+ else if (status == FileTransfer.FAILED)
+ {
+ progressBar.setVisible(false);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_RECEIVE_FAILED",
+ new String[]{fromContactName}));
+
+ setWarningStyle(true);
+ }
+ else if (status == FileTransfer.IN_PROGRESS)
+ {
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_RECEIVING_FROM",
+ new String[]{fromContactName}));
+ setWarningStyle(false);
+
+ if (!progressBar.isVisible())
+ {
+ progressBar.setVisible(true);
+ }
+ }
+ else if (status == FileTransfer.COMPLETED)
+ {
+ if (downloadFile != null)
+ {
+ imageLabel.setFile(downloadFile);
+ setFileIcon(downloadFile);
+ }
+
+ progressBar.setVisible(false);
+ cancelButton.setVisible(false);
+ openFileButton.setVisible(true);
+ openFolderButton.setVisible(true);
+
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_RECEIVE_COMPLETED",
+ new String[]{fromContactName}));
+ fileLabel.setText(fileTransferRequest.getFileName());
+
+ imageLabel.setToolTipText(
+ resources.getI18NString("service.gui.OPEN_FILE_FROM_IMAGE"));
+ imageLabel.addMouseListener(new MouseAdapter()
+ {
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() > 1)
+ {
+ openFile(downloadFile);
+ }
+ }
+ });
+ }
+ else if (status == FileTransfer.CANCELED)
+ {
+ progressBar.setVisible(false);
+ cancelButton.setVisible(false);
+
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_TRANSFER_CANCELED"));
+ setWarningStyle(true);
+ }
+ else if (status == FileTransfer.REFUSED)
+ {
+ progressBar.setVisible(false);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_TRANSFER_REFUSED",
+ new String[]{fromContactName}));
+ cancelButton.setVisible(false);
+ setWarningStyle(true);
+ }
+ }
+
+ /**
+ * Updates progress bar progress line every time a progress event has been
+ * received.
+ */
+ public void progressChanged(FileTransferProgressEvent event)
+ {
+ progressBar.setValue((int) event.getProgress());
+
+ ByteFormat format = new ByteFormat();
+ String bytesSent = format.format(
+ event.getFileTransfer().getTransferedBytes());
+ progressBar.setString(bytesSent
+ + " " + resources.getI18NString("service.gui.SENT"));
+ }
+
+ /**
+ * Sets the icon for the given file.
+ *
+ * @param file the file to set an icon for
+ */
+ private void setFileIcon(File file)
+ {
+ if (FileUtils.isImage(file.getName()))
+ {
+ try
+ {
+ ImageIcon image = new ImageIcon(file.toURI().toURL());
+ image = ImageUtils
+ .getScaledRoundedIcon(image.getImage(), 64, 64);
+ imageLabel.setIcon(image);
+ }
+ catch (MalformedURLException e)
+ {
+ logger.debug("Could not locate image.", e);
+ imageLabel.setIcon(new ImageIcon(
+ ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON)));
+ }
+ }
+ else
+ {
+ Icon icon = FileUtils.getIcon(file);
+
+ if (icon == null)
+ icon = new ImageIcon(
+ ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON));
+
+ imageLabel.setIcon(icon);
+ }
+ }
+
+ /**
+ * Accepts the file in a new thread.
+ */
+ private class AcceptFile extends SwingWorker
+ {
+ public Object construct()
+ {
+ fileTransfer = fileTransferRequest.acceptFile(downloadFile);
+
+ return "";
+ }
+
+ public void finished()
+ {
+ fileTransfer.addStatusListener(
+ ReceiveFileConversationComponent.this);
+ fileTransfer.addProgressListener(
+ ReceiveFileConversationComponent.this);
+ }
+ }
+
+ /**
+ * Shows the given error message in the error area of this component.
+ *
+ * @param message the message to show
+ */
+ private void showErrorMessage(String message)
+ {
+ errorArea.setText(message);
+ errorIconLabel.setVisible(true);
+ errorArea.setVisible(true);
+ }
+
+ /**
+ * Sets a custom style for the given text area.
+ *
+ * @param textArea the text area to style
+ */
+ private void setTextAreaStyle(JTextArea textArea)
+ {
+ textArea.setOpaque(false);
+ textArea.setLineWrap(true);
+ textArea.setWrapStyleWord(true);
+ }
+
+ /**
+ * Opens the given file through the <tt>DesktopService</tt>.
+ *
+ * @param downloadFile the file to open
+ */
+ private void openFile(File downloadFile)
+ {
+ try
+ {
+ GuiActivator.getDesktopService().open(downloadFile);
+ }
+ catch (IllegalArgumentException e)
+ {
+ logger.debug("Unable to open file.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FILE_DOES_NOT_EXIST"));
+ }
+ catch (NullPointerException e)
+ {
+ logger.debug("Unable to open file.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FILE_DOES_NOT_EXIST"));
+ }
+ catch (UnsupportedOperationException e)
+ {
+ logger.debug("Unable to open file.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FILE_OPEN_NOT_SUPPORTED"));
+ }
+ catch (SecurityException e)
+ {
+ logger.debug("Unable to open file.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FILE_OPEN_NO_PERMISSION"));
+ }
+ catch (IOException e)
+ {
+ logger.debug("Unable to open file.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FILE_OPEN_NO_APPLICATION"));
+ }
+ catch (Exception e)
+ {
+ logger.debug("Unable to open file.", e);
+
+ this.showErrorMessage(
+ resources.getI18NString(
+ "service.gui.FILE_OPEN_FAILED"));
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/SendFileConversationComponent.java b/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/SendFileConversationComponent.java
new file mode 100644
index 0000000..2b94a07
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/filetransfer/SendFileConversationComponent.java
@@ -0,0 +1,317 @@
+/*
+ * 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.gui.main.chat.filetransfer;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.impl.gui.*;
+import net.java.sip.communicator.impl.gui.main.chat.*;
+import net.java.sip.communicator.impl.gui.utils.*;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.service.resources.*;
+import net.java.sip.communicator.util.*;
+
+/**
+ * The <tt>SendFileConversationComponent</tt> is the component added in the
+ * chat conversation when user sends a file.
+ *
+ * @author Yana Stamcheva
+ */
+public class SendFileConversationComponent
+ extends ChatConversationComponent
+ implements ActionListener,
+ FileTransferStatusListener,
+ FileTransferProgressListener
+{
+ private final Logger logger
+ = Logger.getLogger(SendFileConversationComponent.class);
+
+ private final JLabel imageLabel = new JLabel();
+ private final JLabel titleLabel = new JLabel();
+ private final JLabel fileLabel = new JLabel();
+
+ private ChatConversationButton cancelButton = new ChatConversationButton();
+ private ChatConversationButton retryButton = new ChatConversationButton();
+
+ private JProgressBar progressBar = new JProgressBar();
+
+ private static final ResourceManagementService resources
+ = GuiActivator.getResources();
+
+ private final String toContactName;
+
+ private FileTransfer fileTransfer;
+
+ private final ChatPanel parentChatPanel;
+
+ private final File file;
+
+ /**
+ * Creates a <tt>SendFileConversationComponent</tt> by specifying the parent
+ * chat panel, where this component is added, the destination contact of
+ * the transfer and file to transfer.
+ *
+ * @param chatPanel the parent chat panel, where this component is added
+ * @param toContactName the name of the destination contact
+ * @param file the file to transfer
+ */
+ public SendFileConversationComponent( ChatPanel chatPanel,
+ String toContactName,
+ File file)
+ {
+ this.parentChatPanel = chatPanel;
+ this.toContactName = toContactName;
+ this.file = file;
+
+ constraints.gridx = 0;
+ constraints.gridy = 0;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 4;
+ constraints.anchor = GridBagConstraints.NORTHWEST;
+ constraints.insets = new Insets(5, 5, 5, 5);
+
+ add(imageLabel, constraints);
+ this.setFileIcon(file);
+
+ constraints.gridx = 1;
+ constraints.gridy = 0;
+ constraints.gridwidth = 2;
+ constraints.gridheight = 1;
+ constraints.weightx = 1.0;
+ constraints.anchor = GridBagConstraints.NORTHWEST;
+ constraints.insets = new Insets(5, 5, 5, 5);
+
+ add(titleLabel, constraints);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_WAITING_TO_ACCEPT",
+ new String[]{toContactName}));
+ titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, 11f));
+
+ constraints.gridx = 1;
+ constraints.gridy = 1;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 5, 5);
+
+ add(fileLabel, constraints);
+ fileLabel.setText(getFileName(file));
+
+ constraints.gridx = 1;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = 0.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+
+ add(cancelButton, constraints);
+ cancelButton.setText(
+ GuiActivator.getResources().getI18NString("service.gui.CANCEL"));
+ cancelButton.addActionListener(this);
+
+ constraints.gridx = 1;
+ constraints.gridy = 3;
+ constraints.gridwidth = 1;
+ constraints.gridheight = 1;
+ constraints.weightx = 0.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+
+ add(retryButton, constraints);
+ retryButton.setText(
+ GuiActivator.getResources().getI18NString("service.gui.RETRY"));
+ retryButton.addActionListener(this);
+ retryButton.setVisible(false);
+
+ constraints.gridx = 1;
+ constraints.gridy = 2;
+ constraints.gridwidth = 2;
+ constraints.gridheight = 1;
+ constraints.weightx = 1.0;
+ constraints.anchor = GridBagConstraints.WEST;
+ constraints.insets = new Insets(0, 5, 0, 5);
+ constraints.ipadx = 150;
+
+ add(progressBar, constraints);
+ progressBar.setMaximum((int) file.length());
+ progressBar.setVisible(false);
+ progressBar.setStringPainted(true);
+ }
+
+ /**
+ * Sets the <tt>FileTransfer</tt> object received from the protocol and
+ * corresponding to the file transfer process associated with this panel.
+ *
+ * @param fileTransfer the <tt>FileTransfer</tt> object associated with this
+ * panel
+ */
+ public void setProtocolFileTransfer(FileTransfer fileTransfer)
+ {
+ this.fileTransfer = fileTransfer;
+
+ fileTransfer.addStatusListener(this);
+ fileTransfer.addProgressListener(this);
+ }
+
+ /**
+ * Returns the name of the given file.
+ *
+ * @param file the file
+ * @return the name of the given file
+ */
+ private String getFileName(File file)
+ {
+ String fileName = file.getName();
+ long fileSize = file.length();
+ ByteFormat format = new ByteFormat();
+ String text = format.format(fileSize);
+
+ return fileName + " (" + text + ")";
+ }
+
+ /**
+ * Sets the icon for the given file.
+ *
+ * @param file the file to set an icon for
+ */
+ private void setFileIcon(File file)
+ {
+ if (FileUtils.isImage(file.getName()))
+ {
+ try
+ {
+ ImageIcon image = new ImageIcon(file.toURI().toURL());
+ image = ImageUtils
+ .getScaledRoundedIcon(image.getImage(), 64, 64);
+ imageLabel.setIcon(image);
+ }
+ catch (MalformedURLException e)
+ {
+ logger.debug("Could not locate image.", e);
+ imageLabel.setIcon(new ImageIcon(
+ ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON)));
+ }
+ }
+ else
+ {
+ Icon icon = FileUtils.getIcon(file);
+
+ if (icon == null)
+ icon = new ImageIcon(
+ ImageLoader.getImage(ImageLoader.DEFAULT_FILE_ICON));
+
+ imageLabel.setIcon(icon);
+ }
+ }
+
+ /**
+ * Handles file transfer status changes. Updates the interface to reflect
+ * the changes.
+ */
+ public void statusChanged(FileTransferStatusChangeEvent event)
+ {
+ int status = event.getNewStatus();
+
+ if (status == FileTransfer.PREPARING)
+ {
+ progressBar.setVisible(false);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_TRANSFER_PREPARING",
+ new String[]{toContactName}));
+ cancelButton.setVisible(true);
+ retryButton.setVisible(false);
+ }
+ else if (status == FileTransfer.FAILED)
+ {
+ progressBar.setVisible(false);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_UNABLE_TO_SEND",
+ new String[]{toContactName}));
+ cancelButton.setVisible(false);
+ retryButton.setVisible(true);
+ setWarningStyle(true);
+ }
+ else if (status == FileTransfer.IN_PROGRESS)
+ {
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_SENDING_TO",
+ new String[]{toContactName}));
+ setWarningStyle(false);
+
+ if (!progressBar.isVisible())
+ {
+ progressBar.setVisible(true);
+ }
+ }
+ else if (status == FileTransfer.COMPLETED)
+ {
+ progressBar.setVisible(false);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_SEND_COMPLETED",
+ new String[]{toContactName}));
+ cancelButton.setVisible(false);
+ retryButton.setVisible(false);
+ }
+ else if (status == FileTransfer.CANCELED)
+ {
+ progressBar.setVisible(false);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_TRANSFER_CANCELED"));
+ cancelButton.setVisible(false);
+ retryButton.setVisible(true);
+ setWarningStyle(true);
+ }
+ else if (status == FileTransfer.REFUSED)
+ {
+ progressBar.setVisible(false);
+ titleLabel.setText(resources.getI18NString(
+ "service.gui.FILE_SEND_REFUSED",
+ new String[]{toContactName}));
+ cancelButton.setVisible(false);
+ retryButton.setVisible(true);
+ setWarningStyle(true);
+ }
+ }
+
+ /**
+ * Updates progress bar progress line every time a progress event has been
+ * received.
+ */
+ public void progressChanged(FileTransferProgressEvent event)
+ {
+ progressBar.setValue((int) event.getProgress());
+
+ ByteFormat format = new ByteFormat();
+ String bytesSent = format.format(
+ event.getFileTransfer().getTransferedBytes());
+ progressBar.setString(bytesSent
+ + " " + resources.getI18NString("service.gui.SENT"));
+ }
+
+ /**
+ * Handles button actions.
+ */
+ public void actionPerformed(ActionEvent e)
+ {
+ JButton sourceButton = (JButton) e.getSource();
+
+ if (sourceButton.equals(cancelButton))
+ {
+ if (fileTransfer != null)
+ fileTransfer.cancel();
+ }
+ else if (sourceButton.equals(retryButton))
+ {
+ parentChatPanel.sendFile(file, this);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java b/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java
index 2ef9973..3f21be2 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java
@@ -42,7 +42,6 @@ public class HistoryWindow
MessageListener,
ChatRoomMessageListener
{
-
private static final Logger logger = Logger
.getLogger(HistoryWindow.class.getName());
@@ -66,7 +65,8 @@ public class HistoryWindow
private MessageHistoryService msgHistory;
- private Hashtable<Date, HTMLDocument> dateHistoryTable = new Hashtable<Date, HTMLDocument>();
+ private Hashtable<Date, HTMLDocument> dateHistoryTable
+ = new Hashtable<Date, HTMLDocument>();
private JLabel readyLabel = new JLabel(
GuiActivator.getResources().getI18NString("service.gui.READY"));
@@ -219,10 +219,12 @@ public class HistoryWindow
Iterator<EventObject> i = historyRecords.iterator();
String processedMessage = "";
- while (i.hasNext()) {
-
+ while (i.hasNext())
+ {
Object o = i.next();
+ ChatMessage chatMessage = null;
+
if(o instanceof MessageDeliveredEvent)
{
MessageDeliveredEvent evt = (MessageDeliveredEvent) o;
@@ -230,55 +232,60 @@ public class HistoryWindow
ProtocolProviderService protocolProvider = evt
.getDestinationContact().getProtocolProvider();
- processedMessage = chatConvPanel.processMessage(
+ chatMessage = new ChatMessage(
GuiActivator.getUIService().getMainFrame()
- .getAccount(protocolProvider),
- evt.getTimestamp(), Constants.OUTGOING_MESSAGE,
+ .getAccount(protocolProvider),
+ evt.getTimestamp(),
+ Constants.OUTGOING_MESSAGE,
evt.getSourceMessage().getContent(),
- evt.getSourceMessage().getContentType(),
- searchKeyword);
+ evt.getSourceMessage().getContentType());
}
else if(o instanceof MessageReceivedEvent)
{
MessageReceivedEvent evt = (MessageReceivedEvent) o;
- processedMessage = chatConvPanel.processMessage(
- evt.getSourceContact().getDisplayName(),
- evt.getTimestamp(), Constants.INCOMING_MESSAGE,
- evt.getSourceMessage().getContent(),
- evt.getSourceMessage().getContentType(),
- searchKeyword);
+ chatMessage = new ChatMessage(
+ evt.getSourceContact().getDisplayName(),
+ evt.getTimestamp(),
+ Constants.INCOMING_MESSAGE,
+ evt.getSourceMessage().getContent(),
+ evt.getSourceMessage().getContentType());
}
else if(o instanceof ChatRoomMessageReceivedEvent)
{
ChatRoomMessageReceivedEvent evt
= (ChatRoomMessageReceivedEvent) o;
- processedMessage = chatConvPanel.processMessage(
- evt.getSourceChatRoomMember().getName(),
- evt.getTimestamp(), Constants.INCOMING_MESSAGE,
- evt.getMessage().getContent(),
- evt.getMessage().getContentType(),
- searchKeyword);
+ chatMessage = new ChatMessage(
+ evt.getSourceChatRoomMember().getName(),
+ evt.getTimestamp(), Constants.INCOMING_MESSAGE,
+ evt.getMessage().getContent(),
+ evt.getMessage().getContentType());
}
else if(o instanceof ChatRoomMessageDeliveredEvent)
{
ChatRoomMessageDeliveredEvent evt
= (ChatRoomMessageDeliveredEvent) o;
+ chatMessage = new ChatMessage(
+ evt.getSourceChatRoom().getParentProvider()
+ .getAccountID().getUserID(),
+ evt.getTimestamp(), Constants.INCOMING_MESSAGE,
+ evt.getMessage().getContent(),
+ evt.getMessage().getContentType());
+ }
+
+ if (chatMessage != null)
+ {
processedMessage = chatConvPanel.processMessage(
- evt.getSourceChatRoom().getParentProvider()
- .getAccountID().getUserID(),
- evt.getTimestamp(), Constants.INCOMING_MESSAGE,
- evt.getMessage().getContent(),
- evt.getMessage().getContentType(),
- searchKeyword);
+ chatMessage, searchKeyword);
+
+ chatConvPanel.appendMessageToEnd(processedMessage);
}
- chatConvPanel.appendMessageToEnd(processedMessage);
}
}
this.chatConvPanel.setDefaultContent();
-
+
return this.chatConvPanel.getContent();
}
@@ -457,8 +464,8 @@ public class HistoryWindow
if(date != null) {
ignoreProgressDate = date;
}
- //Initializes the conversation panel with the data of the
- //last conversation.
+ //Initializes the conversation panel with the data of
+ //the last conversation.
int lastDateIndex = datesPanel.getDatesNumber() - 1;
datesPanel.setSelected(lastDateIndex);
}
@@ -531,7 +538,8 @@ public class HistoryWindow
/**
* Loads dates found for keyword.
*/
- private class KeywordDatesLoader extends Thread {
+ private class KeywordDatesLoader extends Thread
+ {
private Vector<Date> keywordDatesVector = new Vector<Date>();
private final String keyword;
@@ -568,37 +576,46 @@ public class HistoryWindow
}
if (msgList != null)
- for (Object o : msgList) {
+ for (Object o : msgList)
+ {
long date = 0;
-
- if (o instanceof MessageDeliveredEvent) {
+
+ if (o instanceof MessageDeliveredEvent)
+ {
MessageDeliveredEvent evt = (MessageDeliveredEvent)o;
date = evt.getTimestamp();
}
- else if (o instanceof MessageReceivedEvent) {
+ else if (o instanceof MessageReceivedEvent)
+ {
MessageReceivedEvent evt = (MessageReceivedEvent)o;
date = evt.getTimestamp();
}
-
+
long milisecondsPerDay = 24*60*60*1000;
- for(int j = 0; j < datesVector.size(); j ++) {
+ for(int j = 0; j < datesVector.size(); j ++)
+ {
Date date1 = datesVector.get(j);
-
+
if(Math.floor(date1.getTime()/milisecondsPerDay)
== Math.floor(date/milisecondsPerDay)
- && !keywordDatesVector.contains(date1)) {
-
+ && !keywordDatesVector.contains(date1))
+ {
+
keywordDatesVector.add(date1);
- }
- }
+ }
+ }
}
- Runnable updateDatesPanel = new Runnable() {
- public void run() {
+ Runnable updateDatesPanel = new Runnable()
+ {
+ public void run()
+ {
datesPanel.removeAllDates();
- if(keywordDatesVector.size() > 0) {
+ if(keywordDatesVector.size() > 0)
+ {
Date date = null;
- for(int i = 0; i < keywordDatesVector.size(); i++) {
+ for(int i = 0; i < keywordDatesVector.size(); i++)
+ {
date = keywordDatesVector.get(i);
/* I have tried to remove and add dates in the
@@ -608,7 +625,7 @@ public class HistoryWindow
* that a problem occured when one and the same
* selection was done twice.
*
- * if(!keywordDatesVector.contains(date)) {
+ * if(!keywordDatesVector.contains(date)) {
* datesPanel.removeDate(date);
* }
* else {
@@ -618,12 +635,14 @@ public class HistoryWindow
}*/
datesPanel.addDate(date);
}
- if(date != null) {
+ if(date != null)
+ {
ignoreProgressDate = date;
}
datesPanel.setSelected(datesPanel.getDatesNumber() - 1);
}
- else {
+ else
+ {
chatConvPanel.setDefaultContent();
}
}
@@ -729,27 +748,29 @@ public class HistoryWindow
if(containedContact != null)
{
int lastDateIndex = datesPanel.getDatesNumber() - 1;
-
+
// If dates aren't yet loaded we don't process the message.
if(lastDateIndex < 0)
return;
-
+
Date lastDate = datesPanel.getDate(lastDateIndex);
-
+
if(lastDate != null
&& GuiUtils.compareDates(lastDate.getTime(), timestamp) == 0)
{
HTMLDocument document = dateHistoryTable.get(lastDate);
-
+
if(document != null)
{
- String processedMessage = chatConvPanel.processMessage(
+ ChatMessage chatMessage = new ChatMessage(
contact.getDisplayName(),
timestamp, messageType,
messageContent,
- messageContentType,
- searchKeyword);
-
+ messageContentType);
+
+ String processedMessage = chatConvPanel.processMessage(
+ chatMessage, searchKeyword);
+
this.appendMessageToDocument(document, processedMessage);
}
}
@@ -757,9 +778,9 @@ public class HistoryWindow
|| GuiUtils.compareDates(lastDate.getTime(), timestamp) < 0)
{
long milisecondsPerDay = 24*60*60*1000;
-
+
Date date = new Date(timestamp - timestamp % milisecondsPerDay);
-
+
datesVector.add(date);
datesPanel.addDate(date);
}
@@ -775,31 +796,27 @@ public class HistoryWindow
{
Element root = doc.getDefaultRootElement();
- try {
+ try
+ {
doc.insertAfterEnd(root
.getElement(root.getElementCount() - 1), chatString);
- } catch (BadLocationException e) {
+ }
+ catch (BadLocationException e)
+ {
logger.error("Insert in the HTMLDocument failed.", e);
- } catch (IOException e) {
+ }
+ catch (IOException e)
+ {
logger.error("Insert in the HTMLDocument failed.", e);
}
}
public void messageDelivered(ChatRoomMessageDeliveredEvent evt)
- {
- // TODO Auto-generated method stub
-
- }
+ {}
public void messageDeliveryFailed(ChatRoomMessageDeliveryFailedEvent evt)
- {
- // TODO Auto-generated method stub
-
- }
+ {}
public void messageReceived(ChatRoomMessageReceivedEvent evt)
- {
- // TODO Auto-generated method stub
-
- }
+ {}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
index 33653b2..c95a6f1 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/toolBars/MainToolBar.java
@@ -8,6 +8,7 @@ package net.java.sip.communicator.impl.gui.main.chat.toolBars;
import java.awt.*;
import java.awt.event.*;
+import java.io.*;
import java.util.*;
import javax.swing.*;
@@ -87,41 +88,42 @@ public class MainToolBar
this.add(inviteButton);
this.add(historyButton);
this.add(optionsButton);
+ this.add(sendFileButton);
this.add(previousButton);
this.add(nextButton);
- this.previousButton.setName("previous");
- this.previousButton.setToolTipText(
- GuiActivator.getResources().getI18NString("service.gui.PREVIOUS"));
-
- this.nextButton.setName("next");
- this.nextButton.setToolTipText(
- GuiActivator.getResources().getI18NString("service.gui.NEXT"));
-
- this.sendFileButton.setName("sendFile");
- this.sendFileButton.setToolTipText(
- GuiActivator.getResources().getI18NString("service.gui.SEND_FILE"));
+ this.inviteButton.setName("invite");
+ this.inviteButton.setToolTipText(
+ GuiActivator.getResources().getI18NString("service.gui.INVITE"));
this.historyButton.setName("history");
this.historyButton.setToolTipText(
GuiActivator.getResources().getI18NString("service.gui.HISTORY")
+ " Ctrl-H");
- this.inviteButton.setName("invite");
- this.inviteButton.setToolTipText(
- GuiActivator.getResources().getI18NString("service.gui.INVITE"));
-
this.optionsButton.setName("options");
this.optionsButton.setToolTipText(
GuiActivator.getResources().getI18NString("service.gui.OPTIONS"));
- this.previousButton.addActionListener(this);
- this.nextButton.addActionListener(this);
- this.sendFileButton.addActionListener(this);
- this.historyButton.addActionListener(this);
+ this.sendFileButton.setName("sendFile");
+ this.sendFileButton.setToolTipText(
+ GuiActivator.getResources().getI18NString("service.gui.SEND_FILE"));
+
+ this.previousButton.setName("previous");
+ this.previousButton.setToolTipText(
+ GuiActivator.getResources().getI18NString("service.gui.PREVIOUS"));
+
+ this.nextButton.setName("next");
+ this.nextButton.setToolTipText(
+ GuiActivator.getResources().getI18NString("service.gui.NEXT"));
+
this.inviteButton.addActionListener(this);
+ this.historyButton.addActionListener(this);
this.optionsButton.addActionListener(this);
+ this.sendFileButton.addActionListener(this);
+ this.previousButton.addActionListener(this);
+ this.nextButton.addActionListener(this);
this.initPluginComponents();
}
@@ -155,8 +157,18 @@ public class MainToolBar
{
chatPanel.loadNextPageFromHistory();
}
- else if (buttonText.equals("sendFile")) {
+ else if (buttonText.equals("sendFile"))
+ {
+ JFileChooser fileChooser = new JFileChooser();
+ int result = fileChooser.showOpenDialog(this);
+
+ if (result == JFileChooser.APPROVE_OPTION)
+ {
+ File selectedFile = fileChooser.getSelectedFile();
+
+ messageWindow.getCurrentChatPanel().sendFile(selectedFile);
+ }
}
else if (buttonText.equals("history"))
{
@@ -327,8 +339,22 @@ public class MainToolBar
public void enableInviteButton(boolean isEnabled)
{
if (isEnabled)
- this.add(inviteButton, 0);
+ inviteButton.setVisible(true);
+ else
+ inviteButton.setVisible(false);
+ }
+
+ /**
+ * Enables or disables the send file button in this tool bar.
+ *
+ * @param isEnabled <code>true</code> if the send file button should be
+ * enabled, <code>false</code> - otherwise.
+ */
+ public void enableSendFileButton(boolean isEnabled)
+ {
+ if (isEnabled)
+ sendFileButton.setVisible(true);
else
- this.remove(inviteButton);
+ sendFileButton.setVisible(false);
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java
index 210ea1a..f2d1eea 100755
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java
@@ -42,6 +42,7 @@ public class ContactListPane
extends SCScrollPane
implements MessageListener,
TypingNotificationsListener,
+ FileTransferRequestListener,
ContactListListener,
PluginComponentListener
{
@@ -346,7 +347,7 @@ public class ContactListPane
messageType = Constants.SMS_MESSAGE;
}
- chatPanel.processMessage(
+ chatPanel.addMessage(
protocolContact.getDisplayName(),
evt.getTimestamp(),
messageType,
@@ -419,11 +420,12 @@ public class ContactListPane
ProtocolProviderService protocolProvider = evt
.getDestinationContact().getProtocolProvider();
- logger.trace("MESSAGE DELIVERED: process message to chat for contact: "
- + evt.getDestinationContact().getAddress()
- + " MESSAGE: " + msg.getContent());
+ logger.trace(
+ "MESSAGE DELIVERED: process message to chat for contact: "
+ + evt.getDestinationContact().getAddress()
+ + " MESSAGE: " + msg.getContent());
- chatPanel.processMessage(
+ chatPanel.addMessage(
this.mainFrame.getAccount(protocolProvider),
evt.getTimestamp(),
Constants.OUTGOING_MESSAGE,
@@ -485,19 +487,16 @@ public class ContactListPane
ChatPanel chatPanel = chatWindowManager
.getContactChat(metaContact, sourceContact);
- chatPanel.processMessage(
+ chatPanel.addMessage(
metaContact.getDisplayName(),
System.currentTimeMillis(),
Constants.OUTGOING_MESSAGE,
sourceMessage.getContent(),
sourceMessage.getContentType());
- chatPanel.processMessage(
+ chatPanel.addErrorMessage(
metaContact.getDisplayName(),
- System.currentTimeMillis(),
- Constants.ERROR_MESSAGE,
- errorMsg,
- "text");
+ errorMsg);
chatWindowManager.openChat(chatPanel, false);
}
@@ -569,6 +568,30 @@ public class ContactListPane
}
/**
+ * When a request has been received we show it to the user through the
+ * chat session renderer.
+ *
+ * @see FileTransferRequestListener#incomingRequestReceived(
+ * FileTransferRequestEvent)
+ */
+ public void incomingRequestReceived(FileTransferRequestEvent event)
+ {
+ IncomingFileTransferRequest request = event.getRequest();
+
+ Contact sourceContact = request.getSender();
+
+ MetaContact metaContact = mainFrame.getContactList()
+ .findMetaContactByContact(sourceContact);
+
+ ChatPanel chatPanel = chatWindowManager
+ .getContactChat(metaContact, sourceContact);
+
+ chatPanel.addIncomingFileTransferRequest(request);
+
+ chatWindowManager.openChat(chatPanel, false);
+ }
+
+ /**
* Send a proactive notification according to the proactive timer.
* The notification is fired only if another notification hasn't been
* recieved for more than 1 minute
@@ -733,9 +756,9 @@ public class ContactListPane
Object constraints = null;
if (pluginConstraints != null)
- constraints =
- UIServiceImpl
- .getBorderLayoutConstraintsFromContainer(pluginConstraints);
+ constraints = UIServiceImpl
+ .getBorderLayoutConstraintsFromContainer(
+ pluginConstraints);
else
constraints = BorderLayout.SOUTH;
diff --git a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
index 4d1f1cc..45ef291 100644
--- a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
+++ b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
@@ -25,6 +25,8 @@ Import-Package: org.osgi.framework,
net.java.sip.communicator.service.protocol.event,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.service.systray,
+ net.java.sip.communicator.service.desktop,
+ net.java.sip.communicator.service.fileaccess,
net.java.sip.communicator.util,
net.java.sip.communicator.util.swing,
net.java.sip.communicator.util.swing.event,
diff --git a/src/net/java/sip/communicator/impl/gui/utils/Constants.java b/src/net/java/sip/communicator/impl/gui/utils/Constants.java
index a2a097b..8d83c09 100755
--- a/src/net/java/sip/communicator/impl/gui/utils/Constants.java
+++ b/src/net/java/sip/communicator/impl/gui/utils/Constants.java
@@ -10,8 +10,10 @@ import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
+import java.util.*;
import javax.swing.*;
+import javax.swing.text.*;
import javax.swing.text.html.*;
import net.java.sip.communicator.impl.gui.*;
@@ -415,7 +417,7 @@ public class Constants
* Temporary method to load the css style used in the chat window.
* @param style
*/
- public static void loadSimpleStyle(StyleSheet style, Font defaultFont)
+ public static void loadSimpleStyle(StyleSheet styleSheet, Font defaultFont)
{
Reader r =
new BufferedReader(
@@ -424,7 +426,7 @@ public class Constants
"service.gui.HTML_TEXT_STYLE")));
if (defaultFont != null)
- style.addRule(
+ styleSheet.addRule(
"body, div, h1, h2, h3, h4, h5, h6, h7, p, td, th { "
+ "font-family: "
+ defaultFont.getName()
@@ -434,7 +436,7 @@ public class Constants
try
{
- style.loadRules(r, null);
+ styleSheet.loadRules(r, null);
}
catch (IOException ex)
{
diff --git a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java
index b651a32..469ec24 100644
--- a/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java
+++ b/src/net/java/sip/communicator/impl/gui/utils/ImageLoader.java
@@ -730,6 +730,12 @@ public class ImageLoader
public static final ImageID HIDE_ACTIONS_ROLLOVER_BUTTON
= new ImageID("service.gui.buttons.HIDE_ACTIONS_ROLLOVER_BUTTON");
+ /**
+ * The default icon used in file transfer ui.
+ */
+ public static final ImageID DEFAULT_FILE_ICON
+ = new ImageID("service.gui.icons.DEFAULT_FILE_ICON");
+
/*
* =======================================================================
* ------------------------ EDIT TOOLBAR ICONS ---------------------------
diff --git a/src/net/java/sip/communicator/impl/gui/utils/SIPCommHTMLEditorKit.java b/src/net/java/sip/communicator/impl/gui/utils/SIPCommHTMLEditorKit.java
index 2b10f37..955aba3 100644
--- a/src/net/java/sip/communicator/impl/gui/utils/SIPCommHTMLEditorKit.java
+++ b/src/net/java/sip/communicator/impl/gui/utils/SIPCommHTMLEditorKit.java
@@ -20,7 +20,6 @@ import javax.swing.text.html.ParagraphView;
*/
public class SIPCommHTMLEditorKit extends HTMLEditorKit
{
-
/**
* Returns the extended <tt>HTMLFactory</tt> defined here.
*/
@@ -66,7 +65,7 @@ public class SIPCommHTMLEditorKit extends HTMLEditorKit
}
/**
- * Calculate equirements along the minor axis. This
+ * Calculate requirements along the minor axis. This
* is implemented to forward the request to the logical
* view by calling getMinimumSpan, getPreferredSpan, and
* getMaximumSpan on it.
@@ -91,26 +90,4 @@ public class SIPCommHTMLEditorKit extends HTMLEditorKit
return sizeRequirements;
}
}
-
-
- /**
- * Create an uninitialized text storage model
- * that is appropriate for this type of editor.
- *
- * @return the model.
- */
- public Document createDefaultDocument()
- {
- StyleSheet styles = getStyleSheet();
- StyleSheet ss = new StyleSheet();
-
- ss.addStyleSheet(styles);
-
- HTMLDocument doc = new HTMLDocument(ss);
- doc.setParser(getParser());
- doc.setAsynchronousLoadPriority(4);
- doc.setTokenThreshold(100);
-
- return doc;
- }
}
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/systray/NewStatusMessageDialog.java b/src/net/java/sip/communicator/impl/osdependent/NewStatusMessageDialog.java
index 6380f58..fe1fb51 100644
--- a/src/net/java/sip/communicator/impl/systray/NewStatusMessageDialog.java
+++ b/src/net/java/sip/communicator/impl/osdependent/NewStatusMessageDialog.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray;
+package net.java.sip.communicator.impl.osdependent;
import java.awt.*;
import java.awt.event.*;
@@ -30,7 +30,7 @@ public class NewStatusMessageDialog
private final JTextField messageTextField = new JTextField();
private final JButton cancelButton = new JButton(
- SystrayActivator.getResources().getI18NString("service.gui.CANCEL"));
+ OsDependentActivator.getResources().getI18NString("service.gui.CANCEL"));
private final ProtocolProviderService protocolProvider;
@@ -53,17 +53,18 @@ public class NewStatusMessageDialog
*/
private void init()
{
- this.setTitle(SystrayActivator.getResources()
+ this.setTitle(OsDependentActivator.getResources()
.getI18NString("service.gui.NEW_STATUS_MESSAGE"));
JButton okButton =
- new JButton(SystrayActivator.getResources().getI18NString("service.gui.OK"));
+ new JButton(OsDependentActivator.getResources()
+ .getI18NString("service.gui.OK"));
this.getRootPane().setDefaultButton(okButton);
this.setPreferredSize(new Dimension(500, 200));
JTextArea infoArea = new JTextArea(
- SystrayActivator.getResources().getI18NString(
+ OsDependentActivator.getResources().getI18NString(
"service.gui.STATUS_MESSAGE_INFO"));
infoArea.setEditable(false);
infoArea.setLineWrap(true);
@@ -71,7 +72,7 @@ public class NewStatusMessageDialog
infoArea.setOpaque(false);
JLabel messageLabel = new JLabel(
- SystrayActivator.getResources().getI18NString(
+ OsDependentActivator.getResources().getI18NString(
"service.gui.NEW_STATUS_MESSAGE"));
JPanel dataPanel = new TransparentPanel(new BorderLayout(5, 5));
@@ -79,7 +80,7 @@ public class NewStatusMessageDialog
dataPanel.add(messageTextField, BorderLayout.CENTER);
JLabel infoTitleLabel = new JLabel(
- SystrayActivator.getResources().getI18NString(
+ OsDependentActivator.getResources().getI18NString(
"service.gui.NEW_STATUS_MESSAGE"));
infoTitleLabel.setHorizontalAlignment(JLabel.CENTER);
infoTitleLabel.setFont(
@@ -114,9 +115,11 @@ public class NewStatusMessageDialog
this.cancelButton.setName("cancel");
okButton.setMnemonic(
- SystrayActivator.getResources().getI18nMnemonic("service.gui.OK"));
+ OsDependentActivator.getResources()
+ .getI18nMnemonic("service.gui.OK"));
this.cancelButton.setMnemonic(
- SystrayActivator.getResources().getI18nMnemonic("service.gui.CANCEL"));
+ OsDependentActivator.getResources()
+ .getI18nMnemonic("service.gui.CANCEL"));
okButton.addActionListener(this);
this.cancelButton.addActionListener(this);
diff --git a/src/net/java/sip/communicator/impl/systray/SystrayActivator.java b/src/net/java/sip/communicator/impl/osdependent/OsDependentActivator.java
index 82511a0..8f548c9 100644
--- a/src/net/java/sip/communicator/impl/systray/SystrayActivator.java
+++ b/src/net/java/sip/communicator/impl/osdependent/OsDependentActivator.java
@@ -4,10 +4,11 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray;
+package net.java.sip.communicator.impl.osdependent;
-import net.java.sip.communicator.impl.systray.jdic.*;
+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.*;
@@ -20,7 +21,7 @@ import org.osgi.framework.*;
*
* @author Nicolas Chamouard
*/
-public class SystrayActivator
+public class OsDependentActivator
implements BundleActivator
{
/**
@@ -35,7 +36,7 @@ public class SystrayActivator
private static ResourceManagementService resourcesService;
private static final Logger logger =
- Logger.getLogger(SystrayActivator.class);
+ Logger.getLogger(OsDependentActivator.class);
/**
* Called when this bundle is started.
@@ -58,9 +59,21 @@ public class SystrayActivator
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 {
diff --git a/src/net/java/sip/communicator/impl/systray/PopupMessageHandlerTrayIconImpl.java b/src/net/java/sip/communicator/impl/osdependent/PopupMessageHandlerTrayIconImpl.java
index 1cbe327..55211db 100644
--- a/src/net/java/sip/communicator/impl/systray/PopupMessageHandlerTrayIconImpl.java
+++ b/src/net/java/sip/communicator/impl/osdependent/PopupMessageHandlerTrayIconImpl.java
@@ -4,19 +4,18 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray;
+package net.java.sip.communicator.impl.osdependent;
import java.awt.event.*;
import java.util.*;
-import java.util.List;
-import net.java.sip.communicator.impl.systray.jdic.*;
import net.java.sip.communicator.service.systray.*;
import net.java.sip.communicator.service.systray.event.*;
import net.java.sip.communicator.util.*;
/**
- * An implementation of the <tt>PopupMsystrayessageHandler</tt> using the tray icon.
+ * An implementation of the <tt>PopupMsystrayessageHandler</tt> using the
+ * tray icon.
*/
public class PopupMessageHandlerTrayIconImpl implements PopupMessageHandler
{
@@ -125,7 +124,7 @@ public class PopupMessageHandlerTrayIconImpl implements PopupMessageHandler
*/
public String toString()
{
- return SystrayActivator.getResources()
+ return OsDependentActivator.getResources()
.getI18NString("impl.systray.POPUP_MESSAGE_HANDLER");
}
}
diff --git a/src/net/java/sip/communicator/impl/systray/Resources.java b/src/net/java/sip/communicator/impl/osdependent/Resources.java
index baad7cf..ec63890 100644
--- a/src/net/java/sip/communicator/impl/systray/Resources.java
+++ b/src/net/java/sip/communicator/impl/osdependent/Resources.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray;
+package net.java.sip.communicator.impl.osdependent;
import java.net.*;
@@ -82,7 +82,7 @@ public class Resources
if (resourcesService == null)
resourcesService =
ResourceManagementServiceUtils
- .getService(SystrayActivator.bundleContext);
+ .getService(OsDependentActivator.bundleContext);
return resourcesService;
}
}
diff --git a/src/net/java/sip/communicator/impl/systray/StatusMessageMenu.java b/src/net/java/sip/communicator/impl/osdependent/StatusMessageMenu.java
index ce0f595..44b2a26 100644
--- a/src/net/java/sip/communicator/impl/systray/StatusMessageMenu.java
+++ b/src/net/java/sip/communicator/impl/osdependent/StatusMessageMenu.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray;
+package net.java.sip.communicator.impl.osdependent;
import java.awt.*;
import java.awt.event.*;
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/SystemTray.java b/src/net/java/sip/communicator/impl/osdependent/SystemTray.java
index a3d4472..7e98385 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/SystemTray.java
+++ b/src/net/java/sip/communicator/impl/osdependent/SystemTray.java
@@ -4,14 +4,14 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent;
import java.awt.*;
import java.lang.reflect.*;
import javax.swing.*;
-import net.java.sip.communicator.impl.systray.jdic.TrayIcon.*;
+import net.java.sip.communicator.impl.osdependent.TrayIcon.*;
import net.java.sip.communicator.util.*;
/**
@@ -48,10 +48,9 @@ public class SystemTray
}
catch (Exception ex)
{
- logger
- .error(
- "Failed to initialize the java.awt.SystemTray implementation.",
- ex);
+ logger.error(
+ "Failed to initialize the java.awt.SystemTray implementation.",
+ ex);
// We'll try org.jdesktop.jdic.tray then.
}
@@ -62,10 +61,9 @@ public class SystemTray
}
catch (Exception ex)
{
- logger
- .error(
- "Failed to initialize the org.jdesktop.jdic.tray implementation.",
- ex);
+ logger.error(
+ "Failed to initialize the org.jdesktop.jdic.tray implementation.",
+ ex);
}
return (defaultSystemTray = new SystemTray(peer));
}
@@ -103,7 +101,9 @@ public class SystemTray
throws NullPointerException,
IllegalArgumentException;
- TrayIconPeer createTrayIcon(ImageIcon icon, String tooltip, Object popup)
+ TrayIconPeer createTrayIcon(ImageIcon icon,
+ String tooltip,
+ Object popup)
throws IllegalArgumentException,
UnsupportedOperationException,
HeadlessException,
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/TrayIcon.java b/src/net/java/sip/communicator/impl/osdependent/TrayIcon.java
index 123a41a..f18b015 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/TrayIcon.java
+++ b/src/net/java/sip/communicator/impl/osdependent/TrayIcon.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent;
import java.awt.*;
import java.awt.event.*;
@@ -13,7 +13,7 @@ import java.lang.reflect.*;
import javax.swing.*;
import javax.swing.event.*;
-import net.java.sip.communicator.impl.systray.jdic.SystemTray.*;
+import net.java.sip.communicator.impl.osdependent.SystemTray.*;
/**
* @author Lubomir Marinov
@@ -165,12 +165,14 @@ public class TrayIcon
{
if (popup instanceof JPopupMenu)
{
- impl = constructor.newInstance(new Object[] { image, tooltip });
+ impl = constructor.newInstance(
+ new Object[] { image, tooltip });
addMouseListener(new AWTMouseAdapter((JPopupMenu) popup));
}
else
{
- impl = constructor.newInstance(new Object[] { image, tooltip, popup });
+ impl = constructor.newInstance(
+ new Object[] { image, tooltip, popup });
}
}
catch (IllegalAccessException ex)
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/ProviderRegistration.java b/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderRegistration.java
index 3157ba9..b5f7630 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/ProviderRegistration.java
+++ b/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderRegistration.java
@@ -5,9 +5,9 @@
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent.jdic;
-import net.java.sip.communicator.impl.systray.*;
+import net.java.sip.communicator.impl.osdependent.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
@@ -52,7 +52,7 @@ public class ProviderRegistration
{
try
{
- protocolProvider.register(SystrayActivator.getUIService()
+ protocolProvider.register(OsDependentActivator.getUIService()
.getDefaultSecurityAuthority(protocolProvider));
}
catch (OperationFailedException ex)
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/ProviderUnRegistration.java b/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderUnRegistration.java
index 0d41e12..11d30fd 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/ProviderUnRegistration.java
+++ b/src/net/java/sip/communicator/impl/osdependent/jdic/ProviderUnRegistration.java
@@ -5,7 +5,7 @@
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent.jdic;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/StatusSelector.java b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSelector.java
index 4d3002b..879f509 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/StatusSelector.java
+++ b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSelector.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent.jdic;
import java.awt.*;
import java.awt.event.*;
@@ -12,7 +12,7 @@ import java.util.*;
import javax.swing.*;
-import net.java.sip.communicator.impl.systray.*;
+import net.java.sip.communicator.impl.osdependent.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.util.*;
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/StatusSimpleSelector.java b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSimpleSelector.java
index dfb71fb..fe2b061 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/StatusSimpleSelector.java
+++ b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSimpleSelector.java
@@ -4,14 +4,14 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent.jdic;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
-import net.java.sip.communicator.impl.systray.*;
+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.*;
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/StatusSubMenu.java b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSubMenu.java
index 5b178c0..fc3ae09 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/StatusSubMenu.java
+++ b/src/net/java/sip/communicator/impl/osdependent/jdic/StatusSubMenu.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent.jdic;
import java.awt.*;
import java.beans.PropertyChangeEvent;
@@ -12,7 +12,7 @@ import java.util.*;
import javax.swing.*;
-import net.java.sip.communicator.impl.systray.*;
+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.*;
@@ -156,14 +156,14 @@ public class StatusSubMenu
*/
private void init()
{
- SystrayActivator.bundleContext
+ OsDependentActivator.bundleContext
.addServiceListener(new ProtocolProviderServiceListener());
ServiceReference[] protocolProviderRefs = null;
try
{
protocolProviderRefs
- = SystrayActivator.bundleContext.getServiceReferences(
+ = OsDependentActivator.bundleContext.getServiceReferences(
ProtocolProviderService.class.getName(),null);
}
catch (InvalidSyntaxException ex)
@@ -181,7 +181,7 @@ public class StatusSubMenu
for (int i = 0; i < protocolProviderRefs.length; i++)
{
ProtocolProviderService provider
- = (ProtocolProviderService) SystrayActivator.bundleContext
+ = (ProtocolProviderService) OsDependentActivator.bundleContext
.getService(protocolProviderRefs[i]);
boolean isHidden =
@@ -218,7 +218,7 @@ public class StatusSubMenu
return;
}
- Object service = SystrayActivator.bundleContext
+ Object service = OsDependentActivator.bundleContext
.getService( event.getServiceReference());
if (! (service instanceof ProtocolProviderService))
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java b/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java
index 563c3b8..06dd90f 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/SystrayServiceJdicImpl.java
+++ b/src/net/java/sip/communicator/impl/osdependent/jdic/SystrayServiceJdicImpl.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent.jdic;
import org.osgi.framework.*;
@@ -15,7 +15,7 @@ import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
-import net.java.sip.communicator.impl.systray.*;
+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.*;
@@ -67,7 +67,7 @@ public class SystrayServiceJdicImpl
* A reference of the <tt>ConfigurationService</tt> obtained from the
* <tt>SystrayServiceActivator</tt>
*/
- private final ConfigurationService configService = SystrayActivator.
+ private final ConfigurationService configService = OsDependentActivator.
getConfigurationService();
/**
@@ -129,7 +129,7 @@ public class SystrayServiceJdicImpl
{
this.initSystray();
- UIService ui = SystrayActivator.getUIService();
+ UIService ui = OsDependentActivator.getUIService();
if (ui != null)
ui.setExitOnMainWindowClose(false);
}
@@ -209,7 +209,7 @@ public class SystrayServiceJdicImpl
{
public void actionPerformed(ActionEvent e)
{
- UIService uiService = SystrayActivator.getUIService();
+ UIService uiService = OsDependentActivator.getUIService();
ExportedWindow win =
uiService.getExportedWindow(ExportedWindow.MAIN_WINDOW);
boolean setIsVisible = !win.isVisible();
@@ -271,13 +271,13 @@ public class SystrayServiceJdicImpl
{
pph = new PopupMessageHandlerTrayIconImpl(trayIcon);
popupHandlerSet.put(pph.getClass().getName(), pph);
- SystrayActivator.bundleContext.registerService(
+ OsDependentActivator.bundleContext.registerService(
PopupMessageHandler.class.getName(),
pph, null);
}
try
{
- SystrayActivator.bundleContext.addServiceListener(
+ OsDependentActivator.bundleContext.addServiceListener(
new ServiceListenerImpl(),
"(objectclass=" + PopupMessageHandler.class.getName() + ")");
} catch (Exception e)
@@ -290,7 +290,7 @@ public class SystrayServiceJdicImpl
ServiceReference[] handlerRefs = null;
try
{
- handlerRefs = SystrayActivator.bundleContext.getServiceReferences(
+ handlerRefs = OsDependentActivator.bundleContext.getServiceReferences(
PopupMessageHandler.class.getName(),
null);
} catch (InvalidSyntaxException ex)
@@ -304,7 +304,7 @@ public class SystrayServiceJdicImpl
for (int i = 0; i < handlerRefs.length; i++)
{
PopupMessageHandler handler =
- (PopupMessageHandler) SystrayActivator.bundleContext.
+ (PopupMessageHandler) OsDependentActivator.bundleContext.
getService(handlerRefs[i]);
String handlerName = handler.getClass().getName();
if (!popupHandlerSet.containsKey(handlerName))
@@ -600,7 +600,7 @@ public class SystrayServiceJdicImpl
Object o = evt.getTag();
if (o instanceof Contact)
- SystrayActivator.getUIService().
+ OsDependentActivator.getUIService().
getChat((Contact) o).setChatVisible(true);
}
}
@@ -615,7 +615,7 @@ public class SystrayServiceJdicImpl
try
{
PopupMessageHandler handler =
- (PopupMessageHandler) SystrayActivator.bundleContext.
+ (PopupMessageHandler) OsDependentActivator.bundleContext.
getService(serviceEvent.getServiceReference());
if (serviceEvent.getType() == ServiceEvent.REGISTERED)
diff --git a/src/net/java/sip/communicator/impl/systray/jdic/TrayMenuFactory.java b/src/net/java/sip/communicator/impl/osdependent/jdic/TrayMenuFactory.java
index 52faeed..6f32c48 100644
--- a/src/net/java/sip/communicator/impl/systray/jdic/TrayMenuFactory.java
+++ b/src/net/java/sip/communicator/impl/osdependent/jdic/TrayMenuFactory.java
@@ -4,7 +4,7 @@
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
-package net.java.sip.communicator.impl.systray.jdic;
+package net.java.sip.communicator.impl.osdependent.jdic;
import java.awt.*;
import java.awt.event.*;
@@ -12,7 +12,7 @@ import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
-import net.java.sip.communicator.impl.systray.*;
+import net.java.sip.communicator.impl.osdependent.*;
import net.java.sip.communicator.service.gui.*;
/**
@@ -47,22 +47,22 @@ public final class TrayMenuFactory
if (itemName.equals("settings"))
{
- SystrayActivator.getUIService().setConfigurationWindowVisible(true);
+ OsDependentActivator.getUIService().setConfigurationWindowVisible(true);
}
else if (itemName.equals("service.gui.CLOSE"))
{
- SystrayActivator.getUIService().beginShutdown();
+ OsDependentActivator.getUIService().beginShutdown();
}
else if (itemName.equals("addContact"))
{
ExportedWindow dialog =
- SystrayActivator.getUIService().getExportedWindow(
+ OsDependentActivator.getUIService().getExportedWindow(
ExportedWindow.ADD_CONTACT_WINDOW);
if (dialog != null)
dialog.setVisible(true);
else
- SystrayActivator.getUIService().getPopupDialog()
+ OsDependentActivator.getUIService().getPopupDialog()
.showMessagePopupDialog(Resources.getString(
"impl.systray.FAILED_TO_OPEN_ADD_CONTACT_DIALOG"));
}
diff --git a/src/net/java/sip/communicator/impl/systray/systray.manifest.mf b/src/net/java/sip/communicator/impl/osdependent/osdependent.manifest.mf
index c97e127..3a0a1ff 100644
--- a/src/net/java/sip/communicator/impl/systray/systray.manifest.mf
+++ b/src/net/java/sip/communicator/impl/osdependent/osdependent.manifest.mf
@@ -1,13 +1,15 @@
-Bundle-Activator: net.java.sip.communicator.impl.systray.SystrayActivator
-Bundle-Name: Systray
-Bundle-Description: Systray.
+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.systray.event,
+ net.java.sip.communicator.service.desktop
Import-Package: org.osgi.framework,
- org.jdesktop.jdic.tray,
+ org.jdesktop.jdic.tray,
+ org.jdesktop.jdic.desktop,
com.apple.cocoa.application,
com.apple.cocoa.foundation,
net.java.sip.communicator.service.configuration,
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/IncomingFileTransferJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/IncomingFileTransferJabberImpl.java
new file mode 100644
index 0000000..ba2dcb9
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/IncomingFileTransferJabberImpl.java
@@ -0,0 +1,48 @@
+/*
+ * 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.protocol.jabber;
+
+import org.jivesoftware.smackx.filetransfer.*;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * The Jabber protocol extension of the <tt>AbstractFileTransfer</tt>.
+ *
+ * @author Yana Stamcheva
+ */
+public class IncomingFileTransferJabberImpl
+ extends AbstractFileTransfer
+{
+ /**
+ * The jabber incoming file transfer.
+ */
+ private IncomingFileTransfer jabberTransfer;
+
+ public IncomingFileTransferJabberImpl(IncomingFileTransfer jabberTransfer)
+ {
+ this.jabberTransfer = jabberTransfer;
+ }
+
+ /**
+ * Cancels the file transfer.
+ */
+ public void cancel()
+ {
+ this.jabberTransfer.cancel();
+ }
+
+ /**
+ * Returns the number of bytes already received from the recipient.
+ *
+ * @return the number of bytes already received from the recipient.
+ */
+ public long getTransferedBytes()
+ {
+ return jabberTransfer.getAmountWritten();
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/IncomingFileTransferRequestJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/IncomingFileTransferRequestJabberImpl.java
new file mode 100644
index 0000000..ccdf891
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/IncomingFileTransferRequestJabberImpl.java
@@ -0,0 +1,143 @@
+/*
+ * 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.protocol.jabber;
+
+import java.io.File;
+
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.util.*;
+import org.jivesoftware.smackx.filetransfer.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.FileTransfer;
+import net.java.sip.communicator.util.Logger;
+
+/**
+ * Jabber implementation of the incoming file transfer request
+ *
+ * @author Nicolas Riegel
+ *
+ */
+public class IncomingFileTransferRequestJabberImpl
+ implements IncomingFileTransferRequest
+{
+ /**
+ * The logger for this class.
+ */
+ private static final Logger logger =
+ Logger.getLogger(IncomingFileTransferRequestJabberImpl.class);
+
+ /**
+ * The Jabber file transfer request.
+ */
+ private final FileTransferRequest fileTransferRequest;
+
+ private Contact sender;
+
+ /**
+ * Creates an <tt>IncomingFileTransferRequestJabberImpl</tt> based on the
+ * given <tt>fileTransferRequest</tt>, coming from the Jabber protocol.
+ *
+ * @param jabberProvider the protocol provider
+ * @param fileTransferRequest the request coming from the Jabber protocol
+ */
+ public IncomingFileTransferRequestJabberImpl(
+ ProtocolProviderServiceJabberImpl jabberProvider,
+ FileTransferRequest fileTransferRequest)
+ {
+ this.fileTransferRequest = fileTransferRequest;
+
+ String fromUserID
+ = StringUtils.parseBareAddress(fileTransferRequest.getRequestor());
+
+ OperationSetPersistentPresenceJabberImpl opSetPersPresence
+ = (OperationSetPersistentPresenceJabberImpl)
+ jabberProvider.getOperationSet(
+ OperationSetPersistentPresence.class);
+
+ sender = opSetPersPresence.findContactByID(fromUserID);
+ }
+
+ /**
+ * Returns the <tt>Contact</tt> making this request.
+ *
+ * @return the <tt>Contact</tt> making this request
+ */
+ public Contact getSender()
+ {
+ return sender;
+ }
+
+ /**
+ * Returns the description of the file corresponding to this request.
+ *
+ * @return the description of the file corresponding to this request
+ */
+ public String getFileDescription()
+ {
+ return fileTransferRequest.getDescription();
+ }
+
+ /**
+ * Returns the name of the file corresponding to this request.
+ *
+ * @return the name of the file corresponding to this request
+ */
+ public String getFileName()
+ {
+ return fileTransferRequest.getFileName();
+ }
+
+ /**
+ * Returns the size of the file corresponding to this request.
+ *
+ * @return the size of the file corresponding to this request
+ */
+ public long getFileSize()
+ {
+ return fileTransferRequest.getFileSize();
+ }
+
+ /**
+ * Accepts the file and starts the transfer.
+ *
+ * @return a boolean : <code>false</code> if the transfer fails,
+ * <code>true</code> otherwise
+ */
+ public FileTransfer acceptFile(File file)
+ {
+ AbstractFileTransfer incomingTransfer = null;
+
+ IncomingFileTransfer jabberTransfer = fileTransferRequest.accept();
+ try
+ {
+ incomingTransfer
+ = new IncomingFileTransferJabberImpl(jabberTransfer);
+
+ jabberTransfer.recieveFile(file);
+
+ new OperationSetFileTransferJabberImpl
+ .FileTransferProgressThread(
+ jabberTransfer, incomingTransfer, getFileSize()).start();
+
+ }
+ catch (XMPPException e)
+ {
+ logger.debug("Receiving file failed.", e);
+ }
+
+ return incomingTransfer;
+ }
+
+ /**
+ * Refuses the file transfer request.
+ */
+ public void rejectFile()
+ {
+ fileTransferRequest.reject();
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetFileTransferJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetFileTransferJabberImpl.java
new file mode 100644
index 0000000..0bd29a6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetFileTransferJabberImpl.java
@@ -0,0 +1,392 @@
+/*
+ * 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.protocol.jabber;
+
+import java.io.*;
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.FileTransfer;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+import org.jivesoftware.smack.*;
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smackx.filetransfer.*;
+import org.jivesoftware.smackx.filetransfer.FileTransfer.*;
+
+/**
+ * The Jabber implementation of the <tt>OperationSetFileTransfer</tt>
+ * interface.
+ *
+ * @author Gregory Bande
+ * @author Nicolas Riegel
+ * @author Yana Stamcheva
+ */
+public class OperationSetFileTransferJabberImpl
+ implements OperationSetFileTransfer
+{
+ /**
+ * The logger for this class.
+ */
+ private static final Logger logger =
+ Logger.getLogger(OperationSetFileTransferJabberImpl.class);
+
+ /**
+ * The provider that created us.
+ */
+ private final ProtocolProviderServiceJabberImpl jabberProvider;
+
+ /**
+ * The Jabber file transfer manager.
+ */
+ private FileTransferManager manager = null;
+
+ /**
+ * The Jabber file transfer listener.
+ */
+ private JabberFileTransferListener jabberFileTransferListener;
+
+ /**
+ * A list of listeners registered for message events.
+ */
+ private Vector<FileTransferRequestListener> fileTransferListeners
+ = new Vector<FileTransferRequestListener>();
+
+ /**
+ * Constructor
+ * @param provider is the provider that created us
+ */
+ public OperationSetFileTransferJabberImpl(
+ ProtocolProviderServiceJabberImpl provider)
+ {
+ this.jabberProvider = provider;
+
+ provider.addRegistrationStateChangeListener(
+ new RegistrationStateListener());
+ }
+
+ /**
+ * Sends a file transfer request to the given <tt>toContact</tt> by
+ * specifying the local and remote file path and the <tt>fromContact</tt>,
+ * sending the file.
+ *
+ * @return the transfer object
+ *
+ * @param toContact the contact that should receive the file
+ * @param fromContact the contact sending the file
+ * @param remotePath the remote file path
+ * @param localPath the local file path
+ */
+ public FileTransfer sendFile( Contact toContact,
+ File file)
+ throws IllegalStateException,
+ IllegalArgumentException
+ {
+ AbstractFileTransfer outgoingTransfer = null;
+
+ try
+ {
+ assertConnected();
+
+ Roster roster = jabberProvider.getConnection().getRoster();
+ Presence presence = roster.getPresence(toContact.getAddress());
+
+ OutgoingFileTransfer transfer
+ = manager.createOutgoingFileTransfer(presence.getFrom());
+
+ outgoingTransfer
+ = new OutgoingFileTransferJabberImpl(transfer);
+
+ transfer.sendFile(file, "Sending file.");
+
+ new FileTransferProgressThread(
+ transfer, outgoingTransfer).start();
+ }
+ catch(XMPPException e)
+ {
+ logger.error("Failed to send file.", e);
+ }
+
+ return outgoingTransfer;
+ }
+
+ /**
+ * Sends a file transfer request to the given <tt>toContact</tt> by
+ * specifying the local and remote file path and the <tt>fromContact</tt>,
+ * sending the file.
+ *
+ * @return the transfer object
+ *
+ * @param toContact the contact that should receive the file
+ * @param fromContact the contact sending the file
+ * @param remotePath the remote file path
+ * @param localPath the local file path
+ */
+ public FileTransfer sendFile( Contact toContact,
+ Contact fromContact,
+ String remotePath,
+ String localPath)
+ throws IllegalStateException,
+ IllegalArgumentException
+ {
+ return this.sendFile(toContact, new File(localPath));
+ }
+
+ /**
+ * Adds the given <tt>listener</tt> that would listen for
+ * <tt>FileTransferRequestEvent</tt>-s and that should be notified every
+ * time a file transfer request has been received.
+ *
+ * @param listener the <tt>FileTransferRequestListener</tt> to add
+ */
+ public void addFileTransferRequestListener(
+ FileTransferRequestListener listener)
+ {
+ synchronized(fileTransferListeners)
+ {
+ if(!fileTransferListeners.contains(listener))
+ {
+ this.fileTransferListeners.add(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes the given <tt>listener</tt> that listens for
+ * <tt>FileTransferRequestEvent</tt>-s and is notified every time a file
+ * transfer request has been received.
+ *
+ * @param listener the <tt>FileTransferRequestListener</tt> to remove
+ */
+ public void removeFileTransferRequestListener(
+ FileTransferRequestListener listener)
+ {
+ synchronized(fileTransferListeners)
+ {
+ this.fileTransferListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Utility method throwing an exception if the stack is not properly
+ * initialized.
+ * @throws java.lang.IllegalStateException if the underlying stack is
+ * not registered and initialized.
+ */
+ private void assertConnected()
+ throws IllegalStateException
+ {
+ if (jabberProvider == null)
+ throw new IllegalStateException(
+ "The provider must be non-null and signed on the "
+ +"service before being able to send a file.");
+ else if (!jabberProvider.isRegistered())
+ throw new IllegalStateException(
+ "The provider must be signed on the service before "
+ +"being able to send a file.");
+ }
+
+ /**
+ * Our listener that will tell us when we're registered to
+ */
+ private class RegistrationStateListener
+ implements RegistrationStateChangeListener
+ {
+ /**
+ * The method is called by a ProtocolProvider implementation whenever
+ * a change in the registration state of the corresponding provider had
+ * occurred.
+ * @param evt ProviderStatusChangeEvent the event describing the status
+ * change.
+ */
+ public void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+ logger.debug("The provider changed state from: "
+ + evt.getOldState()
+ + " to: " + evt.getNewState());
+
+ if (evt.getNewState() == RegistrationState.REGISTERED)
+ {
+ // Create the Jabber FileTransferManager.
+ manager = new FileTransferManager(
+ jabberProvider.getConnection());
+
+ // Create the Jabber file transfer listener.
+ jabberFileTransferListener = new JabberFileTransferListener();
+
+ // Add the Jabber file transfer listener to the manager.
+ manager.addFileTransferListener(jabberFileTransferListener);
+ }
+ else if (evt.getNewState() == RegistrationState.UNREGISTERED)
+ {
+ if(jabberFileTransferListener != null
+ && manager != null)
+ {
+ manager.removeFileTransferListener(
+ jabberFileTransferListener);
+
+ manager = null;
+ jabberFileTransferListener = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * Listener for Jabber incoming file transfer requests.
+ */
+ private class JabberFileTransferListener
+ implements FileTransferListener
+ {
+ /**
+ * Function called when a jabber file transfer request arrive.
+ */
+ public void fileTransferRequest(FileTransferRequest request)
+ {
+ logger.debug("Incoming Jabber file transfer request.");
+
+ // Create a global incoming file transfer request.
+ IncomingFileTransferRequest incomingFileTransferRequest
+ = new IncomingFileTransferRequestJabberImpl(
+ jabberProvider, request);
+
+ // Create an event associated to this global request.
+ FileTransferRequestEvent fileTransferRequestEvent
+ = new FileTransferRequestEvent( incomingFileTransferRequest,
+ new Date());
+
+ // Notify the global listener that a request has arrived.
+ fireFileTransferRequest(fileTransferRequestEvent);
+ }
+ }
+
+ /**
+ * Delivers the specified event to all registered file transfer listeners.
+ *
+ * @param event the <tt>EventObject</tt> that we'd like delivered to all
+ * registered file transfer listeners.
+ */
+ private void fireFileTransferRequest(FileTransferRequestEvent event)
+ {
+ Iterator<FileTransferRequestListener> listeners = null;
+ synchronized (fileTransferListeners)
+ {
+ listeners = new ArrayList<FileTransferRequestListener>
+ (fileTransferListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ FileTransferRequestListener listener = listeners.next();
+
+ listener.incomingRequestReceived(event);
+ }
+ }
+
+ /**
+ * Updates file transfer progress and status while sending or receiving a
+ * file.
+ */
+ protected static class FileTransferProgressThread extends Thread
+ {
+ private final org.jivesoftware.smackx.filetransfer.FileTransfer
+ jabberTransfer;
+ private final AbstractFileTransfer fileTransfer;
+
+ private long initialFileSize;
+
+ public FileTransferProgressThread(
+ org.jivesoftware.smackx.filetransfer.FileTransfer jabberTransfer,
+ AbstractFileTransfer transfer,
+ long initialFileSize)
+ {
+ this.jabberTransfer = jabberTransfer;
+ this.fileTransfer = transfer;
+ this.initialFileSize = initialFileSize;
+ }
+
+ public FileTransferProgressThread(
+ org.jivesoftware.smackx.filetransfer.FileTransfer jabberTransfer,
+ AbstractFileTransfer transfer)
+ {
+ this.jabberTransfer = jabberTransfer;
+ this.fileTransfer = transfer;
+ }
+
+ public void run()
+ {
+ int status;
+ double progress;
+
+ while (true)
+ {
+ try
+ {
+ Thread.sleep(10);
+
+ status = parseJabberStatus(jabberTransfer.getStatus());
+ progress = fileTransfer.getTransferedBytes();
+
+ if (status == FileTransfer.FAILED
+ || status == FileTransfer.COMPLETED
+ || status == FileTransfer.CANCELED
+ || status == FileTransfer.REFUSED)
+ {
+ break;
+ }
+
+ fileTransfer.fireStatusChangeEvent(status);
+ fileTransfer.fireProgressChangeEvent((int)progress);
+ }
+ catch (InterruptedException e)
+ {
+ logger.debug("Unable to sleep thread.", e);
+ }
+ }
+
+ if (initialFileSize > 0
+ && status == FileTransfer.COMPLETED
+ && fileTransfer.getTransferedBytes() < initialFileSize)
+ {
+ status = FileTransfer.CANCELED;
+ }
+
+ fileTransfer.fireStatusChangeEvent(status);
+ fileTransfer.fireProgressChangeEvent((int)progress);
+ }
+ }
+
+ /**
+ * Parses the given Jabber status to a <tt>FileTransfer</tt> interface
+ * status.
+ *
+ * @param jabberStatus the Jabber status to parse
+ * @return the parsed status
+ */
+ private static int parseJabberStatus(Status jabberStatus)
+ {
+ if (jabberStatus.equals(Status.complete))
+ return FileTransfer.COMPLETED;
+ else if (jabberStatus.equals(Status.cancelled))
+ return FileTransfer.CANCELED;
+ else if (jabberStatus.equals(Status.in_progress)
+ || jabberStatus.equals(Status.negotiated))
+ return FileTransfer.IN_PROGRESS;
+ else if (jabberStatus.equals(Status.error))
+ return FileTransfer.FAILED;
+ else if (jabberStatus.equals(Status.refused))
+ return FileTransfer.REFUSED;
+ else if (jabberStatus.equals(Status.negotiating_transfer)
+ || jabberStatus.equals(Status.negotiating_stream))
+ return FileTransfer.PREPARING;
+ else
+ // FileTransfer.Status.initial
+ return FileTransfer.WAITING;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java
new file mode 100644
index 0000000..6ad8dd6
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OutgoingFileTransferJabberImpl.java
@@ -0,0 +1,55 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.jabber;
+
+import net.java.sip.communicator.service.protocol.*;
+
+import org.jivesoftware.smackx.filetransfer.*;
+
+/**
+ * The Jabber protocol extension of the <tt>AbstractFileTransfer</tt>.
+ *
+ * @author Yana Stamcheva
+ */
+public class OutgoingFileTransferJabberImpl
+ extends AbstractFileTransfer
+{
+ /**
+ * The jabber outgoing file transfer.
+ */
+ private OutgoingFileTransfer jabberTransfer;
+
+ /**
+ * Creates an <tt>OutgoingFileTransferJabberImpl</tt> by specifying the
+ * Jabber transfer object.
+ *
+ * @param jabberTransfer the Jabber transfer object, containing all transfer
+ * information
+ */
+ public OutgoingFileTransferJabberImpl(OutgoingFileTransfer jabberTransfer)
+ {
+ this.jabberTransfer = jabberTransfer;
+ }
+
+ /**
+ * Cancels the file transfer.
+ */
+ public void cancel()
+ {
+ this.jabberTransfer.cancel();
+ }
+
+ /**
+ * Returns the number of bytes already sent to the recipient.
+ *
+ * @return the number of bytes already sent to the recipient.
+ */
+ public long getTransferedBytes()
+ {
+ return jabberTransfer.getBytesSent();
+ }
+} \ No newline at end of file
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
index 3c4c3bd..79f8624 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
@@ -611,6 +611,14 @@ public class ProtocolProviderServiceJabberImpl
OperationSetServerStoredAccountInfo.class.getName(),
accountInfo);
+ // initialize the file transfer operation set
+ OperationSetFileTransfer fileTransfer
+ = new OperationSetFileTransferJabberImpl(this);
+
+ supportedOperationSets.put(
+ OperationSetFileTransfer.class.getName(),
+ fileTransfer);
+
// TODO: this is the "main" feature to advertise when a client
// support muc. We have to add some features for
// specific functionnality we support in muc.
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
index 6aa6e2d..dfda50f 100755
--- a/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/jabber.provider.manifest.mf
@@ -19,6 +19,7 @@ Import-Package: org.osgi.framework,
org.jivesoftware.smackx.jingle.nat,
org.jivesoftware.smackx.jingle.packet,
org.jivesoftware.smackx.jingle.provider,
+ org.jivesoftware.smackx.filetransfer,
net.java.sip.communicator.service.configuration,
net.java.sip.communicator.service.resources,
net.java.sip.communicator.util,
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java
index 6390cec..08b929c 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java
@@ -316,5 +316,5 @@ public class OperationSetBasicInstantMessagingMsnImpl
MsnContact contact)
{
}
- }
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/FileTransferSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/FileTransferSSHImpl.java
new file mode 100644
index 0000000..58c36ab
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/ssh/FileTransferSSHImpl.java
@@ -0,0 +1,50 @@
+/*
+ * 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.protocol.ssh;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * SSH implementation of the <tt>AbstractFileTransfer</tt>.
+ *
+ * @author Yana Stamcheva
+ */
+public class FileTransferSSHImpl
+ extends AbstractFileTransfer
+{
+ private final SSHFileTransferDaemon fileTransfer;
+
+ /**
+ * Creates an SSH implementation of the file transfer interface.
+ *
+ * @param fileTransfer the SSH file transfer
+ */
+ public FileTransferSSHImpl(SSHFileTransferDaemon fileTransfer)
+ {
+ this.fileTransfer = fileTransfer;
+ }
+
+ /**
+ * Cancels this file transfer. When this method is called transfer should
+ * be interrupted.
+ */
+ public void cancel()
+ {
+ // TODO: Implement cancel() for SSH file transfer.
+ }
+
+ /**
+ * Returns the number of bytes already transfered through this file transfer.
+ *
+ * @return the number of bytes already transfered through this file transfer
+ */
+ public long getTransferedBytes()
+ {
+ // TODO: Implement getTransferedBytes() for SSH file transfer.
+ return 0;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java b/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java
index 69f2d76..f2bbcc1 100644
--- a/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/ssh/OperationSetFileTransferSSHImpl.java
@@ -11,6 +11,7 @@
*/
package net.java.sip.communicator.impl.protocol.ssh;
+import java.io.*;
import java.util.*;
import net.java.sip.communicator.service.protocol.*;
@@ -31,7 +32,8 @@ public class OperationSetFileTransferSSHImpl
/**
* Currently registered message listeners.
*/
- private Vector fileTransferListeners = new Vector();
+ private Vector<FileTransferRequestListener> fileTransferListeners
+ = new Vector<FileTransferRequestListener>();
/**
* The protocol provider that created us.
@@ -52,12 +54,43 @@ public class OperationSetFileTransferSSHImpl
*
* @param listener the <tt>FileListener</tt> to register.
*/
- public void addFileListener(FileListener listener)
+ public void addFileTransferRequestListener(
+ FileTransferRequestListener listener)
{
- if(!fileTransferListeners.contains(listener))
- fileTransferListeners.add(listener);
+ synchronized (fileTransferListeners)
+ {
+ if(!fileTransferListeners.contains(listener))
+ fileTransferListeners.add(listener);
+ }
}
-
+
+ public void removeFileTransferRequestListener(
+ FileTransferRequestListener listener)
+ {
+ synchronized (fileTransferListeners)
+ {
+ fileTransferListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Sends a file transfer request to the given <tt>toContact</tt> by
+ * specifying the local and remote file path and the <tt>fromContact</tt>,
+ * sending the file.
+ *
+ * @param toContact the contact that should receive the file
+ * @param fromContact the contact sending the file
+ * @param file the file to send
+ */
+ public FileTransfer sendFile( Contact toContact,
+ File file)
+ {
+ return this.sendFile( toContact,
+ null,
+ file.getAbsolutePath(),
+ file.getAbsolutePath());
+ }
+
/**
* The file transfer method to/from the remote machine
* either toContact is null(we are downloading file from remote machine
@@ -68,7 +101,7 @@ public class OperationSetFileTransferSSHImpl
* @param remotePath - the identifier for the remote file
* @param localPath - the identifier for the local file
*/
- public void sendFile(
+ public FileTransfer sendFile(
Contact toContact,
Contact fromContact,
String remotePath,
@@ -80,16 +113,16 @@ public class OperationSetFileTransferSSHImpl
= new SSHFileTransferDaemon(
(ContactSSH)fromContact,
parentProvider);
-
+
if(localPath.endsWith(System.getProperty("file.separator")))
localPath += remotePath.substring(remotePath.lastIndexOf(
System.getProperty("file.separator")) + 1);
-
+
fileTransferDaemon.downloadFile(
remotePath,
localPath);
-
- return;
+
+ return new FileTransferSSHImpl(fileTransferDaemon);
}
else if(fromContact == null)
{
@@ -97,17 +130,17 @@ public class OperationSetFileTransferSSHImpl
= new SSHFileTransferDaemon(
(ContactSSH) toContact,
parentProvider);
-
+
fileTransferDaemon.uploadFile(
remotePath,
localPath);
-
- return;
+
+ return new FileTransferSSHImpl(fileTransferDaemon);
}
-
+
// code should not reach here
// assert false;
logger.error("we should not be here !");
+ return null;
}
-
}
diff --git a/src/net/java/sip/communicator/service/desktop/DesktopService.java b/src/net/java/sip/communicator/service/desktop/DesktopService.java
new file mode 100644
index 0000000..c214299
--- /dev/null
+++ b/src/net/java/sip/communicator/service/desktop/DesktopService.java
@@ -0,0 +1,111 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.desktop;
+
+import java.io.*;
+import java.net.*;
+
+/**
+ * The <tt>DesktopService</tt> manages the .
+ *
+ * @author Yana Stamcheva
+ */
+public interface DesktopService
+{
+ /**
+ * Launches the associated application to open the file.
+ *
+ * @param file the file to be opened
+ *
+ * @throws NullPointerException if file is null
+ * @throws IllegalArgumentException if the specified file dosen't exist
+ * @throws UnsupportedOperationException if the current platform does not
+ * support the Desktop.Action.OPEN action
+ * @throws IOException if the specified file has no associated application
+ * or the associated application fails to be launched
+ * @throws SecurityException if a security manager exists and its
+ * SecurityManager.checkRead(java.lang.String) method denies read access to
+ * the file, or it denies the AWTPermission("showWindowWithoutWarningBanner")
+ * permission, or the calling thread is not allowed to create a subprocess
+ */
+ public void open(File file)
+ throws NullPointerException,
+ IllegalArgumentException,
+ UnsupportedOperationException,
+ IOException,
+ SecurityException;
+
+ /**
+ * Prints a file with the native desktop printing facility, using the
+ * associated application's print command.
+ *
+ * @param file the file to be opened
+ *
+ * @throws NullPointerException if file is null
+ * @throws IllegalArgumentException if the specified file dosen't exist
+ * @throws UnsupportedOperationException if the current platform does not
+ * support the Desktop.Action.OPEN action
+ * @throws IOException if the specified file has no associated application
+ * or the associated application fails to be launched
+ * @throws SecurityException if a security manager exists and its
+ * SecurityManager.checkRead(java.lang.String) method denies read access to
+ * the file, or it denies the AWTPermission("showWindowWithoutWarningBanner")
+ * permission, or the calling thread is not allowed to create a subprocess
+ */
+ public void print(File file)
+ throws NullPointerException,
+ IllegalArgumentException,
+ UnsupportedOperationException,
+ IOException,
+ SecurityException;
+
+ /**
+ * Launches the associated editor application and opens a file for editing.
+ *
+ * @param file the file to open for editing
+ *
+ * @throws NullPointerException if file is null
+ * @throws IllegalArgumentException if the specified file dosen't exist
+ * @throws UnsupportedOperationException if the current platform does not
+ * support the Desktop.Action.OPEN action
+ * @throws IOException if the specified file has no associated application
+ * or the associated application fails to be launched
+ * @throws SecurityException if a security manager exists and its
+ * SecurityManager.checkRead(java.lang.String) method denies read access to
+ * the file, or it denies the AWTPermission("showWindowWithoutWarningBanner")
+ * permission, or the calling thread is not allowed to create a subprocess
+ */
+ public void edit(File file)
+ throws NullPointerException,
+ IllegalArgumentException,
+ UnsupportedOperationException,
+ IOException,
+ SecurityException;
+
+ /**
+ * Launches the default browser to display a URI.
+ *
+ * @param uri the URI to be displayed in the user default browser
+ *
+ * @throws NullPointerException if file is null
+ * @throws IllegalArgumentException if the specified file dosen't exist
+ * @throws UnsupportedOperationException if the current platform does not
+ * support the Desktop.Action.OPEN action
+ * @throws IOException if the specified file has no associated application
+ * or the associated application fails to be launched
+ * @throws SecurityException if a security manager exists and its
+ * SecurityManager.checkRead(java.lang.String) method denies read access to
+ * the file, or it denies the AWTPermission("showWindowWithoutWarningBanner")
+ * permission, or the calling thread is not allowed to create a subprocess
+ */
+ public void browse(URI uri)
+ throws NullPointerException,
+ IllegalArgumentException,
+ UnsupportedOperationException,
+ IOException,
+ SecurityException;
+}
diff --git a/src/net/java/sip/communicator/service/fileaccess/FileAccessService.java b/src/net/java/sip/communicator/service/fileaccess/FileAccessService.java
index 634932f..4fa567a 100644
--- a/src/net/java/sip/communicator/service/fileaccess/FileAccessService.java
+++ b/src/net/java/sip/communicator/service/fileaccess/FileAccessService.java
@@ -106,7 +106,14 @@ public interface FileAccessService {
* directory.
*/
File getPrivatePersistentDirectory(String[] dirNames) throws Exception;
-
+
+ /**
+ * Returns the default download directory depending on the operating system.
+ *
+ * @return the default download directory depending on the operating system
+ */
+ File getDefaultDownloadDirectory() throws IOException;
+
/**
* Creates a failsafe transaction which can be used to safely store
* informations into a file.
diff --git a/src/net/java/sip/communicator/service/protocol/AbstractFileTransfer.java b/src/net/java/sip/communicator/service/protocol/AbstractFileTransfer.java
new file mode 100644
index 0000000..18a85f9
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/AbstractFileTransfer.java
@@ -0,0 +1,180 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.event.*;
+
+/**
+ * An abstract implementation of the <tt>FileTransfer</tt> interface providing
+ * implementation of status and progress events related methods and leaving all
+ * protocol specific methods abstract. A protocol specific implementation could
+ * extend this class and implement only <tt>cancel()</tt> and
+ * <tt>getTransferredBytes()</tt>.
+ *
+ * @author Yana Stamcheva
+ */
+public abstract class AbstractFileTransfer
+ implements FileTransfer
+{
+ /**
+ * A list of listeners registered for file transfer status events.
+ */
+ private Vector<FileTransferStatusListener> statusListeners
+ = new Vector<FileTransferStatusListener>();
+
+ /**
+ * A list of listeners registered for file transfer status events.
+ */
+ private Vector<FileTransferProgressListener> progressListeners
+ = new Vector<FileTransferProgressListener>();
+
+ private int status;
+
+ /**
+ * Cancels this file transfer. When this method is called transfer should
+ * be interrupted.
+ */
+ abstract public void cancel();
+
+ /**
+ * Returns the number of bytes already transfered through this file transfer.
+ *
+ * @return the number of bytes already transfered through this file transfer
+ */
+ abstract public long getTransferedBytes();
+
+ /**
+ * Adds the given <tt>FileTransferProgressListener</tt> to listen for
+ * status changes on this file transfer.
+ *
+ * @param listener the listener to add
+ */
+ public void addProgressListener(FileTransferProgressListener listener)
+ {
+ synchronized(progressListeners)
+ {
+ if(!progressListeners.contains(listener))
+ {
+ this.progressListeners.add(listener);
+ }
+ }
+ }
+
+ /**
+ * Adds the given <tt>FileTransferStatusListener</tt> to listen for
+ * status changes on this file transfer.
+ *
+ * @param listener the listener to add
+ */
+ public void addStatusListener(FileTransferStatusListener listener)
+ {
+ synchronized(statusListeners)
+ {
+ if(!statusListeners.contains(listener))
+ {
+ this.statusListeners.add(listener);
+ }
+ }
+ }
+
+ /**
+ * Removes the given <tt>FileTransferProgressListener</tt>.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeProgressListener(FileTransferProgressListener listener)
+ {
+ synchronized(progressListeners)
+ {
+ this.progressListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Removes the given <tt>FileTransferStatusListener</tt>.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeStatusListener(FileTransferStatusListener listener)
+ {
+ synchronized(statusListeners)
+ {
+ this.statusListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Returns the current status of the transfer. This information could be
+ * used from the user interface to show a progress bar indicating the
+ * file transfer status.
+ *
+ * @return the current status of the transfer
+ */
+ public int getStatus()
+ {
+ return status;
+ }
+
+ /**
+ * Notifies all status listeners that a new
+ * <tt>FileTransferStatusChangeEvent</tt> occured.
+ */
+ public void fireStatusChangeEvent(int newStatus)
+ {
+ Collection<FileTransferStatusListener> listeners = null;
+ synchronized (statusListeners)
+ {
+ listeners
+ = new ArrayList<FileTransferStatusListener>(statusListeners);
+ }
+
+ FileTransferStatusChangeEvent statusEvent
+ = new FileTransferStatusChangeEvent(this, status, newStatus);
+
+ // Updates the status.
+ this.status = newStatus;
+
+ Iterator<FileTransferStatusListener> listenersIter
+ = listeners.iterator();
+
+ while (listenersIter.hasNext())
+ {
+ FileTransferStatusListener statusListener = listenersIter.next();
+
+ statusListener.statusChanged(statusEvent);
+ }
+ }
+
+ /**
+ * Notifies all status listeners that a new
+ * <tt>FileTransferProgressEvent</tt> occured.
+ */
+ public void fireProgressChangeEvent(int progress)
+ {
+ Collection<FileTransferProgressListener> listeners = null;
+ synchronized (progressListeners)
+ {
+ listeners
+ = new ArrayList<FileTransferProgressListener>(progressListeners);
+ }
+
+ FileTransferProgressEvent progressEvent
+ = new FileTransferProgressEvent(this, progress);
+
+ Iterator<FileTransferProgressListener> listenersIter
+ = listeners.iterator();
+
+ while (listenersIter.hasNext())
+ {
+ FileTransferProgressListener statusListener = listenersIter.next();
+
+ statusListener.progressChanged(progressEvent);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/FileTransfer.java b/src/net/java/sip/communicator/service/protocol/FileTransfer.java
new file mode 100644
index 0000000..d0f7d23
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/FileTransfer.java
@@ -0,0 +1,109 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+import net.java.sip.communicator.service.protocol.event.*;
+
+/**
+ * The <tt>FileTransfer</tt> interface is meant to be used by parties interested
+ * in the file transfer process. It contains information about the status and
+ * the progress of the transfer as well as the bytes that have been transfered.
+ *
+ * @author Yana Stamcheva
+ */
+public interface FileTransfer
+{
+ /**
+ * Indicates that the file transfer has been completed.
+ */
+ public static final int COMPLETED = 0;
+
+ /**
+ * Indicates that the file transfer has been canceled.
+ */
+ public static final int CANCELED = 1;
+
+ /**
+ * Indicates that the file transfer has failed.
+ */
+ public static final int FAILED = 2;
+
+ /**
+ * Indicates that the file transfer has been refused.
+ */
+ public static final int REFUSED = 3;
+
+ /**
+ * Indicates that the file transfer is in progress.
+ */
+ public static final int IN_PROGRESS = 4;
+
+ /**
+ * Indicates that the file transfer waits for the recipient to accept the
+ * file.
+ */
+ public static final int WAITING = 5;
+
+ /**
+ * Indicates that the file transfer is in negotiation.
+ */
+ public static final int PREPARING = 6;
+
+ /**
+ * Cancels this file transfer. When this method is called transfer should
+ * be interrupted.
+ */
+ public void cancel();
+
+ /**
+ * Returns the current status of the transfer. This information could be
+ * used from the user interface to show the current status of the transfer.
+ * The status is returned as an <tt>int</tt> and could be equal to one of
+ * the static constants declared in this interface (i.e. COMPLETED,
+ * CANCELED, FAILED, etc.).
+ *
+ * @return the current status of the transfer
+ */
+ public int getStatus();
+
+ /**
+ * Returns the number of bytes already transfered through this file transfer.
+ *
+ * @return the number of bytes already transfered through this file transfer
+ */
+ public long getTransferedBytes();
+
+ /**
+ * Adds the given <tt>FileTransferStatusListener</tt> to listen for
+ * status changes on this file transfer.
+ *
+ * @param listener the listener to add
+ */
+ public void addStatusListener(FileTransferStatusListener listener);
+
+ /**
+ * Removes the given <tt>FileTransferStatusListener</tt>.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeStatusListener(FileTransferStatusListener listener);
+
+ /**
+ * Adds the given <tt>FileTransferProgressListener</tt> to listen for
+ * status changes on this file transfer.
+ *
+ * @param listener the listener to add
+ */
+ public void addProgressListener(FileTransferProgressListener listener);
+
+ /**
+ * Removes the given <tt>FileTransferProgressListener</tt>.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeProgressListener(FileTransferProgressListener listener);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/IncomingFileTransferRequest.java b/src/net/java/sip/communicator/service/protocol/IncomingFileTransferRequest.java
new file mode 100644
index 0000000..73e17cf
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/IncomingFileTransferRequest.java
@@ -0,0 +1,67 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.service.protocol;
+
+import java.io.*;
+
+/**
+ * Used for incoming file transfer request.
+ *
+ * @author Nicolas Riegel
+ * @author Yana Stamcheva
+ */
+public interface IncomingFileTransferRequest
+{
+ /**
+ * Returns a String that represents the name of the file that is being
+ * received.
+ * If there is no name, returns null.
+ * @return a String that represents the name of the file
+ */
+ public String getFileName();
+
+ /**
+ * Returns a String that represents the description of the file that is
+ * being received.
+ * If there is no description available, returns null.
+ *
+ * @return a String that represents the description of the file
+ */
+ public String getFileDescription();
+
+ /**
+ * Returns a long that represents the size of the file that is being
+ * received.
+ * If there is no file size available, returns null.
+ *
+ * @return a long that represents the size of the file
+ */
+ public long getFileSize();
+
+ /**
+ * Returns a String that represents the name of the sender of the file
+ * being received.
+ * If there is no sender name available, returns null.
+ *
+ * @return a String that represents the name of the sender
+ */
+ public Contact getSender();
+
+ /**
+ * Function called to accept and receive the file.
+ *
+ * @param file the file to accept
+ * @return the <tt>FileTransfer</tt> object managing the transfer
+ */
+ public FileTransfer acceptFile(File file);
+
+ /**
+ * Function called to refuse the file.
+ */
+ public void rejectFile();
+}
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java b/src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java
index 12517ec..6b006a7 100644
--- a/src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetFileTransfer.java
@@ -6,24 +6,81 @@
*/
package net.java.sip.communicator.service.protocol;
+import java.io.*;
+
import net.java.sip.communicator.service.protocol.event.*;
/**
* The File Transfer Operation Set provides an interface towards those functions
- * of a given protocl, that allow transferring files among users.
- *
- * @todo say that meta contacts must be implemented by the user interface
+ * of a given protocol, that allow transferring files among users.
*
* @author Emil Ivov
+ * @author Yana Stamcheva
*/
public interface OperationSetFileTransfer
extends OperationSet
{
- public void sendFile(
- Contact toContact,
- Contact fromContact,
- String remotePath,
- String localPath);
+ /**
+ * Sends a file transfer request to the given <tt>toContact</tt> by
+ * specifying the local and remote file path and the <tt>fromContact</tt>,
+ * sending the file.
+ *
+ * @param toContact the contact that should receive the file
+ * @param file the file to send
+ *
+ * @return the transfer object
+ *
+ * @throws IllegalStateException if the protocol provider is not registered
+ * or connected
+ * @throws IllegalArgumentException if some of the arguments doesn't fit the
+ * protocol requirements
+ */
+ public FileTransfer sendFile( Contact toContact,
+ File file)
+ throws IllegalStateException,
+ IllegalArgumentException;
+
+ /**
+ * Sends a file transfer request to the given <tt>toContact</tt> by
+ * specifying the local and remote file path and the <tt>fromContact</tt>,
+ * sending the file.
+ *
+ * @param toContact the contact that should receive the file
+ * @param fromContact the contact sending the file
+ * @param remotePath the remote file path
+ * @param localPath the local file path
+ *
+ * @return the transfer object
+ *
+ * @throws IllegalStateException if the protocol provider is not registered
+ * or connected
+ * @throws IllegalArgumentException if some of the arguments doesn't fit the
+ * protocol requirements
+ */
+ public FileTransfer sendFile( Contact toContact,
+ Contact fromContact,
+ String remotePath,
+ String localPath)
+ throws IllegalStateException,
+ IllegalArgumentException;
+
+ /**
+ * Adds the given <tt>FileTransferRequestListener</tt> that would listen for
+ * <tt>FileTransferRequestEvent</tt>-s and that should be notified every
+ * time a file transfer request has been received.
+ *
+ * @param listener the <tt>FileTransferRequestListener</tt> to add
+ */
+ public void addFileTransferRequestListener(
+ FileTransferRequestListener listener);
- public void addFileListener(FileListener listener);
+ /**
+ * Removes the given <tt>FileTransferRequestListener</tt> that listens for
+ * <tt>FileTransferRequestEvent</tt>-s and is notified every time a file
+ * transfer request has been received.
+ *
+ * @param listener the <tt>FileTransferRequestListener</tt> to remove
+ */
+ public void removeFileTransferRequestListener(
+ FileTransferRequestListener listener);
}
diff --git a/src/net/java/sip/communicator/service/protocol/event/FileListener.java b/src/net/java/sip/communicator/service/protocol/event/FileListener.java
deleted file mode 100644
index cc19ba3..0000000
--- a/src/net/java/sip/communicator/service/protocol/event/FileListener.java
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package net.java.sip.communicator.service.protocol.event;
-
-import java.util.*;
-
-/**
- *
- *
- * @author Emil Ivov
- */
-public interface FileListener
- extends EventListener
-{
-
-}
diff --git a/src/net/java/sip/communicator/service/protocol/event/FileTransferProgressEvent.java b/src/net/java/sip/communicator/service/protocol/event/FileTransferProgressEvent.java
new file mode 100644
index 0000000..600275e
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/FileTransferProgressEvent.java
@@ -0,0 +1,63 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * The <tt>FileTransferProgressEvent</tt> indicates the progress of a file
+ * transfer.
+ *
+ * @author Yana Stamcheva
+ */
+public class FileTransferProgressEvent
+ extends EventObject
+{
+ /**
+ * Indicates the progress of a file transfer in bytes.
+ */
+ private int progress;
+
+ /**
+ * Creates a <tt>FileTransferProgressEvent</tt> by specifying the source
+ * file transfer object, that triggered the event and the new progress
+ * value.
+ *
+ * @param fileTransfer the source file transfer object, that triggered the
+ * event
+ * @param progress the new progress value
+ */
+ public FileTransferProgressEvent( FileTransfer fileTransfer,
+ int progress)
+ {
+ super(fileTransfer);
+
+ this.progress = progress;
+ }
+
+ /**
+ * Returns the source <tt>FileTransfer</tt> that triggered this event.
+ *
+ * @return the source <tt>FileTransfer</tt> that triggered this event
+ */
+ public FileTransfer getFileTransfer()
+ {
+ return (FileTransfer) source;
+ }
+
+ /**
+ * Returns the progress of the file transfer.
+ *
+ * @return the progress of the file transfer
+ */
+ public int getProgress()
+ {
+ return progress;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/FileTransferProgressListener.java b/src/net/java/sip/communicator/service/protocol/event/FileTransferProgressListener.java
new file mode 100644
index 0000000..b3d3f50
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/FileTransferProgressListener.java
@@ -0,0 +1,24 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+/**
+ * The <tt>FileTransferStatusListener</tt> listens for
+ * <tt>FileTransferStatusChangeEvent</tt> in order to indicate a change in the
+ * current progress of a file transfer.
+ *
+ * @author Yana Stamcheva
+ */
+public interface FileTransferProgressListener
+{
+ /**
+ * Indicates a change in the file transfer progress.
+ *
+ * @param event the event containing information about the change
+ */
+ public void progressChanged(FileTransferProgressEvent event);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/FileTransferRequestEvent.java b/src/net/java/sip/communicator/service/protocol/event/FileTransferRequestEvent.java
new file mode 100644
index 0000000..ed38c77
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/FileTransferRequestEvent.java
@@ -0,0 +1,65 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * The <tt>FileTransferRequestEvent</tt> indicates the reception of a file
+ * transfer request.
+ *
+ * @author Nicolas Riegel
+ * @author Yana Stamcheva
+ */
+public class FileTransferRequestEvent
+ extends EventObject
+{
+ /**
+ * The timestamp indicating the exact date when the event occurred.
+ */
+ private final Date timestamp;
+
+ /**
+ * Creates a <tt>FileTransferRequestEvent</tt> representing reception
+ * of an incoming file transfer request.
+ *
+ * @param request the <tt>IncomingFileTranferRequest</tt> whose reception
+ * this event represents.
+ * @param timestamp the timestamp indicating the exact date when the event
+ * occurred
+ */
+ public FileTransferRequestEvent(IncomingFileTransferRequest request,
+ Date timestamp)
+ {
+ super(request);
+
+ this.timestamp = timestamp;
+ }
+
+ /**
+ * Returns the incoming file transfer request that triggered this event.
+ *
+ * @return the <tt>IncomingFileTransferRequest</tt> that triggered this
+ * event.
+ */
+ public IncomingFileTransferRequest getRequest()
+ {
+ return (IncomingFileTransferRequest) getSource();
+ }
+
+ /**
+ * A timestamp indicating the exact date when the event occurred.
+ *
+ * @return a Date indicating when the event occurred.
+ */
+ public Date getTimestamp()
+ {
+ return timestamp;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/FileTransferRequestListener.java b/src/net/java/sip/communicator/service/protocol/event/FileTransferRequestListener.java
new file mode 100644
index 0000000..718aaca
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/FileTransferRequestListener.java
@@ -0,0 +1,28 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+/**
+ * A listener that would gather events notifying of incoming file transfer
+ * requests.
+ *
+ * @author Emil Ivov
+ * @author Yana Stamcheva
+ */
+public interface FileTransferRequestListener
+ extends EventListener
+{
+ /**
+ * Called when a new <tt>IncomingFileTransferRequest</tt> has been received.
+ *
+ * @param event the <tt>FileTransferRequestEvent</tt> containing the newly
+ * received request and other details.
+ */
+ public void incomingRequestReceived(FileTransferRequestEvent event);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/FileTransferStatusChangeEvent.java b/src/net/java/sip/communicator/service/protocol/event/FileTransferStatusChangeEvent.java
new file mode 100644
index 0000000..b3056ba
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/FileTransferStatusChangeEvent.java
@@ -0,0 +1,80 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+
+/**
+ * The <tt>FileTransferStatusChangeEvent</tt> is the event indicating of a
+ * change in the state of a file transfer.
+ *
+ * @author Yana Stamcheva
+ */
+public class FileTransferStatusChangeEvent
+ extends EventObject
+{
+ /**
+ * The state of the file transfer before this event occured.
+ */
+ private final int oldStatus;
+
+ /**
+ * The new state of the file transfer.
+ */
+ private final int newStatus;
+
+ /**
+ * Creates a <tt>FileTransferStatusChangeEvent</tt> by specifying the
+ * source <tt>fileTransfer</tt>, the old transfer status and the new status.
+ *
+ * @param fileTransfer the source file transfer, for which this status
+ * change occured
+ * @param oldStatus the old status
+ * @param newStatus the new status
+ */
+ public FileTransferStatusChangeEvent( FileTransfer fileTransfer,
+ int oldStatus,
+ int newStatus)
+ {
+ super(fileTransfer);
+
+ this.oldStatus = oldStatus;
+ this.newStatus = newStatus;
+ }
+
+ /**
+ * Returns the source <tt>FileTransfer</tt> that triggered this event.
+ *
+ * @return the source <tt>FileTransfer</tt> that triggered this event
+ */
+ public FileTransfer getFileTransfer()
+ {
+ return (FileTransfer) source;
+ }
+
+ /**
+ * Returns the state of the file transfer before this event occured.
+ *
+ * @return the old state
+ */
+ public int getOldStatus()
+ {
+ return oldStatus;
+ }
+
+ /**
+ * The new state of the file transfer.
+ *
+ * @return the new state
+ */
+ public int getNewStatus()
+ {
+ return newStatus;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/FileTransferStatusListener.java b/src/net/java/sip/communicator/service/protocol/event/FileTransferStatusListener.java
new file mode 100644
index 0000000..d7b36da
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/event/FileTransferStatusListener.java
@@ -0,0 +1,24 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.event;
+
+/**
+ * The <tt>FileTransferStatusListener</tt> listens for
+ * <tt>FileTransferStatusChangeEvent</tt> in order to indicate a change in the
+ * current status of a file transfer.
+ *
+ * @author Yana Stamcheva
+ */
+public interface FileTransferStatusListener
+{
+ /**
+ * Indicates a change in the file transfer status.
+ *
+ * @param event the event containing information about the change
+ */
+ public void statusChanged(FileTransferStatusChangeEvent event);
+}
diff --git a/src/net/java/sip/communicator/util/ByteFormat.java b/src/net/java/sip/communicator/util/ByteFormat.java
new file mode 100644
index 0000000..82f349b
--- /dev/null
+++ b/src/net/java/sip/communicator/util/ByteFormat.java
@@ -0,0 +1,101 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package net.java.sip.communicator.util;
+
+import java.text.DecimalFormat;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+
+/**
+ * Acknowledgement: This file was originally provided by the Ignite Realtime
+ * community, and was part of the Spark project (distributed under the terms of
+ * the LGPL).
+ *
+ * A formatter for formatting byte sizes. For example, formatting 12345 byes
+ * results in "12.1 K" and 1234567 results in "1.18 MB".
+ *
+ * @author Bill Lynch
+ */
+public class ByteFormat extends Format
+{
+ public ByteFormat()
+ {}
+
+ // Implemented from the Format class
+ /**
+ * Formats a long which represent a number of bytes.
+ */
+ public String format(long bytes)
+ {
+ return super.format(bytes);
+ }
+
+ /**
+ * Formats a long which represent a number of kilobytes.
+ *
+ * @param kilobytes Long kbytes to format as a string.
+ * @return String representation of kbytes.
+ */
+ public String formatKB(long kilobytes)
+ {
+ return super.format(kilobytes * 1024);
+ }
+
+ /**
+ * Format the given object (must be a Long).
+ *
+ * @param obj assumed to be the number of bytes as a Long.
+ * @param buf the StringBuffer to append to.
+ * @param pos field position.
+ * @return A formatted string representing the given bytes in more
+ * human-readable form.
+ */
+ public StringBuffer format(Object obj, StringBuffer buf, FieldPosition pos)
+ {
+ if (obj instanceof Long)
+ {
+ long numBytes = (Long) obj;
+ if (numBytes < 1024) {
+ DecimalFormat formatter = new DecimalFormat("#,##0");
+ buf.append(formatter.format((double)numBytes)).append(" bytes");
+ }
+ else if (numBytes < 1024 * 1024) {
+ DecimalFormat formatter = new DecimalFormat("#,##0.0");
+ buf.append(
+ formatter.format((double)numBytes / 1024.0)).append(" K");
+ }
+ else if (numBytes < 1024 * 1024 * 1024) {
+ DecimalFormat formatter = new DecimalFormat("#,##0.0");
+ buf.append(
+ formatter.format((double)numBytes / (1024.0 * 1024.0)))
+ .append(" MB");
+ }
+ else {
+ DecimalFormat formatter = new DecimalFormat("#,##0.0");
+ buf.append(
+ formatter.format(
+ (double)numBytes / (1024.0 * 1024.0 * 1024.0)))
+ .append(" GB");
+ }
+ }
+ return buf;
+ }
+
+ /**
+ * In this implementation, returns null always.
+ *
+ * @param source Source string to parse.
+ * @param pos Position to parse from.
+ * @return returns null in this implementation.
+ */
+ public Object parseObject(String source, ParsePosition pos)
+ {
+ return null;
+ }
+}
diff --git a/src/net/java/sip/communicator/util/FileUtils.java b/src/net/java/sip/communicator/util/FileUtils.java
new file mode 100644
index 0000000..dec27bc
--- /dev/null
+++ b/src/net/java/sip/communicator/util/FileUtils.java
@@ -0,0 +1,84 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.util;
+
+import java.io.*;
+
+import javax.swing.*;
+
+/**
+ * Utility class that allows to check if a given file is an image or to obtain
+ * the file thumbnail icon.
+ *
+ * @author Yana Stamcheva
+ */
+public class FileUtils
+{
+ private static final Logger logger = Logger.getLogger(FileUtils.class);
+
+ /**
+ * Returns <code>true</code> if the file given by <tt>fileName</tt> is an
+ * image, <tt>false</tt> - otherwise.
+ *
+ * @param fileName the name of the file to check
+ * @return <code>true</code> if the file is an image, <tt>false</tt> -
+ * otherwise.
+ */
+ public static boolean isImage(String fileName)
+ {
+ fileName = fileName.toLowerCase();
+
+ String[] imageTypes = {"jpeg", "jpg", "png", "gif"};
+
+ for (String imageType : imageTypes)
+ {
+ if (fileName.endsWith(imageType))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns the native icon of the given file if one exists, otherwise
+ * returns null.
+ *
+ * @param file the file to obtain icon for
+ * @return the native icon of the given file if one exists, otherwise
+ * returns null.
+ * TODO: Use JNA to implement this under Linux.
+ */
+ public static Icon getIcon(File file)
+ {
+ Icon fileIcon = null;
+
+ try
+ {
+ sun.awt.shell.ShellFolder shellFolder
+ = sun.awt.shell.ShellFolder.getShellFolder(file);
+
+ fileIcon = new ImageIcon( shellFolder.getIcon(true),
+ shellFolder.getFolderType());
+ }
+ catch (Exception e)
+ {
+ logger.debug("Failed to obtain file icon from ShellFolder.", e);
+ try
+ {
+ fileIcon = new JFileChooser().getIcon(file);
+ }
+ catch (Exception e1)
+ {
+ logger.debug("Failed to obtain file icon from JFileChooser.", e);
+ }
+ }
+
+ return fileIcon;
+ }
+}
diff --git a/src/net/java/sip/communicator/util/swing/FileDragLabel.java b/src/net/java/sip/communicator/util/swing/FileDragLabel.java
new file mode 100644
index 0000000..9d185dd
--- /dev/null
+++ b/src/net/java/sip/communicator/util/swing/FileDragLabel.java
@@ -0,0 +1,194 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.util.swing;
+
+import java.awt.datatransfer.*;
+import java.awt.dnd.*;
+import java.io.*;
+import java.util.*;
+
+import javax.swing.*;
+
+import net.java.sip.communicator.util.*;
+
+/**
+ * The <tt>FileDragLabel</tt> extends <tt>JLabel</tt> and associates to it a
+ * file. The label is made draggable and it is possible to drag it directly to
+ * the file browser of the operating system.
+ *
+ * @author Yana Stamcheva
+ */
+public class FileDragLabel
+ extends JLabel
+ implements DropTargetListener,
+ DragSourceListener,
+ DragGestureListener
+{
+ private static final Logger logger = Logger.getLogger(FileDragLabel.class);
+
+ private final DragSource dragSource = DragSource.getDefaultDragSource();
+
+ private File file;
+
+ /**
+ * Creates a <tt>FileDragLabel</tt>.
+ */
+ public FileDragLabel()
+ {
+ dragSource.createDefaultDragGestureRecognizer(
+ this, DnDConstants.ACTION_COPY, this);
+ }
+
+ /**
+ * Sets the file associated with this file drag label.
+ *
+ * @param file the file associated with this file drag label
+ */
+ public void setFile(File file)
+ {
+ this.file = file;
+ }
+
+ /**
+ * Called while a drag operation is ongoing, when the mouse pointer enters
+ * the operable part of the drop site for the <code>DropTarget</code>
+ * registered with this listener.
+ *
+ * @param dtde the <code>DropTargetDragEvent</code>
+ */
+ public void dragEnter(DropTargetDragEvent dropTargetDragEvent)
+ {
+ dropTargetDragEvent.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
+ }
+
+ /**Called when the drag operation has terminated with a drop on
+ * the operable part of the drop site for the <code>DropTarget</code>
+ * registered with this listener.
+ */
+ public synchronized void drop(DropTargetDropEvent event)
+ {
+ try
+ {
+ Transferable transferable = event.getTransferable();
+
+ if (transferable.isDataFlavorSupported(
+ DataFlavor.javaFileListFlavor))
+ {
+ event.acceptDrop(DnDConstants.ACTION_COPY);
+ event.getDropTargetContext().dropComplete(true);
+ }
+ else
+ {
+ event.rejectDrop();
+ }
+ }
+ catch (Exception ex)
+ {
+ logger.debug("Unable to drop label.", ex);
+ event.rejectDrop();
+ }
+ }
+
+ /**
+ * A <code>DragGestureRecognizer</code> has detected
+ * a platform-dependent drag initiating gesture and
+ * is notifying this listener
+ * in order for it to initiate the action for the user.
+ * <P>
+ * @param dge the <code>DragGestureEvent</code> describing
+ * the gesture that has just occurred
+ */
+ public void dragGestureRecognized(DragGestureEvent dragGestureEvent)
+ {
+ if (file == null)
+ {
+ // Nothing selected, nothing to drag
+ getToolkit().beep();
+ }
+ else
+ {
+ FileTransferable transferable = new FileTransferable(file);
+ dragGestureEvent.startDrag( DragSource.DefaultCopyDrop,
+ transferable,
+ this);
+ }
+ }
+
+ public void dragDropEnd(DragSourceDropEvent DragSourceDropEvent) {}
+
+ public void dragEnter(DragSourceDragEvent DragSourceDragEvent) {}
+
+ public void dragExit(DragSourceEvent DragSourceEvent) {}
+
+ public void dragOver(DragSourceDragEvent DragSourceDragEvent) {}
+
+ public void dropActionChanged(DragSourceDragEvent DragSourceDragEvent) {}
+
+ public void dragExit(DropTargetEvent dropTargetEvent) {}
+
+ public void dragOver(DropTargetDragEvent dropTargetDragEvent) {}
+
+ public void dropActionChanged(DropTargetDragEvent dropTargetDragEvent) {}
+
+ /**
+ * File transferable.
+ */
+ private class FileTransferable
+ extends Vector<File>
+ implements Transferable
+ {
+ final static int FILE = 0;
+ final static int STRING = 1;
+ final static int PLAIN = 2;
+
+ // Don't have other possibility for now instead of using the deprecated
+ // plainTextFlavor method.
+ DataFlavor flavors[] = {DataFlavor.javaFileListFlavor,
+ DataFlavor.stringFlavor,
+ DataFlavor.plainTextFlavor};
+
+ public FileTransferable(File file)
+ {
+ addElement(file);
+ }
+
+ public synchronized DataFlavor[] getTransferDataFlavors()
+ {
+ return flavors;
+ }
+
+ public boolean isDataFlavorSupported(DataFlavor flavor)
+ {
+ boolean b = false;
+ b = b | flavor.equals(flavors[FILE]);
+ b |= flavor.equals(flavors[STRING]);
+ b |= flavor.equals(flavors[PLAIN]);
+ return (b);
+ }
+
+ public synchronized Object getTransferData(DataFlavor flavor)
+ throws UnsupportedFlavorException, IOException
+ {
+ if (flavor.equals(flavors[FILE]))
+ {
+ return this;
+ }
+ else if (flavor.equals(flavors[PLAIN]))
+ {
+ return new StringReader(file.getAbsolutePath());
+ }
+ else if (flavor.equals(flavors[STRING]))
+ {
+ return (file.getAbsolutePath());
+ }
+ else
+ {
+ throw new UnsupportedFlavorException(flavor);
+ }
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/util/swing/SwingWorker.java b/src/net/java/sip/communicator/util/swing/SwingWorker.java
new file mode 100644
index 0000000..8fd1769
--- /dev/null
+++ b/src/net/java/sip/communicator/util/swing/SwingWorker.java
@@ -0,0 +1,219 @@
+/*
+ * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ *
+ * Based on the 3rd version of SwingWorker (also known as SwingWorker 3), an
+ * abstract class that you subclass to perform GUI-related work in a dedicated
+ * thread. For instructions on using this class, see:
+ *
+ * http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
+ *
+ * Note that the API changed slightly in the 3rd version:
+ * You must now invoke start() on the SwingWorker after
+ * creating it.
+ */
+package net.java.sip.communicator.util.swing;
+
+import java.lang.Thread.*;
+
+import javax.swing.SwingUtilities;
+
+/**
+ * Utility class based on the javax.swing.SwingWorker. <tt>SwingWorker</tt> is
+ * an abstract class that you subclass to perform GUI-related work in a
+ * dedicated thread. In addition to the original SwingWorker this class takes
+ * care of exceptions occured during the execution of the separate thread. It
+ * would call a catchException() method in the Swing thread if an exception
+ * occurs.
+ *
+ * @author Yana Stamcheva
+ */
+public abstract class SwingWorker
+{
+ private Object value; // see getValue(), setValue()
+
+ /**
+ * Class to maintain reference to current worker thread
+ * under separate synchronization control.
+ */
+ private static class ThreadVar
+ {
+ private Thread thread;
+ ThreadVar(Thread t)
+ {
+ thread = t;
+ }
+ synchronized Thread get()
+ {
+ return thread;
+ }
+ synchronized void clear()
+ {
+ thread = null;
+ }
+ }
+
+ private ThreadVar threadVar;
+
+ /**
+ * Get the value produced by the worker thread, or null if it
+ * hasn't been constructed yet.
+ */
+ protected synchronized Object getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Set the value produced by worker thread
+ */
+ private synchronized void setValue(Object x)
+ {
+ value = x;
+ }
+
+ /**
+ * Compute the value to be returned by the <code>get</code> method.
+ */
+ public abstract Object construct()
+ throws Exception;
+
+ /**
+ * Called on the event dispatching thread (not on the worker thread)
+ * after the <code>construct</code> method has returned.
+ */
+ public void finished()
+ {
+ }
+
+ /**
+ * Called on the event dispatching thread (not on the worker thread)
+ * if an exception has occured during the <code>construct</code> method.
+ *
+ * @param exception the exception that has occured
+ */
+ public void catchException(Throwable exception)
+ {
+ }
+
+ /**
+ * A new method that interrupts the worker thread. Call this method
+ * to force the worker to stop what it's doing.
+ */
+ public void interrupt()
+ {
+ Thread t = threadVar.get();
+ if (t != null)
+ {
+ t.interrupt();
+ }
+ threadVar.clear();
+ }
+
+ /**
+ * Return the value created by the <code>construct</code> method.
+ * Returns null if either the constructing thread or the current
+ * thread was interrupted before a value was produced.
+ *
+ * @return the value created by the <code>construct</code> method
+ */
+ public Object get()
+ {
+ while (true)
+ {
+ Thread t = threadVar.get();
+ if (t == null)
+ {
+ return getValue();
+ }
+ try
+ {
+ t.join();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt(); // propagate
+ return null;
+ }
+ }
+ }
+
+
+ /**
+ * Start a thread that will call the <code>construct</code> method
+ * and then exit.
+ */
+ public SwingWorker()
+ {
+ final Runnable doFinished = new Runnable()
+ {
+ public void run() { finished(); }
+ };
+
+ Runnable doConstruct = new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ setValue(construct());
+ }
+ catch (final Exception exception)
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ catchException(exception);
+ }
+ });
+ }
+ finally
+ {
+ threadVar.clear();
+ }
+
+ SwingUtilities.invokeLater(doFinished);
+ }
+ };
+
+ Thread t = new Thread(doConstruct);
+
+ t.setUncaughtExceptionHandler(new SwingUncaughtExceptionHandler());
+ threadVar = new ThreadVar(t);
+ }
+
+ /**
+ * Start the worker thread.
+ */
+ public void start()
+ {
+ Thread t = threadVar.get();
+ if (t != null)
+ {
+ t.start();
+ }
+ }
+
+ /**
+ * An exception handler that calls the catchException() in the Swing thread
+ * if an exception occurs while processing the construct method in a
+ * separate thread.
+ */
+ private class SwingUncaughtExceptionHandler
+ implements UncaughtExceptionHandler
+ {
+ public void uncaughtException(Thread t, final Throwable e)
+ {
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ catchException(e);
+ }
+ });
+ }
+ }
+} \ No newline at end of file