Index: src/java/org/jivesoftware/LoginDialog.java
===================================================================
--- src/java/org/jivesoftware/LoginDialog.java	(revision 10832)
+++ src/java/org/jivesoftware/LoginDialog.java	(working copy)
@@ -24,6 +24,7 @@
 import org.jivesoftware.smack.SASLAuthentication;
 import org.jivesoftware.smack.packet.XMPPError;
 import org.jivesoftware.smack.util.StringUtils;
+import org.jivesoftware.smackx.workgroup.packet.Transcript;
 import org.jivesoftware.spark.SessionManager;
 import org.jivesoftware.spark.SparkManager;
 import org.jivesoftware.spark.Workspace;
@@ -50,6 +51,7 @@
 import javax.security.auth.callback.PasswordCallback;
 import javax.swing.ImageIcon;
 import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
@@ -230,6 +232,9 @@
         private JLabel accountNameLabel = new JLabel();
         private JLabel serverNameLabel = new JLabel();
         private JLabel ssoServerLabel = new JLabel();
+//        private JLabel profilesLabel = new JLabel("Profiles");
+        
+//        private JComboBox profilesBox = new JComboBox();
 
 
         LoginPanel() {
@@ -308,6 +313,16 @@
                     new GridBagConstraints(1, 6, 2, 1, 1.0, 0.0,
                             GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
 
+//            add(profilesLabel,
+//               new GridBagConstraints(0, 7, 2, 1, 1.0, 0.0,
+//                       GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
+            
+//            add(profilesBox,
+//               new GridBagConstraints(1, 7, 2, 1, 1.0, 0.0,
+//                       GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 0, 5), 0, 0));
+
+//            profilesBox.addItem(SettingsManager.getSettingsFile().getName());
+            
             // Add button but disable the login button initially
             savePasswordBox.addActionListener(this);
             autoLoginBox.addActionListener(this);
Index: src/java/org/jivesoftware/spark/ChatManager.java
===================================================================
--- src/java/org/jivesoftware/spark/ChatManager.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ChatManager.java	(working copy)
@@ -209,16 +209,32 @@
      * @return the newly created <code>ChatRoom</code>.
      */
     public ChatRoom createChatRoom(String userJID, String nickname, String title) {
-        ChatRoom chatRoom;
-        try {
-            chatRoom = getChatContainer().getChatRoom(userJID);
-        }
-        catch (ChatRoomNotFoundException e) {
-            chatRoom = new ChatRoomImpl(userJID, nickname, title);
-            getChatContainer().addChatRoom(chatRoom);
-        }
-
-        return chatRoom;
+   	 ChatRoom chatRoom;
+       try 
+       {
+      	  /*if(userJID.contains("/"))
+      	  {
+      		  String[] JID = userJID.split("/");
+      		  userJID = JID[0];
+      	  }*/
+           chatRoom = getChatContainer().getChatRoom(userJID);
+       }
+       catch(Exception e) {
+	        chatRoom = SparkManager.getExternalizedChatRoom(nickname);
+	        if(chatRoom == null)
+	        {
+			     chatRoom = new ChatRoomImpl(userJID, nickname, title);
+			     LocalPreferences pref = SettingsManager.getLocalPreferences();
+			     if(!pref.isTabsExternalizedOn())
+			   	  getChatContainer().addChatRoom(chatRoom);
+			     else
+			     {
+			   	  //new ChatRoomImpl(userJID, title, title)
+			   	  SparkManager.getChatManager().getChatContainer().externalizeTab((ChatRoomImpl)chatRoom, SparkManager.getChatManager().getChatContainer().getX(), SparkManager.getChatManager().getChatContainer().getY(), false);
+			     }
+	        }  
+       }
+       return chatRoom;
     }
 
     /**
@@ -304,7 +320,6 @@
                 }
 
                 ChatContainer chatRooms = chatManager.getChatContainer();
-
                 try {
                     chatRoom = chatRooms.getChatRoom(jid);
                 }
@@ -604,12 +619,15 @@
                         // Notify Decorators
                         notifySparkTabHandlers(chatRoom);
                     }
+                    if(SparkManager.getExternalizedFrame(chatRoom.getRoomTitle()) != null)
+                    {
+                  	  SparkManager.getExternalizedFrame(chatRoom.getRoomTitle()).setIconImage(SparkRes.getImageIcon(SparkRes.SMALL_MESSAGE_EDIT_IMAGE).getImage());
+                    }
                 }
                 catch (ChatRoomNotFoundException e) {
                     // Do nothing
                 }
 
-
                 contactList.setIconFor(from, SparkRes.getImageIcon(SparkRes.SMALL_MESSAGE_EDIT_IMAGE));
             }
         });
@@ -870,7 +888,7 @@
         if (nickname == null) {
             nickname = jid;
         }
-
+ 
         ChatManager chatManager = SparkManager.getChatManager();
         ChatRoom chatRoom = chatManager.createChatRoom(jid, nickname, nickname);
         if (body != null) {
Index: src/java/org/jivesoftware/spark/SparkManager.java
===================================================================
--- src/java/org/jivesoftware/spark/SparkManager.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/SparkManager.java	(working copy)
@@ -17,9 +17,11 @@
 import org.jivesoftware.smack.XMPPConnection;
 import org.jivesoftware.smackx.MessageEventManager;
 import org.jivesoftware.smackx.ServiceDiscoveryManager;
+import org.jivesoftware.spark.component.tabbedPane.SparkTabbedPane;
 import org.jivesoftware.spark.filetransfer.SparkTransferManager;
 import org.jivesoftware.spark.preference.PreferenceManager;
 import org.jivesoftware.spark.search.SearchManager;
+import org.jivesoftware.spark.ui.ChatFrame;
 import org.jivesoftware.spark.ui.ChatPrinter;
 import org.jivesoftware.spark.ui.ChatRoom;
 import org.jivesoftware.spark.ui.ContactList;
@@ -28,6 +30,7 @@
 import org.jivesoftware.sparkimpl.profile.VCardManager;
 
 import java.awt.Component;
+import java.awt.Frame;
 import java.awt.KeyboardFocusManager;
 import java.awt.Toolkit;
 import java.awt.datatransfer.DataFlavor;
@@ -37,8 +40,10 @@
 import java.beans.PropertyChangeListener;
 import java.io.File;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 
 import javax.swing.ImageIcon;
+import javax.swing.JFrame;
 
 /**
  * Used as the System Manager for the Spark IM client. The SparkManager is responsible for
@@ -408,5 +413,57 @@
         }
         return mainImage;
     }
+    
+    
+    /**
+     * Returns ChatRoomImpl of an externalized Tab
+     * @param participantNickname
+     * @return ChatRoomImpl of an externalized Tab
+     */
+    
+    public static ChatRoom getExternalizedChatRoom(String participantNickname)
+    {
+   	 Frame[] frames = JFrame.getFrames();
+   	 		for(Frame frame : frames)
+      	  	{
+       	  		if(frame.getTitle().equals(participantNickname)){
+       	  			if(((JFrame) frame).getContentPane().getComponent(0) instanceof ChatRoom)
+						{
+       	  				return (ChatRoom)(((JFrame) frame).getContentPane().getComponent(0));
+						}
+       	  		}
+       	  	}
+       	  	return null;
+        }
+    
+    /**
+     * Returns frame of an externalized Tab
+     * @param participantNickname
+     * @return frame of an externalized Tab
+     */
+    public static JFrame getExternalizedFrame(String participantNickname)
+    {
+   		Frame[] frames = JFrame.getFrames();
+   	  	for(Frame frame : frames)
+   	  	{
+   	  		if(frame.getTitle().equals(participantNickname) && !(frame instanceof ChatFrame)){
+   	  			return (JFrame)frame;
+   	  		}
+   	  	}
+   	  	return null;
+    }
+    
+    public static ArrayList<ChatRoom> getExternalizedChatRooms()
+    {
+   	  ArrayList<JFrame> frames = SparkTabbedPane.getExternalizedFrames();
+   	  ArrayList<ChatRoom> rooms = new ArrayList<ChatRoom>();
+   	  
+   	  for(Frame frame : frames)
+  	  	  {
+   		  rooms.add((ChatRoom)(((JFrame) frame).getContentPane().getComponent(0)));
+  	  	  }
+   	  
+   	  return rooms;
+    }
 
 }
Index: src/java/org/jivesoftware/spark/component/tabbedPane/SparkTabbedPane.java
===================================================================
--- src/java/org/jivesoftware/spark/component/tabbedPane/SparkTabbedPane.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/component/tabbedPane/SparkTabbedPane.java	(working copy)
@@ -19,13 +19,21 @@
 import java.util.List;
 
 import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JTabbedPane;
 
 import org.jivesoftware.Spark;
+import org.jivesoftware.resource.Res;
 import org.jivesoftware.resource.SparkRes;
+import org.jivesoftware.spark.SparkManager;
+import org.jivesoftware.spark.ui.ChatRoom;
+import org.jivesoftware.spark.ui.ChatRoomButton;
+import org.jivesoftware.spark.ui.ChatRoomListener;
 import org.jivesoftware.spark.ui.conferences.ConferenceUtils;
+import org.jivesoftware.spark.ui.rooms.ChatRoomImpl;
 import org.jivesoftware.spark.util.ModelUtil;
 import org.jivesoftware.spark.util.SwingWorker;
 import org.jivesoftware.spark.util.log.Log;
@@ -38,23 +46,30 @@
  * @author Derek DeMoro
  */
 public class SparkTabbedPane extends JPanel implements MouseListener {
-    private JPanel tabs;
+	
+	 private JPanel tabs;
     private JPanel mainPanel;
-
+    
     private boolean closeButtonEnabled;
     private Icon closeInactiveButtonIcon;
     private Icon closeActiveButtonIcon;
-
+    
+    ChatRoomButton internalizeButton;
+   
+    
     private boolean popupAllowed;
 
     private boolean activeButtonBold;
-
-
+    
     private int tabPlacement = JTabbedPane.TOP;
 
     private Color backgroundColor;
     private Color borderColor;
-
+    
+    private static ArrayList<JFrame> externalizedFrames = new ArrayList<JFrame>();
+    public static boolean externalizeTheTab = false;
+    private static Dimension coordinates = new Dimension(100, 100);
+    
     /**
      * The default Hand cursor.
      */
@@ -76,7 +91,6 @@
 
     public SparkTabbedPane(int placement) {
         this.tabPlacement = placement;
-
         createUI();
     }
 
@@ -418,7 +432,11 @@
         deselectAllTabsExcept(tab);
 
         tab.setSelected(true);
-        fireTabSelected(tab, getSelectedComponent(), getIndex(tab));
+        
+        if(!externalizeTheTab)
+        {
+      	  fireTabSelected(tab, getSelectedComponent(), getIndex(tab));
+        }
     }
 
     public void mousePressed(MouseEvent e) {
@@ -434,6 +452,14 @@
     }
 
     public void mouseReleased(MouseEvent e) {
+   	 if(e.getY() < -5 || e.getY() > 30)
+   	 {
+   		 externalizeTab((ChatRoomImpl)this.getComponentAt((getSelectedIndex())), e.getXOnScreen(), e.getYOnScreen(), true);
+   	 }
+   	 else
+   	 {
+   		
+		 }
     }
 
     public void mouseEntered(MouseEvent e) {
@@ -602,4 +628,79 @@
     public void setBorderColor(Color borderColor) {
         this.borderColor = borderColor;
     }
+    
+    public void externalizeTab(ChatRoomImpl chatroom, int x, int y, boolean externalizedATab)
+	 {
+   	 
+		 final JFrame externalFrame = new JFrame();
+		 externalFrame.setTitle(chatroom.getParticipantNickname());
+		 
+		 Dimension d;
+		 if(SparkManager.getChatManager().getChatContainer().getWidth() == 0)
+			 d = new Dimension(600, 400);
+		 else
+			 d = SparkManager.getChatManager().getChatContainer().getSize();
+		 
+		 if(externalizedATab)
+   	 {
+	   	 externalizeTheTab = true;
+	   	 this.removeTabAt(getSelectedIndex());
+			 SparkManager.getChatManager().getChatContainer().closeTab(this);
+			 externalizeTheTab = false;
+			 externalFrame.setBounds(x - (d.width/2), y, d.width, d.height);
+   	 }
+   	 else
+   	 {
+   		 externalFrame.setBounds(coordinates.width, coordinates.height, d.width, d.height);
+   		 coordinates.setSize(coordinates.width + 25, coordinates.height + 25);
+   		 if(coordinates.width == 400)
+   		 {
+   			 coordinates.setSize(100, 100);
+   		 }
+   	 }
+		 
+		 externalFrame.addWindowListener(new java.awt.event.WindowAdapter(){
+			public void windowClosing(java.awt.event.WindowEvent evt)
+			{
+				ChatRoom chatRoom = (ChatRoom)(externalFrame.getContentPane().getComponent(0));
+				SparkManager.getWorkspace().getTranscriptPlugin().chatRoomClosed((ChatRoom)(externalFrame.getContentPane().getComponent(0)));
+				externalFrame.setTitle("");
+				externalFrame.dispose();
+				getExternalizedFrames().remove(externalFrame);
+				chatRoom.closeChatRoom();
+			}
+		 });
+		 String[] jid = chatroom.getParticipantJID().split("/spark");
+		 
+		 chatroom.closeChatRoom();
+		 ChatRoomImpl externalChatroom = new ChatRoomImpl(jid[0], chatroom.getParticipantNickname(), chatroom.getTabTitle());
+		
+		 try
+		 {
+			 externalFrame.setIconImage(((ImageIcon)(SparkManager.getContactList().getContactItemByJID(chatroom.getParticipantJID())).getIcon()).getImage());
+		 }
+		 catch(Exception e)
+		 {
+			 externalFrame.setIconImage(SparkRes.getImageIcon("CLEAR_BALL_ICON").getImage());
+		 }
+		 
+		 internalizeButton = new ChatRoomButton("", SparkRes.getImageIcon("RIGHT_ARROW_IMAGE"));
+	    internalizeButton.setToolTipText(Res.getString("message.internalize.tab"));
+		 externalChatroom.setInternalizeButton(internalizeButton);
+		 externalChatroom.getToolBar().addChatRoomButton(internalizeButton);
+	    for (ChatRoomListener chatRoomListener : new ArrayList<ChatRoomListener>(SparkManager.getChatManager().getChatContainer().getChatRoomListener())) 
+	    {
+          chatRoomListener.chatRoomOpened(externalChatroom);
+	    }
+	    externalFrame.add(externalChatroom);
+	    externalFrame.setVisible(true);
+	    externalizedFrames.add(externalFrame);
+	    externalChatroom.getChatInputEditor().requestFocus();
+	    externalChatroom.getChatInputEditor().requestFocusInWindow();
+	 }
+    
+    public static ArrayList<JFrame> getExternalizedFrames()
+    {
+   	 return externalizedFrames;
+    }
 }
Index: src/java/org/jivesoftware/spark/filetransfer/ChatRoomTransferDecorator.java
===================================================================
--- src/java/org/jivesoftware/spark/filetransfer/ChatRoomTransferDecorator.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/filetransfer/ChatRoomTransferDecorator.java	(working copy)
@@ -54,7 +54,6 @@
 
         sendFileButton = new ChatRoomButton("", SparkRes.getImageIcon(SparkRes.SEND_FILE_24x24));
         sendFileButton.setToolTipText(Res.getString("message.send.file.to.user"));
-
         chatRoom.getToolBar().addChatRoomButton(sendFileButton);
 
         sendScreenShotButton = new ChatRoomButton("", SparkRes.getImageIcon(SparkRes.PHOTO_IMAGE));
Index: src/java/org/jivesoftware/spark/filetransfer/SparkTransferManager.java
===================================================================
--- src/java/org/jivesoftware/spark/filetransfer/SparkTransferManager.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/filetransfer/SparkTransferManager.java	(working copy)
@@ -335,20 +335,20 @@
     public void sendScreenshot(final ChatRoomButton button, final ChatRoom room) {
         button.setEnabled(false);
 
-        final MainWindow mainWindow = SparkManager.getMainWindow();
-        final ChatFrame chatFrame = SparkManager.getChatManager().getChatContainer().getChatFrame();
-
-        final boolean mainWindowVisible = mainWindow.isVisible();
-        final boolean chatFrameVisible = chatFrame.isVisible();
-
-        if (mainWindowVisible) {
-            mainWindow.setVisible(false);
-        }
-
-        if (chatFrameVisible) {
-            chatFrame.setVisible(false);
+        final Frame[] frames = JFrame.getFrames();
+        final Frame[] framesToSetVisible = new Frame[JFrame.getFrames().length];
+        
+        int i = 0;
+        for(Frame frame : frames)
+        {
+      	  if(frame.isVisible())
+      	  { 
+      		  framesToSetVisible[i] = frame;
+      		  i++;
+      		  frame.setVisible(false);  
+      	  }
         }
-
+        
         final SwingWorker worker = new SwingWorker() {
             public Object construct() {
                 try {
@@ -358,15 +358,11 @@
                 }
                 catch (Throwable e) {
                     Log.error(e);
-
-                    if (mainWindowVisible) {
-                        mainWindow.setVisible(true);
+                    
+                    for(Frame frame : framesToSetVisible)
+                    {
+                  	  frame.setVisible(true);
                     }
-
-                    if (chatFrameVisible) {
-                        chatFrame.setVisible(true);
-                    }
-
                 }
                 return null;
             }
@@ -403,14 +399,11 @@
                         frame.dispose();
                         frame.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
 
-                        if (mainWindowVisible) {
-                            mainWindow.setVisible(true);
-                        }
-
-                        if (chatFrameVisible) {
-                            chatFrame.setVisible(true);
+                        for(Frame frame : framesToSetVisible)
+                        {
+                      	  frame.setVisible(true);
                         }
-
+                        
                         selectionPanel.removeMouseListener(this);
                     }
                 });
@@ -420,12 +413,10 @@
                         if (e.getKeyChar() == KeyEvent.VK_ESCAPE) {
                             frame.dispose();
                             frame.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
-                            if (mainWindowVisible) {
-                                mainWindow.setVisible(true);
-                            }
-
-                            if (chatFrameVisible) {
-                                chatFrame.setVisible(true);
+                            
+                            for(Frame frame : framesToSetVisible)
+                            {
+                          	  frame.setVisible(true);
                             }
                         }
                     }
@@ -540,7 +531,6 @@
 
         // The image must first be wrapped in a style
         Style style = doc.addStyle("StyleName", null);
-
         SendMessage sendingUI = new SendMessage();
         try {
             transfer.sendFile(file, "Sending file");
@@ -592,6 +582,9 @@
             Log.error(e);
         }
 
+        JFrame frame = SparkManager.getExternalizedFrame(contactItem.getDisplayName());
+        frame.toFront();
+        frame.requestFocus();
         chatRoom.scrollToBottom();
         return chatRoom;
     }
Index: src/java/org/jivesoftware/spark/ui/ChatArea.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ChatArea.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ui/ChatArea.java	(working copy)
@@ -17,6 +17,7 @@
 import org.jivesoftware.spark.util.BrowserLauncher;
 import org.jivesoftware.spark.util.ModelUtil;
 import org.jivesoftware.spark.util.log.Log;
+import org.jivesoftware.sparkimpl.plugin.emoticons.Emoticon;
 import org.jivesoftware.sparkimpl.plugin.emoticons.EmoticonManager;
 import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
 import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
@@ -24,6 +25,7 @@
 import javax.swing.AbstractAction;
 import javax.swing.Icon;
 import javax.swing.JComponent;
+import javax.swing.JFrame;
 import javax.swing.JMenuItem;
 import javax.swing.JPopupMenu;
 import javax.swing.JTextPane;
@@ -207,8 +209,7 @@
         boolean bold = false;
         boolean italic = false;
         boolean underlined = false;
-
-
+        
         final StringTokenizer tokenizer = new StringTokenizer(text, " \n \t,", true);
         while (tokenizer.hasMoreTokens()) {
             String textFound = tokenizer.nextToken();
@@ -219,12 +220,12 @@
             }
             else if ( textFound.startsWith("\\\\") || (textFound.indexOf("://") > 0 && textFound.indexOf(".") < 1) ) {
                 insertAddress(textFound);
-            }     
+            }   
             else if (!insertImage(textFound)) {
                 insertText(textFound);
-            }
+            }    
         }
