/**
* $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 org.jivesoftware.resource.Res;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.spark.PresenceManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.Workspace;
import org.jivesoftware.spark.component.VerticalFlowLayout;
import org.jivesoftware.spark.component.panes.CollapsiblePane;
import org.jivesoftware.spark.component.renderer.JPanelRenderer;
import org.jivesoftware.spark.util.GraphicUtils;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.UIComponentRegistry;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionAdapter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPanel;
/**
* Container representing a RosterGroup within the Contact List.
*/
public class ContactGroup extends CollapsiblePane implements MouseListener {
private static final long serialVersionUID = 6578057848913010799L;
private List<ContactItem> contactItems = new ArrayList<ContactItem>();
private List<ContactGroup> contactGroups = new ArrayList<ContactGroup>();
private List<ContactGroupListener> listeners = new ArrayList<ContactGroupListener>();
private List<ContactItem> offlineContacts = new ArrayList<ContactItem>();
private String groupName;
private DefaultListModel model;
private JList contactItemList;
private boolean sharedGroup;
private JPanel listPanel;
// Used to display no contacts in list.
private final ContactItem noContacts = UIComponentRegistry.createContactItem(
Res.getString("group.empty"), null, null);
private final ListMotionListener motionListener = new ListMotionListener();
private boolean canShowPopup;
private boolean mouseDragged = false;
private LocalPreferences preferences;
private ContactList contactList = Workspace.getInstance().getContactList();
private DisplayWindowTask timerTask = null;
private Timer timer = new Timer();
/**
* Create a new ContactGroup.
*
* @param groupName the name of the new ContactGroup.
*/
public ContactGroup(String groupName) {
// Initialize Model and UI
model = new DefaultListModel();
contactItemList = new JList(model);
preferences = SettingsManager.getLocalPreferences();
setTitle(getGroupTitle(groupName));
// Use JPanel Renderer
contactItemList.setCellRenderer(new JPanelRenderer());
this.groupName = groupName;
listPanel = new JPanel(new VerticalFlowLayout(VerticalFlowLayout.TOP, 0, 0, true, false));
listPanel.add(contactItemList, listPanel);
this.setContentPane(listPanel);
if (!isOfflineGroup()) {
contactItemList.setDragEnabled(true);
contactItemList.setTransferHandler(new ContactGroupTransferHandler());
}
// Allow for mouse events to take place on the title bar
getTitlePane().addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
checkPopup(e);
}
public void mouseReleased(MouseEvent e) {
checkPopup(e);
}
public void mouseClicked(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1)
{
contactList = Workspace.getInstance().getContactList();
contactList.saveState();
}
}
public void checkPopup(MouseEvent e) {
if (e.isPopupTrigger())
{
e.consume();
fireContactGroupPopupEvent(e);
}
}
});
// Items should have selection listener
contactItemList.addMouseListener(this);
contactItemList.addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent keyEvent) {
}
public void keyPressed(KeyEvent keyEvent) {
if (keyEvent.getKeyChar() == KeyEvent.VK_ENTER) {
ContactItem item = (ContactItem)contactItemList.getSelectedValue();
fireContactItemDoubleClicked(item);
}
ContactList.activeKeyEvent = keyEvent;
}
public void keyReleased(KeyEvent keyEvent) {
ContactList.activeKeyEvent = null;
}
});
noContacts.getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, 11));
noContacts.getNicknameLabel().setForeground(Color.GRAY);
model.addElement(noContacts);
// Add Popup Window
addPopupWindow();
}
/**
* Adds a new offline contact.
*
* @param alias the alias of the offline contact.
* @param nickname the nickname of the offline contact.
* @param jid the jid of the offline contact.
* @param status the current status of the offline contact.
*/
public void addOfflineContactItem(final String alias, final String nickname, final String jid, final String status) {
if(EventQueue.isDispatchThread()) {
// Build new ContactItem
final ContactItem offlineItem = UIComponentRegistry.createContactItem(alias, nickname, jid);
offlineItem.setGroupName(getGroupName());
final Presence offlinePresence = PresenceManager.getPresence(jid);
offlineItem.setPresence(offlinePresence);
// set offline icon
offlineItem.setIcon(PresenceManager.getIconFromPresence(offlinePresence));
// Set status if applicable.
if (ModelUtil.hasLength(status)) {
offlineItem.setStatusText(status);
}
// Add to offline contacts.
offlineContacts.add(offlineItem);
insertOfflineContactItem(offlineItem);
}
else {
try {
// invokeAndWait, because the contacts must be added before they can moved to offline group
EventQueue.invokeAndWait(new Runnable(){
public void run() {
// Build new ContactItem
final ContactItem offlineItem = UIComponentRegistry.createContactItem(alias, nickname, jid);
offlineItem.setGroupName(getGroupName());
final Presence offlinePresence = PresenceManager.getPresence(jid);
offlineItem.setPresence(offlinePresence);
// set offline icon
offlineItem.setIcon(PresenceManager.getIconFromPresence(offlinePresence));
// Set status if applicable.
if (ModelUtil.hasLength(status)) {
offlineItem.setStatusText(status);
}
// Add to offline contacts.
offlineContacts.add(offlineItem);
insertOfflineContactItem(offlineItem);
}
});
}
catch(Exception ex) {
Log.error(ex);
}
}
}
/**
* Inserts a new offline <code>ContactItem</code> into the ui model.
*
* @param offlineItem the ContactItem to add.
*/
public void insertOfflineContactItem(ContactItem offlineItem) {
if (model.contains(offlineItem)) {
return;
}
if (!preferences.isOfflineGroupVisible()) {
Collections.sort(offlineContacts, itemComparator);
int index = offlineContacts.indexOf(offlineItem);
int totalListSize = contactItems.size();
int newPos = totalListSize + index;
if (newPos > model.size()) {
newPos = model.size();
}
model.insertElementAt(offlineItem, newPos);
if (model.contains(noContacts)) {
model.removeElement(noContacts);
}
}
}
/**
* Removes an offline <code>ContactItem</code> from the Offline contact
* model and ui.
*
* @param item the offline contact item to remove.
*/
public void removeOfflineContactItem(ContactItem item) {
offlineContacts.remove(item);
//removeContactItem(item);
}
/**
* Removes an offline <code>ContactItem</code> from the offline contact model and ui.
*
* @param jid the offline contact item to remove.
*/
public void removeOfflineContactItem(String jid) {
final List<ContactItem> items = new ArrayList<ContactItem>(offlineContacts);
for (ContactItem item : items) {
if (item.getJID().equals(jid)) {
removeOfflineContactItem(item);
}
}
}
/**
* Toggles the visibility of Offline Contacts.
*
* @param show true if offline contacts should be shown, otherwise false.
*/
public void toggleOfflineVisibility(boolean show) {
final List<ContactItem> items = new ArrayList<ContactItem>(offlineContacts);
for (ContactItem item : items) {
if (show) {
insertOfflineContactItem(item);
}
else {
model.removeElement(item);
}
}
if (model.getSize() == 0) {
model.addElement(noContacts);
}
}
/**
* Adds a <code>ContactItem</code> to the ContactGroup.
*
* @param item the ContactItem.
*/
public void addContactItem(ContactItem item) {
// Remove from offline group if it exists
removeOfflineContactItem(item.getJID());
if (model.contains(noContacts)) {
model.remove(0);
}
if (Res.getString("group.offline").equals(groupName)) {
setOfflineGroupNameFont(item);
}
item.setGroupName(getGroupName());
contactItems.add(item);
List<ContactItem> tempItems = getContactItems();
Collections.sort(tempItems, itemComparator);
int index = tempItems.indexOf(item);
Object[] objs = contactItemList.getSelectedValues();
model.insertElementAt(item, index);
int[] intList = new int[objs.length];
for (int i = 0; i < objs.length; i++) {
ContactItem contact = (ContactItem)objs[i];
intList[i] = model.indexOf(contact);
}
if (intList.length > 0) {
contactItemList.setSelectedIndices(intList);
}
fireContactItemAdded(item);
}
protected void setOfflineGroupNameFont(ContactItem item) {
item.getNicknameLabel().setFont(new Font("Dialog", Font.PLAIN, 11));
item.getNicknameLabel().setForeground(Color.GRAY);
}
/**
* Call whenever the UI needs to be updated.
*/
public void fireContactGroupUpdated() {
contactItemList.validate();
contactItemList.repaint();
updateTitle();
}
/**
* Adds a sub group to this Contact group.
*
* @param contactGroup
* that should be the new subgroup
*/
public void addContactGroup(ContactGroup contactGroup) {
final JPanel panel = new JPanel(new GridBagLayout());
panel.add(contactGroup, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 15, 0, 0), 0, 0));
panel.setBackground(Color.white);
contactGroup.setSubPane(true);
// contactGroup.setStyle(CollapsiblePane.TREE_STYLE);
contactGroups.add(contactGroup);
Collections.sort(contactGroups, ContactList.GROUP_COMPARATOR);
listPanel.add(panel, contactGroups.indexOf(contactGroup));
}
/**
* Removes a child ContactGroup.
*
* @param contactGroup the contact group to remove.
*/
public void removeContactGroup(ContactGroup contactGroup) {
Component[] comps = listPanel.getComponents();
for (Component comp : comps) {
if (comp instanceof JPanel) {
JPanel panel = (JPanel) comp;
ContactGroup group = (ContactGroup) panel.getComponent(0);
if (group == contactGroup) {
listPanel.remove(panel);
break;
}
}
}
contactGroups.remove(contactGroup);
}
public void setPanelBackground(Color color) {
Component[] comps = listPanel.getComponents();
for (Component comp : comps) {
if (comp instanceof JPanel) {
JPanel panel = (JPanel) comp;
panel.setBackground(color);
}
}
}
/**
* Returns a ContactGroup based on it's name.
*
* @param groupName the name of the group.
* @return the ContactGroup.
*/
public ContactGroup getContactGroup(String groupName) {
for (ContactGroup group : new ArrayList<ContactGroup>(contactGroups)) {
if (group.getGroupName().equals(groupName)) {
return group;
}
}
return null;
}
/**
* Removes a <code>ContactItem</code>.
*
* @param item the ContactItem to remove.
*/
public void removeContactItem(ContactItem item) {
contactItems.remove(item);
if (contactItems.isEmpty()) {
removeContactGroup(this);
}
model.removeElement(item);
updateTitle();
fireContactItemRemoved(item);
}
/**
* Returns a <code>ContactItem</code> by the displayed name the user has been assigned.
*
* @param displayName the displayed name of the user.
* @return the ContactItem.
*/
public ContactItem getContactItemByDisplayName(String displayName) {
for (ContactItem item : new ArrayList<ContactItem>(contactItems)) {
if (item.getDisplayName().equals(displayName)) {
return item;
}
}
return null;
}
/**
* Returns a <code>ContactItem</code> from offlineContacts by the displayed name the user has been assigned.
*
* @param displayName the displayed name of the user.
* @return the ContactItem.
*/
public ContactItem getOfflineContactItemByDisplayName(String displayName) {
for (ContactItem item : new ArrayList<ContactItem>(offlineContacts)) {
if (item.getDisplayName().equals(displayName)) {
return item;
}
}
return null;
}
/**
* Returns a <code>ContactItem</code> by the displayed name the user has been assigned.
*
* @param displayName the displayed name of the user.
* @param searchInOffline should we search <code>ContactItem</code> in offline contacts
* @return the ContactItem.
*/
public ContactItem getContactItemByDisplayName(String displayName, boolean searchInOffline) {
if (searchInOffline) {
ContactItem item = getContactItemByDisplayName(displayName);
if (item == null) {
item = getOfflineContactItemByDisplayName(displayName);
}
return item;
}
return getContactItemByDisplayName(displayName);
}
/**
* Returns a <code>ContactItem</code> by the users bare bareJID.
*
* @param bareJID the bareJID of the user.
* @return the ContactItem.
*/
public ContactItem getContactItemByJID(String bareJID) {
for (ContactItem item : new ArrayList<ContactItem>(contactItems)) {
if (item != null && item.getJID().equals(bareJID)) {
return item;
}
}
return null;
}
/**
* Returns a <code>ContactItem</code> from offlineContacts by the users bare bareJID.
*
* @param bareJID the bareJID of the user.
* @return the ContactItem.
*/
public ContactItem getOfflineContactItemByJID(String bareJID) {
for (ContactItem item : new ArrayList<ContactItem>(offlineContacts)) {
if (item.getJID().equals(bareJID)) {
return item;
}
}
return null;
}
/**
* Returns a <code>ContactItem</code> by the users bare bareJID.
*
* @param bareJID the bareJID of the user.
* @param searchInOffline should we search <code>ContactItem</code> in offline contacts
* @return the ContactItem.
*/
public ContactItem getContactItemByJID(String bareJID, boolean searchInOffline) {
if (searchInOffline) {
ContactItem item = getContactItemByJID(bareJID);
if (item == null) {
item = getOfflineContactItemByJID(bareJID);
}
return item;
}
return getContactItemByJID(bareJID);
}
/**
* Returns all <code>ContactItem</cod>s in the ContactGroup.
*
* @return all ContactItems.
*/
public List<ContactItem> getContactItems() {
final List<ContactItem> list = new ArrayList<ContactItem>(contactItems);
Collections.sort(list, itemComparator);
return list;
}
/**
* Returns the name of the ContactGroup.
*
* @return the name of the ContactGroup.
*/
public String getGroupName() {
return groupName;
}
public void mouseClicked(MouseEvent e) {
Object o = contactItemList.getSelectedValue();
if (!(o instanceof ContactItem)) {
return;
}
// Iterator through rest
ContactItem item = (ContactItem)o;
if (e.getClickCount() == 2) {
fireContactItemDoubleClicked(item);
}
else if (e.getClickCount() == 1) {
fireContactItemClicked(item);
}
}
public void mouseEntered(MouseEvent e) {
int loc = contactItemList.locationToIndex(e.getPoint());
Object o = model.getElementAt(loc);
if (!(o instanceof ContactItem)) {
return;
}
contactItemList.setCursor(GraphicUtils.HAND_CURSOR);
}
public void mouseExited(MouseEvent e) {
Object o;
try {
int loc = contactItemList.locationToIndex(e.getPoint());
if (loc == -1) {
return;
}
o = model.getElementAt(loc);
if (!(o instanceof ContactItem)) {
UIComponentRegistry.getContactInfoWindow().dispose();
return;
}
}
catch (Exception e1) {
Log.error(e1);
return;
}
contactItemList.setCursor(GraphicUtils.DEFAULT_CURSOR);
}
public void mousePressed(MouseEvent e) {
checkPopup(e);
}
public void mouseReleased(MouseEvent e) {
checkPopup(e);
}
private void checkPopup(MouseEvent e) {
if (e.isPopupTrigger()) {
// Otherwise, handle single selection
int index = contactItemList.locationToIndex(e.getPoint());
if (index != -1) {
int[] indexes = contactItemList.getSelectedIndices();
boolean selected = false;
for (int o : indexes) {
if (index == o) {
selected = true;
}
}
if (!selected) {
contactItemList.setSelectedIndex(index);
fireContactItemClicked((ContactItem)contactItemList.getSelectedValue());
}
}
final Collection<ContactItem> selectedItems = SparkManager.getChatManager().getSelectedContactItems();
if (selectedItems.size() > 1) {
firePopupEvent(e, selectedItems);
}
else if (selectedItems.size() == 1) {
final ContactItem contactItem = selectedItems.iterator().next();
firePopupEvent(e, contactItem);
}
}
}
/**
* Add a <code>ContactGroupListener</code>.
*
* @param listener the ContactGroupListener.
*/
public void addContactGroupListener(ContactGroupListener listener) {
listeners.add(listener);
}
/**
* Removes a <code>ContactGroupListener</code>.
*
* @param listener the ContactGroupListener.
*/
public void removeContactGroupListener(ContactGroupListener listener) {
listeners.remove(listener);
}
private void fireContactItemClicked(ContactItem item) {
for (ContactGroupListener contactGroupListener : new ArrayList<ContactGroupListener>(listeners)) {
contactGroupListener.contactItemClicked(item);
}
}
private void fireContactItemDoubleClicked(ContactItem item) {
for (ContactGroupListener contactGroupListener : new ArrayList<ContactGroupListener>(listeners)) {
contactGroupListener.contactItemDoubleClicked(item);
}
}
private void firePopupEvent(MouseEvent e, ContactItem item) {
for (ContactGroupListener contactGroupListener : new ArrayList<ContactGroupListener>(listeners)) {
contactGroupListener.showPopup(e, item);
}
}
private void firePopupEvent(MouseEvent e, Collection<ContactItem> items) {
for (ContactGroupListener contactGroupListener : new ArrayList<ContactGroupListener>(listeners)) {
contactGroupListener.showPopup(e, items);
}
}
private void fireContactGroupPopupEvent(MouseEvent e) {
for (ContactGroupListener contactGroupListener : new ArrayList<ContactGroupListener>(listeners)) {
contactGroupListener.contactGroupPopup(e, this);
}
}
private void fireContactItemAdded(ContactItem item) {
for (ContactGroupListener contactGroupListener : new ArrayList<ContactGroupListener>(listeners)) {
contactGroupListener.contactItemAdded(item);
}
}
private void fireContactItemRemoved(ContactItem item) {
for (ContactGroupListener contactGroupListener : new ArrayList<ContactGroupListener>(listeners)) {
contactGroupListener.contactItemRemoved(item);
}
}
private void updateTitle() {
if (Res.getString("group.offline").equals(groupName)) {
setTitle(Res.getString("group.offline"));
return;
}
int count = 0;
List<ContactItem> list = new ArrayList<ContactItem>(getContactItems());
int size = list.size();
for (int i = 0; i < size; i++) {
ContactItem it = list.get(i);
if (it.isAvailable()) {
count++;
}
}
setTitle(getGroupTitle(groupName) + " (" + count + " " + Res.getString("online") + ")");
if (model.getSize() == 0) {
model.addElement(noContacts);
}
}
/**
* Returns the containing <code>JList</code> of the ContactGroup.
*
* @return the JList.
*/
public JList getList() {
return contactItemList;
}
/**
* Clears all selections within this group.
*/
public void clearSelection() {
contactItemList.clearSelection();
}
public void removeAllContacts() {
// Remove all users from online group.
for (ContactItem item : new ArrayList<ContactItem>(getContactItems())) {
removeContactItem(item);
}
// Remove all users from offline group.
for (ContactItem item : getOfflineContacts()) {
removeOfflineContactItem(item);
}
}
/**
* Returns true if the ContactGroup contains available users.
*
* @return true if the ContactGroup contains available users.
*/
public boolean hasAvailableContacts() {
for (ContactGroup group : contactGroups) {
if (group.hasAvailableContacts()) {
return true;
}
}
for (ContactItem item : getContactItems()) {
if (item.getPresence() != null) {
return true;
}
}
return false;
}
public Collection<ContactItem> getOfflineContacts() {
return new ArrayList<ContactItem>(offlineContacts);
}
/**
* Sorts ContactItems.
*/
final protected Comparator<ContactItem> itemComparator = new Comparator<ContactItem>() {
public int compare(ContactItem item1, ContactItem item2) {
return item1.getDisplayName().toLowerCase().compareTo(item2.getDisplayName().toLowerCase());
}
};
/**
* Returns true if this ContactGroup is the Offline Group.
*
* @return true if OfflineGroup.
*/
public boolean isOfflineGroup() {
return Res.getString("group.offline").equals(getGroupName());
}
/**
* Returns true if this ContactGroup is the Unfiled Group.
*
* @return true if UnfiledGroup.
*/
public boolean isUnfiledGroup() {
//TODO: Don't identify the unfiled group by name, because the user
//could have a custom group of that name.
return Res.getString("unfiled").equals(getGroupName());
}
public String toString() {
return getGroupName();
}
/**
* Returns true if ContactGroup is a Shared Group.
*
* @return true if Shared Group.
*/
public boolean isSharedGroup() {
return sharedGroup;
}
/**
* Set to true if this ContactGroup is a shared Group.
*
* @param sharedGroup true if shared group.
*/
protected void setSharedGroup(boolean sharedGroup) {
this.sharedGroup = sharedGroup;
if (sharedGroup) {
setToolTipText(Res.getString("message.is.shared.group", getGroupName()));
}
}
/**
* Returns all Selected Contacts within the ContactGroup.
*
* @return all selected ContactItems.
*/
public List<ContactItem> getSelectedContacts() {
final List<ContactItem> items = new ArrayList<ContactItem>();
Object[] selections = contactItemList.getSelectedValues();
final int no = selections != null ? selections.length : 0;
for (int i = 0; i < no; i++) {
try {
ContactItem item = (ContactItem)selections[i];
items.add(item);
}
catch (NullPointerException e) {
// TODO: Evaluate if we should do something here.
}
}
return items;
}
public JPanel getContainerPanel() {
return listPanel;
}
public Collection<ContactGroup> getContactGroups() {
return contactGroups;
}
/**
* Lets make sure that the panel doesn't stretch past the
* scrollpane view pane.
*
* @return the preferred dimension
*/
public Dimension getPreferredSize() {
final Dimension size = super.getPreferredSize();
size.width = 0;
return size;
}
/**
* Sets the name of group.
*
* @param groupName the contact group name.
*/
public void setGroupName(String groupName) {
this.groupName = groupName;
}
/**
* Returns the "pretty" title of the ContactGroup.
*
* @param title the title.
* @return the new title.
*/
public String getGroupTitle(String title) {
int lastIndex = title.lastIndexOf("::");
if (lastIndex != -1) {
title = title.substring(lastIndex + 2);
}
return title;
}
/**
* Returns true if the group is nested.
*
* @param groupName the name of the group.
* @return true if the group is nested.
*/
public boolean isSubGroup(String groupName) {
return groupName.indexOf("::") != -1;
}
/**
* Returns true if this group is nested.
*
* @return true if nested.
*/
public boolean isSubGroup() {
return isSubGroup(getGroupName());
}
/**
* Returns the underlying container for the JList.
*
* @return the underlying container of the JList.
*/
public JPanel getListPanel() {
return listPanel;
}
/**
* Adds an internal popup listesner.
*/
private void addPopupWindow() {
contactItemList.addMouseListener(new MouseAdapter() {
public void mouseEntered(MouseEvent mouseEvent) {
canShowPopup = true;
timerTask = new DisplayWindowTask(mouseEvent);
timer.schedule(timerTask, 500, 1000);
}
public void mouseExited(MouseEvent mouseEvent) {
canShowPopup = false;
UIComponentRegistry.getContactInfoWindow().dispose();
}
});
contactItemList.addMouseMotionListener(motionListener);
}
private class DisplayWindowTask extends TimerTask {
private MouseEvent event;
private boolean newPopupShown = false;
public DisplayWindowTask(MouseEvent e) {
event = e;
}
@Override
public void run() {
if (canShowPopup) {
if (!newPopupShown && !mouseDragged) {
displayWindow(event);
newPopupShown = true;
}
}
}
public void setEvent(MouseEvent event) {
this.event = event;
}
public void setNewPopupShown(boolean popupChanged) {
this.newPopupShown = popupChanged;
}
public boolean isNewPopupShown() {
return newPopupShown;
}
}
private class ListMotionListener extends MouseMotionAdapter {
@Override
public void mouseMoved(MouseEvent e) {
if (!canShowPopup) {
return;
}
if (e == null) {
return;
}
timerTask.setEvent(e);
if (needToChangePopup(e) && timerTask.isNewPopupShown()) {
UIComponentRegistry.getContactInfoWindow().dispose();
timerTask.setNewPopupShown(false);
}
mouseDragged = false;
}
@Override
public void mouseDragged(MouseEvent e) {
if(timerTask.isNewPopupShown()) {
UIComponentRegistry.getContactInfoWindow().dispose();
}
mouseDragged = true;
}
}
/**
* Displays the <code>ContactInfoWindow</code>.
*
* @param e the mouseEvent that triggered this event.
*/
private void displayWindow(MouseEvent e) {
if(preferences.areVCardsVisible()) {
UIComponentRegistry.getContactInfoWindow().display(this, e);
}
}
private boolean needToChangePopup(MouseEvent e) {
ContactInfoWindow contact = UIComponentRegistry.getContactInfoWindow();
int loc = getList().locationToIndex(e.getPoint());
ContactItem item = (ContactItem)getList().getModel().getElementAt(loc);
return item == null || contact == null || contact.getContactItem() == null ? true : !contact.getContactItem().getJID().equals(item.getJID());
}
protected DefaultListModel getModel() {
return model;
}
protected JList getContactItemList() {
return contactItemList;
}
}