diff --git a/src/java/org/jivesoftware/spark/ui/ChatContainer.java b/src/java/org/jivesoftware/spark/ui/ChatContainer.java index 35f7a0d5..1b41a4c1 100644 --- a/src/java/org/jivesoftware/spark/ui/ChatContainer.java +++ b/src/java/org/jivesoftware/spark/ui/ChatContainer.java @@ -14,6 +14,7 @@ import org.jivesoftware.MainWindow; import org.jivesoftware.Spark; import org.jivesoftware.resource.Res; import org.jivesoftware.resource.SparkRes; +import org.jivesoftware.resource.Default; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.FromContainsFilter; @@ -45,9 +46,9 @@ import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; -import javax.swing.JTabbedPane; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; +import javax.swing.JTabbedPane; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; @@ -57,6 +58,10 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.Toolkit; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; @@ -97,9 +102,7 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C * Creates the ChatRooms to hold all ChatRooms. */ public ChatContainer() { - // Have the chat start at the bottom. super(JTabbedPane.BOTTOM); - // Set minimum size setMinimumSize(new Dimension(400, 200)); // Don't allow tabs to shrink and allow scrolling. @@ -132,9 +135,12 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C this.setFocusable(false); setOpaque(true); + setBackground(Color.white); } + + /** * Adds navigation capability to chat rooms. Users can navigate using the alt-left or right arrow keys. */ @@ -176,10 +182,8 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C } }); - this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ctrl W"), "escape"); this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "escape"); - this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control W"), "escape"); - + this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("Ctrl W"), "escape"); this.getActionMap().put("escape", new AbstractAction("escape") { public void actionPerformed(ActionEvent evt) { @@ -192,7 +196,7 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C String appleString = org.jivesoftware.spark.util.StringUtils.keyStroke2String(appleStroke); // Handle Apple Key W - this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(appleString + " W"), "appleStroke"); + this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(appleString + "w"), "appleStroke"); this.getActionMap().put("appleStroke", new AbstractAction("appleStroke") { public void actionPerformed(ActionEvent evt) { closeActiveRoom(); @@ -216,7 +220,7 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C * * @param room the ChatRoom to add. */ - public void addChatRoom(final ChatRoom room) { + public synchronized void addChatRoom(final ChatRoom room) { createFrameIfNeeded(); room.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.LIGHT_GRAY)); @@ -247,7 +251,7 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C tooltip = "Contact: " + nickname + "
JID: " + tooltip; } else { - tooltip = ((GroupChatRoom)room).getRoomname(); + tooltip = room.getRoomname(); } // Create ChatRoom UI and dock @@ -270,7 +274,7 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C chatFrame.setTitle(room.getRoomTitle()); } - SwingWorker worker = new SwingWorker() { + final SwingWorker visibilityThread = new SwingWorker() { public Object construct() { try { Thread.sleep(100); @@ -286,13 +290,15 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C } }; - worker.start(); + visibilityThread.start(); // Add to ChatRoomList chatRoomList.add(room); + // Notify users that the chat room has been opened. fireChatRoomOpened(room); + // Focus Chat focusChat(); } @@ -377,7 +383,25 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C flashWindow(chatRoom); } else if (!chatFrame.isVisible()) { - handleHiddenChatFrame(chatRoom); + if (Spark.isWindows()) { + chatFrame.setFocusableWindowState(false); + chatFrame.setState(Frame.ICONIFIED); + } + chatFrame.setVisible(true); + + // Set to new tab. + int tabLocation = indexOfComponent(chatRoom); + setSelectedIndex(tabLocation); + + // If the ContactList is in the tray, we need better notification by flashing + // the chatframe. + if (!SparkManager.getMainWindow().isVisible()) { + flashWindow(chatRoom); + } + else if (chatFrame.getState() == Frame.ICONIFIED) { + flashWindow(chatRoom); + } + } } @@ -398,17 +422,12 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C } fireChatRoomClosed(room); - room.removeMessageListener(this); // Remove mappings presenceMap.remove(room.getRoomname()); chatRoomList.remove(room); - - // Cleanup - room.getTranscriptWindow().clear(); - room.getTranscripts().clear(); } /** @@ -583,9 +602,6 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C } private void handleMessageNotification(final ChatRoom chatRoom) { - if (true) { - return; - } ChatRoom activeChatRoom = null; try { activeChatRoom = getActiveChatRoom(); @@ -623,32 +639,31 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C startFlashing(chatRoom); } else if (!chatFrame.isVisible()) { - handleHiddenChatFrame(chatRoom); + if (Spark.isWindows()) { + chatFrame.setFocusableWindowState(false); + chatFrame.setState(Frame.ICONIFIED); + } + chatFrame.setVisible(true); + + // Set to new tab. + int tabLocation = indexOfComponent(chatRoom); + setSelectedIndex(tabLocation); + + // If the ContactList is in the tray, we need better notification by flashing + // the chatframe. + if (!SparkManager.getMainWindow().isVisible()) { + startFlashing(chatRoom); + } + else if (chatFrame.getState() == Frame.ICONIFIED) { + startFlashing(chatRoom); + } + } else if (chatRoom != activeChatRoom) { startFlashing(chatRoom); } } - private void handleHiddenChatFrame(ChatRoom chatRoom) { - int tabLocation = indexOfComponent(chatRoom); - setSelectedIndex(tabLocation); - if (Spark.isWindows()) { - chatFrame.setState(Frame.ICONIFIED); - } - - chatFrame.setVisible(true); - - // If the ContactList is in the tray, we need better notification by flashing - // the chatframe. - if (!SparkManager.getMainWindow().isVisible()) { - flashWindow(chatRoom); - } - else if (chatFrame.getState() == Frame.ICONIFIED) { - flashWindow(chatRoom); - } - } - public void messageSent(ChatRoom room, Message message) { useTabDefault(room); } @@ -670,6 +685,7 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C // Set the title of the room. chatFrame.setTitle(room.getRoomTitle()); + chatFrame.setIconImage(SparkManager.getMainWindow().getIconImage()); } catch (ChatRoomNotFoundException e1) { // Ignore @@ -961,14 +977,8 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C if (room instanceof ChatRoomImpl) { final ChatRoomImpl chatRoomImpl = (ChatRoomImpl)room; if (!chatRoomImpl.isIconHandler()) { - Icon icon = chatRoomImpl.getAlternativeIcon(); - - // if an alternative icon is not used, get the icon based on the users - // presence. - if (icon == null) { - Presence presence = chatRoomImpl.getPresence(); - icon = SparkManager.getUserManager().getTabIconForPresence(presence); - } + Presence presence = chatRoomImpl.getPresence(); + Icon icon = SparkManager.getUserManager().getTabIconForPresence(presence); tab.setIcon(icon); } } @@ -1076,7 +1086,6 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C // Set the title of the room. chatFrame.setTitle(room.getRoomTitle()); - chatFrame.setIconImage(SparkManager.getMainWindow().getIconImage()); } catch (ChatRoomNotFoundException e1) { } @@ -1086,9 +1095,6 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C public void windowDeactivated(WindowEvent windowEvent) { } - public void windowClosing(WindowEvent e) { - } - }); // Start timer @@ -1100,7 +1106,7 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C SwingWorker worker = new SwingWorker() { public Object construct() { try { - Thread.sleep(50); + Thread.sleep(1000); } catch (InterruptedException e1) { Log.error(e1); diff --git a/src/java/org/jivesoftware/spark/ui/ChatRoom.java b/src/java/org/jivesoftware/spark/ui/ChatRoom.java index a2dd74c2..8a006dc5 100644 --- a/src/java/org/jivesoftware/spark/ui/ChatRoom.java +++ b/src/java/org/jivesoftware/spark/ui/ChatRoom.java @@ -94,7 +94,7 @@ public abstract class ChatRoom extends BackgroundPanel implements ActionListener private final List packetIDList; private final List messageListeners; - private List transcript; + private List transcript; private List fileDropListeners; /** @@ -110,7 +110,7 @@ public abstract class ChatRoom extends BackgroundPanel implements ActionListener bottomPanel = new JPanel(); messageListeners = new ArrayList(); - transcript = new ArrayList(); + transcript = new ArrayList(); editorBar = new JPanel(new FlowLayout(FlowLayout.LEFT, 1, 1)); fileDropListeners = new ArrayList(); @@ -529,7 +529,7 @@ public abstract class ChatRoom extends BackgroundPanel implements ActionListener * * @return - the map of current chat responses. */ - public List getTranscripts() { + public List getTranscripts() { return transcript; } diff --git a/src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscriptPlugin.java b/src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscriptPlugin.java index 12bf6847..ede590ce 100644 --- a/src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscriptPlugin.java +++ b/src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscriptPlugin.java @@ -189,13 +189,9 @@ public class ChatTranscriptPlugin implements ChatRoomListener { final String jid = room.getRoomname(); - List transcripts = room.getTranscripts(); - - Iterator messages = transcripts.iterator(); - - ChatTranscript transcript = ChatTranscripts.getChatTranscript(jid); - while (messages.hasNext()) { - Message message = (Message)messages.next(); + final List transcripts = room.getTranscripts(); + ChatTranscript transcript = new ChatTranscript(); + for(Message message : transcripts){ HistoryMessage history = new HistoryMessage(); history.setTo(message.getTo()); history.setFrom(message.getFrom()); @@ -210,7 +206,7 @@ public class ChatTranscriptPlugin implements ChatRoomListener { transcript.addHistoryMessage(history); } - ChatTranscripts.saveTranscript(jid); + ChatTranscripts.appendToTranscript(jid, transcript); } public void chatRoomActivated(ChatRoom room) { diff --git a/src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscripts.java b/src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscripts.java index fedcb70e..0cc6e021 100644 --- a/src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscripts.java +++ b/src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscripts.java @@ -10,34 +10,35 @@ package org.jivesoftware.sparkimpl.plugin.transcripts; -import org.dom4j.Document; -import org.dom4j.DocumentException; -import org.dom4j.DocumentHelper; -import org.dom4j.Element; -import org.dom4j.io.SAXReader; -import org.dom4j.io.XMLWriter; import org.jivesoftware.spark.SparkManager; +import org.jivesoftware.spark.util.URLFileSystem; import org.jivesoftware.spark.util.log.Log; +import org.xmlpull.mxp1.MXParser; +import org.xmlpull.v1.XmlPullParser; import java.io.File; -import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStreamReader; import java.io.OutputStreamWriter; +import java.io.RandomAccessFile; +import java.io.StringReader; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Collection; import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -public class ChatTranscripts { - private static Map TRANSCRIPTS = new HashMap(); - private static Map CURRENT_TRANSCRIPTS = new HashMap(); +/** + * A Utility class that manages the Chat Transcripts within Spark. + * + * @author Derek DeMoro + */ +final public class ChatTranscripts { + + /** + * Default Date Formatter * + */ private static DateFormat FORMATTER; static { @@ -48,159 +49,131 @@ public class ChatTranscripts { } - public static ChatTranscript getChatTranscript(String jid) { - ChatTranscript transcript = TRANSCRIPTS.get(jid); - if (transcript == null) { - final File transcriptFile = getTranscriptFile(jid); - transcript = load(transcriptFile); - TRANSCRIPTS.put(jid, transcript); + /** + * Appends the given ChatTranscript to the transcript file associated with a JID. + * + * @param jid the jid of the user. + * @param transcript the ChatTranscript. + */ + public static void appendToTranscript(String jid, ChatTranscript transcript) { + final File transcriptFile = getTranscriptFile(jid); + + // Write Full Transcript + writeToFile(transcriptFile, transcript.getMessages()); + + // Write to current history File + final File currentHistoryFile = getCurrentHistoryFile(jid); + writeToFile(currentHistoryFile, transcript.getNumberOfEntries(20)); + } + + private static void writeToFile(File transcriptFile, Collection messages) { + final StringBuilder builder = new StringBuilder(); + + // Handle new transcript file. + if (!transcriptFile.exists()) { + builder.append(""); } - return transcript; - } - public static ChatTranscript getCurrentChatTranscript(String jid) { - ChatTranscript transcript = CURRENT_TRANSCRIPTS.get(jid); - if (transcript == null) { - final File transcriptFile = getCurrentHistoryFile(jid); - transcript = load(transcriptFile); - CURRENT_TRANSCRIPTS.put(jid, transcript); + for (HistoryMessage m : messages) { + builder.append(""); + builder.append("").append(m.getTo()).append(""); + builder.append("").append(m.getFrom()).append(""); + builder.append("").append(m.getBody()).append(""); + + String dateString = FORMATTER.format(m.getDate()); + builder.append("").append(dateString).append(""); + builder.append(""); } - return transcript; - } - public static void addChatTranscript(String jid, ChatTranscript transcript) { - TRANSCRIPTS.put(jid, transcript); - } - - public static void saveTranscript(String jid) { - try { - File transcriptFile = getTranscriptFile(jid); - transcriptFile.getParentFile().mkdirs(); - ChatTranscript transcript = getChatTranscript(jid); - if (transcript.getMessages().size() == 0) { - return; - } - - FileOutputStream fout = new FileOutputStream(transcriptFile); - - Element root = DocumentHelper.createElement("transcript"); - Element messages = root.addElement("messages"); - - for (HistoryMessage m : transcript.getMessages()) { - Element message = messages.addElement("message"); - - message.addElement("to").setText(m.getTo()); - message.addElement("from").setText(m.getFrom()); - message.addElement("body").setText(m.getBody()); - - String dateString = FORMATTER.format(m.getDate()); - message.addElement("date").setText(dateString); - } - - ChatTranscript t = new ChatTranscript(); - for(HistoryMessage mes : transcript.getNumberOfEntries(20)){ - t.addHistoryMessage(mes); - } - CURRENT_TRANSCRIPTS.put(jid, t); + if (!transcriptFile.exists()) { + builder.append(""); + } + if (!transcriptFile.exists()) { + // Write out new File try { - // Write out main transcript + FileOutputStream fout = new FileOutputStream(transcriptFile); OutputStreamWriter ow = new OutputStreamWriter(fout, "UTF-8"); - XMLWriter saxWriter = new XMLWriter(ow); - saxWriter.write(root); - saxWriter.flush(); - saxWriter.close(); - - // Write out current transcript - List list = messages.elements(); - int size = list.size(); - if (list.size() > 20) { - for (int i = 0; i < size - 20; i++) { - final Element ele = (Element)list.get(i); - messages.remove(ele); - } - } - - // Write out current transcript - fout = new FileOutputStream(getCurrentHistoryFile(jid)); - - ow = new OutputStreamWriter(fout, "UTF-8"); - saxWriter = new XMLWriter(ow); - saxWriter.write(root); - saxWriter.flush(); - saxWriter.close(); + ow.write(builder.toString()); + ow.close(); } catch (IOException e) { Log.error(e); } - - } - catch (Exception e) { - Log.error("Error saving settings.", e); + return; } + // Append to File + try { + RandomAccessFile raf = new RandomAccessFile(transcriptFile, "rw"); + // Seek to end of file + raf.seek(transcriptFile.length() - 24); + + builder.append(""); + + // Append to the end + raf.writeBytes(builder.toString()); + raf.close(); + } + catch (IOException e) { + Log.error(e); + } } - private static ChatTranscript load(File transcriptFile) { - final ChatTranscript transcript = new ChatTranscript(); + /** + * Retrieve the current chat history. + * + * @param jid the jid of the user whos history you wish to retrieve. + * @return the ChatTranscript (last 20 messages max). + */ + public static ChatTranscript getCurrentChatTranscript(String jid) { + return getTranscript(getCurrentHistoryFile(jid)); + } + /** + * Retrieve the full chat history. + * + * @param jid the jid of the the user whos history you wish to retrieve. + * @return the ChatTranscript. + */ + public static ChatTranscript getChatTranscript(String jid) { + return getTranscript(getTranscriptFile(jid)); + } + + /** + * Reads in the transcript file using the Xml Pull Parser. + * + * @param transcriptFile the transcript file to read. + * @return the ChatTranscript. + */ + public static ChatTranscript getTranscript(File transcriptFile) { + final ChatTranscript transcript = new ChatTranscript(); if (!transcriptFile.exists()) { return transcript; } - + final String contents = URLFileSystem.getContents(transcriptFile); try { - FileInputStream fis = new FileInputStream(transcriptFile); - InputStreamReader isr = new InputStreamReader(fis, "UTF-8"); - SAXReader saxReader = new SAXReader(); - Document pluginXML = null; - try { - pluginXML = saxReader.read(isr); - } - catch (DocumentException e) { - Log.error(e); - return transcript; - } - - - List messages = pluginXML.selectNodes("/transcript/messages/message"); - Iterator iter = messages.iterator(); - - while (iter.hasNext()) { - HistoryMessage message = new HistoryMessage(); - - - try { - Element messageElement = (Element)iter.next(); - - String to = messageElement.selectSingleNode("to").getText(); - String from = messageElement.selectSingleNode("from").getText(); - String body = messageElement.selectSingleNode("body").getText(); - String date = messageElement.selectSingleNode("date").getText(); - - message.setTo(to); - message.setFrom(from); - message.setBody(body); - Date d = null; - try { - d = FORMATTER.parse(date); - } - catch (ParseException e) { - d = new Date(); - } - message.setDate(d); - transcript.addHistoryMessage(message); + MXParser parser = new MXParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + parser.setInput(new StringReader(contents)); + boolean done = false; + while (!done) { + int eventType = parser.next(); + if (eventType == XmlPullParser.START_TAG && "message".equals(parser.getName())) { + transcript.addHistoryMessage(getHistoryMessage(parser)); } - catch (Exception ex) { - + else if (eventType == XmlPullParser.END_TAG && "transcript".equals(parser.getName())) { + done = true; } } } catch (Exception e) { - // Ignore + e.printStackTrace(); } + return transcript; } @@ -224,5 +197,40 @@ public class ChatTranscripts { return new File(SparkManager.getUserDirectory(), "transcripts/" + jid + "_current.xml"); } + private static HistoryMessage getHistoryMessage(XmlPullParser parser) throws Exception { + HistoryMessage message = new HistoryMessage(); + + // Check for nickname + boolean done = false; + while (!done) { + int eventType = parser.next(); + if (eventType == XmlPullParser.START_TAG && "to".equals(parser.getName())) { + message.setTo(parser.nextText()); + } + else if (eventType == XmlPullParser.START_TAG && "from".equals(parser.getName())) { + message.setFrom(parser.nextText()); + } + else if (eventType == XmlPullParser.START_TAG && "body".equals(parser.getName())) { + message.setBody(parser.nextText()); + } + else if (eventType == XmlPullParser.START_TAG && "date".equals(parser.getName())) { + Date d = null; + try { + d = FORMATTER.parse(parser.nextText()); + } + catch (ParseException e) { + d = new Date(); + } + message.setDate(d); + } + else if (eventType == XmlPullParser.END_TAG && "message".equals(parser.getName())) { + done = true; + } + } + + + return message; + } + } \ No newline at end of file