-
+        
         // By default, always have decorations off.
         StyleConstants.setBold(styles, bold);
         StyleConstants.setItalic(styles, italic);
@@ -303,21 +304,26 @@
      * @return true if the image was found, otherwise false.
      */
     public boolean insertImage(String imageKey) {
-        if(!forceEmoticons && !SettingsManager.getLocalPreferences().areEmoticonsEnabled()){
-            return false;
-        }
-        final Document doc = getDocument();
-        Icon emotion = emoticonManager.getEmoticonImage(imageKey.toLowerCase());
-        if (emotion == null) {
-            return false;
-        }
-
-        setEditable(true);
-        select(doc.getLength(), doc.getLength());
-        insertIcon(emotion);
-        setEditable(false);
-
-        return true;
+   	  if(!imageKey.equals(" ") && Emoticon.getAllEquivalants().contains(imageKey))
+   	  {
+	        if(!forceEmoticons && !SettingsManager.getLocalPreferences().areEmoticonsEnabled()){
+	            return false;
+	        }
+	        final Document doc = getDocument();
+	        Icon emotion = emoticonManager.getEmoticonImage(imageKey.toLowerCase());
+	        if (emotion == null) {
+	            return false;
+	        }
+	      
+	        //setEditable(true);
+	        select(doc.getLength(), doc.getLength());
+	        insertIcon(emotion);
+	        //setEditable(false);
+	        
+	        return true;
+   	  }
+   	  else
+   		  return false;
     }
 
     /**
Index: src/java/org/jivesoftware/spark/ui/ChatContainer.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ChatContainer.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ui/ChatContainer.java	(working copy)
@@ -26,6 +26,7 @@
 import org.jivesoftware.spark.component.tabbedPane.SparkTab;
 import org.jivesoftware.spark.component.tabbedPane.SparkTabbedPane;
 import org.jivesoftware.spark.component.tabbedPane.SparkTabbedPaneListener;
+import org.jivesoftware.spark.preference.PreferenceManager;
 import org.jivesoftware.spark.ui.rooms.ChatRoomImpl;
 import org.jivesoftware.spark.ui.rooms.GroupChatRoom;
 import org.jivesoftware.spark.util.SwingTimerTask;
@@ -41,6 +42,7 @@
 import javax.swing.JComponent;
 import javax.swing.JFrame;
 import javax.swing.JOptionPane;
+import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JTabbedPane;
 import javax.swing.KeyStroke;
@@ -89,6 +91,8 @@
 
     private ChatFrame chatFrame;
     
+    private JFrame externalizedFrame;
+    
     private LocalPreferences localPref;
 
     private final TimerTask focusTask;
@@ -237,7 +241,6 @@
      */
     public synchronized void addChatRoom(final ChatRoom room) {
         createFrameIfNeeded();
-
         room.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.LIGHT_GRAY));
         AndFilter presenceFilter = new AndFilter(new PacketTypeFilter(Presence.class), new FromContainsFilter(room.getRoomname()));
 
@@ -252,7 +255,6 @@
             }
         };
 
-
         SparkManager.getConnection().addPacketListener(myListener, presenceFilter);
 
         // Add to PresenceMap
@@ -268,19 +270,19 @@
         else {
             tooltip = room.getRoomname();
         }
-
+        
         // Create ChatRoom UI and dock
         SparkTab tab = addTab(room.getTabTitle(), room.getTabIcon(), room, tooltip);
-        tab.addMouseListener(new MouseAdapter() {
-            public void mouseReleased(MouseEvent e) {
-                checkTabPopup(e);
-            }
-
-            public void mousePressed(MouseEvent e) {
-                checkTabPopup(e);
-            }
-        });
-
+	     tab.addMouseListener(new MouseAdapter() {
+	         public void mouseReleased(MouseEvent e) {
+	             checkTabPopup(e);
+	         }
+	         public void mousePressed(MouseEvent e) {
+	             checkTabPopup(e);
+	         }
+	     });
+       
+	     
         room.addMessageListener(this);
 
         // Remove brand panel
@@ -289,15 +291,14 @@
             chatFrame.setTitle(room.getRoomTitle());
         }
 
-
         final TimerTask visibleTask = new SwingTimerTask() {
-            public void doRun() {
-                checkVisibility(room);
-            }
+          public void doRun() {
+              checkVisibility(room);
+          }
         };
 
         TaskEngine.getInstance().schedule(visibleTask, 100);
-
+	
         // Add to ChatRoomList
         chatRoomList.add(room);
 
@@ -306,7 +307,10 @@
 
         // Focus Chat
         focusChat();
+        
 
