/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* 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 net.java.sip.communicator.plugin.contactinfo;
import java.awt.*;
import java.awt.event.*;
import java.text.*;
import java.util.*;
import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.html.*;
import net.java.sip.communicator.plugin.desktoputil.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.BinaryDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.BirthDateDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.CalendarDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.EmailAddressDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.FirstNameDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenderDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.GenericDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.LastNameDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.LocaleDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.MiddleNameDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.PhoneNumberDetail;
import net.java.sip.communicator.service.protocol.ServerStoredDetails.TimeZoneDetail;
/**
* The right side panel of ContactInfoDialog. Shows one tab of a summary of
* contact information for the selected subcontact, and has an extended tab
* listing all of the details.
*
* @author Adam Goldstein
* @author Yana Stamcheva
*/
public class ContactInfoDetailsPanel
extends TransparentPanel
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The tabbed pane containing the two different tabs for details.
*/
private final JTabbedPane tabbedPane = new SIPCommTabbedPane();
/**
* The operation set giving access to the server stored contact details.
*/
private OperationSetServerStoredContactInfo contactInfoOpSet;
/**
* The currently selected sub-contact we are displaying information about.
*/
private Contact contact;
/**
* The default width of hte avater area.
*/
private static final int AVATAR_AREA_WIDTH = 105;
/**
* The default height of hte avater area.
*/
private static final int AVATAR_AREA_HEIGHT = 130;
/**
* Construct a tabbed pane that will have one tab with a summary of info for
* the selected subcontact and one tab for all of the extended details.
*/
public ContactInfoDetailsPanel()
{
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
this.setPreferredSize(new Dimension(400, 300));
this.tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
}
/**
* Retrieve and display the information for the newly selected contact, c.
*
* @param c the sub-contact we are now focusing on.
*/
public void loadContactDetails(Contact c)
{
this.contact = c;
ProtocolProviderService pps = contact.getProtocolProvider();
contactInfoOpSet
= pps.getOperationSet(OperationSetServerStoredContactInfo.class);
this.removeAll();
if (contactInfoOpSet == null || !pps.isRegistered())
{
JPanel unsupportedPanel = createUnsupportedPanel();
this.add(unsupportedPanel);
this.revalidate();
this.repaint();
return;
}
this.tabbedPane.removeAll();
ImageIcon icon =
new ImageIcon(contact.getProtocolProvider().getProtocolIcon()
.getIcon(ProtocolIcon.ICON_SIZE_16x16));
JPanel summaryPanel = createSummaryInfoPanel();
JPanel extendedPanel = createExtendedInfoPanel();
JScrollPane extendedScrollPane = new JScrollPane(extendedPanel);
this.tabbedPane.addTab(
Resources.getString("service.gui.SUMMARY"), icon,
summaryPanel,
Resources.getString(
"plugin.contactinfo.CONTACT_SUMMARY_DESCRIPTION")
+ contact.getDisplayName());
this.tabbedPane.setMnemonicAt(0, KeyEvent.VK_1);
this.tabbedPane.addTab(
Resources.getString("plugin.accountinfo.EXTENDED"), icon,
extendedScrollPane,
Resources.getString(
"plugin.contactinfo.CONTACT_EXTENDED_DESCRIPTION")
+ contact.getDisplayName());
this.tabbedPane.setMnemonicAt(1, KeyEvent.VK_2);
this.add(tabbedPane);
this.revalidate();
this.repaint();
}
/**
* Creates the panel that indicates to the user that the currently selected
* contact does not support server stored contact info.
*
* @return the panel that is added and shows a message that the selected
* sub-contact does not have the operation set for server stored
* contact info supported.
*/
private JPanel createUnsupportedPanel()
{
JTextArea unsupportedTextArea = new JTextArea(
Resources.getString("service.gui.CONTACT_INFO_NOT_SUPPORTED"));
unsupportedTextArea.setEditable(false);
unsupportedTextArea.setLineWrap(true);
JPanel unsupportedPanel = new TransparentPanel(new BorderLayout());
unsupportedPanel.add(unsupportedTextArea);
return unsupportedPanel;
}
/**
* Creates a panel that can be added as the summary tab that displays the
* following details: -
*
* Avatar(Contact image) - FirstNameDetail - MiddleNameDetail -
* LastNameDetail - BirthdateDetail (and calculate age) - GenderDetail -
* EmailAddressDetail - PhoneNumberDetail. All other details will be* added
* to our list of extended details.
*
* @return the panel that will be added as the summary tab.
*/
private JPanel createSummaryInfoPanel()
{
JPanel summaryPanel = new TransparentPanel();
summaryPanel.setLayout(new BorderLayout(10, 5));
summaryPanel.setSize(this.getWidth(), this.getHeight());
// Create the avatar panel.
JPanel avatarPanel = new TransparentPanel();
avatarPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
byte[] bytes = this.contact.getImage();
ImageIcon scaledImage = null;
// If the user has a contact image, let's use it. If not, add the
// default
if (bytes != null)
{
scaledImage = ImageUtils.getScaledRoundedIcon(
bytes,
AVATAR_AREA_WIDTH,
AVATAR_AREA_HEIGHT
);
}
else
scaledImage =
ImageUtils.getScaledRoundedIcon(Resources
.getImage("service.gui.DEFAULT_USER_PHOTO"),
AVATAR_AREA_WIDTH, AVATAR_AREA_HEIGHT);
JLabel label = new JLabel(scaledImage);
label.setVerticalAlignment(JLabel.CENTER);
label.setHorizontalAlignment(JLabel.CENTER);
label.setPreferredSize(new Dimension(
AVATAR_AREA_WIDTH,
AVATAR_AREA_HEIGHT)
);
avatarPanel.add(label);
summaryPanel.add(avatarPanel, BorderLayout.WEST);
// Create the summary details panel.
JPanel detailsPanel = new TransparentPanel();
detailsPanel.setLayout(new BorderLayout());
detailsPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
summaryPanel.add(detailsPanel);
// Labels panel.
JPanel labelsPanel = new TransparentPanel(new GridLayout(0, 1, 5, 5));
labelsPanel.add(new JLabel(
Resources.getString("plugin.accountinfo.FIRST_NAME")));
labelsPanel.add(new JLabel(
Resources.getString("plugin.accountinfo.MIDDLE_NAME")));
labelsPanel.add(new JLabel(
Resources.getString("plugin.accountinfo.LAST_NAME")));
labelsPanel.add(new JLabel(
Resources.getString("plugin.accountinfo.GENDER")));
labelsPanel.add(new JLabel(
Resources.getString("plugin.accountinfo.BDAY")));
labelsPanel.add(new JLabel(
Resources.getString("plugin.accountinfo.AGE")));
labelsPanel.add(new JLabel(
Resources.getString("plugin.accountinfo.EMAIL")));
labelsPanel.add(new JLabel(
Resources.getString("plugin.accountinfo.PHONE")));
detailsPanel.add(labelsPanel, BorderLayout.WEST);
// Values panel.
JPanel valuesPanel = new TransparentPanel(new GridLayout(0, 1, 5, 5));
detailsPanel.add(valuesPanel, BorderLayout.CENTER);
Iterator contactDetails;
GenericDetail genericDetail;
// First name details.
contactDetails =
contactInfoOpSet.getDetails(contact, FirstNameDetail.class);
String firstNameDetail = "";
while (contactDetails.hasNext())
{
genericDetail = contactDetails.next();
firstNameDetail =
firstNameDetail + " " + genericDetail.getDetailValue();
}
if (firstNameDetail.equals(""))
firstNameDetail
= Resources.getString("plugin.contactinfo.NOT_SPECIFIED");
valuesPanel.add(new JLabel(firstNameDetail));
// Middle name details.
contactDetails =
contactInfoOpSet.getDetails(contact, MiddleNameDetail.class);
String middleNameDetail = "";
while (contactDetails.hasNext())
{
genericDetail = contactDetails.next();
middleNameDetail =
middleNameDetail + " " + genericDetail.getDetailValue();
}
if (middleNameDetail.trim().equals(""))
middleNameDetail
= Resources.getString("plugin.contactinfo.NOT_SPECIFIED");
valuesPanel.add(new JLabel(middleNameDetail));
// Last name details.
contactDetails =
contactInfoOpSet.getDetails(contact, LastNameDetail.class);
String lastNameDetail = "";
while (contactDetails.hasNext())
{
genericDetail = contactDetails.next();
lastNameDetail =
lastNameDetail + " " + genericDetail.getDetailValue();
}
if (lastNameDetail.trim().equals(""))
lastNameDetail
= Resources.getString("plugin.contactinfo.NOT_SPECIFIED");
valuesPanel.add(new JLabel(lastNameDetail));
// Gender details.
contactDetails =
contactInfoOpSet.getDetails(contact, GenderDetail.class);
String genderDetail = "";
while (contactDetails.hasNext())
{
genericDetail = contactDetails.next();
genderDetail = genderDetail + " " + genericDetail.getDetailValue();
}
if (genderDetail.trim().equals(""))
genderDetail
= Resources.getString("plugin.contactinfo.NOT_SPECIFIED");
valuesPanel.add(new JLabel(genderDetail));
// Birthday details.
contactDetails =
contactInfoOpSet.getDetails(contact, BirthDateDetail.class);
String birthDateDetail = "";
String ageDetail = "";
if (contactDetails.hasNext())
{
genericDetail = contactDetails.next();
Calendar calendarDetail =
(Calendar) genericDetail.getDetailValue();
Date birthDate = calendarDetail.getTime();
DateFormat dateFormat = DateFormat.getDateInstance();
birthDateDetail = dateFormat.format(birthDate).trim();
Calendar c = Calendar.getInstance();
int age = c.get(Calendar.YEAR) - calendarDetail.get(Calendar.YEAR);
if (c.get(Calendar.MONTH) < calendarDetail.get(Calendar.MONTH))
age--;
ageDetail = Integer.toString(age).trim();
}
if (birthDateDetail.equals(""))
birthDateDetail
= Resources.getString("plugin.contactinfo.NOT_SPECIFIED");
if (ageDetail.equals(""))
ageDetail = Resources.getString("plugin.contactinfo.NOT_SPECIFIED");
valuesPanel.add(new JLabel(birthDateDetail));
valuesPanel.add(new JLabel(ageDetail));
// Email details.
contactDetails =
contactInfoOpSet.getDetails(contact, EmailAddressDetail.class);
String emailDetail = "";
while (contactDetails.hasNext())
{
genericDetail = contactDetails.next();
emailDetail = emailDetail + " " + genericDetail.getDetailValue();
}
if (emailDetail.trim().equals(""))
emailDetail
= Resources.getString("plugin.contactinfo.NOT_SPECIFIED");
valuesPanel.add(new JLabel(emailDetail));
// Phone number details.
contactDetails =
contactInfoOpSet.getDetails(contact, PhoneNumberDetail.class);
String phoneNumberDetail = "";
while (contactDetails.hasNext())
{
genericDetail = contactDetails.next();
phoneNumberDetail =
phoneNumberDetail + " " + genericDetail.getDetailValue();
}
if (phoneNumberDetail.trim().equals(""))
phoneNumberDetail
= Resources.getString("plugin.contactinfo.NOT_SPECIFIED");
valuesPanel.add(new JLabel(phoneNumberDetail));
return summaryPanel;
}
/**
* A panel that displays all of the details retrieved from the opSet.
*
* @return a panel that will be added as the extended tab.
*/
private JPanel createExtendedInfoPanel()
{
JPanel mainExtendedPanel = new TransparentPanel(new BorderLayout());
JPanel extendedPanel = new TransparentPanel();
extendedPanel.setLayout(new BoxLayout(extendedPanel, BoxLayout.Y_AXIS));
JPanel imagePanel = new TransparentPanel();
// The imagePanel will be used for any BinaryDetails and will be added at
// the bottom so we don't disrupt the standard look of the other details
imagePanel.setLayout(new BoxLayout(imagePanel, BoxLayout.LINE_AXIS));
imagePanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory
.createTitledBorder(
Resources.getString("plugin.contactinfo.USER_PICTURES")),
BorderFactory.createEmptyBorder(0, 5, 5, 5)));
// Obtain all the details for a contact.
Iterator iter
= contactInfoOpSet.getAllDetailsForContact(contact);
GenericDetail detail;
JLabel detailLabel;
JTextArea detailValueArea;
JPanel detailPanel;
while (iter.hasNext())
{
detail = iter.next();
if (detail.getDetailValue().toString().equals(""))
continue;
detailLabel = new JLabel();
detailValueArea = new JTextArea();
detailPanel = new TransparentPanel(new BorderLayout(10, 10));
detailValueArea.setAlignmentX(JTextArea.CENTER_ALIGNMENT);
detailValueArea.setEditable(false);
detailValueArea.setLineWrap(true);
detailPanel.add(detailLabel, BorderLayout.WEST);
detailPanel.add(detailValueArea, BorderLayout.CENTER);
detailPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
extendedPanel.add(detailPanel);
if (detail instanceof BinaryDetail)
{
JLabel imageLabel =
new JLabel(new ImageIcon((byte[]) detail
.getDetailValue()));
imagePanel.add(imageLabel);
}
else if (detail instanceof CalendarDetail)
{
detailLabel.setText(detail.getDetailDisplayName() + ": ");
Date detailDate =
((Calendar) detail.getDetailValue()).getTime();
DateFormat df = DateFormat.getDateInstance();
detailValueArea.setText(df.format(detailDate).trim());
}
else if (detail instanceof LocaleDetail)
{
detailLabel.setText(detail.getDetailDisplayName() + ": ");
Object value = detail.getDetailValue();
String valueStr = "";
if(value instanceof Locale)
valueStr = ((Locale) value).getDisplayName().trim();
else if(value instanceof String)
valueStr = (String)value;
detailValueArea.setText(valueStr);
}
else if (detail instanceof TimeZoneDetail)
{
detailLabel.setText(detail.getDetailDisplayName() + ": ");
detailValueArea.setText(((TimeZone) detail.getDetailValue())
.getDisplayName().trim());
}
else
{
detailLabel.setText(detail.getDetailDisplayName() + ": ");
detailValueArea.setText(
detail.getDetailValue().toString().trim());
}
}
// Add users status message to extended details if it exists
String statusMessage = contact.getStatusMessage();
if(statusMessage != null && statusMessage.length() > 0)
{
detailLabel = new JLabel();
HTMLTextPane detailValuePane = new HTMLTextPane();
detailPanel = new TransparentPanel(new BorderLayout(10, 10));
detailValuePane.setEditable(false);
detailValuePane.setOpaque(false);
detailPanel.add(detailLabel, BorderLayout.WEST);
detailPanel.add(detailValuePane, BorderLayout.CENTER);
detailPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
extendedPanel.add(detailPanel);
detailLabel.setText(Resources.getString(
"plugin.contactinfo.USER_STATUS_MESSAGE") + ": ");
detailValuePane.setText(statusMessage);
}
// If the contact's protocol supports web info, give them a button to
// get it
OperationSetWebContactInfo webContactInfo
= contact
.getProtocolProvider()
.getOperationSet(OperationSetWebContactInfo.class);
if (webContactInfo != null)
{
final String urlString
= webContactInfo.getWebContactInfo(contact).toString();
JLabel webInfoLabel = new JLabel("Click to see web info: ");
JEditorPane webInfoValue = new JEditorPane();
JPanel webInfoPanel = new TransparentPanel(new BorderLayout());
webInfoPanel.add(webInfoLabel, BorderLayout.WEST);
webInfoPanel.add(webInfoValue, BorderLayout.CENTER);
extendedPanel.add(webInfoPanel);
webInfoValue.setOpaque(false);
webInfoValue.setContentType("text/html");
webInfoValue.setEditable(false);
webInfoValue.setText( ""
+ contact.getDisplayName()
+ " web info");
webInfoValue.addHyperlinkListener(new HyperlinkListener()
{
public void hyperlinkUpdate(HyperlinkEvent e)
{
if (e.getEventType()
.equals(HyperlinkEvent.EventType.ACTIVATED))
{
ContactInfoActivator
.getBrowserLauncher().openURL(urlString);
}
}
});
}
if (imagePanel.getComponentCount() > 0)
mainExtendedPanel.add(imagePanel, BorderLayout.CENTER);
mainExtendedPanel.add(extendedPanel, BorderLayout.NORTH);
return mainExtendedPanel;
}
/**
* The HTMLTextPane is a pane that handles displaying HTML and
* hyperlinking urls found in the text.
*/
private class HTMLTextPane
extends JTextPane
implements HyperlinkListener
{
/**
* Serial version UID.
*/
private static final long serialVersionUID = 0L;
/**
* The regular expression (in the form of compiled Pattern)
* which matches URLs for the purposed of turning them into links.
*/
private final Pattern URL_PATTERN = Pattern.compile("("
+ "(\\bwww\\.[^\\s<>\"]+\\.[^\\s<>\"]+/*[?#]*(\\w+[&=;?]\\w+)*\\b)" // wwwURL
+ "|" + "(\\b\\w+://[^\\s<>\"]+/*[?#]*(\\w+[&=;?]\\w+)*\\b)" // protocolURL
+ ")");
private SIPCommHTMLEditorKit editorKit;
private HTMLDocument document;
/**
* Creates and instance of HTMLTextPane
*/
public HTMLTextPane()
{
editorKit = new SIPCommHTMLEditorKit(this);
this.document = (HTMLDocument) editorKit.createDefaultDocument();
this.addHyperlinkListener(this);
this.setContentType("text/html");
this.setEditorKitForContentType("text/html", editorKit);
this.setEditorKit(editorKit);
this.setDocument(document);
putClientProperty(
JTextPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
}
/**
* Override of parent setText(String) to search for URLs and
* set as hyperlinks.
* @param string String to display.
*/
@Override
public void setText(String string)
{
Matcher m = URL_PATTERN.matcher(string);
StringBuffer msgBuffer = new StringBuffer();
int prevEnd = 0;
while (m.find())
{
String fromPrevEndToStart = string.substring(prevEnd, m.start());
msgBuffer.append(fromPrevEndToStart);
prevEnd = m.end();
String url = m.group().trim();
msgBuffer.append("");
msgBuffer.append(url);
msgBuffer.append("");
}
String fromPrevEndToEnd = string.substring(prevEnd);
msgBuffer.append(fromPrevEndToEnd);
super.setText(msgBuffer.toString());
}
/**
* Handles activations of hyperlinks
* @param e HyperlinkEvent to handle.
*/
public void hyperlinkUpdate(HyperlinkEvent e)
{
if(e.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
ContactInfoActivator.getBrowserLauncher()
.openURL(e.getURL().toString());
}
}
}