package org.chartsy.chatsy.chat.ui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.StringTokenizer; import java.util.Timer; import java.util.TimerTask; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JComponent; 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.SwingUtilities; import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.Roster; import org.jivesoftware.smack.RosterEntry; import org.jivesoftware.smack.RosterGroup; import org.jivesoftware.smack.RosterListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.filter.PacketTypeFilter; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.RosterPacket; import org.jivesoftware.smack.util.StringUtils; import org.chartsy.chatsy.chat.ChatManager; import org.chartsy.chatsy.chat.PresenceManager; import org.chartsy.chatsy.chat.ChatsyManager; import org.chartsy.chatsy.chat.Workspace; import org.chartsy.chatsy.chat.component.tabbedPane.AbstractTab; import org.chartsy.chatsy.chat.plugin.Plugin; import org.chartsy.chatsy.chat.util.TaskEngine; import org.chartsy.chatsy.chatimpl.profile.VCardManager; public final class ContactList extends AbstractTab implements ContactGroupListener, Plugin, RosterListener, ConnectionListener { private static final Logger LOG = Logger.getLogger(ContactList.class.getName()); private JPanel mainPanel = new JPanel(); private JScrollPane contactListScrollPane; private final List<String> groupList = new ArrayList<String>(); private final List<ContactItem> selectedContacts = new ArrayList<ContactItem>(); private List<Presence> initialPresences = new ArrayList<Presence>(); private final Timer presenceTimer = new Timer(); private final List<ContactListListener> contactListListeners = new ArrayList<ContactListListener>(); private Workspace workspace; public static KeyEvent activeKeyEvent; public ContactList() { setName("Contacts"); if (!initialized) { buildContent(); initialized = true; } } @Override protected void buildContent() { mainPanel.setLayout(new LayoutManager() { public void addLayoutComponent(String name, Component comp) { } public void removeLayoutComponent(Component comp) { } public Dimension preferredLayoutSize(Container parent) { return new Dimension(0, 0); } public Dimension minimumLayoutSize(Container parent) { return new Dimension(0, 0); } public void layoutContainer(Container parent) { final Component[] components = parent.getComponents(); if (components.length == 0) return; final Insets insets = parent.getInsets(); final int width = parent.getWidth() - insets.left - insets.right; final int x = insets.left; int y = insets.top; for (int i = 0; i < components.length; i++) { int height = ((ContactGroup)components[i]).getPanelHeight(); components[i].setBounds(x, y, width, height); y += height; } } }); mainPanel.setOpaque(false); contactListScrollPane = new JScrollPane(mainPanel); contactListScrollPane.getViewport().setOpaque(true); contactListScrollPane.getViewport().setBackground(Color.WHITE); contactListScrollPane.setAutoscrolls(true); contactListScrollPane.setBorder(BorderFactory.createEmptyBorder()); contactListScrollPane.getVerticalScrollBar().setBlockIncrement(50); contactListScrollPane.getVerticalScrollBar().setUnitIncrement(20); add(contactListScrollPane, BorderLayout.CENTER); workspace = ChatsyManager.getWorkspace(); ChatsyManager.getConnection().addConnectionListener(this); addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { activeKeyEvent = e; } @Override public void keyReleased(KeyEvent e) { activeKeyEvent = null; } }); } private synchronized void updateUserPresence(Presence presence) throws Exception { if (presence.getError() != null) return; final Roster roster = ChatsyManager.getConnection().getRoster(); final String bareJID = StringUtils.parseBareAddress(presence.getFrom()); RosterEntry entry = roster.getEntry(bareJID); boolean isPending = entry != null && (entry.getType() == RosterPacket.ItemType.none || entry.getType() == RosterPacket.ItemType.from) && RosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus(); if (presence.getType() == Presence.Type.available || (presence.getFrom().indexOf("workgroup.") != -1)) changeOfflineToOnline(entry, presence); else if (presence.getType() == Presence.Type.available) updateContactItemsPresence(presence, entry, bareJID); else if (presence.getType() == Presence.Type.unavailable && !isPending) { Presence rosterPresence = PresenceManager.getPresence(bareJID); if (!rosterPresence.isAvailable()) moveToOfflineGroup(presence, bareJID); else updateContactItemsPresence(rosterPresence, entry, bareJID); } } private void updateContactItemsPresence(Presence presence, RosterEntry entry, String bareJID) { for (ContactGroup group : getContactGroups()) { ContactItem item = group.getContactItemByJID(bareJID); if (item != null) { item.setPresence(presence); group.fireContactGroupUpdated(); } } } private void moveToOfflineGroup(final Presence presence, final String bareJID) { for (ContactGroup grpItem : getContactGroups()) { final ContactGroup group = grpItem; final ContactItem item = group.getContactItemByJID(bareJID); if (item != null) { int numberOfMillisecondsInTheFuture = 3000; Date timeToRun = new Date(System.currentTimeMillis() + numberOfMillisecondsInTheFuture); if (item.getPresence().isAvailable()) { item.showUserGoingOfflineOnline(); item.setIcon(PresenceManager.getIconFromPresence(presence)); group.fireContactGroupUpdated(); final Timer offlineTimer = new Timer(); offlineTimer.schedule(new TimerTask() { public void run() { Presence userPresence = PresenceManager.getPresence(bareJID); if (userPresence.isAvailable()) return; item.setPresence(presence); group.fireContactGroupUpdated(); checkGroup(group); } }, timeToRun); } } } } private void changeOfflineToOnline(final RosterEntry entry, Presence presence) { if (entry != null) for (RosterGroup rosterGroup : entry.getGroups()) { ContactGroup contactGroup = getContactGroup(rosterGroup.getName()); if (contactGroup == null) contactGroup = addContactGroup(rosterGroup.getName()); if (contactGroup != null) { ContactItem contactItem = null; if (contactGroup.getContactItemByJID(entry.getUser()) == null) { contactItem = new ContactItem(entry.getName(), null, entry.getUser()); contactGroup.addContactItem(contactItem); } else if (contactGroup.getContactItemByJID(entry.getUser()) != null) { contactItem = contactGroup.getContactItemByJID(entry.getUser()); } try { contactItem.setPresence(presence); } catch (NullPointerException e) { } contactItem.setOffline(false); toggleGroupVisibility(contactGroup.getGroupName(), true); contactItem.updateAvatarInSideIcon(); contactItem.showUserComingOnline(); contactGroup.fireContactGroupUpdated(); int numberOfMillisecondsInTheFuture = 5000; Date timeToRun = new Date(System.currentTimeMillis() + numberOfMillisecondsInTheFuture); Timer timer = new Timer(); final ContactItem staticItem = contactItem; final ContactGroup staticGroup = contactGroup; timer.schedule(new TimerTask() { public void run() { staticItem.updatePresenceIcon(staticItem.getPresence()); staticGroup.fireContactGroupUpdated(); } }, timeToRun); } } } private void buildContactList() { XMPPConnection con = ChatsyManager.getConnection(); final Roster roster = con.getRoster(); roster.addRosterListener(this); for (RosterGroup group : roster.getGroups()) addContactGroup(group.getName()); for (RosterGroup group : roster.getGroups()) { if (group.getName() != null || !group.getName().isEmpty()) { ContactGroup contactGroup = getContactGroup(group.getName()); if (contactGroup != null) { for (RosterEntry entry : group.getEntries()) { ContactItem contactItem = new ContactItem(entry.getName(), null, entry.getUser()); contactGroup.addContactItem(contactItem); contactGroup.setVisible(true); updateContactItemsPresence(PresenceManager.getPresence(contactItem.getJID()), entry, contactItem.getJID()); } } } } for (RosterEntry entry : roster.getUnfiledEntries()) { ContactItem contactItem = new ContactItem(entry.getName(), null, entry.getUser()); moveToOffline(contactItem); } } public void entriesAdded(final Collection<String> addresses) { SwingUtilities.invokeLater(new Runnable() { public void run() { Roster roster = ChatsyManager.getConnection().getRoster(); for (String jid : addresses) { RosterEntry entry = roster.getEntry(jid); addUser(entry); } } }); } private void addUser(RosterEntry entry) { ContactItem newContactItem = new ContactItem(entry.getName(), null, entry.getUser()); if (entry.getType() == RosterPacket.ItemType.none || entry.getType() == RosterPacket.ItemType.from) { for (RosterGroup group : entry.getGroups()) { ContactGroup contactGroup = getContactGroup(group.getName()); if (contactGroup == null) contactGroup = addContactGroup(group.getName()); boolean isPending = entry.getType() == RosterPacket.ItemType.none || entry.getType() == RosterPacket.ItemType.from && RosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus(); if (isPending) contactGroup.setVisible(true); contactGroup.addContactItem(newContactItem); } return; } else { moveToOffline(newContactItem); } Presence presence = ChatsyManager.getConnection().getRoster().getPresence(entry.getUser()); try { updateUserPresence(presence); } catch (Exception e) { LOG.log(Level.SEVERE, "", e); } } public void entriesUpdated(final Collection<String> addresses) { handleEntriesUpdated(addresses); } public void entriesDeleted(final Collection<String> addresses) { SwingUtilities.invokeLater(new Runnable() { public void run() { for (String jid : addresses) removeContactItem(jid); } }); } private synchronized void handleEntriesUpdated(final Collection<String> addresses) { SwingUtilities.invokeLater(new Runnable() { public void run() { Roster roster = ChatsyManager.getConnection().getRoster(); Iterator<String> jids = addresses.iterator(); while (jids.hasNext()) { String jid = jids.next(); RosterEntry rosterEntry = roster.getEntry(jid); if (rosterEntry != null) { for (RosterGroup group : rosterEntry.getGroups()) { if (getContactGroup(group.getName()) == null) { ContactGroup contactGroup = addContactGroup(group.getName()); contactGroup.setVisible(false); contactGroup = getContactGroup(group.getName()); ContactItem contactItem = new ContactItem(rosterEntry.getName(), null, rosterEntry.getUser()); contactGroup.addContactItem(contactItem); Presence presence = PresenceManager.getPresence(jid); contactItem.setPresence(presence); if (presence.isAvailable()) contactGroup.setVisible(true); } else { ContactGroup contactGroup = getContactGroup(group.getName()); ContactItem item = contactGroup.getContactItemByJID(jid); if (item == null) { item = new ContactItem(rosterEntry.getName(), null, rosterEntry.getUser()); Presence presence = PresenceManager.getPresence(jid); item.setPresence(presence); if (presence.isAvailable()) { contactGroup.addContactItem(item); contactGroup.fireContactGroupUpdated(); } else { moveToOffline(item); contactGroup.fireContactGroupUpdated(); } } else { RosterEntry entry = roster.getEntry(jid); Presence presence = PresenceManager.getPresence(jid); item.setPresence(presence); try { updateUserPresence(presence); } catch (Exception e) { LOG.log(Level.SEVERE, "", e); } if (entry != null && (entry.getType() == RosterPacket.ItemType.none || entry.getType() == RosterPacket.ItemType.from) && RosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus()) contactGroup.setVisible(true); contactGroup.fireContactGroupUpdated(); } } } final Set<String> userGroupSet = new HashSet<String>(); jids = addresses.iterator(); while (jids.hasNext()) { jid = (String)jids.next(); rosterEntry = roster.getEntry(jid); boolean unfiled = true; for (RosterGroup g : rosterEntry.getGroups()) { userGroupSet.add(g.getName()); unfiled = false; } for (ContactGroup group : new ArrayList<ContactGroup>(getContactGroups())) { ContactItem itemFound = group.getContactItemByJID(jid); if (itemFound != null && !unfiled) if (!userGroupSet.contains(group.getGroupName())) removeContactGroup(group); } } } } } }); } public void presenceChanged(Presence presence) { } public ContactItem getContactItemByJID(String jid) { for (ContactGroup group : getContactGroups()) { String JID = StringUtils.parseBareAddress(jid); ContactItem item = group.getContactItemByJID(JID); if (item != null) return item; } return null; } public Collection<ContactItem> getContactItemsByJID(String jid) { final List<ContactItem> list = new ArrayList<ContactItem>(); for (ContactGroup group : getContactGroups()) { ContactItem item = group.getContactItemByJID(StringUtils.parseBareAddress(jid)); if (item != null) list.add(item); } for (ContactGroup group : getContactGroups()) { for (ContactItem offlineItem : group.getOfflineContacts()) if (offlineItem != null && offlineItem.getJID().equalsIgnoreCase(StringUtils.parseBareAddress(jid))) if (!list.contains(offlineItem)) list.add(offlineItem); } return list; } public void setIconFor(String jid, Icon icon) { for (ContactGroup group : getContactGroups()) { ContactItem item = group.getContactItemByJID(StringUtils.parseBareAddress(jid)); if (item != null) { item.setIcon(icon); group.fireContactGroupUpdated(); } } } public void useDefaults(String jid) { for (ContactGroup group : getContactGroups()) { ContactItem item = group.getContactItemByJID(StringUtils.parseBareAddress(jid)); if (item != null) { item.updatePresenceIcon(item.getPresence()); group.fireContactGroupUpdated(); } } } public ContactItem getContactItemByDisplayName(String displayName) { for (ContactGroup contactGroup : getContactGroups()) { ContactItem item = contactGroup.getContactItemByDisplayName(displayName); if (item != null) return item; } return null; } private void addContactGroup(ContactGroup group) { Roster roster = ChatsyManager.getConnection().getRoster(); RosterGroup rosterGroup = roster.getGroup(group.getGroupName()); if (rosterGroup == null) rosterGroup = roster.createGroup(group.getGroupName()); groupList.add(group.getName()); mainPanel.add(group); group.addContactGroupListener(this); fireContactGroupAdded(group); group.setExpanded(false); } private ContactGroup addContactGroup(String groupName) { StringTokenizer tkn = new StringTokenizer(groupName, "::"); StringBuilder buf = new StringBuilder(); ContactGroup newContactGroup = null; while (tkn.hasMoreTokens()) { String group = tkn.nextToken(); buf.append(group); if (tkn.hasMoreTokens()) buf.append("::"); String name = buf.toString(); if (name.endsWith("::")) name = name.substring(0, name.length() - 2); newContactGroup = getContactGroup(name); if (newContactGroup == null) { newContactGroup = new ContactGroup(group); String realGroupName = buf.toString(); if (realGroupName.endsWith("::")) realGroupName = realGroupName.substring(0, realGroupName.length() - 2); newContactGroup.setGroupName(realGroupName); newContactGroup.addContactGroupListener(this); fireContactGroupAdded(newContactGroup); newContactGroup.setExpanded(false); } } if (newContactGroup != null) { final List<String> tempList = new ArrayList<String>(); final Component[] comps = mainPanel.getComponents(); for (Component c : comps) { if (c instanceof ContactGroup) tempList.add(c.getName()); } tempList.add(newContactGroup.getName()); groupList.add(newContactGroup.getName()); Collections.sort(tempList); int loc = tempList.indexOf(newContactGroup.getName()); try { mainPanel.add(newContactGroup, loc); } catch (Exception e) { LOG.log(Level.SEVERE, "", e); } } return getContactGroup(groupName); } private void removeContactGroup(ContactGroup contactGroup) { contactGroup.removeContactGroupListener(this); groupList.remove(contactGroup.getName()); mainPanel.remove(contactGroup); contactListScrollPane.validate(); mainPanel.invalidate(); mainPanel.repaint(); fireContactGroupRemoved(contactGroup); } public ContactGroup getContactGroup(String groupName) { ContactGroup cGroup = null; for (String group : groupList) { if (group.equals(groupName)) { cGroup = (ContactGroup) mainPanel.getComponent(groupList.indexOf(groupName)); break; } } return cGroup; } public void toggleGroupVisibility(String groupName, boolean visible) { StringTokenizer tkn = new StringTokenizer(groupName, "::"); while (tkn.hasMoreTokens()) { String group = tkn.nextToken(); ContactGroup contactGroup = getContactGroup(group); if (contactGroup != null) contactGroup.setVisible(visible); } ContactGroup group = getContactGroup(groupName); if (group != null) group.setVisible(true); } private void removeContactFromGroup(ContactItem item) { String groupName = item.getGroupName(); ContactGroup contactGroup = getContactGroup(groupName); Roster roster = ChatsyManager.getConnection().getRoster(); RosterEntry entry = roster.getEntry(item.getJID()); if (entry != null && contactGroup != null) { try { RosterGroup rosterGroup = roster.getGroup(groupName); if (rosterGroup != null) { RosterEntry rosterEntry = rosterGroup.getEntry(entry.getUser()); if (rosterEntry != null) rosterGroup.removeEntry(rosterEntry); } contactGroup.removeContactItem(contactGroup.getContactItemByJID(item.getJID())); checkGroup(contactGroup); } catch (Exception e) { LOG.log(Level.SEVERE, "Error removing user from contact list.", e); } } } private void removeContactFromRoster(ContactItem item) { Roster roster = ChatsyManager.getConnection().getRoster(); RosterEntry entry = roster.getEntry(item.getJID()); if (entry != null) { try { roster.removeEntry(entry); } catch (XMPPException e) { LOG.log(Level.SEVERE, "Unable to remove roster entry.", e); } } } private void removeContactItem(String jid) { for (ContactGroup group : new ArrayList<ContactGroup>(getContactGroups())) { ContactItem item = group.getContactItemByJID(jid); group.removeOfflineContactItem(jid); if (item != null) { group.removeContactItem(item); checkGroup(group); } } } public void contactItemClicked(ContactItem item) { if (activeKeyEvent == null || ((activeKeyEvent.getModifiers() & KeyEvent.CTRL_MASK) == 0)) { clearSelectionList(item); } else { if (!selectedContacts.contains(item)) { selectedContacts.add(item); item.setSelected(true); } else { selectedContacts.remove(item); item.setSelected(false); } } fireContactItemClicked(item); } public void contactItemDoubleClicked(ContactItem item) { ChatManager chatManager = ChatsyManager.getChatManager(); boolean handled = chatManager.fireContactItemDoubleClicked(item); if (!handled) chatManager.activateChat(item.getJID(), item.getDisplayName()); fireContactItemDoubleClicked(item); } public void contactGroupPopup(MouseEvent e, final ContactGroup group) { final JPopupMenu popup = new JPopupMenu(); JMenuItem menuItem; popup.add(menuItem = new JMenuItem(new AbstractAction("Add a Contact") { @Override public void actionPerformed(ActionEvent e) { ChatsyManager.getWorkspace().getCommandPanel().addButtonClick(); } })); popup.add(menuItem = new JMenuItem(new AbstractAction("Add a Contact Group") { @Override public void actionPerformed(ActionEvent e) { String groupName = JOptionPane.showInputDialog(getGUI(), "New Group Name:", "Add New Group", JOptionPane.QUESTION_MESSAGE); if (groupName == null && groupName.isEmpty()) return; ContactGroup contactGroup = getContactGroup(groupName); if (contactGroup == null) { contactGroup = addContactGroup(groupName); contactGroup.setVisible(true); validateTree(); repaint(); } } })); popup.add(menuItem = new JMenuItem(new AbstractAction("Invite Group to Conference") { @Override public void actionPerformed(ActionEvent e) { clearSelectionList(null); for (ContactItem item : group.getContactItems()) if (!item.isOffline()) selectedContacts.add(item); ChatsyManager.getWorkspace().getCommandPanel().chatButtonClick(); } })); popup.addSeparator(); popup.add(menuItem = new JMenuItem(new AbstractAction("Delete") { @Override public void actionPerformed(ActionEvent e) { removeContactGroup(group); } })); popup.add(menuItem = new JMenuItem(new AbstractAction("Rename") { @Override public void actionPerformed(ActionEvent e) { String newName = JOptionPane.showInputDialog(group, "New Group Name:", "Rename Group", JOptionPane.QUESTION_MESSAGE); if (newName == null && newName.isEmpty()) return; String groupName = group.getGroupName(); Roster roster = ChatsyManager.getConnection().getRoster(); RosterGroup rosterGroup = roster.getGroup(groupName); if (rosterGroup != null) { rosterGroup.setName(newName); group.setGroupName(newName); } } })); popup.show(group, e.getX(), e.getY()); } public void showPopup(MouseEvent e, final ContactItem item) { final JPopupMenu popup = new JPopupMenu(); JMenu menu; JMenuItem menuItem; popup.add(menuItem = new JMenuItem(new AbstractAction("Start Chat") { @Override public void actionPerformed(ActionEvent e) { ChatsyManager.getWorkspace().getCommandPanel().chatButtonClick(); } })); popup.add(menuItem = new JMenuItem(new AbstractAction("View Profile") { @Override public void actionPerformed(ActionEvent e) { VCardManager vCardManager = ChatsyManager.getVCardManager(); String jid = item.getJID(); vCardManager.viewProfile(jid, ChatsyManager.getWorkspace()); } })); if (getContactGroups().size() > 1) { popup.add(menu = new JMenu("Move to")); ContactGroup group = getContactGroup(item.getGroupName()); for (ContactGroup contactGroup : getContactGroups()) { if (!contactGroup.getGroupName().equals(group.getGroupName())) menu.add(menuItem = new JMenuItem(new AbstractAction(contactGroup.getGroupName()) { @Override public void actionPerformed(ActionEvent e) { String groupName = item.getGroupName(); String newGroupName = (String) getValue(NAME); ContactGroup group = getContactGroup(groupName); ContactGroup newGroup = getContactGroup(newGroupName); if (group == null || newGroup == null) return; group.removeContactItem(item); newGroup.addContactItem(item); revalidate(); repaint(); } })); } } popup.addSeparator(); popup.add(menuItem = new JMenuItem(new AbstractAction("Delete") { @Override public void actionPerformed(ActionEvent e) { removeContactFromRoster(item); revalidate(); repaint(); } })); popup.show(item, e.getX(), e.getY()); } public void showPopup(MouseEvent e, final Collection<ContactItem> items) { ContactGroup group = null; for (ContactItem item : items) { group = getContactGroup(item.getGroupName()); if (group != null) break; } if (group == null) return; final JPopupMenu popup = new JPopupMenu(); JMenu menu; JMenuItem menuItem; popup.add(menuItem = new JMenuItem(new AbstractAction("Start Conference") { @Override public void actionPerformed(ActionEvent e) { ChatsyManager.getWorkspace().getCommandPanel().chatButtonClick(); } })); if (getContactGroups().size() > 1) { popup.add(menu = new JMenu("Move to")); for (ContactGroup contactGroup : getContactGroups()) { if (!contactGroup.getGroupName().equals(group.getGroupName())) menu.add(menuItem = new JMenuItem(new AbstractAction(contactGroup.getGroupName()) { @Override public void actionPerformed(ActionEvent e) { for (ContactItem item : items) { String groupName = item.getGroupName(); String newGroupName = (String) getValue(NAME); ContactGroup group = getContactGroup(groupName); ContactGroup newGroup = getContactGroup(newGroupName); if (group == null || newGroup == null) return; group.removeContactItem(item); newGroup.addContactItem(item); } revalidate(); repaint(); } })); } } popup.addSeparator(); popup.add(menuItem = new JMenuItem(new AbstractAction("Delete") { @Override public void actionPerformed(ActionEvent e) { for (ContactItem item : items) removeContactFromRoster(item); revalidate(); repaint(); } })); popup.show(group.getListPanel(), e.getX(), e.getY()); } public void clearSelectionList(ContactItem contactItem) { if (!selectedContacts.isEmpty()) for (ContactItem item : selectedContacts) item.setSelected(false); selectedContacts.clear(); if (contactItem != null) { selectedContacts.add(contactItem); contactItem.setSelected(true); } } public void initialize() { ChatsyManager.getVCardManager(); ChatsyManager.getMainWindow().getTopToolBar().setVisible(false); final Runnable sharedGroupLoader = new Runnable() { public void run() { SwingUtilities.invokeLater(new Runnable() { public void run() { loadContactList(); } }); } }; TaskEngine.getInstance().submit(sharedGroupLoader); } private void loadContactList() { buildContactList(); showEmptyGroups(false); showOfflineUsers(false); addSubscriptionListener(); ChatsyManager.getWorkspace().loadPlugins(); } public void addSubscriptionListener() { PacketFilter packetFilter = new PacketTypeFilter(Presence.class); PacketListener subscribeListener = new PacketListener() { public void processPacket(Packet packet) { final Presence presence = (Presence)packet; if (presence.getType() == Presence.Type.subscribe) { SwingUtilities.invokeLater(new Runnable() { public void run() { subscriptionRequest(presence.getFrom()); } }); } else if (presence.getType() == Presence.Type.unsubscribe) { SwingUtilities.invokeLater(new Runnable() { public void run() { Roster roster = ChatsyManager.getConnection().getRoster(); RosterEntry entry = roster.getEntry(presence.getFrom()); if (entry != null) { try { removeContactItem(presence.getFrom()); roster.removeEntry(entry); } catch (XMPPException e) { Presence unsub = new Presence(Presence.Type.unsubscribed); unsub.setTo(presence.getFrom()); ChatsyManager.getConnection().sendPacket(unsub); LOG.log(Level.SEVERE, "", e); } } } }); } else if (presence.getType() == Presence.Type.subscribe) { String jid = StringUtils.parseBareAddress(presence.getFrom()); ContactItem item = getContactItemByJID(jid); if (item == null) { final Roster roster = ChatsyManager.getConnection().getRoster(); RosterEntry entry = roster.getEntry(jid); if (entry != null) { item = new ContactItem(entry.getName(), null, jid); moveToOffline(item); } } } else if (presence.getType() == Presence.Type.unsubscribed) { SwingUtilities.invokeLater(new Runnable() { public void run() { Roster roster = ChatsyManager.getConnection().getRoster(); RosterEntry entry = roster.getEntry(presence.getFrom()); if (entry != null) { try { removeContactItem(presence.getFrom()); roster.removeEntry(entry); } catch (XMPPException e) { LOG.log(Level.SEVERE, "", e); } } String jid = StringUtils.parseBareAddress(presence.getFrom()); removeContactItem(jid); } }); } else { try { initialPresences.add(presence); } catch (Exception e) { LOG.log(Level.SEVERE, "", e); } int numberOfMillisecondsInTheFuture = 1000; presenceTimer.schedule(new TimerTask() { public void run() { SwingUtilities.invokeLater(new Runnable() { public void run() { for (Presence userToUpdate : new ArrayList<Presence>(initialPresences)) { initialPresences.remove(userToUpdate); try { updateUserPresence(userToUpdate); } catch (Exception e) { LOG.log(Level.SEVERE, "", e); } } } }); } }, numberOfMillisecondsInTheFuture); } } }; ChatsyManager.getConnection().addPacketListener(subscribeListener, packetFilter); } public void shutdown() { } public boolean canShutDown() { return true; } private void showEmptyGroups(boolean show) { for (ContactGroup group : getContactGroups()) if (group.isEmpty()) group.setVisible(show); } private void showOfflineUsers(boolean show) { for (ContactGroup group : getContactGroups()) { for (ContactItem item : group.getContactItems()) if (item.isOffline()) item.setVisible(show); } } public static final Comparator<ContactGroup> GROUP_COMPARATOR = new Comparator<ContactGroup>() { public int compare(ContactGroup group1, ContactGroup group2) { if (group2.isOfflineGroup()) return -1; return group1.getGroupName().trim().toLowerCase().compareTo(group2.getGroupName().trim().toLowerCase()); } }; public JPanel getMainPanel() { return mainPanel; } public List<ContactGroup> getContactGroups() { final List<ContactGroup> gList = new ArrayList<ContactGroup>(); final Component[] components = mainPanel.getComponents(); for (int i = 0; i < components.length; i++) if (components[i] instanceof ContactGroup) gList.add((ContactGroup)components[i]); return gList; } private void subscriptionRequest(final String jid) { final SubscriptionDialog subscriptionDialog = new SubscriptionDialog(); subscriptionDialog.invoke(jid); } public JComponent getGUI() { return this; } public Collection<ContactItem> getSelectedUsers() { return selectedContacts; } private void checkGroup(ContactGroup group) { if (!group.hasAvailableContacts()) group.setVisible(false); } public void contactItemAdded(ContactItem item) { fireContactItemAdded(item); } public void contactItemRemoved(ContactItem item) { fireContactItemRemoved(item); } public void addContactListListener(ContactListListener listener) { contactListListeners.add(listener); } public void removeContactListListener(ContactListListener listener) { contactListListeners.remove(listener); } public void fireContactItemAdded(ContactItem item) { for (ContactListListener contactListListener : new ArrayList<ContactListListener>(contactListListeners)) contactListListener.contactItemAdded(item); } public void fireContactItemRemoved(ContactItem item) { for (ContactListListener contactListListener : new ArrayList<ContactListListener>(contactListListeners)) contactListListener.contactItemRemoved(item); } public void fireContactGroupAdded(ContactGroup group) { for (ContactListListener contactListListener : new ArrayList<ContactListListener>(contactListListeners)) contactListListener.contactGroupAdded(group); } public void fireContactGroupRemoved(ContactGroup group) { for (ContactListListener contactListListener : new ArrayList<ContactListListener>(contactListListeners)) contactListListener.contactGroupRemoved(group); } public void fireContactItemClicked(ContactItem contactItem) { for (ContactListListener contactListListener : new ArrayList<ContactListListener>(contactListListeners)) contactListListener.contactItemClicked(contactItem); } public void fireContactItemDoubleClicked(ContactItem contactItem) { for (ContactListListener contactListListener : new ArrayList<ContactListListener>(contactListListeners)) contactListListener.contactItemDoubleClicked(contactItem); } public void uninstall() { } public void connectionClosed() { ChatsyManager.getMainWindow().setVisible(true); ChatsyManager.getNativeManager().flashWindowStopOnFocus(null); removeAllUsers(); } private void reconnect() { ChatsyManager.getMainWindow().setVisible(true); removeAllUsers(); } public void clientReconnected() { workspace.changeCardLayout(Workspace.WORKSPACE_PANE); buildContactList(); final TimerTask updatePresence = new TimerTask() { public void run() { final Presence myPresence = ChatsyManager.getWorkspace().getStatusBar().getPresence(); ChatsyManager.getSessionManager().changePresence(myPresence); XMPPConnection con = ChatsyManager.getConnection(); final Roster roster = con.getRoster(); for (RosterEntry entry : roster.getEntries()) { String user = entry.getUser(); Presence presence = roster.getPresence(user); try { updateUserPresence(presence); } catch (Exception e) { LOG.log(Level.SEVERE, "", e); } } } }; TaskEngine.getInstance().schedule(updatePresence, 5000); } public void connectionClosedOnError(final Exception ex) { } private void removeAllUsers() { for (ContactGroup contactGroup : new ArrayList<ContactGroup>(getContactGroups())) contactGroup.removeAllContacts(); } public void reconnectingIn(int i) { } public void reconnectionSuccessful() { clientReconnected(); } public void reconnectionFailed(Exception exception) { } private void moveToOffline(ContactItem contactItem) { String jid = contactItem.getJID(); final Roster roster = ChatsyManager.getConnection().getRoster(); for (RosterGroup group : roster.getEntry(jid).getGroups()) { ContactGroup contactGroup = getContactGroup(group.getName()); if (contactGroup == null && !group.getName().isEmpty()) contactGroup = addContactGroup(group.getName()); if (contactGroup != null) contactGroup.addOfflineContactItem(contactItem.getAlias(), contactItem.getNickname(), contactItem.getJID(), contactItem.getStatus()); } for (ContactGroup group : getContactGroups()) group.toggleOfflineVisibility(false); } public final static Comparator<ContactItem> ContactItemComparator = new Comparator<ContactItem>() { public int compare(ContactItem item1, ContactItem item2) { return item1.getDisplayName().toLowerCase().compareTo(item2.getDisplayName().toLowerCase()); } }; }