+	     
+        
         // Add Room listeners to override issue with input maps and keybinding on the mac.
         if (Spark.isMac()) {
             room.getChatInputEditor().addKeyListener(this);
@@ -361,6 +365,7 @@
     }
 
     private void checkVisibility(Component component) {
+   	
         if (!chatFrame.isVisible() && SparkManager.getMainWindow().isFocusOwner()) {
             chatFrame.setState(Frame.NORMAL);
             chatFrame.setVisible(true);
@@ -416,7 +421,8 @@
         ChatRoom activeChatRoom = null;        
         
         try {
-            activeChatRoom = getActiveChatRoom();
+      	  	if(SparkManager.getChatManager().getChatContainer().getTabCount() != 0)
+      	  		activeChatRoom = getActiveChatRoom();
         }
         catch (ChatRoomNotFoundException e1) {
             Log.error(e1);
@@ -452,26 +458,30 @@
         }
         else if (!chatFrame.isVisible()) {
             // Set to new tab.
-            int tabLocation = indexOfComponent(chatRoom);
-            setSelectedIndex(tabLocation);
-
-            if (Spark.isWindows()) {
-                chatFrame.setFocusableWindowState(false);
-                chatFrame.setState(Frame.ICONIFIED);
-            }
-            chatFrame.setVisible(true);
-            chatFrame.setFocusableWindowState(true);
-
-            // If the ContactList is in the tray, we need better notification by flashing
-            // the chatframe.
-            if (!SparkManager.getMainWindow().isVisible()) {
-                groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
-            }
-            else if (chatFrame.getState() == Frame.ICONIFIED) {
-                groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
-            }
-
-            chatFrame.setTitle(chatRoom.getRoomTitle());
+      	  	LocalPreferences pref = SettingsManager.getLocalPreferences();
+      	  	if(SparkManager.getExternalizedFrame(chatRoom.getTabTitle()) == null && !pref.isTabsExternalizedOn())
+      	  	{
+	            int tabLocation = indexOfComponent(chatRoom);
+	            setSelectedIndex(tabLocation);
+	
+	            if (Spark.isWindows()) {
+	                chatFrame.setFocusableWindowState(false);
+	                chatFrame.setState(Frame.ICONIFIED);
+	            }
+	            chatFrame.setVisible(true);
+	            chatFrame.setFocusableWindowState(true);
+	
+	            // If the ContactList is in the tray, we need better notification by flashing
+	            // the chatframe.
+	            if (!SparkManager.getMainWindow().isVisible()) {
+	                groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
+	            }
+	            else if (chatFrame.getState() == Frame.ICONIFIED) {
+	                groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
+	            }
+	
+	            chatFrame.setTitle(chatRoom.getRoomTitle());
+      	  	}
         }
         else if (chatRoom != activeChatRoom) {
             groupChatMessageCheck(chatRoom, customMsg, customMsgText, customMsgTitle);
@@ -557,7 +567,7 @@
      * @throws ChatRoomNotFoundException if the room was not found.
      */
     public ChatRoom getChatRoom(String roomName) throws ChatRoomNotFoundException {
-        for (int i = 0; i < getTabCount(); i++) {
+   	 for (int i = 0; i < getTabCount(); i++) {
             ChatRoom room = null;
             try {
                 room = getChatRoom(i);
@@ -565,12 +575,31 @@
             catch (ChatRoomNotFoundException e1) {
                 // Ignore
             }
-
-            if (room != null && room.getRoomname().equalsIgnoreCase(roomName) && room.isActive()) {
-                return room;
+            
+            String room_roomname = room.getRoomname();
+            if(room.getRoomname().contains("/spark"))
+            {
+            	String[] roomname = room_roomname.split("/spark");
+            	room_roomname = roomname[0];
+            }
+            
+            if (room != null && room_roomname.equalsIgnoreCase(roomName) && room.isActive()) {
+            	return room; 
             }
         }
-        throw new ChatRoomNotFoundException(roomName + " not found.");
+   	  try
+   	  {
+	   	  String roomTitle = SparkManager.getContactList().getContactItemByJID(roomName).getDisplayName();
+	        if(SparkManager.getExternalizedChatRoom(roomTitle) != null)
+	        {
+	       		return SparkManager.getExternalizedChatRoom(roomTitle);
+	        }
+   	  }
+   	  catch(Exception e)
+   	  {
+   		  throw new ChatRoomNotFoundException(roomName + " not found.");
+   	  }
+   	  throw new ChatRoomNotFoundException(roomName + " not found.");
     }
 
     /**
@@ -631,11 +660,19 @@
      * @param room the ChatRoom to activate.
      */
     public void activateChatRoom(ChatRoom room) {
-        int tabLocation = indexOfComponent(room);
+        if(SparkManager.getExternalizedChatRoom(room.getTabTitle()) != null)
+        {
+      	  SparkManager.getExternalizedFrame(room.getTabTitle()).toFront();
+      	  SparkManager.getExternalizedFrame(room.getTabTitle()).requestFocus();
+        }
+        else
+        {
+   	  int tabLocation = indexOfComponent(room);
         setSelectedIndex(tabLocation);
 
         chatFrame.bringFrameIntoFocus();
         focusChat();
+        }
     }
 
     /**
@@ -661,7 +698,7 @@
      */
     public void messageReceived(ChatRoom room, Message message) {
         room.increaseUnreadMessageCount();
-
+        SparkManager.getWorkspace().getTranscriptPlugin().persistChatRoom(room);
         fireNotifyOnMessage(room, false, null, null);
     }
     
@@ -918,7 +955,7 @@
                         // Check notifications.
                         if (SettingsManager.getLocalPreferences().isChatRoomNotificationsOn() || !(comp instanceof GroupChatRoom)) {
                             if (comp instanceof ChatRoom) {
-                                checkNotificationPreferences((ChatRoom)comp, customMsg, customMsgText, customMsgTitle);
+                                checkNotificationPreferences((ChatRoom)comp, customMsg, customMsgText, customMsgTitle, false);
                             }
                         }
 
@@ -979,26 +1016,47 @@
      * @param fileTName the file name being transfered (if fileTransfer applies)
      *
      */
-    private void checkNotificationPreferences(final ChatRoom room, boolean customMsg, String customMsgText, String customMsgTitle) {
+    public void checkNotificationPreferences(final ChatRoom room, boolean customMsg, String customMsgText, String customMsgTitle, boolean externalChatroom) {
         LocalPreferences pref = SettingsManager.getLocalPreferences();
+        System.out.println("lelelelelelelelelee");
         if (pref.getWindowTakesFocus()) {
-            chatFrame.setState(Frame.NORMAL);
-            chatFrame.setVisible(true);
+      	  if(externalChatroom)
+           {
+         		externalizedFrame = SparkManager.getExternalizedFrame(room.getTabTitle());
+   	      	externalizedFrame.setVisible(true);
+   	      	externalizedFrame.setState(Frame.NORMAL);
+           }
+      	  else
+      	  {
+      		  	chatFrame.setState(Frame.NORMAL);
+           		chatFrame.setVisible(true);
+        	  }
         }
-
         if (pref.getShowToasterPopup()) {
             SparkToaster toaster = new SparkToaster();
-            toaster.setCustomAction(new AbstractAction() {
-                public void actionPerformed(ActionEvent actionEvent) {
-                    chatFrame.setState(Frame.NORMAL);
-                    chatFrame.setVisible(true);
-                    int tabLocation = indexOfComponent(room);
-                    if (tabLocation != -1) {
-                        setSelectedIndex(tabLocation);
-                    }
-                }
-            });
-
+            if(externalChatroom)
+            {
+	            toaster.setCustomAction(new AbstractAction() {
+	               public void actionPerformed(ActionEvent actionEvent) {
+	              	  externalizedFrame.setState(Frame.NORMAL);
+	              	  externalizedFrame.setVisible(true);
+	               }
+	            });
+            }
+            else
+            {
+	            toaster.setCustomAction(new AbstractAction() {
+	                public void actionPerformed(ActionEvent actionEvent) {
+	                    chatFrame.setState(Frame.NORMAL);
+	                    chatFrame.setVisible(true);
+	                    int tabLocation = indexOfComponent(room);
+	                    if (tabLocation != -1) {
+	                        setSelectedIndex(tabLocation);
+	                    }
+	                }
+	            });	
+            }
+            
             toaster.setDisplayTime(5000);
             toaster.setBorder(BorderFactory.createBevelBorder(0));
             
@@ -1036,7 +1094,7 @@
         localPref = SettingsManager.getLocalPreferences();
         boolean isGroupChat = chatRoom.getChatType() == Message.Type.groupchat;
         int size = chatRoom.getTranscripts().size();
-        
+       
         // is this a group chat message and is my name in it?
         if (isGroupChat) {
             // is a group chat, perform some functions
@@ -1088,7 +1146,7 @@
             return;
         } else {
             // normal personal chat
-            Message lastChatMessage = chatRoom.getTranscripts().get(size - 1);
+            Message lastChatMessage = SparkManager.getWorkspace().getTranscriptPlugin().getLastMessage();
             String finalRoomName = chatRoom.getRoomTitle();
             
             boolean customMsgS = true;
@@ -1110,10 +1168,11 @@
     }
 
     private void createFrameIfNeeded() {
-        if (chatFrame != null) {
+   	  if (chatFrame != null) {
             return;
         }
-        LocalPreferences pref = SettingsManager.getLocalPreferences();
+   	  
+   	  LocalPreferences pref = SettingsManager.getLocalPreferences();
         if (pref.isDockingEnabled()) {
             chatFrame = MainWindow.getInstance();
         }
@@ -1170,8 +1229,6 @@
      * Brings the chat into focus.
      */
     public void focusChat() {
-
-
         TaskEngine.getInstance().schedule(focusTask, 50);
     }
 
@@ -1368,5 +1425,10 @@
 
         return messageCount;
     }
+    
+    public List<ChatRoomListener> getChatRoomListener()
+    {
+   	 return chatRoomListeners;
+    }
 }
 
Index: src/java/org/jivesoftware/spark/ui/ChatFrame.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ChatFrame.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ui/ChatFrame.java	(working copy)
@@ -177,8 +177,8 @@
     /**
      * Shake it, come on now, shake that frame.
      */
-    public void buzz() {
-        ShakeWindow d = new ShakeWindow(this);
+    public void buzz(JFrame frame) {
+        ShakeWindow d = new ShakeWindow(frame);
         d.startShake();
     }
 
Index: src/java/org/jivesoftware/spark/ui/ChatRoom.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ChatRoom.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ui/ChatRoom.java	(working copy)
@@ -21,8 +21,10 @@
 import org.jivesoftware.spark.component.BackgroundPanel;
 import org.jivesoftware.spark.component.RolloverButton;
 import org.jivesoftware.spark.plugin.ContextMenuListener;
+import org.jivesoftware.spark.ui.rooms.GroupChatRoom;
 import org.jivesoftware.spark.util.GraphicUtils;
 import org.jivesoftware.spark.util.log.Log;
+import org.jivesoftware.sparkimpl.plugin.alerts.SparkToaster;
 import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
 import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
 
@@ -32,6 +34,7 @@
 import javax.swing.Icon;
 import javax.swing.JButton;
 import javax.swing.JComponent;
+import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
@@ -49,6 +52,7 @@
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.FlowLayout;
+import java.awt.Frame;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.Insets;
@@ -74,15 +78,15 @@
     private final JSplitPane splitPane;
     private JSplitPane verticalSplit;
 
-    private final JLabel notificationLabel;
-    private final TranscriptWindow transcriptWindow;
-    private final ChatAreaSendField chatAreaButton;
-    private final ChatToolBar toolbar;
-    private final JScrollPane textScroller;
-    private final JPanel bottomPanel;
-    private final JPanel editorBar;
+    private final  JLabel notificationLabel;
+    private final  TranscriptWindow transcriptWindow;
+    private final  ChatAreaSendField chatAreaButton;
+    private final  ChatToolBar toolbar;
+    private final  JScrollPane textScroller;
+    private final  JPanel bottomPanel;
+    private final  JPanel editorBar;
     private JPanel chatWindowPanel;
-
+    private JFrame externalizedFrame;
     private int unreadMessageCount;
 
     private boolean mousePressed;
@@ -104,7 +108,7 @@
     /**
      * Initializes the base layout and base background color.
      */
-    protected ChatRoom() {
+   public ChatRoom() {
         chatPanel = new JPanel(new GridBagLayout());
         transcriptWindow = new TranscriptWindow();
         splitPane = new JSplitPane();
@@ -178,12 +182,11 @@
 
         getTranscriptWindow().setTransferHandler(transferHandler);
         getChatInputEditor().setTransferHandler(transferHandler);
-
         add(toolbar, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
 
         // Add Connection Listener
         SparkManager.getConnection().addConnectionListener(this);
-
+        
         // Add Focus Listener
         addFocusListener(this);
     }
@@ -326,8 +329,10 @@
         SparkManager.getChatManager().fireGlobalMessageReceievedListeners(this, message);
 
         addToTranscript(message, true);
-
+        
         fireMessageReceived(message);
+
+        SparkManager.getWorkspace().getTranscriptPlugin().persistChatRoom(this);    
     }
 
 
@@ -345,8 +350,6 @@
         newMessage.setFrom(message.getFrom());
         newMessage.setBody(message.getBody());
         
-        
-        
         newMessage.setProperty("date", new Date());
 
         transcript.add(newMessage);
@@ -466,13 +469,15 @@
      * @param e the KeyEvent
      */
     private void checkForEnter(KeyEvent e) {
-        final KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
+   	 final KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
         if (!keyStroke.equals(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.SHIFT_DOWN_MASK)) &&
                 e.getKeyChar() == KeyEvent.VK_ENTER) {
             e.consume();
             sendMessage();
             getChatInputEditor().setText("");
             getChatInputEditor().setCaretPosition(0);
+            
+            SparkManager.getWorkspace().getTranscriptPlugin().persistChatRoom(this);
         }
         else if (keyStroke.equals(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.SHIFT_DOWN_MASK))) {
             final Document document = getChatInputEditor().getDocument();
@@ -514,6 +519,9 @@
         for (MessageListener messageListener : messageListeners) {
             messageListener.messageReceived(this, message);
         }
+        
+        if(SparkManager.getExternalizedFrame(this.getTabTitle()) != null)
+      	  SparkManager.getChatManager().getChatContainer().checkNotificationPreferences(this, false, null, null, true);
     }
 
     /**
@@ -733,7 +741,6 @@
         return toolbar;
     }
 
-
     public void insertUpdate(DocumentEvent e) {
         // Meant to be overriden
         checkForText(e);
Index: src/java/org/jivesoftware/spark/ui/ContactGroup.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ContactGroup.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ui/ContactGroup.java	(working copy)
@@ -18,6 +18,7 @@
 import org.jivesoftware.spark.component.VerticalFlowLayout;
 import org.jivesoftware.spark.component.panes.CollapsiblePane;
 import org.jivesoftware.spark.component.renderer.JPanelRenderer;
+import org.jivesoftware.spark.ui.rooms.ChatRoomImpl;
 import org.jivesoftware.spark.util.GraphicUtils;
 import org.jivesoftware.spark.util.ModelUtil;
 import org.jivesoftware.spark.util.log.Log;
@@ -28,6 +29,7 @@
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Font;
+import java.awt.Frame;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.Insets;
@@ -46,6 +48,7 @@
 import java.util.List;
 
 import javax.swing.DefaultListModel;
+import javax.swing.JFrame;
 import javax.swing.JList;
 import javax.swing.JPanel;
 import javax.swing.Timer;
@@ -117,7 +120,8 @@
             public void mouseClicked(MouseEvent e) {
 	             if(e.getButton() == MouseEvent.BUTTON1)
 	             {
-	           	 	contactList.saveState();
+	            	 contactList =  Workspace.getInstance().getContactList();
+	           	 	 contactList.saveState(); 
 	             }
             }
 
@@ -158,8 +162,6 @@
 
         // Add Popup Window
         addPopupWindow();
-        
-       
     }
 
     /**
@@ -174,7 +176,6 @@
         // Build new ContactItem
         final ContactItem offlineItem = new ContactItem(alias, nickname, jid);
         offlineItem.setGroupName(getGroupName());
-
         final Presence offlinePresence = PresenceManager.getPresence(jid);
         offlineItem.setPresence(offlinePresence);
 
@@ -277,11 +278,9 @@
     public void addContactItem(ContactItem item) {
         // Remove from offline group if it exists
         removeOfflineContactItem(item.getJID());
-
         if (model.contains(noContacts)) {
             model.remove(0);
         }
-
         if (Res.getString("group.offline").equals(groupName)) {
             item.getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, 11));
             item.getNicknameLabel().setForeground(Color.GRAY);
@@ -464,7 +463,7 @@
         ContactItem item = (ContactItem)o;
 
         if (e.getClickCount() == 2) {
-            fireContactItemDoubleClicked(item);
+      	  	fireContactItemDoubleClicked(item);
         }
         else if (e.getClickCount() == 1) {
             fireContactItemClicked(item);
@@ -772,9 +771,9 @@
      * @return the preferred dimension
      */
     public Dimension getPreferredSize() {
-        final Dimension size = super.getPreferredSize();
-        size.width = 0;
-        return size;
+	     final Dimension size = super.getPreferredSize();
+	     size.width = 0;
+	     return size;
     }
 
     /**
Index: src/java/org/jivesoftware/spark/ui/ContactItem.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ContactItem.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ui/ContactItem.java	(working copy)
@@ -1,11 +1,7 @@
 /**
- * $Revision: $
- * $Date: $
- *
- * Copyright (C) 2006 Jive Software. All rights reserved.
- *
- * This software is published under the terms of the GNU Lesser Public License (LGPL),
- * a copy of which is included in this distribution.
+ * $Revision: $ $Date: $ Copyright (C) 2006 Jive Software. All rights reserved.
+ * This software is published under the terms of the GNU Lesser Public License
+ * (LGPL), a copy of which is included in this distribution.
  */
 
 package org.jivesoftware.spark.ui;
@@ -21,6 +17,7 @@
 import org.jivesoftware.spark.ChatManager;
 import org.jivesoftware.spark.PresenceManager;
 import org.jivesoftware.spark.SparkManager;
+import org.jivesoftware.spark.ui.rooms.ChatRoomImpl;
 import org.jivesoftware.spark.util.GraphicUtils;
 import org.jivesoftware.spark.util.ModelUtil;
 import org.jivesoftware.spark.util.log.Log;
@@ -31,6 +28,7 @@
 import org.jivesoftware.sparkimpl.plugin.layout.LayoutSettingsManager;
 
 import javax.swing.*;
+
 import java.awt.*;
 import java.io.File;
 import java.net.MalformedURLException;
@@ -39,529 +37,628 @@
 /**
  * Represent a single contact within the <code>ContactList</code>.
  */
-public class ContactItem extends JPanel {
-    private JLabel imageLabel;
-    private JLabel displayNameLabel;
-    private JLabel descriptionLabel;
-    private String nickname;
-    private String alias;
-    private String fullyQualifiedJID;
-    private Icon icon;
-
-    private String status;
-    private String groupName;
+public class ContactItem extends JPanel
+{
+	private JLabel		imageLabel;
+	private JLabel		displayNameLabel;
+	private JLabel		descriptionLabel;
+	private String		nickname;
+	private String		alias;
+	private String		fullyQualifiedJID;
+	private Icon		icon;
 
-    boolean available;
+	private String		status;
+	private String		groupName;
 
-    private Presence presence;
+	boolean				available;
 
-    private String hash = "";
+	private Presence	presence;
 
-    private File contactsDir;
+	private String		hash	= "";
 
-    private JLabel sideIcon;
+	private File		contactsDir;
 
-    private int fontSize;
+	private JLabel		sideIcon;
 
-    private int iconSize;
+	private int			fontSize;
 
-    private boolean avatarsShowing;
+	private int			iconSize;
 
-    /**
-     * Creates a new instance of a contact.
-     *
-     * @param alias             the alias of the contact
-     * @param nickname          the nickname of the contact.
-     * @param fullyQualifiedJID the fully-qualified jid of the contact (ex. derek@jivesoftware.com)
-     */
-    public ContactItem(String alias, String nickname, String fullyQualifiedJID) {
-        setLayout(new GridBagLayout());
+	private boolean	avatarsShowing;
 
-        // Set Default Font
-        final LocalPreferences pref = SettingsManager.getLocalPreferences();
-        fontSize = pref.getContactListFontSize();
-        iconSize = pref.getContactListIconSize();
-        avatarsShowing = pref.areAvatarsVisible();
+	/**
+	 * Creates a new instance of a contact.
+	 * 
+	 * @param alias
+	 *           the alias of the contact
+	 * @param nickname
+	 *           the nickname of the contact.
+	 * @param fullyQualifiedJID
+	 *           the fully-qualified jid of the contact (ex.
+	 *           derek@jivesoftware.com)
+	 */
+	public ContactItem(String alias, String nickname, String fullyQualifiedJID)
+	{
+		setLayout(new GridBagLayout());
 
-        // Set default presence
-        presence = new Presence(Presence.Type.unavailable);
+		// Set Default Font
+		final LocalPreferences pref = SettingsManager.getLocalPreferences();
+		fontSize = pref.getContactListFontSize();
+		iconSize = pref.getContactListIconSize();
+		avatarsShowing = pref.areAvatarsVisible();
 
-        contactsDir = new File(SparkManager.getUserDirectory(), "contacts");
+		// Set default presence
+		presence = new Presence(Presence.Type.unavailable);
 
-        displayNameLabel = new JLabel();
-        descriptionLabel = new JLabel();
-        imageLabel = new JLabel();
-        sideIcon = new JLabel();
-        if (avatarsShowing) {
-            sideIcon.setMinimumSize(new Dimension(iconSize, iconSize));
-            sideIcon.setMaximumSize(new Dimension(iconSize, iconSize));
-            sideIcon.setPreferredSize(new Dimension(iconSize, iconSize));
-        }
+		contactsDir = new File(SparkManager.getUserDirectory(), "contacts");
 
-        displayNameLabel.setHorizontalTextPosition(JLabel.LEFT);
-        displayNameLabel.setHorizontalAlignment(JLabel.LEFT);
-        //displayNameLabel.setText(nickname);
+		displayNameLabel = new JLabel();
+		descriptionLabel = new JLabel();
+		imageLabel = new JLabel();
+		sideIcon = new JLabel();
+		if (avatarsShowing)
+		{
+			sideIcon.setMinimumSize(new Dimension(iconSize, iconSize));
+			sideIcon.setMaximumSize(new Dimension(iconSize, iconSize));
+			sideIcon.setPreferredSize(new Dimension(iconSize, iconSize));
+		}
 
+		displayNameLabel.setHorizontalTextPosition(JLabel.LEFT);
+		displayNameLabel.setHorizontalAlignment(JLabel.LEFT);
+		// displayNameLabel.setText(nickname);
 
-        descriptionLabel.setFont(new Font("Dialog", Font.PLAIN, fontSize));
-        descriptionLabel.setForeground((Color)UIManager.get("ContactItemDescription.foreground"));
-        descriptionLabel.setHorizontalTextPosition(JLabel.LEFT);
-        descriptionLabel.setHorizontalAlignment(JLabel.LEFT);
+		descriptionLabel.setFont(new Font("Dialog", Font.PLAIN, fontSize));
+		descriptionLabel.setForeground((Color) UIManager.get("ContactItemDescription.foreground"));
+		descriptionLabel.setHorizontalTextPosition(JLabel.LEFT);
+		descriptionLabel.setHorizontalAlignment(JLabel.LEFT);
 
+		this.setOpaque(true);
 
-        this.setOpaque(true);
+		add(imageLabel, new GridBagConstraints(0, 0, 1, 2, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 15, 0, 0), 0, 0));
+		add(displayNameLabel, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
+		add(descriptionLabel, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 2, 0), 0, 0));
+		add(sideIcon, new GridBagConstraints(3, 0, 1, 2, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
 
-        add(imageLabel, new GridBagConstraints(0, 0, 1, 2, 0.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.HORIZONTAL, new Insets(0, 15, 0, 0), 0, 0));
-        add(displayNameLabel, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
-        add(descriptionLabel, new GridBagConstraints(2, 0, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 2, 0), 0, 0));
-        add(sideIcon, new GridBagConstraints(3, 0, 1, 2, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 5, 0, 0), 0, 0));
+		this.alias = alias;
+		this.nickname = nickname;
+		this.fullyQualifiedJID = fullyQualifiedJID;
 
-        this.alias = alias;
-        this.nickname = nickname;
-        this.fullyQualifiedJID = fullyQualifiedJID;
-        
-        setDisplayName();
-    }
+		setDisplayName();
+	}
 
 	/**
-	 * Returns the name that should be displayed to represent the the contact.
-	 * If an alias has been set, this alias will be returned. If no alias has
-	 * been set, the nickname will be returned. If that hasn't been set either,
-	 * the JID will be returned.
+	 * Returns the name that should be displayed to represent the the contact. If
+	 * an alias has been set, this alias will be returned. If no alias has been
+	 * set, the nickname will be returned. If that hasn't been set either, the
+	 * JID will be returned.
 	 * 
 	 * @return a name suitable to be displayed
 	 */
-    public String getDisplayName() {
-    	final String displayName;
-		if (alias != null) {
+	public String getDisplayName()
+	{
+		final String displayName;
+		if (alias != null)
+		{
 			displayName = alias;
-		} else if (nickname != null) {
+		}
+		else if (nickname != null)
+		{
 			displayName = nickname;
-		} else {
+		}
+		else
+		{
 			displayName = getJID();
 		}
-		
-		if (displayName != null) {
-		return displayName;
-		} else {
+
+		if (displayName != null)
+		{
+			return displayName;
+		}
+		else
+		{
 			return ""; // weird, but happens.
 		}
 	}
 
-    /**
+	/**
 	 * Returns the nickname of the contact. Note that for typical user-interface
 	 * related tasks, you probably should use {@link #getDisplayName()} instead.
 	 * 
 	 * @return the contact nickname.
 	 */
-	public String getNickname() {
+	public String getNickname()
+	{
 		return nickname;
 	}
-	
-    /**
-     * Sets the nickname of the contact.
-     *
-     * @param nickname the contact nickname.
-     */
-    public void setNickname(String nickname) {
-        this.nickname = nickname;
-        if (alias == null) {
-        	setDisplayName();
-        }
-    }
+
+	/**
+	 * Sets the nickname of the contact.
+	 * 
+	 * @param nickname
+	 *           the contact nickname.
+	 */
+	public void setNickname(String nickname)
+	{
+		this.nickname = nickname;
+		if (alias == null)
+		{
+			setDisplayName();
+		}
+	}
 
-    /**
+	/**
 	 * Returns the alias of the contact. Note that for typical user-interface
 	 * related tasks, you probably should use {@link #getDisplayName()} instead.
 	 * 
 	 * @return the contact alias.
 	 */
-	public String getAlias() {
+	public String getAlias()
+	{
 		return alias;
 	}
-    
-    /**
-     * Sets the alias of the contact. 
-     *
-     * @param alias the contact alias.
-     */
-    public void setAlias(String alias) {
-    	this.alias = alias;
-    	setDisplayName();
-    }
+
+	/**
+	 * Sets the alias of the contact.
+	 * 
+	 * @param alias
+	 *           the contact alias.
+	 */
+	public void setAlias(String alias)
+	{
+		this.alias = alias;
+		setDisplayName();
+	}
 
-    /**
+	/**
 	 * Updates the displayed name for the contact. This method tries to use an
 	 * alias first. If that's not set, the nickname will be used instead. If
 	 * that's not set either, the JID of the user will be used.
 	 */
-    private void setDisplayName() {
-    	final String displayName = getDisplayName();
-    	
-        int nickLength = displayName.length();
-        
-        LayoutSettings settings = LayoutSettingsManager.getLayoutSettings();
-        int windowWidth = (int)Math.round((settings.getMainWindowHeight() / 15.2));
-        
-        if (nickLength > windowWidth) {
-            displayNameLabel.setText(StringUtils.unescapeNode(displayName).substring(0, windowWidth) + "...");
-        } else {
-            displayNameLabel.setText(StringUtils.unescapeNode(displayName));
-        }    	
-    }
-    
-    /**
-     * Returns the fully qualified JID of the contact. (If available). Otherwise will
-     * return the bare jid.
-     *
-     * @return the fully qualified jid (ex. derek@jivesoftware.com).
-     */
-    public String getJID() {
-        return fullyQualifiedJID;
-    }
+	private void setDisplayName()
+	{
+		final String displayName = getDisplayName();
 
-    /**
-     * Returns the icon showing the contacts current state or presence.
-     *
-     * @return the icon.
-     */
-    public Icon getIcon() {
-        return icon;
-    }
+		int nickLength = displayName.length();
 
-    /**
-     * Sets the current icon to use.
-     *
-     * @param icon the current icon to use.
-     */
-    public void setIcon(Icon icon) {
-        this.icon = icon;
-        imageLabel.setIcon(icon);
-    }
+		LayoutSettings settings = LayoutSettingsManager.getLayoutSettings();
+		int windowWidth = (int) Math.round((settings.getMainWindowHeight() / 15.2));
 
-    /**
-     * Returns the contacts current status based on their presence.
-     *
-     * @return the contacts current status.
-     */
-    public String getStatus() {
-        return status;
-    }
+		if (nickLength > windowWidth)
+		{
+			displayNameLabel.setText(StringUtils.unescapeNode(displayName).substring(0, windowWidth)
+				+ "...");
+		}
+		else
+		{
+			displayNameLabel.setText(StringUtils.unescapeNode(displayName));
+		}
+	}
 
-    /**
-     * Sets the contacts current status.
-     *
-     * @param status the contacts current status.
-     */
-    public void setStatus(String status) {
-        this.status = status;
-    }
+	/**
+	 * Returns the fully qualified JID of the contact. (If available). Otherwise
+	 * will return the bare jid.
+	 * 
+	 * @return the fully qualified jid (ex. derek@jivesoftware.com).
+	 */
+	public String getJID()
+	{
+		return fullyQualifiedJID;
+	}
 
-    /**
-     * Returns the name of the <code>ContactGroup</code> that this contact belongs to.
-     *
-     * @return the name of the <code>ContactGroup</code>.
-     */
-    public String getGroupName() {
-        return groupName;
-    }
+	/**
+	 * Returns the icon showing the contacts current state or presence.
+	 * 
+	 * @return the icon.
+	 */
+	public Icon getIcon()
+	{
+		return icon;
+	}
 
-    /**
-     * Sets the name of the <code>ContactGrouop</code> that this contact belongs to.
-     *
-     * @param groupName the name of the ContactGroup.
-     */
-    public void setGroupName(String groupName) {
-        this.groupName = groupName;
-    }
+	/**
+	 * Sets the current icon to use.
+	 * 
+	 * @param icon
+	 *           the current icon to use.
+	 */
+	public void setIcon(Icon icon)
+	{
+		this.icon = icon;
+		imageLabel.setIcon(icon);
+	}
 
-    public boolean isAvailable() {
-        return available;
-    }
+	/**
+	 * Returns the contacts current status based on their presence.
+	 * 
+	 * @return the contacts current status.
+	 */
+	public String getStatus()
+	{
+		return status;
+	}
 
-    public void setAvailable(boolean available) {
-        this.available = available;
-    }
+	/**
+	 * Sets the contacts current status.
+	 * 
+	 * @param status
+	 *           the contacts current status.
+	 */
+	public void setStatus(String status)
+	{
+		this.status = status;
+	}
 
-    /**
-     * Returns the <code>JLabel</code> showing the users nickname.
-     *
-     * @return the nickname label.
-     */
-    public JLabel getNicknameLabel() {
-        return displayNameLabel;
-    }
+	/**
+	 * Returns the name of the <code>ContactGroup</code> that this contact
+	 * belongs to.
+	 * 
+	 * @return the name of the <code>ContactGroup</code>.
+	 */
+	public String getGroupName()
+	{
+		return groupName;
+	}
 
-    /**
-     * Returns the <code>JLabel</code> representing the description.
-     *
-     * @return the description label.
-     */
-    public JLabel getDescriptionLabel() {
-        return descriptionLabel;
-    }
+	/**
+	 * Sets the name of the <code>ContactGrouop</code> that this contact belongs
+	 * to.
+	 * 
+	 * @param groupName
+	 *           the name of the ContactGroup.
+	 */
+	public void setGroupName(String groupName)
+	{
+		this.groupName = groupName;
+	}
 
-    /**
-     * Returns the current presence of the contact.
-     *
-     * @return the users current presence.
-     */
-    public Presence getPresence() {
-        return presence;
-    }
+	public boolean isAvailable()
+	{
+		return available;
+	}
 
-    /**
-     * Sets the current presence on this contact item.
-     *
-     * @param presence the presence.
-     */
-    public void setPresence(Presence presence) {
+	public void setAvailable(boolean available)
+	{
+		this.available = available;
+	}
 
-        this.presence = presence;
+	/**
+	 * Returns the <code>JLabel</code> showing the users nickname.
+	 * 
+	 * @return the nickname label.
+	 */
+	public JLabel getNicknameLabel()
+	{
+		return displayNameLabel;
+	}
 
-        final PacketExtension packetExtension = presence.getExtension("x", "vcard-temp:x:update");
+	/**
+	 * Returns the <code>JLabel</code> representing the description.
+	 * 
+	 * @return the description label.
+	 */
+	public JLabel getDescriptionLabel()
+	{
+		return descriptionLabel;
+	}
 
-        // Handle vCard update packet.
-        if (packetExtension != null) {
-            DefaultPacketExtension o = (DefaultPacketExtension)packetExtension;
-            String hash = o.getValue("photo");
-            if (hash != null) {
-                this.hash = hash;
+	/**
+	 * Returns the current presence of the contact.
+	 * 
+	 * @return the users current presence.
+	 */
+	public Presence getPresence()
+	{
+		return presence;
+	}
 
-                if (!hashExists(hash)) {
-                    updateAvatar();
-                }
+	/**
+	 * Sets the current presence on this contact item.
+	 * 
+	 * @param presence
+	 *           the presence.
+	 */
+	public void setPresence(Presence presence)
+	{
 
-                updateAvatarInSideIcon();
-            }
-        }
+		this.presence = presence;
 
-        updatePresenceIcon(presence);
-    }
+		final PacketExtension packetExtension = presence.getExtension("x", "vcard-temp:x:update");
 
-    /**
-     * Checks to see if the hash already exists.
-     *
-     * @param hash the hash.
-     * @return true if the hash exists, otherwise false.
-     */
-    private boolean hashExists(String hash) {
-        contactsDir.mkdirs();
+		// Handle vCard update packet.
+		if (packetExtension != null)
+		{
+			DefaultPacketExtension o = (DefaultPacketExtension) packetExtension;
+			String hash = o.getValue("photo");
+			if (hash != null)
+			{
+				this.hash = hash;
 
-        final File imageFile = new File(contactsDir, hash);
-        return imageFile.exists();
-    }
+				if (!hashExists(hash))
+				{
+					updateAvatar();
+				}
 
-    /**
-     * Returns the url of the avatar belonging to this contact.
-     *
-     * @return the url of the avatar.
-     * @throws MalformedURLException thrown if the address is invalid.
-     */
-    public URL getAvatarURL() throws MalformedURLException {
-        contactsDir.mkdirs();
+				updateAvatarInSideIcon();
+			}
+		}
+		updatePresenceIcon(presence);
+	}
 
-        if (ModelUtil.hasLength(hash)) {
-            final File imageFile = new File(contactsDir, hash);
-            if (imageFile.exists()) {
-                return imageFile.toURL();
-            }
-        }
+	/**
+	 * Checks to see if the hash already exists.
+	 * 
+	 * @param hash
+	 *           the hash.
+	 * @return true if the hash exists, otherwise false.
+	 */
+	private boolean hashExists(String hash)
+	{
+		contactsDir.mkdirs();
 
-        return SparkManager.getVCardManager().getAvatarURL(getJID());
-    }
+		final File imageFile = new File(contactsDir, hash);
+		return imageFile.exists();
+	}
 
-    /**
-     * Persists the avatar locally based on the new hash.
-     */
-    private void updateAvatar() {
-        SparkManager.getVCardManager().addToQueue(getJID());
-    }
+	/**
+	 * Returns the url of the avatar belonging to this contact.
+	 * 
+	 * @return the url of the avatar.
+	 * @throws MalformedURLException
+	 *            thrown if the address is invalid.
+	 */
+	public URL getAvatarURL() throws MalformedURLException
+	{
+		contactsDir.mkdirs();
 
-    public String toString() {
-        return displayNameLabel.getText();
-    }
+		if (ModelUtil.hasLength(hash))
+		{
+			final File imageFile = new File(contactsDir, hash);
+			if (imageFile.exists()) { return imageFile.toURL(); }
+		}
 
+		return SparkManager.getVCardManager().getAvatarURL(getJID());
+	}
 
-    /**
-     * Updates the icon of the user based on their presence.
-     *
-     * @param presence the users presence.
-     */
-    public void updatePresenceIcon(Presence presence) {
-        ChatManager chatManager = SparkManager.getChatManager();
-        boolean handled = chatManager.fireContactItemPresenceChanged(this, presence);
-        if (handled) {
-            return;
-        }
+	/**
+	 * Persists the avatar locally based on the new hash.
+	 */
+	private void updateAvatar()
+	{
+		SparkManager.getVCardManager().addToQueue(getJID());
+	}
 
-        String status = presence.getStatus();
-        Icon statusIcon = SparkRes.getImageIcon(SparkRes.GREEN_BALL);
-        boolean isAvailable = false;
-        if (status == null && presence.isAvailable()) {
-            Presence.Mode mode = presence.getMode();
-            if (mode == Presence.Mode.available) {
-                status = Res.getString("status.available");
-                isAvailable = true;
-            }
-            else if (mode == Presence.Mode.away) {
-                status = Res.getString("status.away");
-                statusIcon = SparkRes.getImageIcon(SparkRes.IM_AWAY);
-            }
-            else if (mode == Presence.Mode.chat) {
-                status = Res.getString("status.free.to.chat");
-            }
-            else if (mode == Presence.Mode.dnd) {
-                status = Res.getString("status.do.not.disturb");
-                statusIcon = SparkRes.getImageIcon(SparkRes.IM_AWAY);
-            }
-            else if (mode == Presence.Mode.xa) {
-                status = Res.getString("status.extended.away");
-                statusIcon = SparkRes.getImageIcon(SparkRes.IM_AWAY);
-            }
-        }
+	public String toString()
+	{
+		return displayNameLabel.getText();
+	}
 
-        if (presence.isAvailable() && (presence.getMode() == Presence.Mode.dnd || presence.getMode() == Presence.Mode.away || presence.getMode() == Presence.Mode.xa)) {
-            statusIcon = SparkRes.getImageIcon(SparkRes.IM_AWAY);
-        }
-        else if (presence.isAvailable()) {
-            isAvailable = true;
-        }
-        else if (!presence.isAvailable()) {
-            getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, fontSize));
-            getNicknameLabel().setForeground((Color)UIManager.get("ContactItemOffline.color"));
+	/**
+	 * Updates the icon of the user based on their presence.
+	 * 
+	 * @param presence
+	 *           the users presence.
+	 */
+	public void updatePresenceIcon(Presence presence)
+	{
+		JFrame externalizedFrame = SparkManager.getExternalizedFrame(getAlias());
+		ChatRoomImpl chatroom = (ChatRoomImpl) SparkManager.getExternalizedChatRoom(getAlias());	
+		ChatManager chatManager = SparkManager.getChatManager();
+		boolean handled = chatManager.fireContactItemPresenceChanged(this, presence);
+		if (handled) { return; }
+		String status = presence.getStatus();
+		Icon statusIcon = SparkRes.getImageIcon(SparkRes.GREEN_BALL);
+		boolean isAvailable = false;
+		if (status == null && presence.isAvailable())
+		{
+			Presence.Mode mode = presence.getMode();
+			if (mode == Presence.Mode.available)
+			{
+				status = Res.getString("status.available");
+				isAvailable = true;
+			}
+			else if (mode == Presence.Mode.away)
+			{
+				status = Res.getString("status.away");
+				statusIcon = SparkRes.getImageIcon(SparkRes.IM_AWAY);
+			}
+			else if (mode == Presence.Mode.chat)
+			{
+				status = Res.getString("status.free.to.chat");
+			}
+			else if (mode == Presence.Mode.dnd)
+			{
+				status = Res.getString("status.do.not.disturb");
+				statusIcon = SparkRes.getImageIcon(SparkRes.IM_AWAY);
+			}
+			else if (mode == Presence.Mode.xa)
+			{
+				status = Res.getString("status.extended.away");
+				statusIcon = SparkRes.getImageIcon(SparkRes.IM_AWAY);
+			}
+		}
 
-            RosterEntry entry = SparkManager.getConnection().getRoster().getEntry(getJID());
-            if (entry != null && (entry.getType() == RosterPacket.ItemType.none || entry.getType() == RosterPacket.ItemType.from)
-                    && RosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus()) {
-                // Do not move out of group.
-                setIcon(SparkRes.getImageIcon(SparkRes.SMALL_QUESTION));
-                getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, fontSize));
-                setStatusText(Res.getString("status.pending"));
-            }
-            else {
-                setIcon(null);
-                setFont(new Font("Dialog", Font.PLAIN, fontSize));
-                getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, fontSize));
-                setAvailable(false);
-                if (ModelUtil.hasLength(status)) {
-                    setStatusText(status);
-                }
-                else {
-                    setStatusText("");
-                }
-            }
+		if (presence.isAvailable()
+			&& (presence.getMode() == Presence.Mode.dnd
+				|| presence.getMode() == Presence.Mode.away || presence.getMode() == Presence.Mode.xa))
+		{
+			statusIcon = SparkRes.getImageIcon(SparkRes.IM_AWAY);
+		}
+		else if (presence.isAvailable())
+		{
+			isAvailable = true;
+		}
+		else if (!presence.isAvailable())
+		{
+			getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, fontSize));
+			getNicknameLabel().setForeground((Color) UIManager.get("ContactItemOffline.color"));
 
-            sideIcon.setIcon(null);
-            setAvailable(false);
-            return;
-        }
+			RosterEntry entry = SparkManager.getConnection().getRoster().getEntry(getJID());
+			if (entry != null
+				&& (entry.getType() == RosterPacket.ItemType.none || entry.getType() == RosterPacket.ItemType.from)
+				&& RosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus())
+			{
+				// Do not move out of group.
+				setIcon(SparkRes.getImageIcon(SparkRes.SMALL_QUESTION));
+				getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, fontSize));
+				setStatusText(Res.getString("status.pending"));
+			}
+			else
+			{
+				setIcon(null);
+				setFont(new Font("Dialog", Font.PLAIN, fontSize));
+				getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, fontSize));
+				setAvailable(false);
+				if (ModelUtil.hasLength(status))
+				{
+					setStatusText(status);
+				}
+				else
+				{
+					setStatusText("");
+				}
+			}
 
-        Icon sIcon = PresenceManager.getIconFromPresence(presence);
-        if (sIcon != null) {
-            setIcon(sIcon);
-        }
-        else {
-            setIcon(statusIcon);
-        }
-        if (status != null) {
-            setStatus(status);
-        }
+			sideIcon.setIcon(null);
+			setAvailable(false);
+			
+			if(externalizedFrame != null)
+				externalizedFrame.setIconImage(SparkRes.getImageIcon(SparkRes.CLEAR_BALL_ICON).getImage());
+			
+			return;
+		}
 
-        if (status != null && status.toLowerCase().indexOf("phone") != -1) {
-            statusIcon = SparkRes.getImageIcon(SparkRes.ON_PHONE_IMAGE);
-            setIcon(statusIcon);
-        }
+		Icon sIcon = PresenceManager.getIconFromPresence(presence);
+		if (sIcon != null)
+		{
+			setIcon(sIcon);
+		}
+		else
+		{
+			setIcon(statusIcon);
+		}
+		if (status != null)
+		{
+			setStatus(status);
+		}
 
-        // Always change nickname label to black.
-        getNicknameLabel().setForeground((Color)UIManager.get("ContactItemNickname.foreground"));
+		if (status != null && status.toLowerCase().indexOf("phone") != -1)
+		{
+			statusIcon = SparkRes.getImageIcon(SparkRes.ON_PHONE_IMAGE);
+			setIcon(statusIcon);
+		}
 
+		// Always change nickname label to black.
+		getNicknameLabel().setForeground((Color) UIManager.get("ContactItemNickname.foreground"));
 
-        if (isAvailable) {
-            getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, fontSize));
-            if (Res.getString("status.online").equals(status) || Res.getString("available").equalsIgnoreCase(status)) {
-                setStatusText("");
-            }
-            else {
-                setStatusText(status);
-            }
-        }
-        else if (presence.isAvailable()) {
-            getNicknameLabel().setFont(new Font("Dialog", Font.ITALIC, fontSize));
-            getNicknameLabel().setForeground(Color.gray);
-            if (status != null) {
-                setStatusText(status);
-            }
-        }
+		if (isAvailable)
+		{
+			getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, fontSize));
+			if (Res.getString("status.online").equals(status)
+				|| Res.getString("available").equalsIgnoreCase(status))
+			{
+				setStatusText("");
+			}
+			else
+			{
+				setStatusText(status);
+			}
+		}
+		else if (presence.isAvailable())
+		{
+			getNicknameLabel().setFont(new Font("Dialog", Font.ITALIC, fontSize));
+			getNicknameLabel().setForeground(Color.gray);
+			if (status != null)
+			{
+				setStatusText(status);
+			}
+		}
 
-        setAvailable(true);
-    }
+		setAvailable(true);
+		
+		if (externalizedFrame != null)
+		{
+			externalizedFrame.setIconImage(((ImageIcon) (SparkManager.getContactList().getContactItemByJID(chatroom.getParticipantJID())).getIcon()).getImage());
+		}
+	}
 
