package org.chartsy.chatsy.chat.ui.conferences;
import org.jdesktop.swingx.JXList;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.muc.Affiliate;
import org.jivesoftware.smackx.muc.InvitationRejectionListener;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.muc.Occupant;
import org.jivesoftware.smackx.muc.UserStatusListener;
import org.jivesoftware.smackx.packet.DiscoverInfo;
import org.chartsy.chatsy.chat.ChatManager;
import org.chartsy.chatsy.chat.PresenceManager;
import org.chartsy.chatsy.chat.ChatsyManager;
import org.chartsy.chatsy.chat.UserManager;
import org.chartsy.chatsy.chat.component.ImageTitlePanel;
import org.chartsy.chatsy.chat.ui.ChatRoom;
import org.chartsy.chatsy.chat.ui.ChatRoomListener;
import org.chartsy.chatsy.chat.ui.rooms.ChatRoomImpl;
import org.chartsy.chatsy.chat.ui.rooms.GroupChatRoom;
import org.chartsy.chatsy.chat.util.ModelUtil;
import org.chartsy.chatsy.chat.util.log.Log;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import org.openide.util.ImageUtilities;
public final class GroupChatParticipantList extends JPanel
implements ChatRoomListener
{
private GroupChatRoom groupChatRoom;
private final ImageTitlePanel agentInfoPanel;
private ChatManager chatManager;
private MultiUserChat chat;
private final Map<String, String> userMap = new HashMap<String, String>();
private UserManager userManager = ChatsyManager.getUserManager();
private DefaultListModel model = new DefaultListModel();
private JXList participantsList;
private PacketListener listener = null;
private Map<String, String> invitees = new HashMap<String, String>();
private boolean allowNicknameChange = true;
private DiscoverInfo roomInformation;
private List<JLabel> users = new ArrayList<JLabel>();
public GroupChatParticipantList()
{
setLayout(new GridBagLayout());
chatManager = ChatsyManager.getChatManager();
agentInfoPanel = new ImageTitlePanel("msg");
participantsList = new JXList(model);
participantsList.setCellRenderer(new ParticipantRenderer());
this.setOpaque(false);
this.setBackground(Color.white);
participantsList.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
if (evt.getClickCount() == 2)
{
String selectedUser = getSelectedUser();
startChat(groupChatRoom, userMap.get(selectedUser));
}
}
public void mouseReleased(final MouseEvent evt)
{
if (evt.isPopupTrigger())
checkPopup(evt);
}
public void mousePressed(final MouseEvent evt)
{
if (evt.isPopupTrigger())
checkPopup(evt);
}
});
JScrollPane scroller = new JScrollPane(participantsList);
scroller.getVerticalScrollBar().setBlockIncrement(50);
scroller.getVerticalScrollBar().setUnitIncrement(20);
scroller.setBackground(Color.white);
scroller.getViewport().setBackground(Color.white);
add(scroller, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
GridBagConstraints.CENTER, GridBagConstraints.BOTH,
new Insets(0, 0, 0, 0), 0, 0));
}
public void setChatRoom(final ChatRoom chatRoom)
{
this.groupChatRoom = (GroupChatRoom) chatRoom;
chatManager.addChatRoomListener(this);
chat = groupChatRoom.getMultiUserChat();
chat.addInvitationRejectionListener(new InvitationRejectionListener()
{
public void invitationDeclined(String jid, String message)
{
String nickname = userManager.getUserNicknameFromJID(jid);
userHasLeft(chatRoom, nickname);
chatRoom.getTranscriptWindow().insertNotificationMessage(
nickname + " has rejected the invitation.",ChatManager.NOTIFICATION_COLOR);
}
});
listener = new PacketListener()
{
public void processPacket(final Packet packet)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Presence p = (Presence) packet;
if (p.getError() != null)
{
if (p.getError().getCondition().equals(
XMPPError.Condition.conflict.toString()))
return;
}
final String userid = p.getFrom();
String displayName = StringUtils.parseResource(userid);
userMap.put(displayName, userid);
if (p.getType() == Presence.Type.available)
{
addParticipant(userid, p);
agentInfoPanel.setVisible(true);
}
else
{
removeUser(displayName);
}
}
});
}
};
chat.addParticipantListener(listener);
ServiceDiscoveryManager disco = ServiceDiscoveryManager.getInstanceFor(ChatsyManager.getConnection());
try
{
roomInformation = disco.discoverInfo(chat.getRoom());
}
catch (XMPPException e)
{
Log.debug("Unable to retrieve room informatino for " + chat.getRoom());
}
}
public void chatRoomOpened(ChatRoom room)
{
if (room != groupChatRoom)
return;
chat.addUserStatusListener(new UserStatusListener()
{
public void kicked(String actor, String reason)
{
}
public void voiceGranted()
{
}
public void voiceRevoked()
{
}
public void banned(String actor, String reason)
{
}
public void membershipGranted()
{
}
public void membershipRevoked()
{
}
public void moderatorGranted()
{
}
public void moderatorRevoked()
{
}
public void ownershipGranted()
{
}
public void ownershipRevoked()
{
}
public void adminGranted()
{
}
public void adminRevoked()
{
}
});
}
public void chatRoomLeft(ChatRoom room)
{
if (this.groupChatRoom == room)
{
chatManager.removeChatRoomListener(this);
agentInfoPanel.setVisible(false);
}
}
public void chatRoomClosed(ChatRoom room)
{
if (this.groupChatRoom == room)
{
chatManager.removeChatRoomListener(this);
chat.removeParticipantListener(listener);
}
}
public void chatRoomActivated(ChatRoom room)
{
}
public void userHasJoined(ChatRoom room, String userid)
{
}
public void addInvitee(String jid, String message)
{
final UserManager userManager = ChatsyManager.getUserManager();
String displayName = userManager.getUserNicknameFromJID(jid);
groupChatRoom.getTranscriptWindow().insertNotificationMessage(
displayName + " has been invited to join this room.", ChatManager.NOTIFICATION_COLOR);
if (roomInformation != null
&& !roomInformation.containsFeature("muc_nonanonymous"))
return;
final ImageIcon inviteIcon = null;
addUser(inviteIcon, displayName);
invitees.put(displayName, message);
}
private ImageIcon getImageIcon(String participantJID)
{
String displayName = StringUtils.parseResource(participantJID);
ImageIcon icon = ImageUtilities.loadImageIcon("org/chartsy/chatsy/resources/available.png", true);
icon.setDescription(displayName);
return icon;
}
private void addParticipant(String participantJID, Presence presence)
{
for (String displayName : invitees.keySet())
{
String jid = ChatsyManager.getUserManager()
.getJIDFromDisplayName(displayName);
Occupant occ = chat.getOccupant(participantJID);
if (occ != null)
{
String actualJID = occ.getJid();
if (actualJID.equals(jid))
removeUser(displayName);
}
}
String nickname = StringUtils.parseResource(participantJID);
if (!exists(nickname))
{
Icon icon;
icon = PresenceManager.getIconFromPresence(presence);
if (icon == null)
icon = ImageUtilities.loadImageIcon("org/chartsy/chatsy/resources/available.png", true);
addUser(icon, nickname);
}
else
{
Icon icon = PresenceManager.getIconFromPresence(presence);
if (icon == null)
icon = ImageUtilities.loadImageIcon("org/chartsy/chatsy/resources/available.png", true);
int index = getIndex(nickname);
if (index != -1)
{
final JLabel userLabel = new JLabel(nickname, icon, JLabel.HORIZONTAL);
model.setElementAt(userLabel, index);
}
}
}
public void userHasLeft(ChatRoom room, String userid)
{
if (room != groupChatRoom)
return;
int index = getIndex(userid);
if (index != -1)
{
removeUser(userid);
userMap.remove(userid);
}
}
private boolean exists(String nickname)
{
for (int i = 0; i < model.getSize(); i++)
{
final JLabel userLabel = (JLabel) model.getElementAt(i);
if (userLabel.getText().equals(nickname))
return true;
}
return false;
}
private String getSelectedUser()
{
JLabel label = (JLabel) participantsList.getSelectedValue();
if (label != null)
return label.getText();
return null;
}
private void startChat(ChatRoom groupChat, String groupJID)
{
String userNickname = StringUtils.parseResource(groupJID);
String roomTitle = userNickname + " - "
+ StringUtils.parseName(groupChat.getRoomname());
String nicknameOfUser = StringUtils.parseResource(groupJID);
String nickname = groupChat.getNickname();
if (nicknameOfUser.equals(nickname))
return;
ChatRoom chatRoom = chatManager.getChatContainer().getChatRoom(groupJID);
if (chatRoom == null)
{
chatRoom = new ChatRoomImpl(groupJID, nicknameOfUser, roomTitle);
chatManager.getChatContainer().addChatRoom(chatRoom);
}
chatManager.getChatContainer().activateChatRoom(chatRoom);
}
public void tabSelected()
{
}
public String getTabTitle()
{
return "Room information";
}
public Icon getTabIcon()
{
return null;
}
public String getTabToolTip()
{
return "Room information";
}
public JComponent getGUI()
{
return this;
}
private void kickUser(String nickname)
{
try
{
chat.kickParticipant(nickname, "kicked");
}
catch (XMPPException e)
{
groupChatRoom.insertText(nickname + " kicked");
}
}
private void banUser(String displayName)
{
try
{
Occupant occupant = chat.getOccupant(userMap.get(displayName));
if (occupant != null)
{
String bareJID = StringUtils
.parseBareAddress(occupant.getJid());
chat.banUser(bareJID, "banned");
}
}
catch (XMPPException e)
{
Log.error(e);
}
}
private void unbanUser(String jid)
{
try
{
chat.grantMembership(jid);
}
catch (XMPPException e)
{
Log.error(e);
}
}
private void grantVoice(String nickname)
{
try
{
chat.grantVoice(nickname);
}
catch (XMPPException e)
{
Log.error(e);
}
}
private void revokeVoice(String nickname)
{
try
{
chat.revokeVoice(nickname);
}
catch (XMPPException e)
{
Log.error(e);
}
}
private void grantModerator(String nickname)
{
try
{
chat.grantModerator(nickname);
}
catch (XMPPException e)
{
Log.error(e);
}
}
private void revokeModerator(String nickname)
{
try
{
chat.revokeModerator(nickname);
}
catch (XMPPException e)
{
Log.error(e);
}
}
public Dimension getPreferredSize()
{
final Dimension size = super.getPreferredSize();
size.width = 150;
return size;
}
private void checkPopup(MouseEvent evt)
{
Point p = evt.getPoint();
final int index = participantsList.locationToIndex(p);
final JPopupMenu popup = new JPopupMenu();
if (index != -1)
{
participantsList.setSelectedIndex(index);
final JLabel userLabel = (JLabel) model.getElementAt(index);
final String selectedUser = userLabel.getText();
final String groupJID = userMap.get(selectedUser);
String groupJIDNickname = StringUtils.parseResource(groupJID);
final String nickname = groupChatRoom.getNickname();
final Occupant occupant = userManager.getOccupant(groupChatRoom,
selectedUser);
final boolean admin = ChatsyManager.getUserManager().isOwnerOrAdmin(
groupChatRoom, chat.getNickname());
final boolean moderator = ChatsyManager.getUserManager()
.isModerator(groupChatRoom, chat.getNickname());
final boolean userIsAdmin = userManager.isOwnerOrAdmin(occupant);
final boolean userIsModerator = userManager.isModerator(occupant);
boolean isMe = nickname.equals(groupJIDNickname);
if (groupJIDNickname == null)
{
Action inviteAgainAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
String message = invitees.get(selectedUser);
String jid = userManager
.getJIDFromDisplayName(selectedUser);
chat.invite(jid, message);
}
};
inviteAgainAction.putValue(Action.NAME, "Invite again");
popup.add(inviteAgainAction);
Action removeInvite = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
int index = getIndex(selectedUser);
if (index != -1)
model.removeElementAt(index);
}
};
removeInvite.putValue(Action.NAME, "Remove");
popup.add(removeInvite);
popup.show(participantsList, evt.getX(), evt.getY());
return;
}
if (isMe)
{
Action changeNicknameAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
String newNickname = JOptionPane.showInputDialog(
groupChatRoom,
"New nickname:",
"Change nickname",
JOptionPane.QUESTION_MESSAGE);
if (ModelUtil.hasLength(newNickname))
{
while (true)
{
newNickname = newNickname.trim();
String nick = chat.getNickname();
if (newNickname.equals(nick))
return;
try
{
chat.changeNickname(newNickname);
break;
}
catch (XMPPException e1)
{
newNickname = JOptionPane.showInputDialog(
groupChatRoom,
"Nickname in use, please specify another Nickname:",
"Change nickname",
JOptionPane.QUESTION_MESSAGE);
if (!ModelUtil.hasLength(newNickname))
break;
}
}
}
}
};
changeNicknameAction.putValue(Action.NAME, "Change nickname");
if (allowNicknameChange)
popup.add(changeNicknameAction);
}
Action chatAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
String selectedUser = getSelectedUser();
startChat(groupChatRoom, userMap.get(selectedUser));
}
};
chatAction.putValue(Action.NAME, "Start a chat");
if (!isMe)
popup.add(chatAction);
Action blockAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
String user = getSelectedUser();
ImageIcon icon;
if (groupChatRoom.isBlocked(groupJID))
{
groupChatRoom.removeBlockedUser(groupJID);
icon = getImageIcon(groupJID);
}
else
{
groupChatRoom.addBlockedUser(groupJID);
icon = null;
}
JLabel label = new JLabel(user, icon, JLabel.HORIZONTAL);
model.setElementAt(label, index);
}
};
blockAction.putValue(Action.NAME, "Block user");
if (!isMe)
{
if (groupChatRoom.isBlocked(groupJID))
blockAction.putValue(Action.NAME, "Unblock user");
popup.add(blockAction);
}
Action kickAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
kickUser(selectedUser);
}
};
kickAction.putValue(Action.NAME, "Kick user");
if (moderator && !userIsAdmin && !isMe)
popup.add(kickAction);
Action voiceAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
if (userManager.hasVoice(groupChatRoom, selectedUser))
{
revokeVoice(selectedUser);
}
else
{
grantVoice(selectedUser);
}
}
};
voiceAction.putValue(Action.NAME, "Voice");
if (moderator && !userIsModerator && !isMe)
{
if (userManager.hasVoice(groupChatRoom, selectedUser))
{
voiceAction.putValue(Action.NAME, "Revoke voice");
}
else
{
voiceAction.putValue(Action.NAME, "Grant voice");
}
popup.add(voiceAction);
}
Action banAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
banUser(selectedUser);
}
};
banAction.putValue(Action.NAME, "Ban user");
if (admin && !userIsModerator && !isMe)
popup.add(banAction);
Action moderatorAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
if (!userIsModerator)
{
grantModerator(selectedUser);
}
else
{
revokeModerator(selectedUser);
}
}
};
if (admin && !userIsModerator)
{
moderatorAction.putValue(Action.NAME, "Grant moderator");
popup.add(moderatorAction);
}
else if (admin && userIsModerator && !isMe)
{
moderatorAction.putValue(Action.NAME, "Revoke moderator");
popup.add(moderatorAction);
}
Action unbanAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
String jid = ((JMenuItem) actionEvent.getSource()).getText();
unbanUser(jid);
}
};
if (admin)
{
JMenu unbanMenu = new JMenu("Unban");
Iterator<Affiliate> bannedUsers = null;
try
{
bannedUsers = chat.getOutcasts().iterator();
}
catch (XMPPException e)
{
Log.error("Error loading all banned users", e);
}
while (bannedUsers != null && bannedUsers.hasNext())
{
Affiliate bannedUser = (Affiliate) bannedUsers.next();
JMenuItem bannedItem = new JMenuItem(bannedUser.getJid());
unbanMenu.add(bannedItem);
bannedItem.addActionListener(unbanAction);
}
if (unbanMenu.getMenuComponentCount() > 0)
popup.add(unbanMenu);
}
}
Action inviteAction = new AbstractAction()
{
public void actionPerformed(ActionEvent actionEvent)
{
ConferenceUtils.inviteUsersToRoom(groupChatRoom.getConferenceService(), groupChatRoom.getRoomname(), null);
}
};
inviteAction.putValue(Action.NAME, "Invite users");
if (index != -1)
popup.addSeparator();
popup.add(inviteAction);
popup.show(participantsList, evt.getX(), evt.getY());
}
public void setNicknameChangeAllowed(boolean allowed)
{
allowNicknameChange = allowed;
}
public int getIndex(String name)
{
for (int i = 0; i < model.getSize(); i++)
{
JLabel label = (JLabel) model.getElementAt(i);
if (label.getText().equals(name))
return i;
}
return -1;
}
public synchronized void removeUser(String displayName)
{
try
{
for (int i = 0; i < users.size(); i++)
{
JLabel label = users.get(i);
if (label.getText().equals(displayName))
{
users.remove(label);
model.removeElement(label);
}
}
for (int i = 0; i < model.size(); i++)
{
JLabel label = (JLabel) model.getElementAt(i);
if (label.getText().equals(displayName))
{
users.remove(label);
model.removeElement(label);
}
}
}
catch (Exception e)
{
Log.error(e);
}
}
public synchronized void addUser(Icon userIcon, String nickname)
{
try
{
final JLabel user = new JLabel(nickname, JLabel.HORIZONTAL);
if (userIcon != null)
user.setIcon(userIcon);
users.add(user);
Collections.sort(users, labelComp);
final int index = users.indexOf(user);
model.insertElementAt(user, index);
}
catch (Exception e)
{
Log.error(e);
}
}
final Comparator<JLabel> labelComp = new Comparator<JLabel>()
{
public int compare(JLabel item1, JLabel item2)
{
return item1.getText().toLowerCase().compareTo(item2.getText().toLowerCase());
}
};
public class ParticipantRenderer extends JLabel implements ListCellRenderer
{
public ParticipantRenderer()
{
setOpaque(true);
}
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus) {
if (isSelected)
{
setBackground(list.getSelectionBackground());
setForeground(list.getSelectionForeground());
}
else
{
setBackground(list.getBackground());
setForeground(list.getForeground());
}
JLabel label = (JLabel) value;
setText(label.getText());
setIcon(label.getIcon());
return this;
}
}
}