/**
* $RCSfile: ,v $
* $Revision: $
* $Date: $
*
* Copyright (C) 2004-2011 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.spark.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JCheckBoxMenuItem;
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.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import org.jivesoftware.MainWindowListener;
import org.jivesoftware.Spark;
import org.jivesoftware.resource.Default;
import org.jivesoftware.resource.Res;
import org.jivesoftware.resource.SparkRes;
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.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.RosterPacket;
import org.jivesoftware.smack.packet.StreamError;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.LastActivityManager;
import org.jivesoftware.smackx.SharedGroupManager;
import org.jivesoftware.smackx.packet.LastActivity;
import org.jivesoftware.spark.ChatManager;
import org.jivesoftware.spark.PresenceManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.Workspace;
import org.jivesoftware.spark.component.InputDialog;
import org.jivesoftware.spark.component.RolloverButton;
import org.jivesoftware.spark.component.VerticalFlowLayout;
import org.jivesoftware.spark.plugin.ContextMenuListener;
import org.jivesoftware.spark.plugin.Plugin;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.ResourceUtils;
import org.jivesoftware.spark.util.SwingWorker;
import org.jivesoftware.spark.util.TaskEngine;
import org.jivesoftware.spark.util.UIComponentRegistry;
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;
public class ContactList extends JPanel implements ActionListener,
ContactGroupListener, Plugin, RosterListener, ConnectionListener {
private static final long serialVersionUID = -4391111935248627078L;
private JPanel mainPanel = new JPanel();
private JScrollPane contactListScrollPane;
private final List<ContactGroup> groupList = new ArrayList<ContactGroup>();
private final RolloverButton addingGroupButton;
private ContactItem activeItem;
private ContactGroup activeGroup;
private ContactGroup unfiledGroup;
// Create Menus
private JMenuItem addContactMenu;
private JMenuItem addContactGroupMenu;
private JMenuItem removeContactFromGroupMenu;
private JMenuItem chatMenu;
private JMenuItem renameMenu;
private ContactGroup offlineGroup;
private final JCheckBoxMenuItem showHideMenu = new JCheckBoxMenuItem();
private final JCheckBoxMenuItem showOfflineGroupMenu = new JCheckBoxMenuItem();
private final JCheckBoxMenuItem showOfflineUsersMenu = new JCheckBoxMenuItem();
private List<String> sharedGroups = new ArrayList<String>();
private final List<ContextMenuListener> contextListeners = new ArrayList<ContextMenuListener>();
private List<Presence> initialPresences = new ArrayList<Presence>();
private final Timer presenceTimer = new Timer();
private final List<FileDropListener> dndListeners = new ArrayList<FileDropListener>();
private final List<ContactListListener> contactListListeners = new ArrayList<ContactListListener>();
private Properties props;
private File propertiesFile;
private LocalPreferences localPreferences;
private ContactItem contactItem;
private String name, user;
public static final String RETRY_PANEL = "RETRY_PANEL";
private ReconnectPanel _reconnectPanel;
private ReconnectPanelSmall _reconnectpanelsmall;
private ReconnectPanelIcon _reconnectpanelicon;
private Workspace workspace;
public static KeyEvent activeKeyEvent;
/**
* Creates a new instance of ContactList.
*/
public ContactList() {
// Load Local Preferences
localPreferences = SettingsManager.getLocalPreferences();
offlineGroup = UIComponentRegistry.createContactGroup(Res.getString("group.offline"));
JToolBar toolbar = new JToolBar();
toolbar.setFloatable(false);
addContactMenu = new JMenuItem(Res.getString("menuitem.add.contact"), SparkRes.getImageIcon(SparkRes.USER1_ADD_16x16));
addContactGroupMenu = new JMenuItem(Res.getString("menuitem.add.contact.group"), SparkRes.getImageIcon(SparkRes.SMALL_ADD_IMAGE));
removeContactFromGroupMenu = new JMenuItem(Res.getString("menuitem.remove.from.group"), SparkRes.getImageIcon(SparkRes.SMALL_DELETE));
chatMenu = new JMenuItem(Res.getString("menuitem.start.a.chat"), SparkRes.getImageIcon(SparkRes.SMALL_MESSAGE_IMAGE));
renameMenu = new JMenuItem(Res.getString("menuitem.rename"), SparkRes.getImageIcon(SparkRes.DESKTOP_IMAGE));
addContactMenu.addActionListener(this);
removeContactFromGroupMenu.addActionListener(this);
chatMenu.addActionListener(this);
renameMenu.addActionListener(this);
setLayout(new BorderLayout());
addingGroupButton = new RolloverButton(SparkRes.getImageIcon(SparkRes.ADD_CONTACT_IMAGE));
RolloverButton groupChatButton = new RolloverButton(SparkRes.getImageIcon(SparkRes.JOIN_GROUPCHAT_IMAGE));
toolbar.add(addingGroupButton);
toolbar.add(groupChatButton);
addingGroupButton.addActionListener(this);
mainPanel.setLayout(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false));
mainPanel.setBackground((Color)UIManager.get("ContactItem.background"));
contactListScrollPane = new JScrollPane(mainPanel);
contactListScrollPane.setAutoscrolls(true);
contactListScrollPane.setBorder(BorderFactory.createEmptyBorder());
contactListScrollPane.getVerticalScrollBar().setBlockIncrement(200);
contactListScrollPane.getVerticalScrollBar().setUnitIncrement(20);
_reconnectPanel = new ReconnectPanel();
_reconnectpanelsmall = new ReconnectPanelSmall(Res.getString("button.reconnect2"));
_reconnectpanelicon = new ReconnectPanelIcon();
workspace = SparkManager.getWorkspace();
workspace.getCardPanel().add(RETRY_PANEL, _reconnectPanel);
add(contactListScrollPane, BorderLayout.CENTER);
// Load Properties file
props = new Properties();
// Save to properties file.
propertiesFile = new File(Spark.getSparkUserHome() + "/groups.properties");
try {
props.load(new FileInputStream(propertiesFile));
}
catch (IOException e) {
// File does not exist.
}
// Add ActionListener(s) to menus
// addContactGroup(unfiledGroup);
addContactGroup(offlineGroup);
showHideMenu.setSelected(false);
// Add KeyMappings
SparkManager.getMainWindow().getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control F"), "searchContacts");
SparkManager.getMainWindow().getRootPane().getActionMap().put("searchContacts", new AbstractAction("searchContacts") {
private static final long serialVersionUID = -5956142123453578689L;
public void actionPerformed(ActionEvent evt) {
SparkManager.getUserManager().searchContacts("", SparkManager.getMainWindow());
}
});
// Handle Command-F on Macs
SparkManager.getMainWindow().getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "appleStrokeF");
SparkManager.getMainWindow().getRootPane().getActionMap().put("appleStrokeF", new AbstractAction("appleStrokeF") {
private static final long serialVersionUID = 7883006402414136652L;
public void actionPerformed(ActionEvent evt) {
SparkManager.getUserManager().searchContacts("", SparkManager.getMainWindow());
}
});
// Save state on shutdown.
SparkManager.getMainWindow().addMainWindowListener(new MainWindowListener() {
public void shutdown() {
saveState();
}
public void mainWindowActivated() {
}
public void mainWindowDeactivated() {
}
});
SparkManager.getConnection().addConnectionListener(this);
// Get command panel and add View Online/Offline, Add Contact
// StatusBar statusBar = SparkManager.getWorkspace().getStatusBar();
// final JPanel commandPanel = SparkManager.getWorkspace().getCommandPanel();
//
//
// final RolloverButton addContactButton = new RolloverButton(SparkRes.getImageIcon(SparkRes.USER1_ADD_16x16));
// if (!Default.getBoolean(Default.ADD_CONTACT_DISABLED)) {
// commandPanel.add(addContactButton);
// }
// addContactButton.setToolTipText(Res.getString("message.add.a.contact"));
// addContactButton.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// new RosterDialog().showRosterDialog();
// }
// });
}
/**
* Switches all users to Offline and Creates a Reconnection Group
*/
private synchronized void switchAllUserOffline(final boolean onError)
{
SwingWorker worker = new SwingWorker() {
@Override
public Object construct() {
mainPanel.add(_reconnectpanelsmall,0);
_reconnectpanelsmall.setClosedOnError(onError);
final Collection<RosterEntry> roster = SparkManager.getConnection().getRoster().getEntries();
for(RosterEntry r : roster)
{
Presence p = new Presence(Presence.Type.unavailable);
moveToOfflineGroup(p, r.getUser());
}
return true;
}
};
worker.start();
}
/**
* Switches all Users to Offline and Creates an Icon in the CommandBar
*/
private synchronized void switchAllUserOfflineNoGroupEntry(final boolean onError) {
SwingWorker worker = new SwingWorker() {
@Override
public Object construct() {
_reconnectpanelicon.getPanel().add(_reconnectpanelicon.getButton(), 0);
_reconnectpanelicon.getPanel().revalidate();
_reconnectpanelicon.setClosedOnError(onError);
final Collection<RosterEntry> roster = SparkManager
.getConnection().getRoster().getEntries();
for (RosterEntry r : roster) {
Presence p = new Presence(Presence.Type.unavailable);
moveToOfflineGroup(p, r.getUser());
}
return true;
}
};
worker.start();
}
/**
* Updates the users presence.
*
* @param presence the user to update.
* @throws Exception if there is a problem while updating the user's presence.
*/
private synchronized void updateUserPresence(Presence presence) throws Exception {
if (presence.getError() != null) {
// We ignore this.
return;
}
final Roster roster = SparkManager.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 online, check to see if they are in the offline group.
// If so, remove from offline group and add to all groups they
// belong to.
if (presence.getType() == Presence.Type.available && offlineGroup.getContactItemByJID(bareJID) != null || (presence.getFrom().indexOf("workgroup.") != -1)) {
changeOfflineToOnline(bareJID, entry, presence);
}
else if (presence.getType() == Presence.Type.available) {
updateContactItemsPresence(presence, entry, bareJID);
}
else if (presence.getType() == Presence.Type.unavailable && !isPending) {
// If not available, move to offline group.
Presence rosterPresence = PresenceManager.getPresence(bareJID);
if (!rosterPresence.isAvailable()) {
moveToOfflineGroup(presence, bareJID);
}
else {
updateContactItemsPresence(rosterPresence, entry, bareJID);
}
}
}
/**
* Updates the presence of one individual based on their JID.
*
* @param presence the users presence.
* @param entry the roster entry being updated.
* @param bareJID the bare jid of the user.
*/
private void updateContactItemsPresence(Presence presence, RosterEntry entry, String bareJID) {
for (ContactGroup group : groupList) {
ContactItem item = group.getContactItemByJID(bareJID);
if (item != null) {
if (group == offlineGroup) {
changeOfflineToOnline(bareJID, entry, presence);
continue;
}
item.setPresence(presence);
group.fireContactGroupUpdated();
}
}
}
/**
* Moves every <code>ContactItem</code> associated with the given bareJID to offline.
*
* @param presence the users presence.
* @param bareJID the bareJID of the user.
*/
private void moveToOfflineGroup(final Presence presence, final String bareJID) {
for (ContactGroup grpItem : new ArrayList<ContactGroup>(groupList)) {
final ContactGroup group = grpItem;
final ContactItem item = group.getContactItemByJID(bareJID);
if (item != null) {
int numberOfMillisecondsInTheFuture = 3000;
Date timeToRun = new Date(System.currentTimeMillis() + numberOfMillisecondsInTheFuture);
// Only run through if the users presence was online before.
if (item.getPresence().isAvailable()) {
item.showUserGoingOfflineOnline();
item.setIcon(SparkRes.getImageIcon(SparkRes.CLEAR_BALL_ICON));
group.fireContactGroupUpdated();
final Timer offlineTimer = new Timer();
offlineTimer.schedule(new TimerTask() {
public void run() {
// Check to see if the user is offline, if so, move them to the offline group.
Presence userPresence = PresenceManager.getPresence(bareJID);
if (userPresence.isAvailable()) {
return;
}
item.setPresence(presence);
// Check for ContactItemHandler.
group.removeContactItem(item);
checkGroup(group);
if (offlineGroup.getContactItemByJID(item.getJID()) == null) {
moveToOffline(item);
offlineGroup.fireContactGroupUpdated();
}
}
}, timeToRun);
}
} else {
final ContactItem offlineItem = offlineGroup.getContactItemByJID(bareJID);
if (offlineItem != null) {
offlineItem.setPresence(presence);
}
}
}
}
/**
* Moves a user to each group they belong to.
*
* @param bareJID the bareJID of the user to show as online.
* @param entry the <code>RosterEntry</code> of the user.
* @param presence the users presence.
*/
private void changeOfflineToOnline(String bareJID, final RosterEntry entry, Presence presence) {
// Move out of offline group. Add to all groups.
final ContactItem offlineItem = offlineGroup.getContactItemByJID(bareJID);
if (offlineItem == null) {
return;
}
offlineGroup.removeContactItem(offlineItem);
// Add To all groups it belongs to.
boolean isFiled = false;
for (RosterGroup rosterGroup : entry.getGroups()) {
isFiled = true;
ContactGroup contactGroup = getContactGroup(rosterGroup.getName());
if (contactGroup == null) {
// Create Contact Group
contactGroup = addContactGroup(rosterGroup.getName());
}
if (contactGroup != null) {
ContactItem changeContactItem = null;
if (contactGroup.getContactItemByJID(entry.getUser()) == null) {
ContactItem offlineCurrentItem = contactGroup.getOfflineContactItemByJID(bareJID);
//prevents from duplicating roster contacts when users going offline and online with Offline Group invisible
contactGroup.removeContactItem(offlineCurrentItem);
// If we are reconnecting we have to check if we are on the
// dispatch thread
if (EventQueue.isDispatchThread()) {
changeContactItem = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
contactGroup.addContactItem(changeContactItem);
changeContactItem.setAvailable(true);
changeContactItem.setPresence(presence);
changeContactItem.updateAvatarInSideIcon();
changeContactItem.showUserComingOnline();
changeContactItem.setSpecialIcon(offlineItem.getSpecialImageLabel().getIcon());
//contactItem.updatePresenceIcon(contactItem.getPresence());
toggleGroupVisibility(contactGroup.getGroupName(), true);
//contactGroup.fireContactGroupUpdated();
int numberOfMillisecondsInTheFuture = 5000;
Date timeToRun = new Date(System.currentTimeMillis()
+ numberOfMillisecondsInTheFuture);
Timer timer = new Timer();
final ContactItem staticItem = changeContactItem;
final ContactGroup staticGroup = contactGroup;
timer.schedule(new TimerTask() {
public void run() {
staticItem.updatePresenceIcon(staticItem.getPresence());
staticGroup.fireContactGroupUpdated();
}
}, timeToRun);
} else {
final ContactGroup staticContactGroup = contactGroup;
final Presence staticItemPrecense = presence;
//Reconnection and not in dispatch Thread -> Add to EVentQueue
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
ContactItem changeContact = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
staticContactGroup.addContactItem(changeContact);
changeContact.setPresence(staticItemPrecense);
changeContact.setAvailable(true);
changeContact.updateAvatarInSideIcon();
changeContact.showUserComingOnline();
changeContact.setSpecialIcon(offlineItem.getSpecialImageLabel().getIcon());
changeContact.updatePresenceIcon(changeContact.getPresence());
toggleGroupVisibility(staticContactGroup.getGroupName(), true);
staticContactGroup.fireContactGroupUpdated();
}
});
}
}
}
}
if (!isFiled) {
if (unfiledGroup.getContactItemByJID(entry.getUser()) == null) {
// If we are reconnecting we have to check if we are on the
// dispatch thread
if (EventQueue.isDispatchThread()) {
contactItem = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
ContactGroup unfiledGrp = getUnfiledGroup();
unfiledGrp.addContactItem(contactItem);
contactItem.setPresence(presence);
contactItem.setAvailable(true);
unfiledGrp.setVisible(true);
unfiledGrp.fireContactGroupUpdated();
} else {
final Presence staticItemPrecense = presence;
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
contactItem = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
ContactGroup unfiledGrp = getUnfiledGroup();
contactItem.setPresence(staticItemPrecense);
contactItem.setAvailable(true);
unfiledGrp.addContactItem(contactItem);
contactItem.updatePresenceIcon(contactItem.getPresence());
unfiledGrp.fireContactGroupUpdated();
}
});
}
}
}
}
/**
* Called to build the initial ContactList.
*/
private void buildContactList() {
XMPPConnection con = SparkManager.getConnection();
final Roster roster = con.getRoster();
roster.addRosterListener(this);
// Add All Groups to List
for (RosterGroup group : roster.getGroups()) {
addContactGroup(group.getName());
}
for (RosterGroup group : roster.getGroups()) {
if(group.getName() == null || group.getName() == ""){
for(RosterEntry entry : group.getEntries()){
ContactItem buildContactItem = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
moveToOffline(buildContactItem);
}
}else{
ContactGroup contactGroup = getContactGroup(group.getName());
if (contactGroup == null) {
contactGroup = getUnfiledGroup();
}
for (RosterEntry entry : group.getEntries()) {
contactItem = null;
name = entry.getName();
user = entry.getUser();
// in case of connection lost, the creation must be done in eventqueue
if(EventQueue.isDispatchThread()) {
contactItem = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
}
else {
try {
EventQueue.invokeAndWait(new Runnable(){
public void run() {
contactItem = UIComponentRegistry.createContactItem(name, null, user);
}
});
} catch(Exception ex) {
ex.printStackTrace();
}
}
// if there was something wrong, try an other
if(contactItem == null)
continue;
contactItem.setPresence(new Presence(Presence.Type.unavailable));
if ((entry.getType() == RosterPacket.ItemType.none || entry.getType() == RosterPacket.ItemType.from)
&& RosterPacket.ItemStatus.SUBSCRIPTION_PENDING == entry.getStatus()) {
// Add to contact group.
contactGroup.addContactItem(contactItem);
contactGroup.setVisible(true);
}
else {
if (offlineGroup.getContactItemByJID(entry.getUser()) == null) {
moveToOffline(contactItem);
}
}
}
}
}
if (EventQueue.isDispatchThread()) {
// Add Unfiled Group
for (RosterEntry entry : roster.getUnfiledEntries()) {
ContactItem moveToOfflineContactItem = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
moveToOffline(moveToOfflineContactItem);
}
}
else
{
try {
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
for (RosterEntry entry : roster.getUnfiledEntries()) {
ContactItem moveToOfflineContactItem = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
moveToOffline(moveToOfflineContactItem);
}
}
});
} catch (Exception e) {
Log.error("moveToOffilne",e);
}
}
}
/**
* Called when NEW entries are added.
*
* @param addresses the address added.
*/
public void entriesAdded(final Collection<String> addresses) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Roster roster = SparkManager.getConnection().getRoster();
for (String jid : addresses) {
RosterEntry entry = roster.getEntry(jid);
addUser(entry);
}
}
});
}
/**
* Adds a single user to the ContactList.
*
* @param entry the <code>RosterEntry</code> of the the user.
*/
private void addUser(RosterEntry entry) {
ContactItem newContactItem = UIComponentRegistry.createContactItem(entry.getName(), null, entry.getUser());
if (entry.getType() == RosterPacket.ItemType.none || entry.getType() == RosterPacket.ItemType.from) {
// Ignore, since the new user is pending to be added.
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);
}
// Update users icon
Presence presence = SparkManager.getConnection().getRoster().getPresence(entry.getUser());
try {
updateUserPresence(presence);
}
catch (Exception e) {
Log.error(e);
}
}
/**
* Handle when the Roster changes based on subscription notices.
*
* @param addresses List of entries that were updated.
*/
public void entriesUpdated(final Collection<String> addresses) {
handleEntriesUpdated(addresses);
}
/**
* Called when users are removed from the roster.
*
* @param addresses the addresses removed from the roster.
*/
public void entriesDeleted(final Collection<String> addresses) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
for (String jid : addresses) {
removeContactItem(jid);
}
}
});
}
/**
* Handles any presence modifications of a user(s).
*
* @param addresses the Collection of addresses that have been modified within the Roster.
*/
private synchronized void handleEntriesUpdated(final Collection<String> addresses) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Roster roster = SparkManager.getConnection().getRoster();
Iterator<String> jids = addresses.iterator();
while (jids.hasNext()) {
String jid = jids.next();
RosterEntry rosterEntry = roster.getEntry(jid);
if (rosterEntry != null) {
// Check for new Roster Groups and add them if they do not exist.
boolean isUnfiled = true;
for (RosterGroup group : rosterEntry.getGroups()) {
isUnfiled = false;
// Handle if this is a new Entry in a new Group.
if (getContactGroup(group.getName()) == null) {
// Create group.
ContactGroup contactGroup = addContactGroup(group.getName());
contactGroup.setVisible(false);
contactGroup = getContactGroup(group.getName());
ContactItem contactItem = UIComponentRegistry.createContactItem(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 = offlineGroup.getContactItemByJID(jid);
if (item == null) {
item = contactGroup.getContactItemByJID(jid);
}
// Check to see if this entry is new to a pre-existing group.
if (item == null) {
item = UIComponentRegistry.createContactItem(rosterEntry.getName(), null, rosterEntry.getUser());
Presence presence = PresenceManager.getPresence(jid);
item.setPresence(presence);
if (presence.isAvailable()) {
contactGroup.addContactItem(item);
contactGroup.fireContactGroupUpdated();
}
else {
moveToOffline(item);
offlineGroup.fireContactGroupUpdated();
}
}
// If not, just update their presence.
else {
RosterEntry entry = roster.getEntry(jid);
Presence presence = PresenceManager.getPresence(jid);
item.setPresence(presence);
try {
updateUserPresence(presence);
}
catch (Exception e) {
Log.error(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();
}
}
}
// Now check to see if groups have been modified or removed. This is used
// to check if Contact Groups have been renamed or removed.
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 && group != getUnfiledGroup() && group != offlineGroup) {
if (!userGroupSet.contains(group.getGroupName())) {
if (group.getContactItems().isEmpty()) {
removeContactGroup(group);
} else {
group.removeContactItem(itemFound);
}
}
}
}
}
if (!isUnfiled) {
return;
}
ContactGroup unfiledGrp = getUnfiledGroup();
ContactItem unfiledItem = unfiledGrp.getContactItemByJID(jid);
if (unfiledItem != null) {
}
else {
ContactItem offlineItem = offlineGroup.getContactItemByJID(jid);
if (offlineItem != null) {
if ((rosterEntry.getType() == RosterPacket.ItemType.none || rosterEntry.getType() == RosterPacket.ItemType.from)
&& RosterPacket.ItemStatus.SUBSCRIPTION_PENDING == rosterEntry.getStatus()) {
// Remove from offlineItem and add to unfiledItem.
offlineGroup.removeContactItem(offlineItem);
unfiledGrp.addContactItem(offlineItem);
unfiledGrp.fireContactGroupUpdated();
unfiledGrp.setVisible(true);
}
}
}
}
}
}
});
}
public void presenceChanged(Presence presence) {
}
/**
* Retrieve the ContactItem by it's jid.
*
* @param jid the JID of the user.
* @return the "first" contact item found.
*/
public ContactItem getContactItemByJID(String jid) {
for (ContactGroup group : getContactGroups()) {
ContactItem item = group.getContactItemByJID(StringUtils.parseBareAddress(jid));
if (item != null) {
return item;
}
}
return null;
}
/**
* Returns a Collection of ContactItems in a ContactList.
*
* @param jid the users JID.
* @return a Collection of <code>ContactItem</code> items.
*/
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);
}
}
/**
* We have to search ContactItems into offline contacts.
* Standart getContactItemByJID() method search ContactItems only in OfflineGroup or into inline cantacts
*/
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;
}
/**
* Set an Icon for all ContactItems that match the given jid.
*
* @param jid the users jid.
* @param icon the icon to use.
*/
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();
}
}
}
/**
* Sets the default settings for a ContactItem.
*
* @param jid the users jid.
*/
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();
}
}
}
/**
* Retrieve the ContactItem by their displayed name (either alias, nickname or username).
*
* @param displayName the users nickname in the contact list.
* @return the "first" contact item found.
*/
public ContactItem getContactItemByDisplayName(String displayName) {
for (ContactGroup contactGroup : getContactGroups()) {
ContactItem item = contactGroup.getContactItemByDisplayName(displayName);
if (item != null) {
return item;
}
}
return null;
}
/**
* Adds a new ContactGroup to the ContactList.
*
* @param group the group to add.
*/
private void addContactGroup(ContactGroup group) {
groupList.add(group);
Collections.sort(groupList, GROUP_COMPARATOR);
try {
mainPanel.add(group, groupList.indexOf(group));
}
catch (Exception e) {
Log.error(e);
}
group.addContactGroupListener(this);
fireContactGroupAdded(group);
// Check state
String prop = props.getProperty(group.getGroupName());
if (prop != null) {
boolean isCollapsed = Boolean.valueOf(prop);
group.setCollapsed(isCollapsed);
}
}
/**
* Creates and adds a new ContactGroup to the ContactList.
*
* @param groupName the name of the ContactGroup to add.
* @return the newly created ContactGroup.
*/
private ContactGroup addContactGroup(String groupName) {
StringTokenizer tkn = new StringTokenizer(groupName, "::");
ContactGroup rootGroup = null;
ContactGroup lastGroup = null;
StringBuffer buf = new StringBuffer();
boolean groupAdded = false;
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);
}
ContactGroup newContactGroup = getContactGroup(name);
if (newContactGroup == null) {
newContactGroup = UIComponentRegistry.createContactGroup(group);
String realGroupName = buf.toString();
if (realGroupName.endsWith("::")) {
realGroupName = realGroupName.substring(0, realGroupName.length() - 2);
}
newContactGroup.setGroupName(realGroupName);
}
else {
if (newContactGroup != offlineGroup && newContactGroup != getUnfiledGroup()) {
rootGroup = newContactGroup;
continue;
}
}
if (lastGroup != null) {
lastGroup.addContactGroup(newContactGroup);
groupList.add(newContactGroup);
}
else if (rootGroup != null) {
rootGroup.addContactGroup(newContactGroup);
groupList.add(newContactGroup);
}
else {
rootGroup = newContactGroup;
}
lastGroup = newContactGroup;
newContactGroup.addContactGroupListener(this);
if (sharedGroups != null) {
boolean isSharedGroup = sharedGroups.contains(newContactGroup.getGroupName());
newContactGroup.setSharedGroup(isSharedGroup);
}
fireContactGroupAdded(newContactGroup);
// Check state
String prop = props.getProperty(newContactGroup.getGroupName());
if (prop != null) {
boolean isCollapsed = Boolean.valueOf(prop);
newContactGroup.setCollapsed(isCollapsed);
}
groupAdded = true;
}
if (!groupAdded) {
return getContactGroup(groupName);
}
final List<ContactGroup> tempList = new ArrayList<ContactGroup>();
final Component[] comps = mainPanel.getComponents();
for (Component c : comps) {
if (c instanceof ContactGroup && c != offlineGroup) {
tempList.add((ContactGroup)c);
}
}
tempList.add(rootGroup);
groupList.add(rootGroup);
Collections.sort(tempList, GROUP_COMPARATOR);
int loc = tempList.indexOf(rootGroup);
try {
mainPanel.add(rootGroup, loc);
}
catch (Exception e) {
Log.error(e);
}
//Check if i should show groups with no users online
if (null != getContactGroup(groupName) && !getContactGroup(groupName).hasAvailableContacts())
{
showEmptyGroups(localPreferences.isEmptyGroupsShown());
}
return getContactGroup(groupName);
}
/**
* Removes a ContactGroup from the group model and ContactList.
*
* @param contactGroup the ContactGroup to remove.
*/
private void removeContactGroup(ContactGroup contactGroup) {
contactGroup.removeContactGroupListener(this);
groupList.remove(contactGroup);
mainPanel.remove(contactGroup);
ContactGroup parent = getParentGroup(contactGroup.getGroupName());
if (parent != null) {
parent.removeContactGroup(contactGroup);
}
contactListScrollPane.validate();
mainPanel.invalidate();
mainPanel.repaint();
fireContactGroupRemoved(contactGroup);
}
/**
* Returns a ContactGroup based on its name.
*
* @param groupName the name of the ContactGroup.
* @return the ContactGroup. If no ContactGroup is found, null is returned.
*/
public ContactGroup getContactGroup(String groupName) {
ContactGroup cGroup = null;
for (ContactGroup contactGroup : groupList) {
if (contactGroup.getGroupName().equals(groupName)) {
cGroup = contactGroup;
break;
}
else {
cGroup = getSubContactGroup(contactGroup, groupName);
if (cGroup != null) {
break;
}
}
}
return cGroup;
}
/**
* For traversing of a nested group. Allows users to find the owning parent of a given contact group.
*
* @param groupName the name of the nested contact group.
* @return the parent ContactGroup. If no parent, null will be returned.
*/
public ContactGroup getParentGroup(String groupName) {
// Check if there is even a parent group
if (!groupName.contains("::")) {
return null;
}
final ContactGroup group = getContactGroup(groupName);
if (group == null) {
return null;
}
// Otherwise, find parent
int index = groupName.lastIndexOf("::");
String parentGroupName = groupName.substring(0, index);
return getContactGroup(parentGroupName);
}
/**
* Returns the nested ContactGroup of a given ContactGroup with associated name.
*
* @param group the parent ContactGroup.
* @param groupName the name of the nested group.
* @return the nested ContactGroup. If not found, null will be returned.
*/
private ContactGroup getSubContactGroup(ContactGroup group, String groupName) {
final Iterator<ContactGroup> contactGroups = group.getContactGroups().iterator();
ContactGroup grp = null;
while (contactGroups.hasNext()) {
ContactGroup contactGroup = contactGroups.next();
if (contactGroup.getGroupName().equals(groupName)) {
grp = contactGroup;
break;
}
else if (contactGroup.getContactGroups().size() > 0) {
grp = getSubContactGroup(contactGroup, groupName);
if (grp != null) {
break;
}
}
}
return grp;
}
/**
* Toggles the visiblity of a ContactGroup.
*
* @param groupName the name of the ContactGroup.
* @param visible true to show, otherwise false.
*/
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(visible);
}
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == addingGroupButton) {
new RosterDialog().showRosterDialog();
}
else if (e.getSource() == chatMenu) {
if (activeItem != null) {
SparkManager.getChatManager().activateChat(activeItem.getJID(), activeItem.getDisplayName());
}
}
else if (e.getSource() == addContactMenu) {
RosterDialog rosterDialog = new RosterDialog();
if (activeGroup != null) {
rosterDialog.setDefaultGroup(activeGroup);
}
rosterDialog.showRosterDialog();
}
else if (e.getSource() == removeContactFromGroupMenu) {
if (activeItem != null) {
removeContactFromGroup(activeItem);
}
}
else if (e.getSource() == renameMenu) {
if (activeItem == null) {
return;
}
String oldAlias = activeItem.getAlias();
String newAlias = JOptionPane.showInputDialog(this, Res.getString("label.rename.to") + ":", oldAlias);
// if user pressed 'cancel', output will be null.
// if user removed alias, output will be an empty String.
if (newAlias != null) {
if (!ModelUtil.hasLength(newAlias)) {
newAlias = null; // allows you to remove an alias.
}
String address = activeItem.getJID();
ContactGroup contactGroup = getContactGroup(activeItem.getGroupName());
ContactItem contactItem = contactGroup.getContactItemByDisplayName(activeItem.getDisplayName());
contactItem.setAlias(newAlias);
final Roster roster = SparkManager.getConnection().getRoster();
RosterEntry entry = roster.getEntry(address);
entry.setName(newAlias);
final Iterator<ContactGroup> contactGroups = groupList.iterator();
String user = StringUtils.parseBareAddress(address);
while (contactGroups.hasNext()) {
ContactGroup cg = contactGroups.next();
ContactItem ci = cg.getContactItemByJID(user);
if (ci != null) {
ci.setAlias(newAlias);
}
}
}
}
}
/**
* Removes a contact item from the group.
*
* @param item the ContactItem to remove.
*/
private void removeContactFromGroup(ContactItem item) {
String groupName = item.getGroupName();
ContactGroup contactGroup = getContactGroup(groupName);
Roster roster = SparkManager.getConnection().getRoster();
RosterEntry entry = roster.getEntry(item.getJID());
if (entry != null && contactGroup != offlineGroup) {
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.error("Error removing user from contact list.", e);
}
}
}
private void removeContactFromRoster(ContactItem item) {
Roster roster = SparkManager.getConnection().getRoster();
RosterEntry entry = roster.getEntry(item.getJID());
if (entry != null) {
try {
roster.removeEntry(entry);
}
catch (XMPPException e) {
Log.warning("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) {
activeItem = item;
if (activeKeyEvent == null || ((activeKeyEvent.getModifiers() & KeyEvent.CTRL_MASK) == 0)) {
clearSelectionList(item);
}
fireContactItemClicked(item);
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 contactGroupPopup(MouseEvent e, final ContactGroup group) {
// Do nothing with offline group
if (group == offlineGroup || group == getUnfiledGroup()) {
return;
}
final JPopupMenu popup = new JPopupMenu();
if (!Default.getBoolean(Default.ADD_CONTACT_DISABLED)) {
popup.add(addContactMenu);
}
if(!Default.getBoolean("ADD_CONTACT_GROUP_DISABLED")){
popup.add(addContactGroupMenu);
}
popup.addSeparator();
fireContextMenuListenerPopup(popup, group);
JMenuItem delete = new JMenuItem(Res.getString("menuitem.delete"));
JMenuItem rename = new JMenuItem(Res.getString("menuitem.rename"));
JMenuItem expand = new JMenuItem(Res.getString("menuitem.expand.all.groups"));
JMenuItem collapse = new JMenuItem(Res.getString("menuitem.collapse.all.groups"));
if (!group.isSharedGroup()) {
popup.addSeparator();
popup.add(delete);
popup.add(rename);
}
popup.addSeparator();
popup.add(expand);
popup.add(collapse);
delete.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int ok = JOptionPane.showConfirmDialog(group, Res.getString("message.delete.confirmation", group.getGroupName()), Res.getString("title.confirmation"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
if (ok == JOptionPane.YES_OPTION) {
String groupName = group.getGroupName();
Roster roster = SparkManager.getConnection().getRoster();
RosterGroup rosterGroup = roster.getGroup(groupName);
if (rosterGroup != null) {
for (RosterEntry entry : rosterGroup.getEntries()) {
try {
rosterGroup.removeEntry(entry);
}
catch (XMPPException e1) {
Log.error("Error removing entry", e1);
}
}
}
// Remove from UI
removeContactGroup(group);
invalidate();
repaint();
}
}
});
rename.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String newName = JOptionPane.showInputDialog(group, Res.getString("label.rename.to") + ":", Res.getString("title.rename.roster.group"), JOptionPane.QUESTION_MESSAGE);
if (!ModelUtil.hasLength(newName)) {
return;
}
String groupName = group.getGroupName();
Roster roster = SparkManager.getConnection().getRoster();
RosterGroup rosterGroup = roster.getGroup(groupName);
//Do not remove ContactGroup if the name entered was the same
if (rosterGroup != null && !groupName.equals(newName)) {
removeContactGroup(group);
rosterGroup.setName(newName);
addContactGroup(newName);
toggleGroupVisibility(newName, true);
getContactGroup(newName).setCollapsed( group.isCollapsed());
}
}
});
expand.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Collection<ContactGroup> groups = getContactGroups();
for (ContactGroup group : groups) {
group.setCollapsed(false);
}
}
});
collapse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Collection<ContactGroup> groups = getContactGroups();
for (ContactGroup group : groups) {
group.setCollapsed(true);
}
}
});
// popup.add(inviteFirstAcceptor);
popup.show(group, e.getX(), e.getY());
activeGroup = group;
}
public void showPopup(MouseEvent e, final ContactItem item)
{
showPopup(null,e,item);
}
/**
* Shows popup for right-clicking of ContactItem.
*
* @param e the MouseEvent
* @param item the ContactItem
* @param component the owning component
*/
public void showPopup(Component component, MouseEvent e, final ContactItem item) {
if (item.getJID() == null) {
return;
}
activeItem = item;
final JPopupMenu popup = new JPopupMenu();
// Add Start Chat Menu
popup.add(chatMenu);
// Add Send File Action
Action sendAction = new AbstractAction() {
private static final long serialVersionUID = -7519717310558205566L;
public void actionPerformed(ActionEvent actionEvent) {
SparkManager.getTransferManager().sendFileTo(item);
}
};
sendAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.DOCUMENT_16x16));
sendAction.putValue(Action.NAME, Res.getString("menuitem.send.a.file"));
if (item.getPresence() != null) {
popup.add(sendAction);
}
popup.addSeparator();
String groupName = item.getGroupName();
ContactGroup contactGroup = getContactGroup(groupName);
// Only show "Remove Contact From Group" if the user belongs to more than one group.
if (!contactGroup.isSharedGroup() && !contactGroup.isOfflineGroup() && contactGroup != getUnfiledGroup()) {
Roster roster = SparkManager.getConnection().getRoster();
RosterEntry entry = roster.getEntry(item.getJID());
if (entry != null) {
int groupCount = entry.getGroups().size();
//todo: It should be possible to remove a user from the only group they're in
// which would put them into the unfiled group.
if (groupCount > 1) {
popup.add(removeContactFromGroupMenu);
}
}
}
// Define remove entry action
Action removeAction = new AbstractAction() {
private static final long serialVersionUID = -2565914214685979320L;
public void actionPerformed(ActionEvent e) {
removeContactFromRoster(item);
}
};
removeAction.putValue(Action.NAME, Res.getString("menuitem.remove.from.roster"));
removeAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMALL_CIRCLE_DELETE));
// Check if user is in shared group.
boolean isInSharedGroup = false;
for (ContactGroup cGroup : new ArrayList<ContactGroup>(getContactGroups())) {
if (cGroup.isSharedGroup()) {
ContactItem it = cGroup.getContactItemByJID(item.getJID());
if (it != null) {
isInSharedGroup = true;
}
}
}
if (!contactGroup.isSharedGroup() && !isInSharedGroup) {
popup.add(removeAction);
}
popup.add(renameMenu);
Action viewProfile = new AbstractAction() {
private static final long serialVersionUID = -2562731455090634805L;
public void actionPerformed(ActionEvent e) {
VCardManager vcardSupport = SparkManager.getVCardManager();
String jid = item.getJID();
vcardSupport.viewProfile(jid, SparkManager.getWorkspace());
}
};
viewProfile.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.PROFILE_IMAGE_16x16));
viewProfile.putValue(Action.NAME, Res.getString("menuitem.view.profile"));
popup.add(viewProfile);
popup.addSeparator();
Action lastActivityAction = new AbstractAction() {
private static final long serialVersionUID = -4884230635430933060L;
public void actionPerformed(ActionEvent actionEvent) {
try {
String client = "";
if (item.getPresence().getType() != Presence.Type.unavailable) {
client = item.getPresence().getFrom();
if ((client != null) && (client.lastIndexOf("/") != -1)) {
client = client.substring(client.lastIndexOf("/"));
} else client = "/";
}
LastActivity activity = LastActivityManager.getLastActivity(SparkManager.getConnection(), item.getJID()+client);
long idleTime = (activity.getIdleTime() * 1000);
String time = ModelUtil.getTimeFromLong(idleTime);
JOptionPane.showMessageDialog(getGUI(), Res.getString("message.idle.for", time), Res.getString("title.last.activity"), JOptionPane.INFORMATION_MESSAGE);
}
catch (Exception e1) {
JOptionPane.showMessageDialog(getGUI(), Res.getString("message.unable.to.retrieve.last.activity", item.getJID()), Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
}
}
};
lastActivityAction.putValue(Action.NAME, Res.getString("menuitem.view.last.activity"));
lastActivityAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMALL_USER1_STOPWATCH));
if (contactGroup == offlineGroup || item.getPresence().isAway() || (item.getPresence().getType() == Presence.Type.unavailable) || (item.getPresence().getType() == null)) {
popup.add(lastActivityAction);
}
Action subscribeAction = new AbstractAction() {
private static final long serialVersionUID = -7754905015338902300L;
public void actionPerformed(ActionEvent e) {
String jid = item.getJID();
Presence response = new Presence(Presence.Type.subscribe);
response.setTo(jid);
SparkManager.getConnection().sendPacket(response);
}
};
subscribeAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMALL_USER1_INFORMATION));
subscribeAction.putValue(Action.NAME, Res.getString("menuitem.subscribe.to"));
Roster roster = SparkManager.getConnection().getRoster();
RosterEntry entry = roster.getEntry(item.getJID());
if (entry != null && entry.getType() == RosterPacket.ItemType.from) {
popup.add(subscribeAction);
}
else if( entry!=null && entry.getType() != RosterPacket.ItemType.both && entry.getStatus() == RosterPacket.ItemStatus.SUBSCRIPTION_PENDING)
{
popup.add(subscribeAction);
}
// Fire Context Menu Listener
fireContextMenuListenerPopup(popup, item);
ContactGroup group = getContactGroup(item.getGroupName());
if (component == null) {
popup.show(group.getList(), e.getX(), e.getY());
} else {
popup.show(component, e.getX(), e.getY());
popup.requestFocus();
}
}
public void showPopup(MouseEvent e, final Collection<ContactItem> items) {
ContactGroup group = null;
for (ContactItem item : items) {
group = getContactGroup(item.getGroupName());
break;
}
final JPopupMenu popup = new JPopupMenu();
final JMenuItem sendMessagesMenu = new JMenuItem(Res.getString("menuitem.send.a.message"), SparkRes.getImageIcon(SparkRes.SMALL_MESSAGE_IMAGE));
fireContextMenuListenerPopup(popup, items);
popup.add(sendMessagesMenu);
sendMessagesMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sendMessages(items);
}
});
try {
popup.show(group.getList(), e.getX(), e.getY());
}
catch (NullPointerException ee) {
// Nothing we can do here
}
}
private void clearSelectionList(ContactItem selectedItem) {
// Check for null. In certain cases the event triggering the model might
// not find the selected object.
if (selectedItem == null) {
return;
}
final ContactGroup owner = getContactGroup(selectedItem.getGroupName());
for (ContactGroup contactGroup : new ArrayList<ContactGroup>(groupList)) {
if (owner != contactGroup) {
contactGroup.clearSelection();
}
}
}
private void sendMessages(Collection<ContactItem> items) {
StringBuffer buf = new StringBuffer();
InputDialog dialog = new InputDialog();
final String messageText = dialog.getInput(Res.getString("title.broadcast.message"), Res.getString("message.enter.broadcast.message"), SparkRes.getImageIcon(SparkRes.BLANK_IMAGE), SparkManager.getMainWindow());
if (ModelUtil.hasLength(messageText)) {
final Map<String, Message> broadcastMessages = new HashMap<String, Message>();
for (ContactItem item : items) {
final Message message = new Message();
message.setTo(item.getJID());
message.setProperty("broadcast", true);
message.setBody(messageText);
if (!broadcastMessages.containsKey(item.getJID())) {
buf.append(item.getDisplayName()).append("\n");
broadcastMessages.put(item.getJID(), message);
}
}
for (Message message : broadcastMessages.values()) {
SparkManager.getConnection().sendPacket(message);
}
JOptionPane.showMessageDialog(SparkManager.getMainWindow(), Res.getString("message.broadcasted.to", buf.toString()), Res.getString("title.notification"), JOptionPane.INFORMATION_MESSAGE);
}
}
// For plugin use only
public void initialize() {
this.setBorder(BorderFactory.createEmptyBorder());
// Add Contact List
addContactListToWorkspace();
// Hide top toolbar
SparkManager.getMainWindow().getTopToolBar().setVisible(false);
final Runnable sharedGroupLoader = new Runnable() {
public void run() {
// Retrieve shared group list.
try {
sharedGroups = SharedGroupManager.getSharedGroups(SparkManager.getConnection());
}
catch (XMPPException e) {
Log.error("Unable to contact shared group info.", e);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
loadContactList();
}
});
}
};
TaskEngine.getInstance().submit(sharedGroupLoader);
}
private void loadContactList() {
// Build the initial contact list.
buildContactList();
boolean show = localPreferences.isEmptyGroupsShown();
// Hide all groups initially
showEmptyGroups(show);
// Hide all Offline Users
showOfflineUsers(localPreferences.isOfflineUsersShown());
// Add a subscription listener.
addSubscriptionListener();
// Load all plugins
SparkManager.getWorkspace().loadPlugins();
}
public void addSubscriptionListener() {
// Add subscription listener
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 = SparkManager.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());
SparkManager.getConnection().sendPacket(unsub);
Log.error(e);
}
}
}
});
}
else if (presence.getType() == Presence.Type.subscribe) {
// Find Contact in Contact List
String jid = StringUtils.parseBareAddress(presence.getFrom());
ContactItem item = getContactItemByJID(jid);
// If item is not in the Contact List, add them.
if (item == null) {
final Roster roster = SparkManager.getConnection().getRoster();
RosterEntry entry = roster.getEntry(jid);
if (entry != null) {
item = UIComponentRegistry.createContactItem(entry.getName(), null, jid);
moveToOffline(item);
offlineGroup.fireContactGroupUpdated();
}
}
}
else if (presence.getType() == Presence.Type.unsubscribed) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Roster roster = SparkManager.getConnection().getRoster();
RosterEntry entry = roster.getEntry(presence.getFrom());
if (entry != null) {
try {
removeContactItem(presence.getFrom());
roster.removeEntry(entry);
}
catch (XMPPException e) {
Log.error(e);
}
}
String jid = StringUtils.parseBareAddress(presence.getFrom());
removeContactItem(jid);
}
});
}
else {
try {
initialPresences.add(presence);
}
catch (Exception e) {
Log.error(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.error(e);
}
}
}
});
}
}, numberOfMillisecondsInTheFuture);
}
}
};
SparkManager.getConnection().addPacketListener(subscribeListener, packetFilter);
}
public void shutdown() {
saveState();
}
public boolean canShutDown() {
return true;
}
private void addContactListToWorkspace() {
Workspace workspace = SparkManager.getWorkspace();
workspace.getWorkspacePane().addTab(Res.getString("tab.contacts"), SparkRes.getImageIcon(SparkRes.SMALL_ALL_CHATS_IMAGE), this);
// Add To Contacts Menu
final JMenu contactsMenu = SparkManager.getMainWindow().getMenuByName(Res.getString("menuitem.contacts"));
JMenuItem addContactsMenu = new JMenuItem("", SparkRes.getImageIcon(SparkRes.USER1_ADD_16x16));
ResourceUtils.resButton(addContactsMenu, Res.getString("menuitem.add.contact"));
ResourceUtils.resButton(addContactGroupMenu, Res.getString("menuitem.add.contact.group"));
if (!Default.getBoolean(Default.ADD_CONTACT_DISABLED)) {
contactsMenu.add(addContactsMenu);
}
if(!Default.getBoolean("ADD_CONTACT_GROUP_DISABLED")){
contactsMenu.add(addContactGroupMenu);
}
addContactsMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new RosterDialog().showRosterDialog();
}
});
addContactGroupMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String groupName = JOptionPane.showInputDialog(getGUI(), Res.getString("message.name.of.group") + ":", Res.getString("title.add.new.group"), JOptionPane.QUESTION_MESSAGE);
if (ModelUtil.hasLength(groupName)) {
ContactGroup contactGroup = getContactGroup(groupName);
if (contactGroup == null) {
contactGroup = addContactGroup(groupName);
contactGroup.setVisible(true);
//validateTree();
repaint();
}
}
}
});
// Add Toggle Contacts Menu
ResourceUtils.resButton(showHideMenu, Res.getString("menuitem.show.empty.groups"));
contactsMenu.add(showHideMenu);
showHideMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showEmptyGroups(showHideMenu.isSelected());
}
});
ResourceUtils.resButton(showOfflineGroupMenu, Res.getString("menuitem.show.offline.group"));
contactsMenu.add(showOfflineGroupMenu);
showOfflineGroupMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
showOfflineGroup(showOfflineGroupMenu.isSelected());
}
});
ResourceUtils.resButton(showOfflineUsersMenu, Res.getString("menuitem.show.offline.users"));
contactsMenu.add(showOfflineUsersMenu);
showOfflineUsersMenu.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
showOfflineUsers(showOfflineUsersMenu.isSelected());
}
});
// Show or Hide Offline Group
showOfflineGroupMenu.setSelected(localPreferences.isOfflineGroupVisible());
showOfflineGroup(localPreferences.isOfflineGroupVisible());
// sets showOfflineUsersMenu selected or not selected
showOfflineUsersMenu.setSelected(localPreferences.isOfflineUsersShown());
// Initialize vcard support
SparkManager.getVCardManager();
}
/**
* Toggles the visibility of empty groups.
*
* @param show true to display empty contact groups within the ContactList, otherwise false.
*/
private void showEmptyGroups(boolean show) {
for (ContactGroup group : getContactGroups()) {
if (group != offlineGroup) {
if (show) {
group.setVisible(true);
} else {
// Never hide offline group.
group.setVisible(group.hasAvailableContacts());
}
}
}
localPreferences.setEmptyGroupsShown(show);
showHideMenu.setSelected(show);
SettingsManager.saveSettings();
}
private void showOfflineUsers(boolean show) {
for (ContactGroup group : getContactGroups())
{
if(group != offlineGroup)
{
group.toggleOfflineVisibility(show);
}
if (group == offlineGroup) {
if (show)
{
group.setVisible(true);
showOfflineGroupMenu.setEnabled(true);
showOfflineGroupMenu.setSelected(localPreferences.isOfflineGroupVisible());
showOfflineGroup(showOfflineGroupMenu.isSelected());
}
else
{
group.setVisible(false);
showOfflineGroupMenu.setEnabled(false);
}
}
}
localPreferences.setOfflineUsersShown(show);
SettingsManager.saveSettings();
}
/**
* Toggles the visiblity of the Offline Group.
*
* @param show true to display the offline group, otherwise false.
*/
private void showOfflineGroup(boolean show) {
// Save in preferences
localPreferences.setOfflineGroupVisible(show);
SettingsManager.saveSettings();
// Toggle Visibility of Offline Group.
offlineGroup.setVisible(show);
if (show) {
// Remove offline items from all groups.
for (ContactGroup group : getContactGroups()) {
group.toggleOfflineVisibility(false);
}
}
else {
// Remove offline items from all groups.
for (ContactGroup group : getContactGroups()) {
group.toggleOfflineVisibility(true);
}
}
}
/**
* Sorts ContactGroups
*/
public static final Comparator<ContactGroup> GROUP_COMPARATOR = new Comparator<ContactGroup>() {
public int compare(ContactGroup group1, ContactGroup group2) {
// Make sure that offline group is always on bottom.
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>(groupList);
Collections.sort(gList, GROUP_COMPARATOR);
return gList;
}
private void subscriptionRequest(final String jid) {
final SubscriptionDialog subscriptionDialog = new SubscriptionDialog();
subscriptionDialog.invoke(jid);
}
public void addContextMenuListener(ContextMenuListener listener) {
contextListeners.add(listener);
}
public void removeContextMenuListener(ContextMenuListener listener) {
contextListeners.remove(listener);
}
public void fireContextMenuListenerPopup(JPopupMenu popup, Object object) {
for (ContextMenuListener listener : new ArrayList<ContextMenuListener>(contextListeners)) {
listener.poppingUp(object, popup);
}
}
public JComponent getGUI() {
return this;
}
public ContactGroup getActiveGroup() {
return activeGroup;
}
public Collection<ContactItem> getSelectedUsers() {
final List<ContactItem> list = new ArrayList<ContactItem>();
for (ContactGroup group : getContactGroups()) {
for (ContactItem item : group.getSelectedContacts()) {
list.add(item);
}
}
return list;
}
/**
* Selects the first user found with specified jid
* @param jid, the Users JID
*/
public void setSelectedUser(String jid) {
for (ContactGroup group : getContactGroups()) {
if (group.getContactItemByJID(jid) != null) {
ContactItem item = group.getContactItemByJID(jid);
group.getList().setSelectedValue(item, false);
return;
}
}
}
private void checkGroup(final ContactGroup group) {
try {
EventQueue.invokeLater(new Runnable() {
public void run() {
if (!group.hasAvailableContacts() && group != offlineGroup && group != getUnfiledGroup() && !showHideMenu.isSelected()) {
group.setVisible(false);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public void addFileDropListener(FileDropListener listener) {
dndListeners.add(listener);
}
public void removeFileDropListener(FileDropListener listener) {
dndListeners.remove(listener);
}
public void fireFilesDropped(Collection<File> files, ContactItem item) {
for (FileDropListener fileDropListener : new ArrayList<FileDropListener>(dndListeners)) {
fileDropListener.filesDropped(files, item);
}
}
public void contactItemAdded(ContactItem item) {
fireContactItemAdded(item);
}
public void contactItemRemoved(ContactItem item) {
fireContactItemRemoved(item);
}
/*
Adding ContactListListener support.
*/
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() {
// Do nothing.
}
public void saveState() {
if (props == null) {
return;
}
for (ContactGroup contactGroup : getContactGroups()) {
props.put(contactGroup.getGroupName(), Boolean.toString(contactGroup.isCollapsed()));
}
try {
props.store(new FileOutputStream(propertiesFile), "Tracks the state of groups.");
}
catch (IOException e) {
Log.error("Unable to save group properties.", e);
}
}
public void connectionClosed() {
// No reason to reconnect.
// Show MainWindow
SparkManager.getMainWindow().setVisible(true);
// Flash That Window.
SparkManager.getNativeManager().flashWindowStopOnFocus(
SparkManager.getMainWindow());
String errorMessage = Res.getString("message.disconnected.error");
switch (localPreferences.getReconnectPanelType()) {
case 0:
_reconnectPanel.setClosedOnError(false);
_reconnectPanel.setDisconnectReason(errorMessage);
removeAllUsers();
workspace.changeCardLayout(RETRY_PANEL);
break;
case 1:
switchAllUserOffline(false);
_reconnectpanelsmall.setReconnectText(errorMessage);
break;
case 2:
switchAllUserOfflineNoGroupEntry(false);
_reconnectpanelicon.setReconnectText(errorMessage);
break;
}
}
/**
* Reconnect using the Panel with Message
* @param message
*/
private void reconnect(final String message) {
// Show MainWindow
SparkManager.getMainWindow().setVisible(true);
// Flash That Window.
SparkManager.getNativeManager().flashWindowStopOnFocus(
SparkManager.getMainWindow());
switch (localPreferences.getReconnectPanelType()) {
case 0:
workspace.changeCardLayout(RETRY_PANEL);
_reconnectPanel.setDisconnectReason(message);
break;
case 1:
switchAllUserOffline(true);
_reconnectpanelsmall.startReconnecting();
break;
case 2:
switchAllUserOfflineNoGroupEntry(true);
_reconnectpanelicon.startReconnecting();
break;
default:
workspace.changeCardLayout(RETRY_PANEL);
}
removeAllUsers();
}
public void clientReconnected() {
switch (localPreferences.getReconnectPanelType()) {
case 0:
workspace.changeCardLayout(Workspace.WORKSPACE_PANE);
break;
case 1:
mainPanel.remove(_reconnectpanelsmall);
break;
case 2:
SwingWorker sw = new SwingWorker() {
@Override
public Object construct() {
_reconnectpanelicon.remove();
_reconnectpanelicon.getPanel().revalidate();
return 42;
}
};
sw.start();
break;
}
offlineGroup.fireContactGroupUpdated();
buildContactList();
final Presence myPresence = SparkManager.getWorkspace().getStatusBar()
.getPresence();
SparkManager.getSessionManager().changePresence(myPresence);
}
public void connectionClosedOnError(final Exception ex) {
String errorMessage = Res.getString("message.disconnected.error");
if (ex != null && ex instanceof XMPPException) {
XMPPException xmppEx = (XMPPException) ex;
StreamError error = xmppEx.getStreamError();
String reason = error.getCode();
if ("conflict".equals(reason)) {
errorMessage = Res
.getString("message.disconnected.conflict.error");
} else if ("system-shutdown".equals(reason)) {
errorMessage = Res.getString("message.disconnected.shutdown");
} else {
errorMessage = Res.getString("message.general.error", reason);
}
}
switch (localPreferences.getReconnectPanelType()) {
case 0:
final String message = errorMessage;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
_reconnectPanel.setClosedOnError(true);
reconnect(message);
}
});
break;
case 1:
switchAllUserOffline(true);
_reconnectpanelsmall.setReconnectText(errorMessage);
break;
case 2:
switchAllUserOfflineNoGroupEntry(true);
_reconnectpanelicon.setReconnectText(errorMessage);
break;
}
}
private void removeAllUsers() {
// Behind the scenes, move everyone to the offline group.
for (ContactGroup contactGroup : new ArrayList<ContactGroup>(getContactGroups())) {
contactGroup.removeAllContacts();
}
}
public void reconnectingIn(int i) {
switch (localPreferences.getReconnectPanelType()) {
case 0:
if (i == 0) {
_reconnectPanel.setReconnectText(Res
.getString("message.reconnect.attempting"));
} else {
_reconnectPanel.setReconnectText(Res.getString(
"message.reconnect.wait", i));
}
break;
case 1:
if (i == 0) {
_reconnectpanelsmall.setReconnectText(Res
.getString("message.reconnect.attempting"));
} else {
_reconnectpanelsmall.setReconnectText(Res.getString(
"message.reconnect.wait", i));
}
break;
case 2:
if (i == 0) {
_reconnectpanelicon.setReconnectText(Res
.getString("message.reconnect.attempting"));
} else {
_reconnectpanelicon.setReconnectText(Res.getString(
"message.reconnect.wait", i));
}
break;
}
}
public void reconnectionSuccessful() {
clientReconnected();
}
public void reconnectionFailed(Exception exception) {
switch (localPreferences.getReconnectPanelType()) {
case 0:
_reconnectPanel.setReconnectText(Res
.getString("message.reconnect.failed"));
break;
case 1:
_reconnectpanelsmall.setReconnectText(Res
.getString("message.reconnect.failed"));
break;
case 2:
_reconnectpanelicon.setReconnectText(Res
.getString("message.reconnect.failed"));
break;
}
}
/**
* Moves a <code>ContactItem</code> to an offline state.
*
* @param contactItem the ContactItem.
*/
private void moveToOffline(ContactItem contactItem) {
offlineGroup.addContactItem(contactItem);
String jid = contactItem.getJID();
Boolean isFiled = false;
final Roster roster = SparkManager.getConnection().getRoster();
for (RosterGroup group : roster.getEntry(jid).getGroups()) {
ContactGroup contactGroup = getContactGroup(group.getName());
if(contactGroup == null && group.getName() != ""){
contactGroup = addContactGroup(group.getName());
}
if (contactGroup != null) {
isFiled = true;
contactGroup.addOfflineContactItem(contactItem.getAlias(), contactItem.getNickname(), contactItem.getJID(), contactItem.getStatus());
}
}
if (!isFiled) {
getUnfiledGroup().addOfflineContactItem(contactItem.getAlias(), contactItem.getNickname(), contactItem.getJID(), contactItem.getStatus());
}
if(localPreferences.isOfflineUsersShown() == false)
{
for (ContactGroup group : getContactGroups())
{
if(group != offlineGroup)
{
group.toggleOfflineVisibility(false);
}
}
}
}
private ContactGroup getUnfiledGroup() {
if (unfiledGroup == null) {
// Add Unfiled Group
if(EventQueue.isDispatchThread()) {
unfiledGroup = UIComponentRegistry.createContactGroup(Res.getString("unfiled"));
addContactGroup(unfiledGroup);
}
else {
try {
EventQueue.invokeAndWait(new Runnable(){
public void run() {
unfiledGroup = UIComponentRegistry.createContactGroup(Res.getString("unfiled"));
addContactGroup(unfiledGroup);
}
});
}catch(Exception ex) {
ex.printStackTrace();
}
}
}
return unfiledGroup;
}
/**
* Sorts ContactItems.
*/
public final static Comparator<ContactItem> ContactItemComparator = new Comparator<ContactItem>() {
public int compare(ContactItem item1, ContactItem item2) {
return item1.getDisplayName().toLowerCase().compareTo(item2.getDisplayName().toLowerCase());
}
};
public void showAddContact(String contact)
{
addContactMenu.doClick();
};
public ContactItem getActiveItem() {
return activeItem;
}
}