-    /**
-     * Sets the status label text based on the users status.
-     *
-     * @param status the users status.
-     */
-    public void setStatusText(String status) {
-        setStatus(status);
+	/**
+	 * Sets the status label text based on the users status.
+	 * 
+	 * @param status
+	 *           the users status.
+	 */
+	public void setStatusText(String status)
+	{
+		setStatus(status);
 
-        if (ModelUtil.hasLength(status)) {
-            getDescriptionLabel().setText(" - " + status);
-        }
-        else {
-            getDescriptionLabel().setText("");
-        }
-    }
+		if (ModelUtil.hasLength(status))
+		{
+			getDescriptionLabel().setText(" - " + status);
+		}
+		else
+		{
+			getDescriptionLabel().setText("");
+		}
+	}
 
-    /**
-     * The icon to use to show extra information about this contact. An example would be to
-     * represent that this user is from a 3rd party transport.
-     *
-     * @param icon the icon to use.
-     */
-    public void setSideIcon(Icon icon) {
-        sideIcon.setIcon(icon);
-    }
+	/**
+	 * The icon to use to show extra information about this contact. An example
+	 * would be to represent that this user is from a 3rd party transport.
+	 * 
+	 * @param icon
+	 *           the icon to use.
+	 */
+	public void setSideIcon(Icon icon)
+	{
+		sideIcon.setIcon(icon);
+	}
 
