Adding autocomplete Button to "Add Contact" menu like Outlook has

git-svn-id: http://svn.igniterealtime.org/svn/repos/spark/trunk@12225 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Wolf Posdorfer
2011-04-04 12:55:40 +00:00
committed by wolf.posdorfer
parent 3de869edc6
commit 21b74bca92
7 changed files with 189 additions and 41 deletions

View File

@ -34,6 +34,7 @@ import java.util.List;
public class SearchManager {
private List<Searchable> searchServices = new ArrayList<Searchable>();
private SearchService ui;
private Collection<String> _searchservicesHosts;
private static SearchManager singleton;
private static final Object LOCK = new Object();
@ -64,7 +65,6 @@ public class SearchManager {
// By default, the user search is first.
SwingWorker worker = new SwingWorker() {
UserSearchService searchWizard;
public Object construct() {
searchWizard = new UserSearchService();
return searchWizard;
@ -74,6 +74,7 @@ public class SearchManager {
if (searchWizard.getSearchServices() != null) {
ui.setActiveSearchService(searchWizard);
addSearchService(searchWizard);
_searchservicesHosts = searchWizard.getSearchServices();
}
}
};
@ -115,6 +116,15 @@ public class SearchManager {
public Collection<Searchable> getSearchServices() {
return searchServices;
}
/**
* Returns all registered search services.
*
* @return the collection of search services.
*/
public Collection<String> getSearchServicesAsString()
{
return _searchservicesHosts;
}
private void checkSearchService() {
Collection searchables = getSearchServices();

View File

@ -19,39 +19,6 @@
*/
package org.jivesoftware.spark.ui;
import org.jivesoftware.resource.Default;
import org.jivesoftware.resource.Res;
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.packet.VCard;
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.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;
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.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
@ -63,12 +30,59 @@ 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.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
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.
@ -86,12 +100,16 @@ public class RosterDialog implements PropertyChangeListener, ActionListener {
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();
@ -108,12 +126,45 @@ public class RosterDialog implements PropertyChangeListener, ActionListener {
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) {
}
});
pane = null;
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(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, 1.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));
@ -469,6 +520,87 @@ public class RosterDialog implements PropertyChangeListener, ActionListener {
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.length() <= 4) {
JOptionPane.showMessageDialog(jidField, Res.getString("message.search.input.short"),
Res.getString("title.notification"),
JOptionPane.ERROR_MESSAGE);
return;
}
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("search", jidField.getText());
answer.setAnswer("Username", true);
data = usersearchManager.getSearchResults(answer,
"search.jabber.int.kn");
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());
}
});
}
}
}
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());
}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.

View File

@ -33,7 +33,6 @@ import org.jivesoftware.sparkimpl.plugin.emoticons.EmoticonManager;
import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
@ -49,7 +48,10 @@ import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
@ -156,7 +158,7 @@ public class ThemePanel extends JPanel {
_lookandfeel = new JComboBox(lafname);
if (Default.getBoolean(Default.LOOK_AND_FEEL_DISABLED)){
_lookandfeel.disable();
_lookandfeel.setEnabled(false);
}
_lookandfeelLabel = new JLabel(Res.getString("lookandfeel.select"));
_lookandfeelpreview = new JButton(Res.getString("lookandfeel.change.now"));

View File

@ -57,6 +57,8 @@ import java.util.List;
* UserSearchResults displays the UI for all users found using the JEP-055 search service.
*/
public class UserSearchResults extends JPanel {
private static final long serialVersionUID = 4196389090818949068L;
private UsersInfoTable resultsTable;
/**

View File

@ -39,7 +39,7 @@ import java.util.Iterator;
import java.util.Set;
public class UserSearchService implements Searchable {
private Collection searchServices;
private Collection<String> searchServices;
public UserSearchService() {
loadSearchServices();
@ -132,7 +132,7 @@ public class UserSearchService implements Searchable {
* @return a Collection of search services found on the server.
* @throws XMPPException thrown if a server error has occurred.
*/
private Collection getServices() throws Exception {
private Collection<String> getServices() throws Exception {
final Set<String> searchServices = new HashSet<String>();
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(SparkManager.getConnection());
DiscoverItems items = SparkManager.getSessionManager().getDiscoveredItems();
@ -172,7 +172,7 @@ public class UserSearchService implements Searchable {
*
* @return the discovered search services.
*/
public Collection getSearchServices() {
public Collection<String> getSearchServices() {
return searchServices;
}

View File

@ -734,6 +734,7 @@ message.room.destruction.reason = Reason for destroying the room?
message.room.information.for = Room information for {0}
message.save.profile = To save changes to your profile, click save
message.search.for.contacts = Search for contacts
message.search.input.short = Please provide atleast five letters.
message.search.for.other.people = Search for other people on the server
message.search.service.not.available = Unable to contact search service
message.searching.please.wait = Searching, please wait...

View File

@ -357,6 +357,7 @@ message.send.picture = Bildschirminhalt versenden.
message.sent.offline.files = Sie haben offline Dateien gesendet.
message.spark.secure = Sichere Verbindung aktiv.
message.search.for.contacts = Nach Kontakten suchen.
message.search.input.short = Bitte gib mehr als f<>nf Zeichen ein.
message.end.conversation = Soll diese Sitzung beendet werden?
message.end.chat = Soll dieser Chat beendet werden?
message.close.this.chat = Diesen Chat schlie<69>en