diff options
author | Yana Stamcheva <yana@jitsi.org> | 2009-07-04 06:58:59 +0000 |
---|---|---|
committer | Yana Stamcheva <yana@jitsi.org> | 2009-07-04 06:58:59 +0000 |
commit | 26c28dfbda79ad47d9b774c119ef442b8e947faf (patch) | |
tree | 3f54a9bd9caa5789f2e37b5c13a1888896062191 /src/net/java/sip | |
parent | 0cadd759954fc55a221db77f256a64322a7792c2 (diff) | |
download | jitsi-26c28dfbda79ad47d9b774c119ef442b8e947faf.zip jitsi-26c28dfbda79ad47d9b774c119ef442b8e947faf.tar.gz jitsi-26c28dfbda79ad47d9b774c119ef442b8e947faf.tar.bz2 |
- Issue #690 (Add drag and drop of files in the contact list).
- Show an error message when file transfer is not supported by the selected account.
Diffstat (limited to 'src/net/java/sip')
7 files changed, 444 insertions, 175 deletions
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 05afb70..7227c70 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 @@ -200,6 +200,7 @@ public class ChatConversationPanel String contentType = chatMessage.getContentType(); long date = chatMessage.getDate(); String messageType = chatMessage.getMessageType(); + String messageTitle = chatMessage.getMessageTitle(); String message = chatMessage.getMessage(); String msgID = "message"; @@ -320,8 +321,7 @@ public class ChatConversationPanel + "' </IMG>"; chatString += errorIcon - + GuiActivator.getResources() - .getI18NString("service.gui.MSG_DELIVERY_FAILURE") + + messageTitle + endHeaderTag + "<h5>" + message + "</h5>"; } else if (messageType.equals(Constants.HISTORY_INCOMING_MESSAGE)) 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 index 21c07bd..eb0b473 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java @@ -30,6 +30,12 @@ public class ChatMessage private final String messageType; /** + * The title of the message. This property is optional and could be used + * to show a title for error messages. + */ + private String messageTitle; + + /** * The content of the message. */ private String message; @@ -62,6 +68,30 @@ public class ChatMessage } /** + * 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 messageTitle, + String message, + String contentType) + { + this.contactName = contactName; + this.date = date; + this.messageType = messageType; + this.messageTitle = messageTitle; + this.message = message; + this.contentType = contentType; + } + + /** * Returns the name of the contact sending the message. * * @return the name of the contact sending the message. @@ -92,6 +122,16 @@ public class ChatMessage } /** + * Returns the title of the message. + * + * @return the title of the message. + */ + public String getMessageTitle() + { + return messageTitle; + } + + /** * Returns the content of the message. * * @return the content of the message. 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 4d56686..465d0f1 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 @@ -574,11 +574,12 @@ public class ChatPanel * for processing and appends it at the end of the conversationPanel * document. * - * @param contactName The name of the contact sending the message. - * @param date The time at which the message is sent or received. - * @param messageType The type of the message. One of OUTGOING_MESSAGE - * or INCOMING_MESSAGE. - * @param message The message text. + * @param contactName the name of the contact sending the message + * @param date the time at which the message is sent or received + * @param messageType the type of the message. One of OUTGOING_MESSAGE + * or INCOMING_MESSAGE + * @param message the message text + * @param contentType the content type */ public void addMessage(String contactName, long date, String messageType, String message, String contentType) @@ -586,6 +587,40 @@ public class ChatPanel ChatMessage chatMessage = new ChatMessage(contactName, date, messageType, message, contentType); + this.addChatMessage(chatMessage); + } + + /** + * Passes the message to the contained <code>ChatConversationPanel</code> + * for processing and appends it at the end of the conversationPanel + * document. + * + * @param contactName the name of the contact sending the message + * @param date the time at which the message is sent or received + * @param messageType the type of the message. One of OUTGOING_MESSAGE + * or INCOMING_MESSAGE + * @param title the title of the message + * @param message the message text + * @param contentType the content type + */ + public void addMessage(String contactName, long date, + String messageType, String title, String message, String contentType) + { + ChatMessage chatMessage = new ChatMessage(contactName, date, + messageType, title, message, contentType); + + this.addChatMessage(chatMessage); + } + + /** + * Passes the message to the contained <code>ChatConversationPanel</code> + * for processing and appends it at the end of the conversationPanel + * document. + * + * @param chatMessage the chat message to add + */ + private void addChatMessage(ChatMessage chatMessage) + { if (ConfigurationManager.isHistoryShown() && !isHistoryLoaded) { synchronized (incomingEventBuffer) @@ -599,7 +634,23 @@ public class ChatPanel } // change the last history message timestamp after we add one. - this.lastHistoryMsgTimestamp = date; + this.lastHistoryMsgTimestamp = chatMessage.getDate(); + } + + /** + * 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, + GuiActivator.getResources() + .getI18NString("service.gui.MSG_DELIVERY_FAILURE"), + message, "text"); } /** @@ -608,10 +659,14 @@ public class ChatPanel * @param contactName the name of the contact, for which the error occured * @param message the error message */ - public void addErrorMessage(String contactName, String message) + public void addErrorMessage(String contactName, + String title, + String message) { this.addMessage(contactName, System.currentTimeMillis(), - Constants.ERROR_MESSAGE, message, "text"); + Constants.ERROR_MESSAGE, + title, + message, "text"); } /** @@ -914,9 +969,7 @@ public class ChatPanel public void catchException(Throwable ex) { - logger.error("Failed to send message.", ex); - - refreshWriteArea(); + logger.error("Failed to send file.", ex); if (ex instanceof IllegalStateException) { @@ -949,13 +1002,38 @@ public class ChatPanel final ChatTransport fileTransferTransport = findFileTransferChatTransport(); + // If there's no operation set we show some "not supported" messages + // and we return. + if (fileTransferTransport == null) + { + logger.error("Failed to send file."); + + this.addErrorMessage( + chatSession.getChatName(), + GuiActivator.getResources().getI18NString( + "service.gui.FILE_SEND_FAILED", + new String[]{file.getName()}), + GuiActivator.getResources().getI18NString( + "service.gui.FILE_TRANSFER_NOT_SUPPORTED")); + + return; + } + final SendFileConversationComponent fileComponent = new SendFileConversationComponent( this, fileTransferTransport.getDisplayName(), file); - getChatConversationPanel().addComponent(fileComponent); + if (ConfigurationManager.isHistoryShown() && !isHistoryLoaded) + { + synchronized (incomingEventBuffer) + { + incomingEventBuffer.add(fileComponent); + } + } + else + getChatConversationPanel().addComponent(fileComponent); this.sendFile(file, fileComponent); } 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 index 4b1c685..f2c8d62 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransferHandler.java @@ -15,6 +15,7 @@ import javax.swing.*; import javax.swing.text.*; import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.*; /** * A TransferHandler that we use to handle copying, pasting and DnD operations @@ -28,7 +29,7 @@ import net.java.sip.communicator.util.*; * @author Yana Stamcheva */ public class ChatTransferHandler - extends TransferHandler + extends ExtendedTransferHandler { /** * This class logger. @@ -53,75 +54,6 @@ public class ChatTransferHandler } /** - * 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; - - for (int i = 0, n = flavor.length; i < n; i++) - { - if (flavor[i].equals(DataFlavor.javaFileListFlavor)) - { - return true; - } - else if (flavor[i].equals(DataFlavor.stringFlavor)) - { - if (c.isEditable() && c.isEnabled()) - { - return true; - } - - return false; - } - } - - 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. @@ -202,95 +134,4 @@ public class ChatTransferHandler } 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/contactlist/ContactListTransferHandler.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTransferHandler.java new file mode 100644 index 0000000..8f1a58f --- /dev/null +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListTransferHandler.java @@ -0,0 +1,118 @@ +/* + * 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.contactlist; + +import java.awt.datatransfer.*; +import java.io.*; +import java.util.*; + +import javax.swing.*; + +import net.java.sip.communicator.impl.gui.*; +import net.java.sip.communicator.impl.gui.main.chat.*; +import net.java.sip.communicator.service.contactlist.*; +import net.java.sip.communicator.util.*; +import net.java.sip.communicator.util.swing.*; + +/** + * A TransferHandler that we use to handle DnD operations of files in our + * <tt>ContactList</tt>. + * + * @author Yana Stamcheva + */ +public class ContactListTransferHandler + extends ExtendedTransferHandler +{ + private static final Logger logger + = Logger.getLogger(ContactListTransferHandler.class); + + private final DefaultContactList contactList; + + public ContactListTransferHandler(DefaultContactList contactList) + { + this.contactList = contactList; + } + + /** + * Handles transfers to the contact list 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); + + ChatPanel chatPanel = getChatPanel(); + + if (chatPanel != null) + { + if (o instanceof java.util.Collection) + { + Collection<File> files = (Collection<File>) o; + + for(File file: files) + { + if (chatPanel != null) + chatPanel.sendFile(file); + + GuiActivator.getUIService().getChatWindowManager() + .openChat(chatPanel, false); + } + + // 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); + } + } + return false; + } + + /** + * Returns the <tt>ChatPanel</tt> corresponding to the currently selected + * contact. + * + * @return the <tt>ChatPanel</tt> corresponding to the currently selected + * contact. + */ + private ChatPanel getChatPanel() + { + ChatPanel chatPanel = null; + + Object selectedObject = contactList.getSelectedValue(); + + if (selectedObject != null && selectedObject instanceof MetaContact) + { + MetaContact metaContact = (MetaContact) selectedObject; + + // Obtain the corresponding chat panel. + chatPanel + = GuiActivator.getUIService().getChatWindowManager() + .getContactChat(metaContact); + } + + return chatPanel; + } +} diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultContactList.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultContactList.java index b8c74d9..a96d748 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultContactList.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/DefaultContactList.java @@ -36,6 +36,7 @@ public class DefaultContactList this.getSelectionModel().setSelectionMode( ListSelectionModel.SINGLE_SELECTION); + this.setTransferHandler(new ContactListTransferHandler(this)); this.setCellRenderer(new ContactListCellRenderer()); } diff --git a/src/net/java/sip/communicator/util/swing/ExtendedTransferHandler.java b/src/net/java/sip/communicator/util/swing/ExtendedTransferHandler.java new file mode 100644 index 0000000..20de777 --- /dev/null +++ b/src/net/java/sip/communicator/util/swing/ExtendedTransferHandler.java @@ -0,0 +1,191 @@ +/* + * SIP Communicator, the OpenSource Java VoIP and Instant Messaging client. + * + * Distributable under LGPL license. + * See terms of license at gnu.org. + */ +package net.java.sip.communicator.util.swing; + +import java.awt.datatransfer.*; +import java.io.*; + +import javax.swing.*; +import javax.swing.text.*; + +/** + * A TransferHandler that we use to handle copying, pasting and DnD operations. + * 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 ExtendedTransferHandler + extends TransferHandler +{ + /** + * 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[]) + { + for (int i = 0, n = flavor.length; i < n; i++) + { + if (flavor[i].equals(DataFlavor.javaFileListFlavor)) + { + return true; + } + else if (flavor[i].equals(DataFlavor.stringFlavor)) + { + if (comp instanceof JTextComponent) + { + JTextComponent c = (JTextComponent)comp; + + if (c.isEditable() && c.isEnabled()) + { + return true; + } + } + + return false; + } + } + + 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 super.createTransferable(comp); + } + + /** + * 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(); + } + } +} |