-    /**
-     * Shows that the user is coming online.
-     */
-    public void showUserComingOnline() {
-        // Change Font
-        getNicknameLabel().setFont(new Font("Dialog", Font.BOLD, fontSize));
-        getNicknameLabel().setForeground(new Color(255, 128, 0));
-    }
+	/**
+	 * Shows that the user is coming online.
+	 */
+	public void showUserComingOnline()
+	{
+		// Change Font
+		getNicknameLabel().setFont(new Font("Dialog", Font.BOLD, fontSize));
+		getNicknameLabel().setForeground(new Color(255, 128, 0));
+	}
 
-    /**
-     * Shows that the user is going offline.
-     */
-    public void showUserGoingOfflineOnline() {
-        // Change Font
-        getNicknameLabel().setFont(new Font("Dialog", Font.BOLD, fontSize));
-        getNicknameLabel().setForeground(Color.red);
-    }
+	/**
+	 * Shows that the user is going offline.
+	 */
+	public void showUserGoingOfflineOnline()
+	{
+		// Change Font
+		getNicknameLabel().setFont(new Font("Dialog", Font.BOLD, fontSize));
+		getNicknameLabel().setForeground(Color.red);
+	}
 
-    /**
-     * Update avatar icon.
-     */
-    public void updateAvatarInSideIcon() {
-        try {
-            final URL url = getAvatarURL();
-            if (url != null) {
-                if (!avatarsShowing) {
-                    setSideIcon(null);
-                }
-                else {
-                    ImageIcon icon = new ImageIcon(url);
-                    icon = GraphicUtils.scale(icon, iconSize, iconSize);
-                    setSideIcon(icon);
-                }
-            }
-        }
-        catch (MalformedURLException e) {
-            Log.error(e);
-        }
-    }
-
+	/**
+	 * Update avatar icon.
+	 */
+	public void updateAvatarInSideIcon()
+	{
+		try
+		{
+			final URL url = getAvatarURL();
+			if (url != null)
+			{
+				if (!avatarsShowing)
+				{
+					setSideIcon(null);
+				}
+				else
+				{
+					ImageIcon icon = new ImageIcon(url);
+					icon = GraphicUtils.scale(icon, iconSize, iconSize);
+					setSideIcon(icon);
+				}
+			}
+		}
+		catch (MalformedURLException e)
+		{
+			Log.error(e);
+		}
+	}
 
 }
