/**
* $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.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.UIManager;
import org.jivesoftware.resource.Default;
import org.jivesoftware.resource.Res;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.ReportedData;
import org.jivesoftware.smackx.ReportedData.Column;
import org.jivesoftware.smackx.ReportedData.Row;
import org.jivesoftware.smackx.packet.VCard;
import org.jivesoftware.smackx.search.UserSearchManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.UserManager;
import org.jivesoftware.spark.component.TitlePanel;
import org.jivesoftware.spark.component.borders.ComponentTitledBorder;
import org.jivesoftware.spark.component.renderer.JPanelRenderer;
import org.jivesoftware.spark.search.SearchManager;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.ResourceUtils;
import org.jivesoftware.spark.util.SwingWorker;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.plugin.gateways.Gateway;
import org.jivesoftware.sparkimpl.plugin.gateways.transports.Transport;
import org.jivesoftware.sparkimpl.plugin.gateways.transports.TransportUtils;
/**
* The RosterDialog is used to add new users to the users XMPP Roster.
*/
public class RosterDialog implements ActionListener {
private JPanel panel;
private JTextField jidField;
private JTextField nicknameField;
private final Vector<String> groupModel = new Vector<String>();
private final JPanel networkPanel = new JPanel(new GridBagLayout());
private JComboBox groupBox;
private JComboBox accounts;
private JDialog dialog;
private ContactList contactList;
private JCheckBox publicBox;
private JButton _searchForName ;
private Collection<String> _usersearchservice;
/**
* Create a new instance of RosterDialog.
*/
public RosterDialog() {
contactList = SparkManager.getWorkspace().getContactList();
_usersearchservice = SearchManager.getInstance().getSearchServicesAsString();
panel = new JPanel();
JLabel contactIDLabel = new JLabel();
jidField = new JTextField();
JLabel nicknameLabel = new JLabel();
nicknameField = new JTextField();
JLabel groupLabel = new JLabel();
groupBox = new JComboBox(groupModel);
JButton newGroupButton = new JButton();
JLabel accountsLabel = new JLabel();
accounts = new JComboBox();
publicBox = new JCheckBox(Res.getString("label.user.on.public.network"));
ResourceUtils.resLabel(accountsLabel, publicBox, Res.getString("label.network"));
_searchForName = new JButton();
_searchForName.setIcon(SparkRes.getImageIcon(SparkRes.TRANSFER_IMAGE_24x24));
_searchForName.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
try {
searchForContact(jidField.getText(), e);
} catch (XMPPException e1) {
Log.error("search contact", e1);
}
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
});
dialog = null;
panel.setLayout(new GridBagLayout());
panel.add(contactIDLabel, new GridBagConstraints(0, 0, 1, 1, 0.0D, 0.0D, 17, 2, new Insets(5, 5, 5, 5), 0, 0));
panel.add(jidField , new GridBagConstraints(1, 0, 1, 1, 1.0D, 0.0D, 17, 2, new Insets(5, 5, 5, 5), 0, 0));
panel.add(_searchForName, new GridBagConstraints(2, 0, 1, 1, 0.0D, 0.0D, 17, 0, new Insets(5, 5, 5, 5), 0, 0));
panel.add(nicknameLabel, new GridBagConstraints(0, 1, 1, 1, 0.0D, 0.0D, 17, 2, new Insets(5, 5, 5, 5), 0, 0));
panel.add(nicknameField, new GridBagConstraints(1, 1, 1, 1, 1.0D, 0.0D, 17, 2, new Insets(5, 5, 5, 5), 0, 0));
ComponentTitledBorder componentBorder = new ComponentTitledBorder(publicBox, networkPanel
, BorderFactory.createEtchedBorder());
networkPanel.add(accountsLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, 17, 2, new Insets(5, 5, 5, 5), 0, 0));
networkPanel.add(accounts, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, 17, 2, new Insets(5, 5, 5, 5), 0, 0));
networkPanel.setBorder(componentBorder);
networkPanel.setVisible(false);
accounts.setEnabled(false);
panel.add(groupLabel, new GridBagConstraints(0, 4, 1, 1, 0.0D, 0.0D, 17, 2, new Insets(5, 5, 5, 5), 0, 0));
panel.add(groupBox, new GridBagConstraints(1, 4, 1, 1, 1.0D, 0.0D, 17, 2, new Insets(5, 5, 5, 5), 0, 0));
if(!Default.getBoolean("ADD_CONTACT_GROUP_DISABLED")){
panel.add(newGroupButton, new GridBagConstraints(2, 4, 1, 1, 0.0D, 0.0D, 17, 1, new Insets(5, 5, 5, 5), 0, 0));
}
newGroupButton.addActionListener(this);
panel.add(networkPanel, new GridBagConstraints(0, 5, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
ResourceUtils.resLabel(contactIDLabel, jidField, Res.getString("label.username") + ":");
ResourceUtils.resLabel(nicknameLabel, nicknameField, Res.getString("label.nickname") + ":");
ResourceUtils.resLabel(groupLabel, groupBox, Res.getString("label.group") + ":");
ResourceUtils.resButton(newGroupButton, Res.getString("button.new"));
accounts.setRenderer(new JPanelRenderer());
for (ContactGroup group : contactList.getContactGroups()) {
if (!group.isOfflineGroup() && !Res.getString("unfiled").equalsIgnoreCase(group.getGroupName()) && !group.isSharedGroup()) {
groupModel.add(group.getGroupName());
}
}
groupBox.setEditable(true);
if (groupModel.size() == 0) {
groupBox.addItem("Friends");
}
if (groupModel.size() > 0) {
groupBox.setSelectedIndex(0);
}
jidField.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
}
public void focusLost(FocusEvent e) {
String jid = getJID();
String vcardNickname = null;
if (!publicBox.isSelected()) {
// This is not a transport.
String fullJID = getJID();
if (fullJID.indexOf("@") == -1) {
fullJID = fullJID + "@" + SparkManager.getConnection().getServiceName();
}
vcardNickname = SparkManager.getUserManager().getNickname(fullJID);
}
String nickname = nicknameField.getText();
if (!ModelUtil.hasLength(nickname) && ModelUtil.hasLength(jid)) {
nickname = StringUtils.parseName(jid);
if (!ModelUtil.hasLength(nickname)) {
nickname = jid;
}
nicknameField.setText(vcardNickname != null ? vcardNickname : nickname);
}
}
});
final List<AccountItem> accountCol = getAccounts();
for (AccountItem item : accountCol) {
accounts.addItem(item);
}
if (accountCol.size() > 0) {
accountsLabel.setVisible(true);
accounts.setVisible(true);
publicBox.setVisible(true);
networkPanel.setVisible(true);
}
publicBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
accounts.setEnabled(publicBox.isSelected());
}
});
}
/**
* Sets the default <code>ContactGroup</code> to display in the combo box.
*
* @param contactGroup the default ContactGroup.
*/
public void setDefaultGroup(ContactGroup contactGroup) {
String groupName = contactGroup.getGroupName();
if (groupModel.contains(groupName)) {
groupBox.setSelectedItem(groupName);
}
else if (groupModel.size() > 0) {
groupBox.addItem(groupName);
groupBox.setSelectedItem(groupName);
}
}
/**
* Sets the default jid to show in the jid field.
*
* @param jid the jid.
*/
public void setDefaultJID(String jid) {
jidField.setText(jid);
}
/**
* Sets the default nickname to show in the nickname field.
*
* @param nickname the nickname.
*/
public void setDefaultNickname(String nickname) {
nicknameField.setText(nickname);
}
public void actionPerformed(ActionEvent e) {
String group = JOptionPane.showInputDialog(dialog, Res.getString("label.enter.group.name") + ":", Res.getString("title.new.roster.group"), 3);
if (group != null && group.length() > 0 && !groupModel.contains(group)) {
SparkManager.getConnection().getRoster().createGroup(group);
groupModel.add(group);
int size = groupModel.size();
groupBox.setSelectedIndex(size - 1);
}
}
/**
* Display the RosterDialog using a parent container.
*
* @param parent the parent Frame.
*/
public void showRosterDialog(JFrame parent) {
TitlePanel titlePanel = new TitlePanel(Res.getString("title.add.contact"), Res.getString("message.add.contact.to.list"), null, true);
JPanel mainPanel = new JPanel() {
private static final long serialVersionUID = -7489967438182277375L;
public Dimension getPreferredSize() {
final Dimension size = super.getPreferredSize();
size.width = 450;
return size;
}
};
mainPanel.setLayout(new BorderLayout());
mainPanel.add(titlePanel, BorderLayout.NORTH);
mainPanel.add(panel, BorderLayout.CENTER);
JButton addbutton = new JButton(Res.getString("add"));
addbutton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addContactButton();
}
});
JButton cancelbutton = new JButton(Res.getString("cancel"));
cancelbutton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dialog.dispose();
}
});
JPanel buttonpanel = new JPanel(new FlowLayout());
buttonpanel.add(addbutton);
buttonpanel.add(cancelbutton);
mainPanel.add(buttonpanel, BorderLayout.SOUTH);
dialog = new JDialog(parent, Res.getString("title.add.contact"), false);
dialog.setContentPane(mainPanel);
dialog.pack();
dialog.setLocationRelativeTo(parent);
dialog.setVisible(true);
dialog.toFront();
dialog.requestFocus();
jidField.requestFocus();
}
/**
* Display the RosterDialog using the MainWindow as the parent.
*/
public void showRosterDialog() {
showRosterDialog(SparkManager.getMainWindow());
}
private void addEntry() {
Transport transport = null;
AccountItem item;
if (publicBox.isSelected()) {
item = (AccountItem)accounts.getSelectedItem();
transport = item.getTransport();
}
if (transport == null) {
String jid = getJID();
if (jid.indexOf("@") == -1) {
jid = jid + "@" + SparkManager.getConnection().getServiceName();
}
String nickname = nicknameField.getText();
String group = (String)groupBox.getSelectedItem();
jid = UserManager.escapeJID(jid);
// Add as a new entry
addRosterEntry(jid, nickname, group);
}
else {
String jid = getJID();
try {
jid = Gateway.getJID(transport.getServiceName(), jid);
}
catch (XMPPException e) {
Log.error(e);
}
String nickname = nicknameField.getText();
String group = (String)groupBox.getSelectedItem();
addRosterEntry(jid, nickname, group);
}
}
/**
* Returns the trimmed version of the JID.
*
* @return the trimmed version.
*/
private String getJID() {
return jidField.getText().trim();
}
private void addRosterEntry(final String jid, final String nickname, final String group) {
final SwingWorker rosterEntryThread = new SwingWorker() {
public Object construct() {
return addEntry(jid, nickname, group);
}
public void finished() {
if (get() == null) {
JOptionPane.showMessageDialog(dialog, Res.getString("label.unable.to.add.contact"), Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
}
}
};
rosterEntryThread.start();
}
/**
* Creates a Popupdialog above the Search Button displaying matching
* Contacts
*
* @param byname
* , the Searchname, atleast 5 Chars long
* @param event
* , the MouseEvent which triggered it
* @throws XMPPException
*/
public void searchForContact(String byname, MouseEvent event)
throws XMPPException {
if (byname.contains("@")) {
byname = byname.substring(0, byname.indexOf("@"));
}
if (byname.length() <= 4) {
JOptionPane.showMessageDialog(jidField,
Res.getString("message.search.input.short"),
Res.getString("title.notification"),
JOptionPane.ERROR_MESSAGE);
} else {
JPopupMenu popup = new JPopupMenu();
JMenuItem header = new JMenuItem(
Res.getString("group.search.results") + ":");
header.setBackground(UIManager.getColor("List.selectionBackground"));
header.setForeground(Color.red);
popup.add(header);
for (String search : _usersearchservice) {
ReportedData data;
UserSearchManager usersearchManager = new UserSearchManager(
SparkManager.getConnection());
Form f = usersearchManager.getSearchForm(search);
Form answer = f.createAnswerForm();
answer.setAnswer("Name", true);
answer.setAnswer("Email", true);
answer.setAnswer("Username", true);
answer.setAnswer("search", byname);
data = usersearchManager.getSearchResults(answer, search);
ArrayList<String> columnnames = new ArrayList<String>();
Iterator<Column> columns = data.getColumns();
while (columns.hasNext()) {
ReportedData.Column column = (ReportedData.Column) columns
.next();
String label = column.getLabel();
columnnames.add(label);
}
Iterator<Row> rows = data.getRows();
while (rows.hasNext()) {
ReportedData.Row row = (ReportedData.Row) rows.next();
if (row.getValues(columnnames.get(0)).hasNext()) {
String s = (String) row.getValues(columnnames.get(0))
.next();
final JMenuItem item = new JMenuItem(s);
popup.add(item);
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
jidField.setText(item.getText());
nicknameField.setText(StringUtils
.parseName(item.getText()));
}
});
}
}
}
if (popup.getComponentCount() > 2) {
popup.setVisible(true);
popup.show(_searchForName, event.getX(), event.getY());
} else if (popup.getComponentCount() == 2) {
jidField.setText(((JMenuItem) popup.getComponent(1)).getText());
nicknameField.setText(StringUtils.parseName(((JMenuItem) popup
.getComponent(1)).getText()));
} else {
JOptionPane.showMessageDialog(jidField,
Res.getString("message.no.results.found"),
Res.getString("title.notification"),
JOptionPane.ERROR_MESSAGE);
}
}
}
/**
* Adds a new entry to the users Roster.
*
* @param jid the jid.
* @param nickname the nickname.
* @param group the contact group.
* @return the new RosterEntry.
*/
public RosterEntry addEntry(String jid, String nickname, String group) {
String[] groups = {group};
Roster roster = SparkManager.getConnection().getRoster();
RosterEntry userEntry = roster.getEntry(jid);
boolean isSubscribed = true;
if (userEntry != null) {
isSubscribed = userEntry.getGroups().size() == 0;
}
if (isSubscribed) {
try {
roster.createEntry(jid, nickname, new String[]{group});
}
catch (XMPPException e) {
Log.error("Unable to add new entry " + jid, e);
}
return roster.getEntry(jid);
}
try {
RosterGroup rosterGroup = roster.getGroup(group);
if (rosterGroup == null) {
rosterGroup = roster.createGroup(group);
}
if (userEntry == null) {
roster.createEntry(jid, nickname, groups);
userEntry = roster.getEntry(jid);
}
else {
userEntry.setName(nickname);
rosterGroup.addEntry(userEntry);
}
userEntry = roster.getEntry(jid);
}
catch (XMPPException ex) {
Log.error(ex);
}
return userEntry;
}
public List<AccountItem> getAccounts() {
List<AccountItem> list = new ArrayList<AccountItem>();
for (Transport transport : TransportUtils.getTransports()) {
if (TransportUtils.isRegistered(SparkManager.getConnection(), transport)) {
AccountItem item = new AccountItem(transport.getIcon(), transport.getName(), transport);
list.add(item);
}
}
return list;
}
/**
* Method to handle the Add-Button
*/
private void addContactButton() {
String errorMessage = Res.getString("title.error");
String jid = getJID();
if(jid.length()==0)
{
JOptionPane.showMessageDialog(dialog, Res.getString("message.invalid.jid.error"),
Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
return;
}
String contact = UserManager.escapeJID(jid);
String nickname = nicknameField.getText();
String group = (String) groupBox.getSelectedItem();
Transport transport = null;
if (publicBox.isSelected()) {
AccountItem item = (AccountItem) accounts.getSelectedItem();
transport = item.getTransport();
}
if (transport == null) {
if (!contact.contains("@")) {
contact = contact + "@"
+ SparkManager.getConnection().getServiceName();
}
} else {
if (!contact.contains("@")) {
contact = contact + "@" + transport.getServiceName();
}
}
if (!ModelUtil.hasLength(nickname) && ModelUtil.hasLength(contact)) {
// Try to load nickname from VCard
VCard vcard = new VCard();
try {
vcard.load(SparkManager.getConnection(), contact);
nickname = vcard.getNickName();
} catch (XMPPException e1) {
Log.error(e1);
}
// If no nickname, use first name.
if (!ModelUtil.hasLength(nickname)) {
nickname = StringUtils.parseName(contact);
}
nicknameField.setText(nickname);
}
ContactGroup contactGroup = contactList.getContactGroup(group);
boolean isSharedGroup = contactGroup != null
&& contactGroup.isSharedGroup();
if (isSharedGroup) {
errorMessage = Res
.getString("message.cannot.add.contact.to.shared.group");
} else if (!ModelUtil.hasLength(contact)) {
errorMessage = Res.getString("message.specify.contact.jid");
} else if (!StringUtils.parseBareAddress(contact).contains("@")) {
errorMessage = Res.getString("message.invalid.jid.error");
} else if (!ModelUtil.hasLength(group)) {
errorMessage = Res.getString("message.specify.group");
} else if (ModelUtil.hasLength(contact) && ModelUtil.hasLength(group)
&& !isSharedGroup) {
addEntry();
dialog.setVisible(false);
return;
} else {
JOptionPane.showMessageDialog(dialog, errorMessage,
Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
}
}
class AccountItem extends JPanel {
private static final long serialVersionUID = -7657731912529801653L;
private Transport transport;
public AccountItem(Icon icon, String name, Transport transport) {
setLayout(new GridBagLayout());
this.transport = transport;
JLabel iconLabel = new JLabel();
iconLabel.setIcon(icon);
JLabel label = new JLabel();
label.setText(name);
label.setFont(new Font("Dialog", Font.PLAIN, 11));
label.setHorizontalTextPosition(JLabel.CENTER);
add(iconLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
add(label, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 10, 0, 0), 0, 0));
setBackground(Color.white);
}
public Transport getTransport() {
return transport;
}
}
}