Files
Spark/src/java/org/jivesoftware/spark/ui/ChatContainer.java
Derek DeMoro 37d657ce06 Fix NPE in ChatRoom
git-svn-id: http://svn.igniterealtime.org/svn/repos/spark/trunk@4946 b35dd754-fafc-0310-a699-88a17e54d16e
2006-08-16 22:38:10 +00:00

1273 lines
43 KiB
Java

/**
* $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;
import org.jivesoftware.MainWindow;
import org.jivesoftware.Spark;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.FromContainsFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.spark.SparkManager;
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.ui.rooms.ChatRoomImpl;
import org.jivesoftware.spark.ui.rooms.GroupChatRoom;
import org.jivesoftware.spark.ui.status.StatusItem;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.SwingWorker;
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;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
/**
* Contains all <code>ChatRoom</code> objects within Spark.
*
* @author Derek DeMoro
*/
public class ChatContainer extends SparkTabbedPane implements MessageListener, ChangeListener {
/**
* List of all ChatRoom Listeners.
*/
private final List<ChatRoomListener> chatRoomListeners = new ArrayList<ChatRoomListener>();
private final List<ChatRoom> chatRoomList = new ArrayList<ChatRoom>();
private final Map<String, PacketListener> presenceMap = new HashMap<String, PacketListener>();
private static final String WELCOME_TITLE = SparkRes.getString(SparkRes.WELCOME);
private ChatFrame chatFrame;
/**
* Creates the ChatRooms to hold all ChatRooms.
*/
public ChatContainer() {
// Set minimum size
setMinimumSize(new Dimension(400, 200));
// Don't allow tabs to shrink and allow scrolling.
addSparkTabbedPaneListener(new SparkTabbedPaneListener() {
public void tabRemoved(SparkTab tab, Component component, int index) {
stateChanged(null);
cleanupChatRoom((ChatRoom)component);
}
public void tabAdded(SparkTab tab, Component component, int index) {
stateChanged(null);
}
public void tabSelected(SparkTab tab, Component component, int index) {
stateChanged(null);
}
public void allTabsRemoved() {
chatFrame.setTitle("");
chatFrame.setVisible(false);
}
});
setCloseButtonEnabled(true);
// Add Key Navigation
addKeyNavigation();
this.setFocusable(false);
setOpaque(true);
setBackground(Color.white);
}
/**
* Adds navigation capability to chat rooms. Users can navigate using the alt-left or right arrow keys.
*/
private void addKeyNavigation() {
KeyStroke leftStroke = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0);
String leftStrokeString = org.jivesoftware.spark.util.StringUtils.keyStroke2String(leftStroke);
// Handle Left Arrow
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("alt " + leftStrokeString + ""), "navigateLeft");
this.getActionMap().put("navigateLeft", new AbstractAction("navigateLeft") {
public void actionPerformed(ActionEvent evt) {
int selectedIndex = getSelectedIndex();
if (selectedIndex > 0) {
setSelectedIndex(selectedIndex - 1);
}
else {
setSelectedIndex(getTabCount() - 1);
}
}
});
KeyStroke rightStroke = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0);
String rightStrokeString = org.jivesoftware.spark.util.StringUtils.keyStroke2String(rightStroke);
// Handle Right Arrow
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("alt " + rightStrokeString + ""), "navigateRight");
this.getActionMap().put("navigateRight", new AbstractAction("navigateRight") {
public void actionPerformed(ActionEvent evt) {
int selectedIndex = getSelectedIndex();
if (selectedIndex > -1) {
int count = getTabCount();
if (selectedIndex == (count - 1)) {
setSelectedIndex(0);
}
else {
setSelectedIndex(selectedIndex + 1);
}
}
}
});
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "escape");
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control W"), "escape");
this.getActionMap().put("escape", new AbstractAction("escape") {
public void actionPerformed(ActionEvent evt) {
closeActiveRoom();
}
});
KeyStroke appleStroke = KeyStroke.getKeyStroke(Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), 0);
String appleString = org.jivesoftware.spark.util.StringUtils.keyStroke2String(appleStroke);
// Handle Apple Key W
this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(appleString + "w"), "appleStroke");
this.getActionMap().put("appleStroke", new AbstractAction("appleStroke") {
public void actionPerformed(ActionEvent evt) {
closeActiveRoom();
}
});
}
/**
* Adds a new ChatRoom to Spark.
*
* @param room the ChatRoom to add.
*/
public 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()));
// Next, create a packet listener. We use an anonymous inner class for brevity.
PacketListener myListener = new PacketListener() {
public void processPacket(final Packet packet) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
handleRoomPresence((Presence)packet);
}
});
}
};
SparkManager.getConnection().addPacketListener(myListener, presenceFilter);
// Add to PresenceMap
presenceMap.put(room.getRoomname(), myListener);
String tooltip = "";
if (room instanceof ChatRoomImpl) {
tooltip = ((ChatRoomImpl)room).getParticipantJID();
String nickname = SparkManager.getUserManager().getUserNicknameFromJID(((ChatRoomImpl)room).getParticipantJID());
tooltip = "<html><body><b>Contact:&nbsp;</b>" + nickname + "<br><b>JID:&nbsp;</b>" + tooltip;
}
else {
tooltip = ((GroupChatRoom)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);
}
});
room.addMessageListener(this);
// Remove brand panel
final String title = getTabAt(0).getActualText();
if (title.equals(WELCOME_TITLE)) {
chatFrame.setTitle(room.getRoomTitle());
}
SwingWorker worker = new SwingWorker() {
public Object construct() {
try {
Thread.sleep(100);
}
catch (InterruptedException e1) {
Log.error(e1);
}
return "";
}
public void finished() {
checkVisibility(room);
}
};
worker.start();
// Add to ChatRoomList
chatRoomList.add(room);
fireChatRoomOpened(room);
focusChat();
}
/**
* Handles the presence of a one to one chat room.
*
* @param p the presence to handle.
*/
private void handleRoomPresence(final Presence p) {
final String roomname = StringUtils.parseBareAddress(p.getFrom());
ChatRoom chatRoom;
try {
chatRoom = getChatRoom(roomname);
}
catch (ChatRoomNotFoundException e1) {
Log.error("Could not locate chat room.", e1);
return;
}
final String userid = StringUtils.parseResource(p.getFrom());
if (p.getType() == Presence.Type.unavailable) {
fireUserHasLeft(chatRoom, userid);
}
else if (p.getType() == Presence.Type.available) {
fireUserHasJoined(chatRoom, userid);
}
// Change tab icon
if (chatRoom instanceof ChatRoomImpl) {
StatusItem statusItem = SparkManager.getWorkspace().getStatusBar().getItemFromPresence(p);
Icon tabIcon = null;
if (statusItem == null && p == null) {
tabIcon = SparkRes.getImageIcon(SparkRes.CLEAR_BALL_ICON);
}
else if (statusItem == null && p != null && p.getType() == Presence.Type.available) {
tabIcon = SparkRes.getImageIcon(SparkRes.GREEN_BALL);
}
else {
String status = p.getStatus();
if (status != null && status.indexOf("phone") != -1) {
tabIcon = SparkRes.getImageIcon(SparkRes.ON_PHONE_IMAGE);
}
else if (statusItem == null) {
tabIcon = SparkRes.getImageIcon(SparkRes.CLEAR_BALL_ICON);
}
else {
tabIcon = statusItem.getIcon();
}
}
Icon icon = SparkManager.getChatManager().getPresenceIconForContactHandler(p);
if (icon != null) {
tabIcon = icon;
}
int tabLoc = indexOfComponent(chatRoom);
if (tabLoc != -1) {
getTabAt(tabLoc).setIcon(tabIcon);
}
}
}
private void checkVisibility(ChatRoom chatRoom) {
if (!chatFrame.isVisible() && SparkManager.getMainWindow().isFocused()) {
chatFrame.setState(Frame.NORMAL);
chatFrame.setVisible(true);
}
else if (chatFrame.isVisible() && !chatFrame.isInFocus()) {
flashWindow(chatRoom);
}
else if (chatFrame.isVisible() && chatFrame.getState() == Frame.ICONIFIED) {
// Set to new tab.
int tabLocation = indexOfComponent(chatRoom);
setSelectedIndex(tabLocation);
// If the ContactList is in the tray, we need better notification by flashing
// the chatframe.
flashWindow(chatRoom);
}
// Handle when chat frame is visible but the Contact List is not.
else if (chatFrame.isVisible() && !SparkManager.getMainWindow().isVisible()) {
flashWindow(chatRoom);
}
else if (!chatFrame.isVisible()) {
if (Spark.isWindows()) {
chatFrame.setFocusableWindowState(false);
chatFrame.setState(Frame.ICONIFIED);
}
chatFrame.setVisible(true);
// Set to new tab.
int tabLocation = indexOfComponent(chatRoom);
setSelectedIndex(tabLocation);
// If the ContactList is in the tray, we need better notification by flashing
// the chatframe.
if (!SparkManager.getMainWindow().isVisible()) {
flashWindow(chatRoom);
}
else if (chatFrame.getState() == Frame.ICONIFIED) {
flashWindow(chatRoom);
}
}
}
/**
* Removes the ChatRoom resources.
*
* @param room the room to remove.
*/
private void cleanupChatRoom(ChatRoom room) {
final PacketListener listener = (PacketListener)presenceMap.get(room.getRoomname());
if (listener != null) {
SparkManager.getConnection().removePacketListener(listener);
}
fireChatRoomClosed(room);
room.removeMessageListener(this);
// Remove mappings
presenceMap.remove(room.getRoomname());
chatRoomList.remove(room);
}
/**
* Close all chat rooms.
*/
public void closeAllChatRooms() {
Iterator iter = new ArrayList(chatRoomList).iterator();
while (iter.hasNext()) {
ChatRoom chatRoom = (ChatRoom)iter.next();
closeTab(chatRoom);
chatRoom.closeChatRoom();
}
}
/**
* Leaves a ChatRoom. Leaving a chat room does everything but close the room itself.
*
* @param room the room to leave.
*/
public void leaveChatRoom(ChatRoom room) {
// Notify that the chatroom has been left.
fireChatRoomLeft(room);
room.leaveChatRoom();
// Setting the tab to be "disabled". Will not actually disable the tab because
// that doesn't allow for selection.
final int location = indexOfComponent(room);
if (location != -1) {
// setBackgroundAt(location, Color.GRAY);
// setForegroundAt(location, Color.GRAY);
// setIconAt(location, null);
}
final PacketListener listener = (PacketListener)presenceMap.get(room.getRoomname());
if (listener != null) {
SparkManager.getConnection().removePacketListener(listener);
}
}
/**
* Returns a ChatRoom by name.
*
* @param roomName the name of the ChatRoom.
* @return the ChatRoom
* @throws ChatRoomNotFoundException
*/
public ChatRoom getChatRoom(String roomName) throws ChatRoomNotFoundException {
for (int i = 0; i < getTabCount(); i++) {
ChatRoom room = null;
try {
room = getChatRoom(i);
}
catch (ChatRoomNotFoundException e1) {
// Ignore
}
if (room != null && room.getRoomname().equalsIgnoreCase(roomName) && room.isActive()) {
return room;
}
}
throw new ChatRoomNotFoundException(roomName + " not found.");
}
/**
* Returns a ChatRoom in the specified tab location.
*
* @param location the tab location.
* @return the ChatRoom found.
* @throws ChatRoomNotFoundException
*/
public ChatRoom getChatRoom(int location) throws ChatRoomNotFoundException {
if (getTabCount() < location) {
return null;
}
try {
Component comp = getComponentAt(location);
if (comp != null && comp instanceof ChatRoom) {
return (ChatRoom)comp;
}
}
catch (ArrayIndexOutOfBoundsException outOfBoundsEx) {
Log.error("Error getting Chat Room", outOfBoundsEx);
}
throw new ChatRoomNotFoundException();
}
/**
* Returns the Active ChatRoom.
*
* @return the ChatRoom active in the tabbed pane.
* @throws ChatRoomNotFoundException is thrown if no chat room is found.
*/
public ChatRoom getActiveChatRoom() throws ChatRoomNotFoundException {
int location = getSelectedIndex();
if (location != -1) {
return getChatRoom(location);
}
throw new ChatRoomNotFoundException();
}
/**
* Returns all the ChatRooms found in the UI.
*
* @return all ChatRooms found in the UI.
*/
public Iterator getAllChatRooms() {
return chatRoomList.iterator();
}
/**
* Activates the specified ChatRoom.
*
* @param room the ChatRoom to activate.
*/
public void activateChatRoom(ChatRoom room) {
int tabLocation = indexOfComponent(room);
setSelectedIndex(tabLocation);
if (!chatFrame.isVisible()) {
chatFrame.setVisible(true);
}
if (chatFrame.getState() == Frame.ICONIFIED) {
chatFrame.setState(Frame.NORMAL);
}
chatFrame.requestFocus();
focusChat();
}
/**
* Activates the component in tabbed pane.
*
* @param component the component contained within the tab to activate.
*/
public void activateComponent(Component component) {
int tabLocation = indexOfComponent(component);
if (tabLocation != -1) {
setSelectedIndex(tabLocation);
}
}
/**
* Used for Tray Notifications.
*
* @param room the ChatRoom where the message was received.
* @param message the message received.
*/
public void messageReceived(ChatRoom room, Message message) {
// Check to see if it's a room update.
String from = message.getFrom();
String insertMessage = message.getBody();
if (room.getChatType() == Message.Type.CHAT) {
from = StringUtils.parseName(from);
}
else {
from = StringUtils.parseResource(from);
}
if (ModelUtil.hasLength(from)) {
insertMessage = from + ": " + insertMessage;
}
fireNotifyOnMessage(room);
}
public void fireNotifyOnMessage(final ChatRoom chatRoom) {
ChatRoom activeChatRoom = null;
try {
activeChatRoom = getActiveChatRoom();
}
catch (ChatRoomNotFoundException e1) {
Log.error(e1);
}
if (chatFrame.isVisible() && (chatFrame.getState() == Frame.ICONIFIED || !chatFrame.isInFocus())) {
int tabLocation = indexOfComponent(chatRoom);
setSelectedIndex(tabLocation);
startFlashing(chatRoom);
return;
}
if (!chatFrame.isVisible() && SparkManager.getMainWindow().isFocused()) {
chatFrame.setState(Frame.NORMAL);
chatFrame.setVisible(true);
}
else if (chatFrame.isVisible() && !chatFrame.isInFocus()) {
startFlashing(chatRoom);
}
else if (chatFrame.isVisible() && chatFrame.getState() == Frame.ICONIFIED) {
// Set to new tab.
int tabLocation = indexOfComponent(chatRoom);
setSelectedIndex(tabLocation);
// If the ContactList is in the tray, we need better notification by flashing
// the chatframe.
startFlashing(chatRoom);
}
// Handle when chat frame is visible but the Contact List is not.
else if (chatFrame.isVisible() && !SparkManager.getMainWindow().isVisible() && !chatFrame.isInFocus()) {
startFlashing(chatRoom);
}
else if (!chatFrame.isVisible()) {
if (Spark.isWindows()) {
chatFrame.setFocusableWindowState(false);
chatFrame.setState(Frame.ICONIFIED);
}
chatFrame.setVisible(true);
// Set to new tab.
int tabLocation = indexOfComponent(chatRoom);
setSelectedIndex(tabLocation);
// If the ContactList is in the tray, we need better notification by flashing
// the chatframe.
if (!SparkManager.getMainWindow().isVisible()) {
startFlashing(chatRoom);
}
else if (chatFrame.getState() == Frame.ICONIFIED) {
startFlashing(chatRoom);
}
}
else if (chatRoom != activeChatRoom) {
startFlashing(chatRoom);
}
}
public void messageSent(ChatRoom room, Message message) {
useTabDefault(room);
}
/**
* Notification that the tab pane has been modified. Generally by changing of the tabs.
*
* @param e the ChangeEvent.
*/
public void stateChanged(ChangeEvent e) {
stopFlashing();
// Request focus in Chat Area if selected
final ChatRoom room;
try {
room = getActiveChatRoom();
focusChat();
// Set the title of the room.
chatFrame.setTitle(room.getRoomTitle());
}
catch (ChatRoomNotFoundException e1) {
// Ignore
}
}
private void stopFlashing() {
// Get current tab
int sel = getSelectedIndex();
if (sel != -1) {
final ChatRoom room;
try {
room = getChatRoom(sel);
stopFlashing(room);
}
catch (ChatRoomNotFoundException e1) {
//AgentLog.logError("Could not find chat room.", e1);
}
}
}
/**
* Closes a tab of a room.
*
* @param component the component inside of the tab to close.
*/
public void closeTab(Component component) {
int location = indexOfComponent(component);
if (location == -1) {
return;
}
if (getTabCount() == 0) {
chatFrame.setTitle("");
chatFrame.setVisible(false);
}
this.removeTabAt(location);
}
public void closeActiveRoom() {
ChatRoom room = null;
try {
room = getActiveChatRoom();
}
catch (ChatRoomNotFoundException e1) {
// AgentLog.logError("Chat room not found", e1);
}
// Confirm end session
boolean isGroupChat = room.getChatType() == Message.Type.GROUP_CHAT;
String message = "Would you like to end this session?";
if (true) {
room.closeChatRoom();
return;
}
else {
if (!room.isActive()) {
room.closeChatRoom();
return;
}
}
final int ok = JOptionPane.showConfirmDialog(SparkManager.getMainWindow(), message,
"Confirmation", JOptionPane.YES_NO_OPTION);
if (ok == JOptionPane.OK_OPTION) {
room.closeChatRoom();
return;
}
}
public String toString() {
StringBuffer buf = new StringBuffer();
Iterator iter = chatRoomList.iterator();
while (iter.hasNext()) {
ChatRoom room = (ChatRoom)iter.next();
buf.append("Roomname=").append(room.getRoomname()).append("\n");
}
return buf.toString();
}
/**
* Returns true if there are any Rooms present.
*
* @return true if Rooms are present, otherwise false.
*/
public boolean hasRooms() {
int count = getSelectedIndex();
return count != -1;
}
/**
* Adds a ChatRoom listener to ChatRooms. The
* listener will be called when either a ChatRoom has been
* added, removed, or activated.
*
* @param listener the <code>ChatRoomListener</code> to register
*/
public void addChatRoomListener(ChatRoomListener listener) {
if (!chatRoomListeners.contains(listener)) {
chatRoomListeners.add(listener);
}
}
/**
* Removes the specified <code>ChatRoomListener</code>.
*
* @param listener the <code>ChatRoomListener</code> to remove
*/
public void removeChatRoomListener(ChatRoomListener listener) {
chatRoomListeners.remove(listener);
}
/**
* Notifies users that a <code>ChatRoom</code> has been opened.
*
* @param room - the <code>ChatRoom</code> that has been opened.
*/
protected void fireChatRoomOpened(ChatRoom room) {
final Iterator iter = new ArrayList(chatRoomListeners).iterator();
while (iter.hasNext()) {
((ChatRoomListener)iter.next()).chatRoomOpened(room);
}
}
/**
* Notifies users that a <code>ChatRoom</code> has been left.
*
* @param room - the <code>ChatRoom</code> that has been left
*/
protected void fireChatRoomLeft(ChatRoom room) {
final Iterator iter = new HashSet(chatRoomListeners).iterator();
while (iter.hasNext()) {
final Object chatRoomListener = iter.next();
((ChatRoomListener)chatRoomListener).chatRoomLeft(room);
}
}
/**
* Notifies users that a <code>ChatRoom</code> has been closed.
*
* @param room - the <code>ChatRoom</code> that has been closed.
*/
protected void fireChatRoomClosed(ChatRoom room) {
final Iterator iter = new HashSet(chatRoomListeners).iterator();
while (iter.hasNext()) {
final Object chatRoomListener = iter.next();
((ChatRoomListener)chatRoomListener).chatRoomClosed(room);
}
}
/**
* Notifies users that a <code>ChatRoom</code> has been activated.
*
* @param room - the <code>ChatRoom</code> that has been activated.
*/
protected void fireChatRoomActivated(ChatRoom room) {
final Iterator iter = new HashSet(chatRoomListeners).iterator();
while (iter.hasNext()) {
((ChatRoomListener)iter.next()).chatRoomActivated(room);
}
}
/**
* Notifies users that a user has joined a <code>ChatRoom</code>.
*
* @param room - the <code>ChatRoom</code> that a user has joined.
* @param userid - the userid of the person.
*/
protected void fireUserHasJoined(final ChatRoom room, final String userid) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final Iterator iter = new HashSet(chatRoomListeners).iterator();
while (iter.hasNext()) {
((ChatRoomListener)iter.next()).userHasJoined(room, userid);
}
}
});
}
/**
* Notifies users that a user has left a <code>ChatRoom</code>.
*
* @param room - the <code>ChatRoom</code> that a user has left.
* @param userid - the userid of the person.
*/
protected void fireUserHasLeft(final ChatRoom room, final String userid) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final Iterator iter = new HashSet(chatRoomListeners).iterator();
while (iter.hasNext()) {
((ChatRoomListener)iter.next()).userHasLeft(room, userid);
}
}
});
}
/**
* Starts flashing of MainWindow.
*
* @param room the ChatRoom to check if a message has been inserted
* but the room is not the selected room.
*/
public void startFlashing(final ChatRoom room) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
final int index = indexOfComponent(room);
if (index != -1) {
room.increaseUnreadMessageCount();
int unreadMessageCount = room.getUnreadMessageCount();
String appendedMessage = "";
if (unreadMessageCount > 1) {
appendedMessage = " (" + unreadMessageCount + ")";
}
SparkTab tab = getTabAt(index);
tab.getTitleLabel().setText(room.getTabTitle() + appendedMessage);
// Check notifications.
if (room instanceof ChatRoomImpl) {
checkNotificationPreferences(room);
}
makeTabRed(room);
}
boolean invokeFlash = SettingsManager.getLocalPreferences().isChatRoomNotificationsOn() || !(room instanceof GroupChatRoom);
if (!chatFrame.isFocused() && invokeFlash) {
SparkManager.getAlertManager().flashWindow(chatFrame);
}
}
catch (Exception ex) {
Log.error("Issue in ChatRooms with tab location.", ex);
}
}
});
}
public void flashWindow(final ChatRoom room) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
boolean invokeFlash = SettingsManager.getLocalPreferences().isChatRoomNotificationsOn() || !(room instanceof GroupChatRoom);
if (!chatFrame.isFocused() && invokeFlash) {
SparkManager.getAlertManager().flashWindow(chatFrame);
}
}
catch (Exception ex) {
Log.error("Issue in ChatRooms with tab location.", ex);
}
}
});
}
public void makeTabRed(final ChatRoom room) {
final int index = indexOfComponent(room);
if (index != -1) {
SparkTab tab = getTabAt(index);
final JLabel titleLabel = tab.getTitleLabel();
Font oldFont = titleLabel.getFont();
Font newFont = new Font(oldFont.getFontName(), Font.BOLD, oldFont.getSize());
titleLabel.setFont(newFont);
titleLabel.setForeground(Color.red);
titleLabel.validate();
titleLabel.repaint();
}
}
public void useTabDefault(final ChatRoom room) {
// Check if room is stale
boolean containsRoom = getStaleChatRooms().contains(room);
if (containsRoom) {
return;
}
final int index = indexOfComponent(room);
if (index != -1) {
SparkTab tab = getTabAt(index);
Font defaultFont = tab.getDefaultFont();
final JLabel titleLabel = tab.getTitleLabel();
if (room instanceof ChatRoomImpl) {
Icon icon = room.getTabIcon();
tab.setIcon(icon);
}
titleLabel.setForeground(Color.black);
titleLabel.setFont(defaultFont);
}
}
/**
* Checks to see if the MainWindow should stop flashing.
*
* @param room the ChatRoom to check.
*/
public void stopFlashing(final ChatRoom room) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
int index = indexOfComponent(room);
if (index != -1) {
SparkTab tab = getTabAt(index);
useTabDefault(room);
tab.getTitleLabel().setText(room.getTabTitle());
room.clearUnreadMessageCount();
}
}
catch (Exception ex) {
Log.error("Could not stop flashing for " + room + " because " + ex.getMessage(), ex);
}
SparkManager.getAlertManager().stopFlashing(chatFrame);
}
});
}
/**
* Handles Notification preferences for incoming messages and rooms.
*
* @param room the chat room.
*/
private void checkNotificationPreferences(final ChatRoom room) {
LocalPreferences pref = SettingsManager.getLocalPreferences();
if (pref.getWindowTakesFocus()) {
chatFrame.setState(Frame.NORMAL);
chatFrame.setVisible(true);
int tabLocation = indexOfComponent(room);
setSelectedIndex(tabLocation);
}
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);
setSelectedIndex(tabLocation);
}
});
toaster.setDisplayTime(5000);
toaster.setBorder(BorderFactory.createBevelBorder(0));
String nickname = ((ChatRoomImpl)room).getParticipantNickname();
toaster.setTitle(nickname);
toaster.setToasterHeight(150);
toaster.setToasterWidth(200);
int size = room.getTranscripts().size();
if (size > 0) {
Message message = (Message)room.getTranscripts().get(size - 1);
toaster.showToaster(room.getTabIcon(), message.getBody());
}
}
}
public void setChatRoomTitle(ChatRoom room, String title) {
int index = indexOfComponent(room);
if (index != -1) {
SparkTab tab = getTabAt(index);
useTabDefault(room);
tab.getTitleLabel().setText(room.getTabTitle());
}
}
private void createFrameIfNeeded() {
if (chatFrame != null) {
return;
}
chatFrame = new ChatFrame();
chatFrame.addWindowListener(new WindowAdapter() {
public void windowActivated(WindowEvent windowEvent) {
stopFlashing();
int sel = getSelectedIndex();
if (sel == -1) {
return;
}
final ChatRoom room;
try {
room = getChatRoom(sel);
focusChat();
// Set the title of the room.
chatFrame.setTitle(room.getRoomTitle());
}
catch (ChatRoomNotFoundException e1) {
}
}
public void windowDeactivated(WindowEvent windowEvent) {
}
});
// Start timer
checkForStaleRooms();
}
public void focusChat() {
SwingWorker worker = new SwingWorker() {
public Object construct() {
try {
Thread.sleep(50);
}
catch (InterruptedException e1) {
Log.error(e1);
}
return "ok";
}
public void finished() {
try {
//chatFrame.requestFocus();
ChatRoom chatRoom = getActiveChatRoom();
chatRoom.requestFocusInWindow();
chatRoom.getChatInputEditor().requestFocusInWindow();
}
catch (ChatRoomNotFoundException e1) {
// Ignore. There may legitamtly not be a chat room.
}
}
};
worker.start();
}
public Collection<ChatRoom> getChatRooms() {
final List<ChatRoom> list = new ArrayList<ChatRoom>(chatRoomList);
return list;
}
public ChatFrame getChatFrame() {
return chatFrame;
}
public void blinkFrameIfNecessary(final JFrame frame) {
final MainWindow mainWindow = SparkManager.getMainWindow();
if (mainWindow.isFocused()) {
frame.setVisible(true);
return;
}
else {
// Set to new tab.
if (Spark.isWindows()) {
frame.setState(Frame.ICONIFIED);
SparkManager.getAlertManager().flashWindow(frame);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
public void windowActivated(WindowEvent e) {
SparkManager.getAlertManager().stopFlashing(frame);
}
});
}
}
}
/**
* Returns a Collection of stale chat rooms.
*
* @return a collection of stale chat rooms.
*/
public Collection<ChatRoom> getStaleChatRooms() {
final List<ChatRoom> staleRooms = new ArrayList<ChatRoom>();
for (ChatRoom chatRoom : getChatRooms()) {
long lastActivity = chatRoom.getLastActivity();
long currentTime = System.currentTimeMillis();
long diff = currentTime - lastActivity;
int minutes = (int)(diff / (60 * 1000F));
LocalPreferences pref = SettingsManager.getLocalPreferences();
int timeoutMinutes = pref.getChatLengthDefaultTimeout();
int unreadCount = chatRoom.getUnreadMessageCount();
if (timeoutMinutes <= minutes && unreadCount == 0) {
staleRooms.add(chatRoom);
}
}
return staleRooms;
}
private void checkTabPopup(MouseEvent e) {
final SparkTab tab = (SparkTab)e.getSource();
if (!e.isPopupTrigger()) {
return;
}
final JPopupMenu popup = new JPopupMenu();
// Handle closing this room.
Action closeThisAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
ChatRoom chatRoom = (ChatRoom)getComponentInTab(tab);
if (chatRoom != null) {
closeTab(chatRoom);
}
}
};
closeThisAction.putValue(Action.NAME, "Close this chat");
popup.add(closeThisAction);
if (getChatRooms().size() > 1) {
// Handle closing other rooms.
Action closeOthersAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
ChatRoom chatRoom = (ChatRoom)getComponentInTab(tab);
if (chatRoom != null) {
for (ChatRoom cRoom : getChatRooms()) {
if (chatRoom != cRoom) {
closeTab(cRoom);
}
}
}
}
};
closeOthersAction.putValue(Action.NAME, "Close all other chats");
popup.add(closeOthersAction);
Action closeOldAction = new AbstractAction() {
public void actionPerformed(ActionEvent e) {
for (ChatRoom rooms : getStaleChatRooms()) {
closeTab(rooms);
}
}
};
closeOldAction.putValue(Action.NAME, "Close stale chats");
popup.add(closeOldAction);
}
popup.show(tab, e.getX(), e.getY());
}
/**
* Checks every room every 30 seconds to see if it's timed out.
*/
private void checkForStaleRooms() {
int delay = 1000; // delay for 1 minute
int period = 60000; // repeat every 30 seconds.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
for (ChatRoom chatRoom : getStaleChatRooms()) {
// Turn tab gray
int index = indexOfComponent(chatRoom);
if (index == -1) {
return;
}
SparkTab tab = getTabAt(index);
final JLabel titleLabel = tab.getTitleLabel();
titleLabel.setForeground(Color.gray);
titleLabel.setFont(tab.getDefaultFont());
String jid = ((ChatRoomImpl)chatRoom).getParticipantJID();
Presence presence = SparkManager.getConnection().getRoster().getPresence(jid);
if (presence == null || presence.getType() == Presence.Type.unavailable) {
tab.setIcon(SparkRes.getImageIcon(SparkRes.IM_UNAVAILABLE_STALE_IMAGE));
}
else if (presence != null) {
Presence.Mode mode = presence.getMode();
if (mode == Presence.Mode.available) {
tab.setIcon(SparkRes.getImageIcon(SparkRes.IM_AVAILABLE_STALE_IMAGE));
}
else if (mode == Presence.Mode.away) {
tab.setIcon(SparkRes.getImageIcon(SparkRes.IM_AWAY_STALE_IMAGE));
}
else if (mode == Presence.Mode.chat) {
tab.setIcon(SparkRes.getImageIcon(SparkRes.IM_FREE_CHAT_STALE_IMAGE));
}
else if (mode == Presence.Mode.dnd) {
tab.setIcon(SparkRes.getImageIcon(SparkRes.IM_DND_STALE_IMAGE));
}
else if (mode == Presence.Mode.xa) {
tab.setIcon(SparkRes.getImageIcon(SparkRes.IM_DND_STALE_IMAGE));
}
}
titleLabel.validate();
titleLabel.repaint();
}
}
}, delay, period);
}
}