Index: src/java/org/jivesoftware/spark/ui/ContactList.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/ContactList.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ui/ContactList.java	(working copy)
@@ -31,16 +31,16 @@
 import org.jivesoftware.spark.component.VerticalFlowLayout;
 import org.jivesoftware.spark.plugin.ContextMenuListener;
 import org.jivesoftware.spark.plugin.Plugin;
+import org.jivesoftware.spark.ui.rooms.ChatRoomImpl;
 import org.jivesoftware.spark.util.ModelUtil;
 import org.jivesoftware.spark.util.ResourceUtils;
+import org.jivesoftware.spark.util.SwingTimerTask;
 import org.jivesoftware.spark.util.TaskEngine;
 import org.jivesoftware.spark.util.log.Log;
 import org.jivesoftware.sparkimpl.profile.VCardManager;
 import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
 import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
 
-import sun.util.logging.resources.logging;
-
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.ActionEvent;
@@ -215,7 +215,6 @@
                 new RosterDialog().showRosterDialog();
             }
         });
-        
     }
 
     /**
@@ -229,7 +228,6 @@
             // We ignore this.
             return;
         }
-
         final Roster roster = SparkManager.getConnection().getRoster();
 
         final String bareJID = StringUtils.parseBareAddress(presence.getFrom());
@@ -1035,7 +1033,12 @@
         }
         else if (e.getSource() == chatMenu) {
             if (activeItem != null) {
-                SparkManager.getChatManager().activateChat(activeItem.getJID(), activeItem.getDisplayName());
+            	if(!(SparkManager.getExternalizedFrame(activeItem.getAlias()) == null))
+         	  	{
+         	  		SparkManager.getExternalizedFrame(activeItem.getAlias()).setVisible(true);
+         	  	}
+            	else
+            		SparkManager.getChatManager().activateChat(activeItem.getJID(), activeItem.getDisplayName());
             }
         }
         else if (e.getSource() == addContactMenu) {
@@ -1153,19 +1156,35 @@
         activeKeyEvent = null;
     }
 
-    public void contactItemDoubleClicked(ContactItem item) {
-        activeItem = item;
-
-        ChatManager chatManager = SparkManager.getChatManager();
-        boolean handled = chatManager.fireContactItemDoubleClicked(item);
-
-        if (!handled) {
-            chatManager.activateChat(item.getJID(), item.getDisplayName());
-        }
-
-        clearSelectionList(item);
-
-        fireContactItemDoubleClicked(item);
+    public void contactItemDoubleClicked(final ContactItem item) {
+        
+   	  JFrame extFrame = SparkManager.getExternalizedFrame(item.getAlias());
+   	  if(extFrame != null)
+   	  {
+   	  	  	extFrame.setVisible(true);
+   	  		extFrame.toFront();
+   	  		extFrame.setState(Frame.NORMAL);
+   	  }
+   	  else
+   	  {
+   		  final ChatManager chatManager = SparkManager.getChatManager();
+   		  if(SettingsManager.getLocalPreferences().isTabsExternalizedOn() && !chatManager.chatRoomExists(item.getJID())) {
+		  	  		chatManager.getChatContainer().externalizeTab(new ChatRoomImpl(item.getJID(), item.getDisplayName(), item.getDisplayName()), chatManager.getChatContainer().getX(), chatManager.getChatContainer().getY(), false);
+		  	  	}
+   		   else {
+			   	activeItem = item;
+			
+			  	  	boolean handled = chatManager.fireContactItemDoubleClicked(item);
+			       
+			  	  	if (!handled) {
+			  	  		chatManager.activateChat(item.getJID(), item.getDisplayName());
+			  	  	}
+			  	  
+			  	  	clearSelectionList(item);
+		
+			  	  	fireContactItemDoubleClicked(item);
+   		   }
+   	  }
     }
 
     public void contactGroupPopup(MouseEvent e, final ContactGroup group) {
Index: src/java/org/jivesoftware/spark/ui/rooms/ChatRoomImpl.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/rooms/ChatRoomImpl.java	(revision 10873)
+++ src/java/org/jivesoftware/spark/ui/rooms/ChatRoomImpl.java	(working copy)
@@ -10,6 +10,23 @@
 
 package org.jivesoftware.spark.ui.rooms;
 
+import java.awt.Color;
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.TimerTask;
+
+import javax.swing.Icon;
+import javax.swing.JComponent;
+import javax.swing.SwingUtilities;
+import javax.swing.event.DocumentEvent;
+
 import org.jivesoftware.resource.Res;
 import org.jivesoftware.resource.SparkRes;
 import org.jivesoftware.smack.Roster;
@@ -30,6 +47,7 @@
 import org.jivesoftware.spark.ChatManager;
 import org.jivesoftware.spark.PresenceManager;
 import org.jivesoftware.spark.SparkManager;
+import org.jivesoftware.spark.ui.ChatContainer;
 import org.jivesoftware.spark.ui.ChatRoom;
 import org.jivesoftware.spark.ui.ChatRoomButton;
 import org.jivesoftware.spark.ui.ContactItem;
@@ -47,19 +65,6 @@
 import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
 import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
 
-import javax.swing.Icon;
-import javax.swing.SwingUtilities;
-import javax.swing.event.DocumentEvent;
-
-import java.awt.*;
-import java.awt.event.ActionEvent;
-import java.text.DateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.TimerTask;
-
 /**
  * This is the Person to Person implementation of <code>ChatRoom</code>
  * This room only allows for 1 to 1 conversations.
@@ -93,9 +98,13 @@
 
     // Information button
     private ChatRoomButton infoButton;
-
+    
     private ChatRoomButton addToRosterButton;
-
+    
+    private ChatRoomImpl me;
+    
+    private ChatRoomButton internalizeButton;
+    
     /**
      * Constructs a 1-to-1 ChatRoom.
      *
@@ -111,11 +120,12 @@
         // Loads the current history for this user.
         loadHistory();
 
+        //throw new Exception("test");
+        
         // Register PacketListeners
         PacketFilter fromFilter = new FromMatchesFilter(participantJID);
         PacketFilter orFilter = new OrFilter(new PacketTypeFilter(Presence.class), new PacketTypeFilter(Message.class));
         PacketFilter andFilter = new AndFilter(orFilter, fromFilter);
-
         SparkManager.getConnection().addPacketListener(this, andFilter);
 
         // The roomname will be the participantJID
@@ -135,15 +145,17 @@
         presence = PresenceManager.getPresence(participantJID);
 
         roster = SparkManager.getConnection().getRoster();
-
+        
         RosterEntry entry = roster.getEntry(participantJID);
 
-        tabIcon = PresenceManager.getIconFromPresence(presence);
+//      tabIcon = PresenceManager.getIconFromPresence(presence);
 
         // Create toolbar buttons.
         infoButton = new ChatRoomButton("", SparkRes.getImageIcon(SparkRes.PROFILE_IMAGE_24x24));
         infoButton.setToolTipText(Res.getString("message.view.information.about.this.user"));
 
+       
+        
         // Create basic toolbar.
         getToolBar().addChatRoomButton(infoButton);
 
@@ -266,7 +278,6 @@
         catch (Exception ex) {
             Log.error("Error sending message", ex);
         }
-
         // Before sending message, let's add our full jid for full verification
         message.setType(Message.Type.chat);
         message.setTo(participantJID);
@@ -429,7 +440,6 @@
                     if (message.getBody() != null) {
                         participantJID = message.getFrom();
                         insertMessage(message);
-
                         showTyping(false);
                     }
                 }
@@ -480,7 +490,7 @@
         if (messageEvent != null) {
             checkEvents(message.getFrom(), message.getPacketID(), messageEvent);
         }
-
+        
         getTranscriptWindow().insertMessage(participantNickname, message, ChatManager.FROM_COLOR, Color.white);
 
         // Set the participant jid to their full JID.
@@ -669,10 +679,9 @@
     // I would normally use the command pattern, but
     // have no real use when dealing with just a couple options.
     public void actionPerformed(ActionEvent e) {
-
         if (e.getSource() == infoButton) {
             VCardManager vcard = SparkManager.getVCardManager();
-            vcard.viewProfile(participantJID, SparkManager.getChatManager().getChatContainer());
+            vcard.viewProfile(participantJID, (JComponent)infoButton.getParent().getParent().getParent());
         }
         else if (e.getSource() == addToRosterButton) {
             RosterDialog rosterDialog = new RosterDialog();
@@ -683,4 +692,27 @@
             super.actionPerformed(e);
         }
     }
+
+    public void setInternalizeButton(ChatRoomButton intButton)
+    {
+   	 internalizeButton = intButton;
+	    internalizeButton.addActionListener(new ActionListener() {
+	       public void actionPerformed(ActionEvent actionEvent) 
+	       {
+	      	 ChatRoomImpl externalChatroom = (ChatRoomImpl)internalizeButton.getParent().getParent().getParent();
+	      	 SparkManager.getWorkspace().getTranscriptPlugin().chatRoomClosed(externalChatroom);
+	      	 internalizeTab(externalChatroom);
+	      	 externalChatroom.closeChatRoom();
+	       }
+	   });
+    }
+    
+    public void internalizeTab(ChatRoomImpl chatroom){
+		 SparkManager.getExternalizedFrame(chatroom.getParticipantNickname()).setVisible(false);
+ 	  	 SparkManager.getExternalizedFrame(chatroom.getParticipantNickname()).setTitle("");
+ 	  	 ChatContainer chatContainer = SparkManager.getChatManager().getChatContainer();
+ 	  	 String[] jid = chatroom.getParticipantJID().split("/spark");
+ 	  	 chatContainer.addChatRoom(new ChatRoomImpl(jid[0], chatroom.getParticipantNickname(), chatroom.getTabTitle()));
+ 	  	 chatContainer.setSelectedTab(chatContainer.getTabAt(chatContainer.indexOfTab(chatroom.getTabTitle())));
+    }
 }
Index: src/java/org/jivesoftware/spark/ui/rooms/GroupChatRoom.java
===================================================================
--- src/java/org/jivesoftware/spark/ui/rooms/GroupChatRoom.java	(revision 10865)
+++ src/java/org/jivesoftware/spark/ui/rooms/GroupChatRoom.java	(working copy)
@@ -591,7 +591,6 @@
             if (ModelUtil.hasLength(message.getBody()) && !isFromMe) {
                 // Update transcript
                 super.insertMessage(message);
-
                 String from = StringUtils.parseResource(message.getFrom());
 
                 if (inf != null) {
Index: src/java/org/jivesoftware/sparkimpl/plugin/alerts/BroadcastPlugin.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/plugin/alerts/BroadcastPlugin.java	(revision 10837)
+++ src/java/org/jivesoftware/sparkimpl/plugin/alerts/BroadcastPlugin.java	(working copy)
@@ -273,7 +273,6 @@
                 SparkManager.getChatManager().getChatContainer().addChatRoom(chatRoom);
             }
 
-
             chatRoom.insertMessage(message);
             broadcastRooms.add(chatRoom);
         }
Index: src/java/org/jivesoftware/sparkimpl/plugin/alerts/BuzzPlugin.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/plugin/alerts/BuzzPlugin.java	(revision 10873)
+++ src/java/org/jivesoftware/sparkimpl/plugin/alerts/BuzzPlugin.java	(working copy)
@@ -22,6 +22,7 @@
 import org.jivesoftware.spark.ui.ChatRoomListener;
 import org.jivesoftware.spark.ui.ChatRoomNotFoundException;
 import org.jivesoftware.spark.ui.ContactItem;
+import org.jivesoftware.spark.ui.ShakeWindow;
 import org.jivesoftware.spark.ui.rooms.ChatRoomImpl;
 import org.jivesoftware.spark.util.SwingTimerTask;
 import org.jivesoftware.spark.util.TaskEngine;
@@ -117,11 +118,19 @@
         }
 
         ChatFrame chatFrame = SparkManager.getChatManager().getChatContainer().getChatFrame();
-        if (chatFrame != null && chatFrame.isVisible()) {
-            chatFrame.buzz();
-            SparkManager.getChatManager().getChatContainer().activateChatRoom(room);
+        
+        if(SparkManager.getExternalizedFrame(room.getTabTitle()) != null)
+        {
+      	  chatFrame.buzz(SparkManager.getExternalizedFrame(room.getTabTitle()));
+        }
+        else
+        {
+	        if (chatFrame != null && chatFrame.isVisible()) {
+	            chatFrame.buzz(chatFrame);
+	            SparkManager.getChatManager().getChatContainer().activateChatRoom(room);
+	        }
         }
-
+        
         // Insert offline message
         room.getTranscriptWindow().insertNotificationMessage("BUZZ", ChatManager.NOTIFICATION_COLOR);
         room.scrollToBottom();
Index: src/java/org/jivesoftware/sparkimpl/plugin/alerts/SparkToaster.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/plugin/alerts/SparkToaster.java	(revision 10865)
+++ src/java/org/jivesoftware/sparkimpl/plugin/alerts/SparkToaster.java	(working copy)
@@ -230,7 +230,6 @@
                 if (customAction != null) {
                     customAction.actionPerformed(null);
                 }
-
                 if (hideable) {
                     setVisible(false);
                     dispose();
Index: src/java/org/jivesoftware/sparkimpl/plugin/emoticons/Emoticon.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/plugin/emoticons/Emoticon.java	(revision 10873)
+++ src/java/org/jivesoftware/sparkimpl/plugin/emoticons/Emoticon.java	(working copy)
@@ -11,6 +11,8 @@
 package org.jivesoftware.sparkimpl.plugin.emoticons;
 
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.List;
 import java.io.File;
 
@@ -25,8 +27,10 @@
     private String emoticonName;
     private File emoticonDirectory;
     private List<String> equivalants = new ArrayList<String>();
-
-
+    private static final List<String> allEquivalants = new ArrayList<String>();
+    private static final Hashtable<String, String> equivalantsMap = new Hashtable<String, String>();
+    private static final Hashtable<String, Emoticon> emoticons 	 = new Hashtable<String, Emoticon>();
+  
     /**
      * Creates a single Emoticon entry.
      *
@@ -38,8 +42,17 @@
     public Emoticon(String nameOfImage, String emoticonName, List<String> equivalants, File emoticonDirectory) {
         this.imageName = nameOfImage;
         this.emoticonName = emoticonName;
-
         this.equivalants = equivalants;
+        
+        
+        for(String string : equivalants)
+        {
+      	  allEquivalants.add(string);
+      	  equivalantsMap.put(string, emoticonName);
+        }
+        emoticons.put(emoticonName, this);
+        
+        
         this.emoticonDirectory = emoticonDirectory;
     }
 
@@ -81,4 +94,19 @@
     public File getEmoticonDirectory(){
         return emoticonDirectory;
     }
+    
+    public static List<String> getAllEquivalants()
+    {
+   	 return allEquivalants;
+    }
+    
+    public static Emoticon getEmoticon(String key)
+    {
+   	 return emoticons.get(key);
+    }
+    
+    public static String getEmoticonname(String key)
+    {
+   	 return equivalantsMap.get(key);
+    }
 }
Index: src/java/org/jivesoftware/sparkimpl/plugin/emoticons/EmoticonManager.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/plugin/emoticons/EmoticonManager.java	(revision 10873)
+++ src/java/org/jivesoftware/sparkimpl/plugin/emoticons/EmoticonManager.java	(working copy)
@@ -326,18 +326,17 @@
      */
     public Emoticon getEmoticon(String key) {
         final Collection<Emoticon> emoticons = emoticonMap.get(getActiveEmoticonSetName());
-
-        for (Emoticon emoticon : emoticons) {
-            for (String string : emoticon.getEquivalants()) {
-                if (key.toLowerCase().equals(string.toLowerCase())) {
-                    return emoticon;
-                }
-            }
-        }
-
+	     for (Emoticon emoticon : emoticons) {
+	        for (String string : emoticon.getEquivalants()) {
+	           if (key.toLowerCase().equals(string.toLowerCase())) {
+	              	 return emoticon;
+	           }
+	         }
+	     }
         return null;
     }
 
