diff options
author | Yana Stamcheva <yana@jitsi.org> | 2012-07-12 17:00:53 +0000 |
---|---|---|
committer | Yana Stamcheva <yana@jitsi.org> | 2012-07-12 17:00:53 +0000 |
commit | 2a5e9c4895f6e04c15645c5898a9ab7537b8ffb2 (patch) | |
tree | 62756bba2293d47b2ddab54a02b63147751050dd /src/net | |
parent | 99a732d5f448270181b48edcae7960854052939b (diff) | |
download | jitsi-2a5e9c4895f6e04c15645c5898a9ab7537b8ffb2.zip jitsi-2a5e9c4895f6e04c15645c5898a9ab7537b8ffb2.tar.gz jitsi-2a5e9c4895f6e04c15645c5898a9ab7537b8ffb2.tar.bz2 |
Adds last message correction functionality. Implementation provided by Ivan Vergiliev.
Diffstat (limited to 'src/net')
21 files changed, 959 insertions, 69 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 678a71f..4e98ef8 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 @@ -20,6 +20,7 @@ import javax.swing.*; import javax.swing.event.*; import javax.swing.text.*; import javax.swing.text.html.*; +import javax.swing.text.html.HTML.*; import net.java.sip.communicator.impl.gui.*; import net.java.sip.communicator.impl.gui.customcontrols.*; @@ -364,6 +365,68 @@ public class ChatConversationPanel // } /** + * Retrieves the contents of the sent message with the given ID. + * + * @param messageUID The ID of the message to retrieve. + * @return The contents of the message, or null if the message is not found. + */ + public String getMessageContents(String messageUID) + { + Element root = document.getDefaultRootElement(); + Element e = document.getElement(root, Attribute.ID, messageUID); + if (e == null) + { + logger.warn("Could not find message with ID" + messageUID); + return null; + } + + int elemLen = e.getEndOffset() - e.getStartOffset(); + String res = null; + try + { + res = document.getText(e.getStartOffset(), elemLen); + } + catch (BadLocationException exc) + { + logger.warn("Could not get message contents for message " + + "with ID" + messageUID, exc); + } + return res; + } + + /** + * Creates a tag that shows the last edit time of a message, in the format + * (Edited at ...). + * If <tt>date < 0</tt>, returns an empty tag that serves as a placeholder + * for future corrections of this message. + * + * @param messageUID The ID of the edited message. + * @param date The date when the message was last edited, or -1 to generate + * an empty tag. + * @return The string representation of the tag. + */ + private String generateEditedAtTag(String messageUID, long date) + { + StringBuilder res = new StringBuilder(); + // Use a <cite /> tag here as most of the other inline tags (e.g. h1-7, + // b, i) cause different problems when used in setOuterHTML. + res.append("<cite id='"); + res.append(messageUID); + res.append("-editedAt'> "); + if (date > 0) + { + res.append(" "); + String contents = GuiActivator.getResources().getI18NString( + "service.gui.EDITED_AT", + new String[] { GuiUtils.formatTime(date) } + ); + res.append(contents); + } + res.append("</cite>"); + return res.toString(); + } + + /** * Processes the message given by the parameters. * * @param chatMessage the message @@ -384,14 +447,18 @@ public class ChatConversationPanel String messageType = chatMessage.getMessageType(); String messageTitle = chatMessage.getMessageTitle(); String message = chatMessage.getMessage(); + String messageUID = chatMessage.getMessageUID(); String msgID = "message"; String msgHeaderID = "messageHeader"; String chatString = ""; String endHeaderTag = ""; String dateString = getDateString(date); + String idAttr = messageUID == null ? "" : " id='" + messageUID + "'"; + String dateAttr = " date='" + date + "'"; + String editedAtTag = generateEditedAtTag(messageUID, -1); - String startDivTag = "<DIV identifier=\"" + msgID + "\">"; + String startDivTag = "<DIV identifier=\"" + msgID + "\"" + idAttr + ">"; String startHistoryDivTag = "<DIV identifier=\"" + msgID + "\" style=\"color:#707070;\">"; String startSystemDivTag @@ -417,7 +484,7 @@ public class ChatConversationPanel this.lastIncomingMsgTimestamp = System.currentTimeMillis(); chatString = "<h2 identifier=\"" + msgHeaderID + "\"" - + " date=\"" + date + "\">" + + dateAttr + ">" + "<a style=\"color:#ef7b1e;" + "font-weight:bold;" + "text-decoration:none;\" " @@ -427,8 +494,8 @@ public class ChatConversationPanel chatString += dateString + contactDisplayName + " at " - + GuiUtils.formatTime(date) - + endHeaderTag + startDivTag + startPlainTextTag + + GuiUtils.formatTime(date) + editedAtTag + endHeaderTag + + startDivTag + startPlainTextTag + formatMessage(message, contentType, keyword) + endPlainTextTag + endDivTag; } @@ -451,7 +518,7 @@ public class ChatConversationPanel else if (messageType.equals(Chat.OUTGOING_MESSAGE)) { chatString = "<h3 identifier=\"" + msgHeaderID + "\"" - + " date=\"" + date + "\">" + + dateAttr + ">" + "<a style=\"color:#2e538b;" + "font-weight:bold;" + "text-decoration:none;\" " @@ -461,7 +528,7 @@ public class ChatConversationPanel chatString += dateString + contactDisplayName + " at " - + GuiUtils.formatTime(date) + endHeaderTag + + GuiUtils.formatTime(date) + editedAtTag + endHeaderTag + startDivTag + startPlainTextTag + formatMessage(message, contentType, keyword) + endPlainTextTag + endDivTag; @@ -514,7 +581,7 @@ public class ChatConversationPanel else if (messageType.equals(Chat.HISTORY_INCOMING_MESSAGE)) { chatString = "<h2 identifier=\"" + msgHeaderID + "\"" - + " date=\"" + date + "\">" + + dateAttr + ">" + "<a style=\"color:#ef7b1e;" + "font-weight:bold;" + "text-decoration:none;\" " @@ -524,15 +591,15 @@ public class ChatConversationPanel chatString += dateString + contactDisplayName - + " at " + GuiUtils.formatTime(date) - + endHeaderTag + startHistoryDivTag + startPlainTextTag + + " at " + GuiUtils.formatTime(date) + endHeaderTag + + editedAtTag + startHistoryDivTag + startPlainTextTag + formatMessage(message, contentType, keyword) + endPlainTextTag + endDivTag; } else if (messageType.equals(Chat.HISTORY_OUTGOING_MESSAGE)) { chatString = "<h3 identifier=\"" + msgHeaderID + "\"" - + " date=\"" + date + "\">" + + dateAttr + ">" + "<a style=\"color:#2e538b;" + "font-weight:bold;" + "text-decoration:none;\" " @@ -542,8 +609,8 @@ public class ChatConversationPanel chatString += dateString - + contactDisplayName - + " at " + GuiUtils.formatTime(date) + endHeaderTag + + contactDisplayName + " at " + GuiUtils.formatTime(date) + + editedAtTag + endHeaderTag + startHistoryDivTag + startPlainTextTag + formatMessage(message, contentType, keyword) + endPlainTextTag + endDivTag; @@ -564,6 +631,68 @@ public class ChatConversationPanel } /** + * Replaces the contents of the message with ID of the corrected message + * specified in chatMessage, with this message. + * + * @param chatMessage A <tt>ChatMessage</tt> that contains all the required + * information to correct the old message. + */ + public void correctMessage(ChatMessage chatMessage) + { + String correctedUID = chatMessage.getCorrectedMessageUID(); + Element root = document.getDefaultRootElement(); + Element e = document.getElement(root, Attribute.ID, correctedUID); + if (e == null) + { + logger.warn("Could not find message with ID " + correctedUID); + return; + } + int len = e.getEndOffset() - e.getStartOffset(); + + StringBuilder newContents = new StringBuilder(); + String bgColor = GuiActivator.getResources().getColorString( + "service.gui.CHAT_EDIT_MESSAGE_BACKGROUND"); + newContents.append("<div identifier='message' id='"); + newContents.append(chatMessage.getMessageUID()); + newContents.append("' bgcolor='"); + newContents.append(bgColor); + newContents.append("'>"); + if (chatMessage.getContentType().equals(TEXT_CONTENT_TYPE)) + { + newContents.append(START_PLAINTEXT_TAG); + newContents.append(chatMessage.getMessage()); + newContents.append(END_PLAINTEXT_TAG); + } + else + { + newContents.append(chatMessage.getMessage()); + } + newContents.append("</div>"); + + Element header = document.getElement(root, Attribute.ID, + correctedUID + "-editedAt"); + + try + { + if (header != null) + { + String newHeaderContents = generateEditedAtTag( + chatMessage.getMessageUID(), chatMessage.getDate()); + document.setOuterHTML(header, newHeaderContents); + } + document.setOuterHTML(e, newContents.toString()); + } + catch (BadLocationException ex) + { + logger.error("Could not replace chat message", ex); + } + catch (IOException ex) + { + logger.error("Could not replace chat message", ex); + } + } + + /** * Appends the given string at the end of the contained in this panel * document. * 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 ca48a06..98e006a 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 @@ -49,6 +49,17 @@ public class ChatMessage * The content type of the message. */ private final String contentType; + + /** + * A unique identifier for this message. + */ + private String messageUID; + + /** + * The unique identifier of the message that this message should replace, + * or <tt>null</tt> if this is a new message. + */ + private String correctedMessageUID; /** * Creates a <tt>ChatMessage</tt> by specifying all parameters of the @@ -65,7 +76,8 @@ public class ChatMessage String message, String contentType) { - this(contactName, null, date, messageType, null, message, contentType); + this(contactName, null, date, messageType, + null, message, contentType, null, null); } /** @@ -86,7 +98,7 @@ public class ChatMessage String contentType) { this(contactName, null, date, messageType, - messageTitle, message, contentType); + messageTitle, message, contentType, null, null); } /** @@ -107,7 +119,7 @@ public class ChatMessage String contentType) { this(contactName, contactDisplayName, date, messageType, - null, message, contentType); + null, message, contentType, null, null); } /** @@ -119,6 +131,8 @@ public class ChatMessage * @param messageType the type (INCOMING or OUTGOING) * @param message the content * @param contentType the content type (e.g. "text", "text/html", etc.) + * @param messageUID The ID of the message. + * @param correctedMessageUID The ID of the message being replaced. */ public ChatMessage( String contactName, String contactDisplayName, @@ -126,7 +140,9 @@ public class ChatMessage String messageType, String messageTitle, String message, - String contentType) + String contentType, + String messageUID, + String correctedMessageUID) { this.contactName = contactName; this.contactDisplayName = contactDisplayName; @@ -135,6 +151,8 @@ public class ChatMessage this.messageTitle = messageTitle; this.message = message; this.contentType = contentType; + this.messageUID = messageUID; + this.correctedMessageUID = correctedMessageUID; } /** @@ -216,4 +234,26 @@ public class ChatMessage { return contentType; } + + /** + * Returns the UID of this message. + * + * @return the UID of this message. + */ + public String getMessageUID() + { + return messageUID; + } + + /** + * Returns the UID of the message that this message replaces, or + * <tt>null</tt> if this is a new message. + * + * @return the UID of the message that this message replaces, or + * <tt>null</tt> if this is a new message. + */ + public String getCorrectedMessageUID() + { + return correctedMessageUID; + } } 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 70a8ab9..9cf6f62 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 @@ -138,6 +138,17 @@ public class ChatPanel */ private final Hashtable<String, Object> activeFileTransfers = new Hashtable<String, Object>(); + + /** + * The ID of the message being corrected, or <tt>null</tt> if + * not correcting any message. + */ + private String correctedMessageUID = null; + + /** + * The ID of the last sent message in this chat. + */ + private String lastSentMessageUID = null; /** * Creates a <tt>ChatPanel</tt> which is added to the given chat window. @@ -490,6 +501,17 @@ public class ChatPanel } /** + * Returns the ID of the last message sent in this chat, or <tt>null</tt> + * if no messages have been sent yet. + * + * @return the ID of the last message sent in this chat, or <tt>null</tt> + * if no messages have been sent yet. + */ + public String getLastSentMessageUID() { + return lastSentMessageUID; + } + + /** * Every time the chat panel is shown we set it as a current chat panel. * This is done here and not in the Tab selection listener, because the tab * change event is not fired when the user clicks on the close tab button @@ -589,7 +611,8 @@ public class ChatPanel evt.getTimestamp(), messageType, evt.getSourceMessage().getContent(), - evt.getSourceMessage().getContentType()); + evt.getSourceMessage().getContentType(), + evt.getSourceMessage().getMessageUID()); } else if(o instanceof MessageReceivedEvent) { @@ -612,7 +635,8 @@ public class ChatPanel evt.getTimestamp(), messageType, evt.getSourceMessage().getContent(), - evt.getSourceMessage().getContentType()); + evt.getSourceMessage().getContentType(), + evt.getSourceMessage().getMessageUID()); } } else if(o instanceof ChatRoomMessageDeliveredEvent) @@ -684,7 +708,8 @@ public class ChatPanel public void addMessage(String contactName, long date, String messageType, String message, String contentType) { - addMessage(contactName, null, date, messageType, message, contentType); + addMessage(contactName, null, date, messageType, message, contentType, + null, null); } /** @@ -701,11 +726,12 @@ public class ChatPanel * @param contentType the content type */ public void addMessage(String contactName, String displayName, long date, - String messageType, String message, String contentType) + String messageType, String message, String contentType, + String messageUID, String correctedMessageUID) { - ChatMessage chatMessage - = new ChatMessage(contactName, displayName, date, - messageType, message, contentType); + ChatMessage chatMessage = new ChatMessage(contactName, displayName, + date, messageType, null, message, contentType, + messageUID, correctedMessageUID); this.addChatMessage(chatMessage); @@ -769,11 +795,15 @@ public class ChatPanel } else { - appendChatMessage(chatMessage); + displayChatMessage(chatMessage); } // change the last history message timestamp after we add one. this.lastHistoryMsgTimestamp = chatMessage.getDate(); + if (chatMessage.getMessageType().equals(Chat.OUTGOING_MESSAGE)) + { + this.lastSentMessageUID = chatMessage.getMessageUID(); + } } /** @@ -809,6 +839,20 @@ public class ChatPanel message, "text"); } + private void displayChatMessage(ChatMessage chatMessage) + { + if (chatMessage.getCorrectedMessageUID() != null + && conversationPanel.getMessageContents( + chatMessage.getCorrectedMessageUID()) != null) + { + applyMessageCorrection(chatMessage); + } + else + { + appendChatMessage(chatMessage); + } + } + /** * Passes the message to the contained <code>ChatConversationPanel</code> * for processing and appends it at the end of the conversationPanel @@ -855,6 +899,17 @@ public class ChatPanel /** * Passes the message to the contained <code>ChatConversationPanel</code> + * for processing and replaces the specified message with this one. + * + * @param chatMessage The message used as a correction. + */ + private void applyMessageCorrection(ChatMessage message) + { + conversationPanel.correctMessage(message); + } + + /** + * Passes the message to the contained <code>ChatConversationPanel</code> * for processing. * * @param contactName The name of the contact sending the message. @@ -875,9 +930,37 @@ public class ChatPanel String message, String contentType) { + return processHistoryMessage(contactName, contactDisplayName, + date, messageType, message, contentType, null); + } + + /** + * Passes the message to the contained <code>ChatConversationPanel</code> + * for processing. + * + * @param contactName The name of the contact sending the message. + * @param contactDisplayName the display 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 of the message (html or plain text) + * @param messageId The ID of the message. + * + * @return a string containing the processed message. + */ + private String processHistoryMessage(String contactName, + String contactDisplayName, + long date, + String messageType, + String message, + String contentType, + String messageId) + { ChatMessage chatMessage = new ChatMessage( contactName, contactDisplayName, date, - messageType, null, message, contentType); + messageType, null, message, contentType, messageId, null); String processedMessage = this.conversationPanel.processMessage(chatMessage); @@ -1372,7 +1455,7 @@ public class ChatPanel OperationSetBasicInstantMessaging.HTML_MIME_TYPE).trim(); plainText = getTextFromWriteArea( - OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE); + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE).trim(); // clear the message earlier // to avoid as much as possible to not sending it twice (double enter) @@ -1399,8 +1482,19 @@ public class ChatPanel try { - chatSession.getCurrentChatTransport() - .sendInstantMessage(messageText, mimeType); + if (isMessageCorrectionActive() + && chatSession.getCurrentChatTransport() + .allowsMessageCorrections()) + { + chatSession.getCurrentChatTransport().correctInstantMessage( + messageText, mimeType, correctedMessageUID); + } + else + { + chatSession.getCurrentChatTransport().sendInstantMessage( + messageText, mimeType); + } + stopMessageCorrection(); } catch (IllegalStateException ex) { @@ -1459,6 +1553,58 @@ public class ChatPanel } /** + * Enters editing mode for the last sent message in this chat. + */ + public void startLastMessageCorrection() + { + startMessageCorrection(lastSentMessageUID); + } + + /** + * Enters editing mode for the message with the specified id - puts the + * message contents in the write panel and changes the background. + * + * @param correctedMessageUID The ID of the message being corrected. + */ + public void startMessageCorrection(String correctedMessageUID) + { + this.correctedMessageUID = correctedMessageUID; + this.refreshWriteArea(); + String messageContents + = conversationPanel.getMessageContents(correctedMessageUID); + if (messageContents == null) + { + this.stopMessageCorrection(); + return; + } + Color bgColor = new Color(GuiActivator.getResources() + .getColor("service.gui.CHAT_EDIT_MESSAGE_BACKGROUND")); + this.writeMessagePanel.setEditorPaneBackground(bgColor); + this.setMessage(messageContents); + } + + /** + * Exits editing mode, clears the write panel and the background. + */ + public void stopMessageCorrection() + { + this.correctedMessageUID = null; + this.writeMessagePanel.setEditorPaneBackground(Color.WHITE); + this.refreshWriteArea(); + } + + /** + * Returns whether a message is currently being edited. + * + * @return <tt>true</tt> if a message is currently being edited, + * <tt>false</tt> otherwise. + */ + public boolean isMessageCorrectionActive() + { + return correctedMessageUID != null; + } + + /** * Listens for SMS messages and shows them in the chat. */ private class SmsMessageListener implements MessageListener @@ -2358,7 +2504,7 @@ public class ChatPanel if (incomingEvent instanceof ChatMessage) { - this.appendChatMessage((ChatMessage) incomingEvent); + this.displayChatMessage((ChatMessage) incomingEvent); } else if (incomingEvent instanceof ChatConversationComponent) { 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 ba13dbc..12aeedd 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 @@ -35,6 +35,15 @@ public interface ChatTransport * messaging, otherwise returns <code>false</code> */ public boolean allowsInstantMessage(); + + /** + * Returns <tt>true</tt> if this chat transport supports message + * corrections and false otherwise. + * + * @return <code>true</code> if this chat transport supports message + * corrections and false otherwise. + */ + public boolean allowsMessageCorrections(); /** * Returns <code>true</code> if this chat transport supports sms @@ -100,6 +109,20 @@ public interface ChatTransport public void sendInstantMessage( String message, String mimeType) throws Exception; + + /** + * Sends <tt>message</tt> as a message correction through this transport, + * specifying the mime type (html or plain text) and the id of the + * message to replace. + * + * @param message The message to send. + * @param mimeType The mime type of the message to send: text/html or + * text/plain. + * @param correctedMessageUID The ID of the message being corrected by + * this message. + */ + public void correctInstantMessage(String message, String mimeType, + String correctedMessageUID); /** * Determines whether this chat transport supports the supplied content type 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 a93cedb..855dd77 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 @@ -674,6 +674,27 @@ public class ChatWritePanel ex.printStackTrace(); } } + else if (e.getKeyCode() == KeyEvent.VK_UP) + { + // Only enters editing mode if the write panel is empty in + // order not to lose the current message contents, if any. + if (this.chatPanel.getLastSentMessageUID() != null + && this.chatPanel.isWriteAreaEmpty()) + { + this.chatPanel.startLastMessageCorrection(); + } + } + else if (e.getKeyCode() == KeyEvent.VK_DOWN) + { + if (chatPanel.isMessageCorrectionActive()) + { + Document doc = editorPane.getDocument(); + if (editorPane.getCaretPosition() == doc.getLength()) + { + chatPanel.stopMessageCorrection(); + } + } + } } public void keyReleased(KeyEvent e) {} @@ -1297,4 +1318,15 @@ public class ChatWritePanel smsNumberLabel.setText(String.valueOf(smsNumberCount)); } } + + /** + * Sets the background of the write area to the specified color. + * + * @param color The color to set the background to. + */ + public void setEditorPaneBackground(Color color) + { + this.centerPanel.setBackground(color); + this.editorPane.setBackground(color); + } } 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 e3e0b83..73a8ae9 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 @@ -110,9 +110,6 @@ public class MetaContactChatTransport } } - - - /** * Returns the contact associated with this transport. * @return the contact associated with this transport @@ -194,6 +191,30 @@ public class MetaContactChatTransport } /** + * Returns <code>true</code> if this chat transport supports message + * corrections and false otherwise. + * + * @return <code>true</code> if this chat transport supports message + * corrections and false otherwise. + */ + public boolean allowsMessageCorrections() + { + OperationSetContactCapabilities capOpSet = getProtocolProvider() + .getOperationSet(OperationSetContactCapabilities.class); + + if (capOpSet != null) + { + return capOpSet.getOperationSet( + contact, OperationSetMessageCorrection.class) != null; + } + else + { + return contact.getProtocolProvider().getOperationSet( + OperationSetMessageCorrection.class) != null; + } + } + + /** * Returns <code>true</code> if this chat transport supports sms * messaging, otherwise returns <code>false</code>. * @@ -260,8 +281,8 @@ public class MetaContactChatTransport } /** - * Sends the given instant message trough this chat transport, by specifying - * the mime type (html or plain text). + * Sends the given instant message through this chat transport, + * by specifying the mime type (html or plain text). * * @param message The message to send. * @param mimeType The mime type of the message to send: text/html or @@ -299,6 +320,45 @@ public class MetaContactChatTransport } /** + * Sends <tt>message</tt> as a message correction through this transport, + * specifying the mime type (html or plain text) and the id of the + * message to replace. + * + * @param message The message to send. + * @param mimeType The mime type of the message to send: text/html or + * text/plain. + * @param correctedMessageUID The ID of the message being corrected by + * this message. + */ + public void correctInstantMessage(String message, String mimeType, + String correctedMessageUID) + { + if (!allowsMessageCorrections()) + { + return; + } + + OperationSetMessageCorrection mcOpSet = contact.getProtocolProvider() + .getOperationSet(OperationSetMessageCorrection.class); + + Message msg; + if (mimeType.equals(OperationSetBasicInstantMessaging.HTML_MIME_TYPE) + && mcOpSet.isContentTypeSupported( + OperationSetBasicInstantMessaging.HTML_MIME_TYPE)) + { + msg = mcOpSet.createMessage(message, + OperationSetBasicInstantMessaging.HTML_MIME_TYPE, + "utf-8", ""); + } + else + { + msg = mcOpSet.createMessage(message); + } + + mcOpSet.correctMessage(contact, msg, correctedMessageUID); + } + + /** * Determines whether this chat transport supports the supplied content type * * @param contentType the type we want to check diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java index 195ea78..48a27dd 100644 --- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java +++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java @@ -316,4 +316,31 @@ public class AdHocConferenceChatTransport // TODO Auto-generated method stub return 0; } + + /** + * Returns <tt>true</tt> if this chat transport supports message + * corrections and false otherwise. + * + * @return <tt>true</tt> if this chat transport supports message + * corrections and false otherwise. + */ + public boolean allowsMessageCorrections() + { + return false; + } + + /** + * Sends <tt>message</tt> as a message correction through this transport, + * specifying the mime type (html or plain text) and the id of the + * message to replace. + * + * @param message The message to send. + * @param mimeType The mime type of the message to send: text/html or + * text/plain. + * @param correctedMessageUID The ID of the message being corrected by + * this message. + */ + public void correctInstantMessage(String message, String mimeType, + String correctedMessageUID) + {} } 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 d4f196a..e2bd0e5 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 @@ -318,4 +318,31 @@ public class ConferenceChatTransport { return chatRoom; } + + /** + * Sends <tt>message</tt> as a message correction through this transport, + * specifying the mime type (html or plain text) and the id of the + * message to replace. + * + * @param message The message to send. + * @param mimeType The mime type of the message to send: text/html or + * text/plain. + * @param correctedMessageUID The ID of the message being corrected by + * this message. + */ + public void correctInstantMessage(String message, String mimeType, + String correctedMessageUID) + {} + + /** + * Returns <code>true</code> if this chat transport supports message + * corrections and false otherwise. + * + * @return <code>true</code> if this chat transport supports message + * corrections and false otherwise. + */ + public boolean allowsMessageCorrections() + { + return false; + } } 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 0a109b6..2c2b216 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 @@ -278,8 +278,11 @@ public class HistoryWindow .getAccountDisplayName(protocolProvider), evt.getTimestamp(), Chat.OUTGOING_MESSAGE, + null, evt.getSourceMessage().getContent(), - evt.getSourceMessage().getContentType()); + evt.getSourceMessage().getContentType(), + evt.getSourceMessage().getMessageUID(), + null); } else if(o instanceof MessageReceivedEvent) { @@ -290,8 +293,11 @@ public class HistoryWindow evt.getSourceContact().getDisplayName(), evt.getTimestamp(), Chat.INCOMING_MESSAGE, + null, evt.getSourceMessage().getContent(), - evt.getSourceMessage().getContentType()); + evt.getSourceMessage().getContentType(), + evt.getSourceMessage().getMessageUID(), + null); } else if(o instanceof ChatRoomMessageReceivedEvent) { 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 2f9e23b..9243cb9 100644 --- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java +++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java @@ -238,8 +238,8 @@ public class ContactListPane if(metaContact != null) { - messageReceived(protocolContact, - metaContact, message, eventType, evt.getTimestamp()); + messageReceived(protocolContact, metaContact, message, eventType, + evt.getTimestamp(), evt.getCorrectedMessageUID()); } else { @@ -266,7 +266,8 @@ public class ContactListPane final MetaContact metaContact, final Message message, final int eventType, - final long timestamp) + final long timestamp, + final String correctedMessageUID) { if(!SwingUtilities.isEventDispatchThread()) { @@ -274,8 +275,8 @@ public class ContactListPane { public void run() { - messageReceived(protocolContact, - metaContact, message, eventType, timestamp); + messageReceived(protocolContact, metaContact, message, + eventType, timestamp, correctedMessageUID); } }); return; @@ -315,7 +316,9 @@ public class ContactListPane timestamp, messageType, message.getContent(), - message.getContentType()); + message.getContentType(), + message.getMessageUID(), + correctedMessageUID); chatWindowManager.openChat(chatPanel, false); @@ -361,7 +364,9 @@ public class ContactListPane evt.getTimestamp(), Chat.OUTGOING_MESSAGE, msg.getContent(), - msg.getContentType()); + msg.getContentType(), + msg.getMessageUID(), + evt.getCorrectedMessageUID()); } } @@ -429,7 +434,9 @@ public class ContactListPane System.currentTimeMillis(), Chat.OUTGOING_MESSAGE, sourceMessage.getContent(), - sourceMessage.getContentType()); + sourceMessage.getContentType(), + sourceMessage.getMessageUID(), + evt.getCorrectedMessageUID()); chatPanel.addErrorMessage( metaContact.getDisplayName(), diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java index f502d2b..d417ebc 100755 --- a/src/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java @@ -33,4 +33,21 @@ public class MessageJabberImpl { super(content, contentType, contentEncoding, subject); } + + /** + * Creates an instance of this Message with the specified parameters. + * + * @param content the text content of the message. + * @param contentType a MIME string indicating the content type of the + * <tt>content</tt> String. + * @param contentEncoding a MIME String indicating the content encoding of + * the <tt>content</tt> String. + * @param subject the subject of the message or null for empty. + * @param + */ + public MessageJabberImpl(String content, String contentType, + String contentEncoding, String subject, String messageUID) + { + super(content, contentType, contentEncoding, subject, messageUID); + } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java index 3b14c28..ff7763a 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java @@ -9,6 +9,7 @@ package net.java.sip.communicator.impl.protocol.jabber; import java.util.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.mailnotification.*; +import net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.Message; import net.java.sip.communicator.service.protocol.event.*; @@ -34,6 +35,7 @@ import org.jivesoftware.smackx.packet.*; */ public class OperationSetBasicInstantMessagingJabberImpl extends AbstractOperationSetBasicInstantMessaging + implements OperationSetMessageCorrection { /** * Our class logger @@ -129,6 +131,13 @@ public class OperationSetBasicInstantMessagingJabberImpl this.jabberProvider = provider; provider.addRegistrationStateChangeListener( new RegistrationStateListener()); + + ProviderManager man = ProviderManager.getInstance(); + MessageCorrectionExtensionProvider extProvider = + new MessageCorrectionExtensionProvider(); + man.addExtensionProvider(MessageCorrectionExtension.ELEMENT_NAME, + MessageCorrectionExtension.NAMESPACE, + extProvider); } /** @@ -159,6 +168,13 @@ public class OperationSetBasicInstantMessagingJabberImpl return new MessageJabberImpl(content, contentType, encoding, subject); } + private Message createMessage(String content, String contentType, + String messageUID) + { + return new MessageJabberImpl(content, contentType, + DEFAULT_MIME_ENCODING, null, messageUID); + } + /** * Determines wheter the protocol provider (or the protocol itself) support * sending and receiving offline messages. Most often this method would @@ -350,18 +366,18 @@ public class OperationSetBasicInstantMessagingJabberImpl } /** - * Sends the <tt>message</tt> to the destination indicated by the - * <tt>to</tt> contact. - * - * @param to the <tt>Contact</tt> to send <tt>message</tt> to - * @param message the <tt>Message</tt> to send. - * @throws java.lang.IllegalStateException if the underlying stack is - * not registered and initialized. - * @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an - * instance of ContactImpl. + * Helper function used to send a message to a contact, with the given + * extensions attached. + * + * @param to The contact to send the message to. + * @param message The message to send. + * @param extensions The XMPP extensions that should be attached to the + * message before sending. + * @return The MessageDeliveryEvent that resulted after attempting to + * send this message, so the calling function can modify it if needed. */ - public void sendInstantMessage(Contact to, Message message) - throws IllegalStateException, IllegalArgumentException + private MessageDeliveredEvent sendMessage(Contact to, Message message, + PacketExtension[] extensions) { if( !(to instanceof ContactJabberImpl) ) throw new IllegalArgumentException( @@ -382,8 +398,14 @@ public class OperationSetBasicInstantMessagingJabberImpl Chat chat = obtainChatInstance(toJID); + msg.setPacketID(message.getMessageUID()); msg.setTo(toJID); + for (PacketExtension ext : extensions) + { + msg.addExtension(ext); + } + if (logger.isTraceEnabled()) logger.trace("Will send a message to:" + toJID + " chat.jid=" + chat.getParticipant() @@ -396,7 +418,7 @@ public class OperationSetBasicInstantMessagingJabberImpl = messageDeliveryPendingTransform(msgDeliveryPendingEvt); if (msgDeliveryPendingEvt == null) - return; + return null; String content = msgDeliveryPendingEvt .getSourceMessage().getContent(); @@ -421,7 +443,7 @@ public class OperationSetBasicInstantMessagingJabberImpl // this is plain text so keep it as it is. msg.setBody(content); } - + //msg.addExtension(new Version()); MessageEventManager. @@ -434,16 +456,53 @@ public class OperationSetBasicInstantMessagingJabberImpl // msgDeliveredEvt = messageDeliveredTransform(msgDeliveredEvt); - if (msgDeliveredEvt != null) - fireMessageEvent(msgDeliveredEvt); + return msgDeliveredEvt; } catch (XMPPException ex) { - logger.error("message not send", ex); + logger.error("message not sent", ex); + return null; } } /** + * Sends the <tt>message</tt> to the destination indicated by the + * <tt>to</tt> contact. + * + * @param to the <tt>Contact</tt> to send <tt>message</tt> to + * @param message the <tt>Message</tt> to send. + * @throws java.lang.IllegalStateException if the underlying stack is + * not registered and initialized. + * @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an + * instance of ContactImpl. + */ + public void sendInstantMessage(Contact to, Message message) + throws IllegalStateException, IllegalArgumentException + { + MessageDeliveredEvent msgDelivered = + sendMessage(to, message, new PacketExtension[0]); + fireMessageEvent(msgDelivered); + } + + /** + * Replaces the message with ID <tt>correctedMessageUID</tt> sent to + * the contact <tt>to</tt> with the message <tt>message</tt> + * + * @param to The contact to send the message to. + * @param message The new message. + * @param correctedMessageUID The ID of the message being replaced. + */ + public void correctMessage(Contact to, Message message, + String correctedMessageUID) + { + PacketExtension[] exts = new PacketExtension[1]; + exts[0] = new MessageCorrectionExtension(correctedMessageUID); + MessageDeliveredEvent msgDelivered = sendMessage(to, message, exts); + msgDelivered.setCorrectedMessageUID(correctedMessageUID); + fireMessageEvent(msgDelivered); + } + + /** * Utility method throwing an exception if the stack is not properly * initialized. * @@ -581,7 +640,8 @@ public class OperationSetBasicInstantMessagingJabberImpl + msg.toXML()); } - Message newMessage = createMessage(msg.getBody()); + Message newMessage = createMessage(msg.getBody(), + DEFAULT_MIME_TYPE, msg.getPacketID()); //check if the message is available in xhtml PacketExtension ext = msg.getExtension( @@ -619,11 +679,20 @@ public class OperationSetBasicInstantMessagingJabberImpl receivedMessage = receivedMessage.replaceAll("'", "'"); - newMessage = - createMessage(receivedMessage, HTML_MIME_TYPE); + newMessage = createMessage(receivedMessage, + HTML_MIME_TYPE, msg.getPacketID()); } } + PacketExtension correctionExtension = + msg.getExtension(MessageCorrectionExtension.NAMESPACE); + String correctedMessageUID = null; + if (correctionExtension != null) + { + correctedMessageUID = ((MessageCorrectionExtension) + correctionExtension).getCorrectedMessageUID(); + } + Contact sourceContact = opSetPersPresence.findContactByID(fromUserID); @@ -652,6 +721,7 @@ public class OperationSetBasicInstantMessagingJabberImpl MessageDeliveryFailedEvent ev = new MessageDeliveryFailedEvent(newMessage, sourceContact, + correctedMessageUID, errorResultCode); // ev = messageDeliveryFailedTransform(ev); @@ -681,9 +751,8 @@ public class OperationSetBasicInstantMessagingJabberImpl .createVolatileContact(fromUserID); } - MessageReceivedEvent msgReceivedEvt - = new MessageReceivedEvent( - newMessage, sourceContact , System.currentTimeMillis() ); + MessageReceivedEvent msgReceivedEvt = new MessageReceivedEvent( + newMessage, sourceContact, correctedMessageUID); // msgReceivedEvt = messageReceivedTransform(msgReceivedEvt); diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java index b030dfb..35d7f83 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java @@ -9,6 +9,7 @@ package net.java.sip.communicator.impl.protocol.jabber; import java.util.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.caps.*; +import net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; import net.java.sip.communicator.util.*; @@ -70,6 +71,7 @@ public class OperationSetContactCapabilitiesJabberImpl static { OFFLINE_OPERATION_SETS.add(OperationSetBasicInstantMessaging.class); + OFFLINE_OPERATION_SETS.add(OperationSetMessageCorrection.class); OPERATION_SETS_TO_FEATURES.put( OperationSetBasicTelephony.class, @@ -98,6 +100,13 @@ public class OperationSetContactCapabilitiesJabberImpl ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RTP_VIDEO }); + OPERATION_SETS_TO_FEATURES.put( + OperationSetMessageCorrection.class, + new String[] + { + MessageCorrectionExtension.NAMESPACE + }); + CAPS_OPERATION_SETS_TO_FEATURES.put( OperationSetBasicTelephony.class, new String[] 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 4a2c4c6..3a8197d 100644 --- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java @@ -25,6 +25,7 @@ import net.java.sip.communicator.impl.protocol.jabber.extensions.inputevt.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.jingleinfo.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.keepalive.*; +import net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection.*; import net.java.sip.communicator.impl.protocol.jabber.extensions.version.*; import net.java.sip.communicator.impl.protocol.jabber.sasl.*; import net.java.sip.communicator.service.certificate.*; @@ -1787,6 +1788,10 @@ public class ProtocolProviderServiceJabberImpl if(versionManager == null) versionManager = new VersionManager(this); + supportedFeatures.add(MessageCorrectionExtension.NAMESPACE); + addSupportedOperationSet(OperationSetMessageCorrection.class, + basicInstantMessaging); + isInitialized = true; } } diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtension.java new file mode 100644 index 0000000..12e3c4a --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtension.java @@ -0,0 +1,109 @@ +/* + * Jitsi, 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.extensions.messagecorrection; + +import org.jivesoftware.smack.packet.*; + +/** + * Represents an XMPP Message correction extension, as defined in XEP-308. + * + * @author Ivan Vergiliev + */ +public class MessageCorrectionExtension + implements PacketExtension +{ + /** + * The XMPP namespace that this extension belongs to. + */ + public static final String NAMESPACE = "urn:xmpp:message-correct:0"; + + /** + * The XMPP namespace that Swift IM use to send message corrections. + * Temporary until they start using the standard one. + */ + public static final String SWIFT_NAMESPACE = + "http://swift.im/protocol/replace"; + + /** + * The XML element name of this extension. + */ + public static final String ELEMENT_NAME = "replace"; + + /** + * Name of the attribute that specifies the ID of the message + * being corrected. + */ + public static final String ID_ATTRIBUTE_NAME = "id"; + + /** + * The ID of the message being corrected. + */ + private String correctedMessageUID; + + /** + * Creates a new message correction extension that corrects the + * message specified by the passed ID. + * + * @param correctedMessageUID The ID of the message being corrected. + */ + public MessageCorrectionExtension(String correctedMessageUID) + { + this.correctedMessageUID = correctedMessageUID; + } + + /** + * Returns the XML element name of this extension. + * + * @return The XML element name of this extension. + */ + public String getElementName() + { + return ELEMENT_NAME; + } + + /** + * Returns the XML namespace this extension belongs to. + * + * @return The XML namespace this extension belongs to. + */ + public String getNamespace() + { + return NAMESPACE; + } + + /** + * Construct an XML element representing this extension; + * has the form '<replace id="..." xmlns="...">'. + * + * @return An XML representation of this extension. + */ + public String toXML() + { + return "<" + ELEMENT_NAME + " id='" + correctedMessageUID + + "' xmlns='" + NAMESPACE + "' />"; + } + + /** + * Returns the correctedMessageUID The UID of the message being corrected. + * + * @return the correctedMessageUID The UID of the message being corrected. + */ + public String getCorrectedMessageUID() + { + return correctedMessageUID; + } + + /** + * Sets the UID of the message being corrected. + * + * @param correctedMessageUID The UID of the message being corrected. + */ + public void setCorrectedMessageUID(String correctedMessageUID) + { + this.correctedMessageUID = correctedMessageUID; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtensionProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtensionProvider.java new file mode 100644 index 0000000..81ac147 --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtensionProvider.java @@ -0,0 +1,46 @@ +/* + * Jitsi, 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.extensions.messagecorrection; + +import org.jivesoftware.smack.packet.*; +import org.jivesoftware.smack.provider.*; +import org.xmlpull.v1.*; + +/** + * Creates Smack packet extensions by parsing <replace /> tags + * from incoming XMPP packets. + * + * @author Ivan Vergiliev + */ +public class MessageCorrectionExtensionProvider + implements PacketExtensionProvider +{ + + /** + * Creates a new correction extension by parsing an XML element. + * + * @param parser An XML parser. + * @return A new MesssageCorrectionExtension parsed from the XML. + * @throws Exception if an error occurs parsing the XML. + */ + public PacketExtension parseExtension(XmlPullParser parser) throws Exception + { + MessageCorrectionExtension res = new MessageCorrectionExtension(null); + + do + { + if (parser.getEventType() == XmlPullParser.START_TAG) + { + res.setCorrectedMessageUID(parser.getAttributeValue( + null, MessageCorrectionExtension.ID_ATTRIBUTE_NAME)); + } + } + while (parser.next() != XmlPullParser.END_TAG); + + return res; + } +} diff --git a/src/net/java/sip/communicator/service/protocol/AbstractMessage.java b/src/net/java/sip/communicator/service/protocol/AbstractMessage.java index a623dd0..620bf78 100644 --- a/src/net/java/sip/communicator/service/protocol/AbstractMessage.java +++ b/src/net/java/sip/communicator/service/protocol/AbstractMessage.java @@ -68,7 +68,7 @@ public abstract class AbstractMessage setEncoding(encoding); setContent(content); - this.messageUID = messageUID; + this.messageUID = messageUID == null ? createMessageUID() : messageUID; } protected String createMessageUID() diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetMessageCorrection.java b/src/net/java/sip/communicator/service/protocol/OperationSetMessageCorrection.java new file mode 100644 index 0000000..01c095f --- /dev/null +++ b/src/net/java/sip/communicator/service/protocol/OperationSetMessageCorrection.java @@ -0,0 +1,27 @@ +/* + * Jitsi, 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; + +/** + * Provides functionality for correcting instant messages. + * + * @author Ivan Vergiliev + */ +public interface OperationSetMessageCorrection + extends OperationSetBasicInstantMessaging +{ + /** + * Replaces the message with ID <tt>correctedMessageUID</tt> sent to + * the contact <tt>to</tt> with the message <tt>message</tt> + * + * @param to The contact to send the message to. + * @param message The new message. + * @param correctedMessageUID The ID of the message being replaced. + */ + public void correctMessage(Contact to, Message message, + String correctedMessageUID); +} diff --git a/src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java b/src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java index 0ffc91b..17a6e0a 100644 --- a/src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java +++ b/src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java @@ -33,6 +33,12 @@ public class MessageDeliveredEvent * A timestamp indicating the exact date when the event occurred. */ private final long timestamp; + + /** + * The ID of the message being corrected, or null if this was a new message + * and not a message correction. + */ + private String correctedMessageUID; /** * Constructor. @@ -44,6 +50,21 @@ public class MessageDeliveredEvent { this(source, to, System.currentTimeMillis()); } + + /** + * Creates a <tt>MessageDeliveredEvent</tt> representing delivery of the + * <tt>source</tt> message to the specified <tt>to</tt> contact. + * + * @param source the <tt>Message</tt> whose delivery this event represents. + * @param to the <tt>Contact</tt> that this message was sent to. + * @param correctedMessageUID The ID of the message being corrected. + */ + public MessageDeliveredEvent(Message source, Contact to, + String correctedMessageUID) + { + this(source, to, System.currentTimeMillis()); + this.correctedMessageUID = correctedMessageUID; + } /** * Creates a <tt>MessageDeliveredEvent</tt> representing delivery of the @@ -93,4 +114,26 @@ public class MessageDeliveredEvent return timestamp; } + /** + * Returns the ID of the message being corrected, or null if this was a + * new message and not a message correction. + * + * @return the ID of the message being corrected, or null if this was a + * new message and not a message correction. + */ + public String getCorrectedMessageUID() + { + return correctedMessageUID; + } + + /** + * Sets the ID of the message being corrected to the passed ID. + * + * @param correctedMessageUID The ID of the message being corrected. + */ + public void setCorrectedMessageUID(String correctedMessageUID) + { + this.correctedMessageUID = correctedMessageUID; + } + } diff --git a/src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java b/src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java index cba4101..e0f60a3 100644 --- a/src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java +++ b/src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java @@ -75,6 +75,12 @@ public class MessageDeliveryFailedEvent private final long timestamp; /** + * The ID of the message being corrected, or null if this was a new message + * and not a message correction. + */ + private String correctedMessageUID; + + /** * Constructor. * * @param source the message @@ -87,6 +93,23 @@ public class MessageDeliveryFailedEvent { this(source, to, errorCode, System.currentTimeMillis(), null); } + + /** + * Constructor. + * + * @param source the message + * @param to the "to" contact + * @param correctedMessageUID The ID of the message being corrected. + * @param errorCode error code + */ + public MessageDeliveryFailedEvent(Message source, + Contact to, + String correctedMessageUID, + int errorCode) + { + this(source, to, errorCode, System.currentTimeMillis(), null); + this.correctedMessageUID = correctedMessageUID; + } /** * Creates a <tt>MessageDeliveryFailedEvent</tt> indicating failure of @@ -190,4 +213,14 @@ public class MessageDeliveryFailedEvent { return reasonPhrase; } + + /** + * Sets the ID of the message being corrected to the passed ID. + * + * @param correctedMessageUID The ID of the message being corrected. + */ + public String getCorrectedMessageUID() + { + return correctedMessageUID; + } } diff --git a/src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java b/src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java index 959101b..cd15cf6 100644 --- a/src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java +++ b/src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java @@ -55,6 +55,12 @@ public class MessageReceivedEvent * The type of message event that this instance represents. */ private int eventType = -1; + + /** + * The ID of the message being corrected, or null if this is a new message + * and not a correction. + */ + private String correctedMessageUID = null; /** * Creates a <tt>MessageReceivedEvent</tt> representing reception of the @@ -77,6 +83,23 @@ public class MessageReceivedEvent * * @param source the <tt>Message</tt> whose reception this event represents. * @param from the <tt>Contact</tt> that has sent this message. + * @param timestamp the exact date when the event ocurred. + */ + public MessageReceivedEvent(Message source, Contact from, + String correctedMessageUID) + { + this(source, from, System.currentTimeMillis(), + CONVERSATION_MESSAGE_RECEIVED); + this.correctedMessageUID = correctedMessageUID; + } + + /** + * Creates a <tt>MessageReceivedEvent</tt> representing reception of the + * <tt>source</tt> message received from the specified <tt>from</tt> + * contact. + * + * @param source the <tt>Message</tt> whose reception this event represents. + * @param from the <tt>Contact</tt> that has sent this message. * @param timestamp the exact date when the event occurred. * @param eventType the type of message event that this instance represents * (one of the XXX_MESSAGE_RECEIVED static fields). @@ -92,10 +115,10 @@ public class MessageReceivedEvent } /** - * Returns a reference to the <tt>Contact</tt> that has send the + * Returns a reference to the <tt>Contact</tt> that has sent the * <tt>Message</tt> whose reception this event represents. * - * @return a reference to the <tt>Contact</tt> that has send the + * @return a reference to the <tt>Contact</tt> that has sent the * <tt>Message</tt> whose reception this event represents. */ public Contact getSourceContact() @@ -135,4 +158,16 @@ public class MessageReceivedEvent { return eventType; } + + /** + * Returns the correctedMessageUID The ID of the message being corrected, + * or null if this is a new message and not a correction. + * + * @return the correctedMessageUID The ID of the message being corrected, + * or null if this is a new message and not a correction. + */ + public String getCorrectedMessageUID() + { + return correctedMessageUID; + } } |