/**
* $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.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JWindow;
import org.jivesoftware.resource.Res;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.packet.VCard;
import org.jivesoftware.smackx.packet.LastActivity;
import org.jivesoftware.smackx.LastActivityManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.ui.ContactItem;
import org.jivesoftware.spark.util.GraphicUtils;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.plugin.gateways.transports.Transport;
import org.jivesoftware.sparkimpl.plugin.gateways.transports.TransportUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Represents the UI for the "ToolTip" functionallity in the ContactList.
*
* @author Derek DeMoro
*/
public class ContactInfoWindow extends JPanel {
private static final long serialVersionUID = 8409694344721276453L;
private final JLabel nicknameLabel = new JLabel();
private final JTextArea statusLabel = new JTextArea();
private final JLabel fullJIDLabel = new JLabel();
private final JLabel avatarLabel = new JLabel();
private final JLabel iconLabel = new JLabel();
private final JLabel titleLabel = new JLabel();
private ContactItem contactItem;
private JWindow window = new JWindow();
private static ContactInfoWindow singleton;
private static final Object LOCK = new Object();
/**
* Returns the singleton instance of <CODE>ContactInfoWindow</CODE>,
* creating it if necessary.
* <p/>
*
* @return the singleton instance of <Code>ContactInfoWindow</CODE>
*/
public static ContactInfoWindow getInstance() {
// Synchronize on LOCK to ensure that we don't end up creating
// two singletons.
synchronized (LOCK) {
if (null == singleton) {
ContactInfoWindow controller = new ContactInfoWindow();
singleton = controller;
return controller;
}
}
return singleton;
}
protected ContactInfoWindow() {
this(true);
}
protected ContactInfoWindow(boolean populate) {
setLayout(new GridBagLayout());
setBackground(Color.white);
if (populate) {
add(avatarLabel, new GridBagConstraints(0, 1, 1, 3, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0));
add(iconLabel, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(2, 2, 0, 2), 0, 0));
add(nicknameLabel, new GridBagConstraints(2, 1, 1, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(2, 0, 0, 2), 0, 0));
add(statusLabel, new GridBagConstraints(2, 2, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 2), 0, 0));
add(titleLabel, new GridBagConstraints(2, 3, 1, 1, 1.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 2, 2), 0, 0));
add(fullJIDLabel, new GridBagConstraints(0, 5, 4, 1, 1.0, 1.0, GridBagConstraints.SOUTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 2, 2, 2), 0, 0));
nicknameLabel.setFont(new Font("Dialog", Font.BOLD, 12));
statusLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
statusLabel.setForeground(Color.gray);
statusLabel.setLineWrap(true);
statusLabel.setWrapStyleWord(true);
statusLabel.setEditable(false);
statusLabel.setBorder(null);
fullJIDLabel.setFont(new Font("Dialog", Font.PLAIN, 12));
fullJIDLabel.setForeground(Color.gray);
titleLabel.setFont(new Font("Dialog", Font.PLAIN, 11));
titleLabel.setForeground(Color.gray);
fullJIDLabel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.gray));
}
setBorder(BorderFactory.createLineBorder(Color.gray, 1));
window.getContentPane().add(this);
final ContactList contactList = SparkManager.getWorkspace().getContactList();
contactList.addContactListListener(new ContactListListener() {
public void contactItemAdded(ContactItem item) {
}
public void contactItemRemoved(ContactItem item) {
}
public void contactGroupAdded(ContactGroup group) {
}
public void contactGroupRemoved(ContactGroup group) {
}
public void contactItemClicked(ContactItem item) {
if (window != null) {
window.dispose();
}
}
public void contactItemDoubleClicked(ContactItem item) {
if (window != null) {
window.dispose();
}
}
});
}
public void display(ContactGroup group, MouseEvent e) {
int loc = group.getList().locationToIndex(e.getPoint());
ContactItem item = (ContactItem)group.getList().getModel().getElementAt(loc);
if (item == null || item.getJID() == null) {
return;
}
if (getContactItem() != null && getContactItem() == item) {
return;
}
iconLabel.setIcon(item.getIcon());
Point point = group.getList().indexToLocation(loc);
window.setFocusableWindowState(false);
setContactItem(item);
window.pack();
Point mainWindowLocation = SparkManager.getMainWindow().getLocationOnScreen();
Point listLocation = group.getList().getLocationOnScreen();
int x = (int)mainWindowLocation.getX() + SparkManager.getMainWindow().getWidth();
int y = (int) listLocation.getY() + (int) point.getY();
setWindowLocation(x, y);
if (!window.isVisible()) {
window.setVisible(true);
}
}
public void setWindowLocation(int x, int y) {
Point mainWindowLocation = SparkManager.getMainWindow().getLocationOnScreen();
final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int actualX = x;
int actualY = y - 5;
if ((int) screenSize.getWidth() - getPreferredSize().getWidth() < x) {
actualX = (int) mainWindowLocation.getX() - (int) getPreferredSize().getWidth();
}
// keep this away from bottom edge
if (actualY + getHeight() > screenSize.height - 64) {
actualY -= actualY + getHeight() - screenSize.height + 64;
}
window.setLocation(actualX, actualY);
}
public void customizeUI(ContactItem contactItem) {
if (contactItem == null) {
return;
}
nicknameLabel.setText(contactItem.getDisplayName());
String status = contactItem.getStatus();
if (!ModelUtil.hasLength(status)) {
if (contactItem.getPresence() == null || contactItem.getPresence().getType() == Presence.Type.unavailable) {
status = Res.getString("offline");
}
else {
status = Res.getString("online");
}
}
if (status.equals(Res.getString("offline")) || contactItem.getPresence().isAway()) {
//If user is offline or away, try to see last activity
try {
String client = "";
if (!status.equals(Res.getString("offline"))) {
//If user is away (not offline), last activity request is sent to client
client = contactItem.getPresence().getFrom();
if ((client != null) && (client.lastIndexOf("/") != -1)) {
client = client.substring(client.lastIndexOf("/"));
} else client = "/";
}
LastActivity activity = LastActivityManager.getLastActivity(SparkManager.getConnection(), contactItem.getJID()+client);
long idleTime = (activity.getIdleTime() * 1000);
if (idleTime > 0) {
if (status.equals(Res.getString("offline"))) {
SimpleDateFormat format = new SimpleDateFormat("M/d/yy");
Date l = new Date();
String curDay = format.format(l);
l.setTime(l.getTime() - idleTime);
//If idleTime is within today show the time, otherwise, show the day, date, and time
if (curDay.equals(format.format(l))) {
format = new SimpleDateFormat("h:mm a");
} else {
format = new SimpleDateFormat("EEE M/d/yy h:mm a");
}
status += (" since " + format.format(l));
} else if (contactItem.getPresence().isAway()) {
status += "\n";
String time = ModelUtil.getTimeFromLong(idleTime);
status += Res.getString("message.idle.for", time);
}
}
} catch (Exception e1) {
}
}
statusLabel.setText(status);
Transport transport = TransportUtils.getTransport(StringUtils.parseServer(contactItem.getJID()));
if (transport != null) {
fullJIDLabel.setIcon(transport.getIcon());
String name = StringUtils.parseName(contactItem.getJID());
name = StringUtils.unescapeNode(name);
fullJIDLabel.setText(transport.getName() + " - " + name);
}
else {
String name = StringUtils.unescapeNode(contactItem.getJID());
fullJIDLabel.setText(name);
fullJIDLabel.setIcon(null);
}
avatarLabel.setBorder(null);
try {
URL avatarURL = contactItem.getAvatarURL();
ImageIcon icon = null;
if (avatarURL != null) {
icon = new ImageIcon(avatarURL);
}
if (icon != null && icon.getIconHeight() > 1) {
icon = GraphicUtils.scaleImageIcon(icon, 96, 96);
avatarLabel.setIcon(icon);
}
else {
icon = SparkRes.getImageIcon(SparkRes.DEFAULT_AVATAR_64x64_IMAGE);
avatarLabel.setIcon(icon);
}
avatarLabel.setBorder(BorderFactory.createBevelBorder(0, Color.white, Color.lightGray));
}
catch (MalformedURLException e) {
Log.error(e);
}
// Get VCard from memory (if available)
String title = "";
VCard vcard = SparkManager.getVCardManager().getVCardFromMemory(StringUtils.parseBareAddress(contactItem.getJID()));
if (vcard != null) {
title = vcard.getField("TITLE");
if (!ModelUtil.hasLength(title)) {
title = "";
}
}
titleLabel.setText(title);
}
public void setContactItem(ContactItem contactItem) {
this.contactItem = contactItem;
customizeUI(this.contactItem);
}
public ContactItem getContactItem() {
return contactItem;
}
public void dispose() {
window.setVisible(false);
contactItem = null;
window.dispose();
}
public Dimension getPreferredSize() {
final Dimension size = super.getPreferredSize();
size.width = 300;
size.height = 125;
return size;
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
Point point = e.getPoint();
Dimension dim = window.getSize();
int x = (int)point.getX();
int y = (int)point.getY();
boolean close = false;
if (x < 0 || x >= dim.getWidth()) {
close = true;
}
if (y < 0 || y >= dim.getHeight()) {
close = true;
}
if (close) {
window.setVisible(false);
contactItem = null;
hideWindow();
}
}
protected void hideWindow() {
window.setVisible(false);
contactItem = null;
}
protected JWindow getWindow() {
return window;
}
protected static Object getLock() {
return LOCK;
}
}