+
     /**
      * Returns the Icon that is mapped to a given key.
      *
@@ -345,19 +344,17 @@
      * @return the Icon representing the key.
      */
     public ImageIcon getEmoticonImage(String key) {
-        final Emoticon emoticon = getEmoticon(key);
-        if (emoticon != null) {
-            ImageIcon icon = imageMap.get(key);
-            if (icon == null) {
-                URL url = getEmoticonURL(emoticon);
-                icon = new ImageIcon(url);
-                imageMap.put(key, icon);
-            }
-
-            return imageMap.get(key);
-        }
-
-        return null;
+   	  final Emoticon emoticon = getEmoticon(key);
+	     if (emoticon != null) {
+	        ImageIcon icon = imageMap.get(key);
+	        if (icon == null) {
+	           URL url = getEmoticonURL(emoticon);
+	           icon = new ImageIcon(url);
+	           imageMap.put(key, icon);
+	        }
+	        return imageMap.get(key);
+	     }
+    	  return null;
     }
 
     /**
Index: src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscriptPlugin.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscriptPlugin.java	(revision 10873)
+++ src/java/org/jivesoftware/sparkimpl/plugin/transcripts/ChatTranscriptPlugin.java	(working copy)
@@ -20,7 +20,6 @@
 import org.jivesoftware.spark.SparkManager;
 import org.jivesoftware.spark.component.BackgroundPanel;
 import org.jivesoftware.spark.plugin.ContextMenuListener;
-import org.jivesoftware.spark.ui.ChatInputEditor;
 import org.jivesoftware.spark.ui.ChatRoom;
 import org.jivesoftware.spark.ui.ChatRoomButton;
 import org.jivesoftware.spark.ui.ChatRoomClosingListener;
@@ -41,14 +40,10 @@
 import javax.swing.JDialog;
 import javax.swing.JEditorPane;
 import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
 import javax.swing.JTextArea;
-import javax.swing.JTextField;
-import javax.swing.event.HyperlinkListener;
 import javax.swing.text.html.HTMLEditorKit;
 
 import java.awt.BorderLayout;
@@ -59,7 +54,6 @@
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.io.File;
-import java.io.IOException;
 import java.text.SimpleDateFormat;
 import java.util.Comparator;
 import java.util.Date;
@@ -77,9 +71,9 @@
     private final String dateFormat = ((SimpleDateFormat)SimpleDateFormat.getDateInstance(SimpleDateFormat.FULL)).toPattern();
     private final SimpleDateFormat notificationDateFormatter;
     private final SimpleDateFormat messageDateFormatter;
-
+    private Message lastMessage;
     private JDialog Frame;
-    private JEditorPane jEditorPane1 ;
+    
     /**
      * Register the listeners for transcript persistence.
      */
@@ -173,6 +167,15 @@
                 }
             }
         }
+        
+        for (ChatRoom room : SparkManager.getExternalizedChatRooms()) {
+           if (room instanceof ChatRoomImpl) {
+               ChatRoomImpl roomImpl = (ChatRoomImpl)room;
+               if (roomImpl.isActive()) {
+                   persistChatRoom(roomImpl);
+               }
+           }
+       }
     }
 
     public boolean canShutDown() {
@@ -184,13 +187,14 @@
         if (!pref.isChatHistoryEnabled()) {
             return;
         }
-
+        
         final String jid = room.getRoomname();
+      
         File transcriptFile = ChatTranscripts.getTranscriptFile(jid);
         if (!transcriptFile.exists()) {
             return;
         }
-
+       
         if (room instanceof ChatRoomImpl) {
             new ChatRoomDecorator(room);
         }
@@ -207,7 +211,7 @@
         }
     }
 
-    private void persistChatRoom(final ChatRoom room) {
+    public void persistChatRoom(final ChatRoom room) {
         LocalPreferences pref = SettingsManager.getLocalPreferences();
         if (!pref.isChatHistoryEnabled()) {
             return;
@@ -218,6 +222,7 @@
         final List<Message> transcripts = room.getTranscripts();
         ChatTranscript transcript = new ChatTranscript();
         for (Message message : transcripts) {
+      	  	lastMessage = message;
             HistoryMessage history = new HistoryMessage();
             history.setTo(message.getTo());
             history.setFrom(message.getFrom());
@@ -233,6 +238,9 @@
         }
 
         ChatTranscripts.appendToTranscript(jid, transcript);
+
+        if(room instanceof ChatRoomImpl)
+      	  room.getTranscripts().clear();
     }
 
     public void chatRoomActivated(ChatRoom room) {
@@ -251,6 +259,11 @@
         // Do nothing.
     }
 
+    public Message getLastMessage()
+    {
+   	 return lastMessage;
+    }
+    
     private void showHistory(final String jid) {
 
         SwingWorker transcriptLoader = new SwingWorker() {
Index: src/java/org/jivesoftware/sparkimpl/preference/PreferenceDialog.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/preference/PreferenceDialog.java	(revision 10865)
+++ src/java/org/jivesoftware/sparkimpl/preference/PreferenceDialog.java	(working copy)
@@ -79,7 +79,7 @@
                 JOptionPane.OK_CANCEL_OPTION, null, options, options[0]);
         mainPanel.add(pane, BorderLayout.CENTER);
         preferenceDialog.pack();
-        preferenceDialog.setSize(700, 480);
+        preferenceDialog.setSize(700, 520);
         preferenceDialog.setContentPane(mainPanel);
         preferenceDialog.setLocationRelativeTo(SparkManager.getMainWindow());
 
Index: src/java/org/jivesoftware/sparkimpl/preference/chat/ChatPreference.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/preference/chat/ChatPreference.java	(revision 10873)
+++ src/java/org/jivesoftware/sparkimpl/preference/chat/ChatPreference.java	(working copy)
@@ -70,6 +70,7 @@
                 boolean chatHistoryHidden = !localPreferences.isChatHistoryEnabled();
                 boolean prevChatHistoryHidden = !localPreferences.isPrevChatHistoryEnabled();
                 boolean tabsOnTop = localPreferences.isTabTopPosition();
+                boolean tabsExternalized = localPreferences.isTabsExternalizedOn();
                 boolean buzzAllowed = localPreferences.isBuzzEnabled();
                 panel.setShowTime(showTime);
                 panel.setSpellCheckerOn(spellCheckerOn);
@@ -78,6 +79,7 @@
                 panel.setPrevChatHistoryHidden(prevChatHistoryHidden);
                 panel.setChatTimeoutTime(localPreferences.getChatLengthDefaultTimeout());
                 panel.setTabsOnTop(tabsOnTop);
+                panel.setTabsExternalized(tabsExternalized);
                 panel.setBuzzEnabled(buzzAllowed);
             }
         };
@@ -99,6 +101,7 @@
         pref.setPrevChatHistoryEnabled(!panel.isPrevChatHistoryHidden());
         pref.setChatLengthDefaultTimeout(panel.getChatTimeoutTime());
         pref.setTabsOnTop(panel.isTabsOnTop());
+        pref.setTabsExternalized(panel.isTabsExternalizeOn());
         pref.setBuzzEnabled(panel.isBuzzEnabled());
 
         SettingsManager.saveSettings();
Index: src/java/org/jivesoftware/sparkimpl/preference/chat/ChatPreferencePanel.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/preference/chat/ChatPreferencePanel.java	(revision 10873)
+++ src/java/org/jivesoftware/sparkimpl/preference/chat/ChatPreferencePanel.java	(working copy)
@@ -58,6 +58,7 @@
     private JCheckBox hideChatHistory = new JCheckBox();
     private JCheckBox hidePrevChatHistory = new JCheckBox();
     private JCheckBox tabsOnTopBox = new JCheckBox();
+    private JCheckBox tabsExternalize = new JCheckBox();
     private JTextField chatTimeoutField = new JTextField();
     private JCheckBox buzzBox = new JCheckBox();
 
@@ -91,6 +92,7 @@
         ResourceUtils.resButton(hideChatHistory, Res.getString("checkbox.disable.chat.history"));
         ResourceUtils.resButton(hidePrevChatHistory, Res.getString("checkbox.disable.prev.chat.history"));
         ResourceUtils.resButton(tabsOnTopBox, Res.getString("checkbox.tabs.on.top"));
+        ResourceUtils.resButton(tabsExternalize, Res.getString("checkbox.tabs.externalize"));
         ResourceUtils.resButton(buzzBox, Res.getString("checkbox.allow.buzz"));
 
         generalPanel.setBorder(BorderFactory.createTitledBorder(Res.getString("group.general.information")));
@@ -113,12 +115,13 @@
         chatWindowPanel.add(hideChatHistory, new GridBagConstraints(0, 3, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
         chatWindowPanel.add(hidePrevChatHistory, new GridBagConstraints(0, 4, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
         chatWindowPanel.add(tabsOnTopBox, new GridBagConstraints(0, 5, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
-        chatWindowPanel.add(buzzBox, new GridBagConstraints(0, 6, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+        chatWindowPanel.add(tabsExternalize, new GridBagConstraints(0, 6, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+        chatWindowPanel.add(buzzBox, new GridBagConstraints(0, 7, 2, 1, 1.0, 1.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        
         JLabel chatTimeoutLabel = new JLabel();
         ResourceUtils.resLabel(chatTimeoutLabel, chatTimeoutField, Res.getString("label.minutes.before.stale.chat") + ":");
-        chatWindowPanel.add(chatTimeoutLabel, new GridBagConstraints(0, 7, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
-        chatWindowPanel.add(chatTimeoutField, new GridBagConstraints(1, 7, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 50, 0));
+        chatWindowPanel.add(chatTimeoutLabel, new GridBagConstraints(0, 8, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
+        chatWindowPanel.add(chatTimeoutField, new GridBagConstraints(1, 8, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 50, 0));
 
 
         generalPanel.add(passwordLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
@@ -236,6 +239,14 @@
     public boolean isTabsOnTop(){
         return tabsOnTopBox.isSelected();
     }
+    
+    public void setTabsExternalized(boolean externalized) {
+       tabsExternalize.setSelected(externalized);
+    }
+    
+    public boolean isTabsExternalizeOn(){
+       return tabsExternalize.isSelected();
+    }
 
     public void setBuzzEnabled(boolean allowBuzz){
         buzzBox.setSelected(allowBuzz);
Index: src/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java
===================================================================
--- src/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java	(revision 10873)
+++ src/java/org/jivesoftware/sparkimpl/settings/local/LocalPreferences.java	(working copy)
@@ -547,6 +547,14 @@
         return getBoolean("tabsOnTop", true);
     }
 
+    public void setTabsExternalized(boolean externalized) {
+   	 setBoolean("tabsExternalized", externalized);
+    }
+    
+    public boolean isTabsExternalizedOn() {
+   	 return getBoolean("tabsExternalized", false);
+    }
+    
     public void setBuzzEnabled(boolean enabled) {
         setBoolean("buzzEnabled", enabled);
     }
Index: src/resources/i18n/spark_i18n.properties
===================================================================
--- src/resources/i18n/spark_i18n.properties	(revision 10873)
+++ src/resources/i18n/spark_i18n.properties	(working copy)
@@ -322,6 +322,7 @@
 checkbox.split.chat.window = Dock &Windows (Requires restart)
 checkbox.start.in.tray = &Start in System Tray
 checkbox.tabs.on.top = &Chat tabs appear on top (Requires restart)
+checkbox.tabs.externalize = New chats open in separate windows 
 checkbox.use.compression = Use Co&mpression
 checkbox.use.proxy.server = &Use Proxy Server
 checkbox.use.system.look.and.feel = Use System Look And &Feel (Requires restart)
@@ -611,6 +612,7 @@
 message.generic.reconnect.message = You have lost your connection to the server. To login again, click on the Reconnect button below.
 message.idle.for = Idle for {0}
 message.image.too.large = This image is too large to use. Please specify an image 16k or smaller.
+message.internalize.tab = Reattach this window to the tab stack
 message.invalid.jabber.id = Not a valid Jabber ID
 message.invalid.jid.error = The JID specified is invalid.
 message.invalid.status = Specify a valid status message.
Index: src/resources/i18n/spark_i18n_de.properties
===================================================================
--- src/resources/i18n/spark_i18n_de.properties	(revision 10873)
+++ src/resources/i18n/spark_i18n_de.properties	(working copy)
@@ -214,6 +214,7 @@
 checkbox.start.in.tray = &Spark automatisch in der Taskleiste starten
 checkbox.split.chat.window = &Fenster 'andocken' (benötigt Neustart von Spark)
 checkbox.tabs.on.top = &Chat tabs oben anzeigen (benötigt Neustart von Spark)
+checkbox.tabs.externalize = Neue Chat Tabs öffnen in seperaten Fenstern
 checkbox.allow.buzz = "Buzzer" Funktion aktivieren.
 checkbox.enable.emoticons = Em&oticons aktivieren 
 checkbox.use.system.look.and.feel = System Look And &Feel verwenden (benötigt Neustart von Spark)
@@ -338,6 +339,7 @@
 message.close.stale.chats = Inaktive Chats schließen 
 message.last.message.received = Letzte Nachricht empfangen um {0}
 message.shared.group = Gemeinsame Gruppen
+message.internalize.tab = Chatroom wieder in Tabliste einbinden
 message.is.shared.group = {0} ist eine gemeinsame Gruppe.
 message.delete.confirmation = {0} - Wirklich löschen?
 message.idle.for = Inaktiv seit {0}

