/**
* $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.fastpath.internal;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
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.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.jivesoftware.fastpath.resources.FastpathRes;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.Form;
import org.jivesoftware.smackx.FormField;
import org.jivesoftware.smackx.packet.VCard;
import org.jivesoftware.smackx.workgroup.settings.ChatSetting;
import org.jivesoftware.smackx.workgroup.settings.ChatSettings;
import org.jivesoftware.smackx.workgroup.user.Workgroup;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.component.tabbedPane.SparkTab;
import org.jivesoftware.spark.ui.ContactGroup;
import org.jivesoftware.spark.ui.ContactItem;
import org.jivesoftware.spark.ui.ContactList;
import org.jivesoftware.spark.ui.ContactListListener;
import org.jivesoftware.spark.ui.conferences.ConferenceUtils;
import org.jivesoftware.spark.ui.conferences.RoomInvitationListener;
import org.jivesoftware.spark.ui.rooms.GroupChatRoom;
import org.jivesoftware.spark.util.GraphicUtils;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.SwingWorker;
import org.jivesoftware.spark.util.log.Log;
/**
* Responsible for retrieving and writing out workgroup form information.
*/
public class WorkgroupManager {
/**
* Stores the ChatSettings of each workgroup, and will be updated
* when packet date of workgroup changes.
*/
private Map<String, ChatSettings> chatSettings = new HashMap<String, ChatSettings>();
private Set<String> invites = new HashSet<String>();
private static WorkgroupManager singleton;
private static final Object LOCK = new Object();
/**
* Returns the singleton instance of <CODE>WorkgroupManager</CODE>,
* creating it if necessary.
* <p/>
*
* @return the singleton instance of <Code>WorkgroupManager</CODE>
*/
public static WorkgroupManager getInstance() {
// Synchronize on LOCK to ensure that we don't end up creating
// two singletons.
synchronized (LOCK) {
if (null == singleton) {
WorkgroupManager controller = new WorkgroupManager();
singleton = controller;
return controller;
}
}
return singleton;
}
private WorkgroupManager() {
// Add own invitation listener to handle invites after the queue.
SparkManager.getChatManager().addInvitationListener(new InviteListener());
// Always check for new contact item to see if it's a workgroup.
final ContactList contactList = SparkManager.getWorkspace().getContactList();
contactList.addContactListListener(new ContactListListener() {
public void contactItemAdded(ContactItem item) {
handleContactItem(item);
}
public void contactItemRemoved(ContactItem item) {
}
public void contactGroupAdded(ContactGroup group) {
}
public void contactGroupRemoved(ContactGroup group) {
}
public void contactItemDoubleClicked(ContactItem item) {
}
public void contactItemClicked(ContactItem item) {
}
});
}
/**
* Returns the chat settings for a particular workgroup.
*
* @param key the key in the chat settings.
* @param workgroupName the name of the workgroup
* @return the <code>ChatSetting</code> found with the specified key.
*/
public ChatSetting getChatSetting(String key, String workgroupName) {
ChatSettings settings = null;
if (chatSettings.containsKey(workgroupName)) {
settings = (ChatSettings)chatSettings.get(workgroupName);
}
else {
XMPPConnection connection = SparkManager.getConnection();
Workgroup workgroup = new Workgroup(workgroupName, connection);
try {
settings = workgroup.getChatSettings();
chatSettings.put(workgroupName, settings);
}
catch (XMPPException e) {
Log.error("Error retrieving chat setting using key=" + key + " and workgroup=" + workgroupName, e);
}
}
if (settings != null) {
return settings.getChatSetting(key);
}
return null;
}
private void showWorkgroup(final ContactItem contactItem) throws Exception {
VCard vcard = SparkManager.getVCardManager().getVCard();
final Map<String, String> variables = new HashMap<String, String>();
String firstName = vcard.getFirstName();
String lastName = vcard.getLastName();
if (ModelUtil.hasLength(firstName) && ModelUtil.hasLength(lastName)) {
variables.put("username", firstName + " " + lastName);
}
else if (ModelUtil.hasLength(firstName)) {
variables.put("username", firstName);
}
else if (ModelUtil.hasLength(lastName)) {
variables.put("username", lastName);
}
String email = vcard.getEmailHome();
String emailWork = vcard.getEmailWork();
if (ModelUtil.hasLength(emailWork)) {
email = emailWork;
}
if (ModelUtil.hasLength(email)) {
variables.put("email", email);
}
String workgroupJID = contactItem.getJID();
String nameOfWorkgroup = StringUtils.parseName(workgroupJID);
final JDialog workgroupDialog = new JDialog(SparkManager.getMainWindow(), "Contact " + nameOfWorkgroup + " Workgroup");
Workgroup workgroup = new Workgroup(workgroupJID, SparkManager.getConnection());
final Form workgroupForm = workgroup.getWorkgroupForm();
String welcomeText = FormText.getWelcomeText(workgroupJID);
String startButton = FormText.getStartButton(workgroupJID);
final WorkgroupDataForm formUI = new WorkgroupDataForm(workgroupForm, variables);
formUI.setBackground(Color.white);
final JPanel titlePane = new LiveTitlePane("Contact Workgroup", FastpathRes.getImageIcon(FastpathRes.FASTPATH_IMAGE_24x24)) {
private static final long serialVersionUID = -4484940286068835770L;
public Dimension getPreferredSize() {
final Dimension size = super.getPreferredSize();
size.width = 400;
return size;
}
};
formUI.add(titlePane, new GridBagConstraints(0, 0, 3, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
final JButton submitButton = new JButton("Start Chat!");
submitButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (validateForm(workgroupDialog, workgroupForm, formUI.getFilledForm())) {
enterQueue(contactItem.getJID(), formUI.getFilledForm());
workgroupDialog.dispose();
}
}
});
formUI.setEnterListener(new WorkgroupDataForm.EnterListener() {
public void enterPressed() {
if (validateForm(workgroupDialog, workgroupForm, formUI.getFilledForm())) {
enterQueue(contactItem.getJID(), formUI.getFilledForm());
workgroupDialog.dispose();
}
}
});
formUI.add(submitButton, new GridBagConstraints(1, 100, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
workgroupDialog.getContentPane().setLayout(new BorderLayout());
workgroupDialog.getContentPane().add(formUI, BorderLayout.CENTER);
workgroupDialog.pack();
GraphicUtils.centerWindowOnScreen(workgroupDialog);
workgroupDialog.setVisible(true);
}
private static boolean validateForm(JDialog parent, Form workgroupForm, Form form) {
Iterator iter = form.getFields();
while (iter.hasNext()) {
FormField field = (FormField)iter.next();
if (field.isRequired() && !field.getValues().hasNext()) {
String variable = field.getVariable();
String elementName = workgroupForm.getField(variable).getLabel();
JOptionPane.showMessageDialog(parent, variable + " is required to complete the form.", "Incomplete Form", JOptionPane.ERROR_MESSAGE);
return false;
}
}
return true;
}
public void handleContactItem(final ContactItem contactItem) {
Presence presence = contactItem.getPresence();
PacketExtension workgroup = presence.getExtension("workgroup", "http://jivesoftware.com/protocol/workgroup");
PacketExtension notifyQueue = presence.getExtension("notify-queue", "http://jabber.org/protocol/workgroup");
if (workgroup == null && notifyQueue == null) {
return;
}
if (!presence.isAway()){
contactItem.setIcon(FastpathRes.getImageIcon(FastpathRes.FASTPATH_IMAGE_16x16));
}
else {
contactItem.setIcon(FastpathRes.getImageIcon(FastpathRes.FASTPATH_OFFLINE_IMAGE_16x16));
contactItem.setStatus(null);
}
}
private void enterQueue(String workgroupJID, Form form) {
String workgroupName = StringUtils.parseName(workgroupJID).toUpperCase();
final JDialog workgroupDialog = new JDialog(SparkManager.getMainWindow(), workgroupName + " Workgroup");
final Workgroup workgroup = new Workgroup(workgroupJID, SparkManager.getConnection());
try {
workgroup.joinQueue(form);
}
catch (XMPPException e) {
Log.error(e);
}
final JPanel titlePane = new LiveTitlePane("Waiting in Queue", FastpathRes.getImageIcon(FastpathRes.FASTPATH_IMAGE_24x24)) {
private static final long serialVersionUID = -7370226759188539384L;
public Dimension getPreferredSize() {
final Dimension size = super.getPreferredSize();
size.width = 400;
return size;
}
};
final JPanel mainPanel = new JPanel();
mainPanel.setLayout(new GridBagLayout());
mainPanel.add(titlePane, new GridBagConstraints(0, 0, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
final JLabel queuePostionLabel = new JLabel();
final JLabel queueWaitTime = new JLabel();
queuePostionLabel.setText("Waiting for position information.");
queueWaitTime.setText("Gathering wait time.");
mainPanel.add(queuePostionLabel, new GridBagConstraints(0, 1, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
mainPanel.add(queueWaitTime, new GridBagConstraints(0, 2, 4, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
final JButton leaveQueueButton = new JButton("Leave Queue");
mainPanel.add(queueWaitTime, new GridBagConstraints(0, 3, 4, 1, 1.0, 1.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
leaveQueueButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (workgroup.isInQueue()) {
try {
invites.add(workgroup.getWorkgroupJID());
workgroup.departQueue();
}
catch (XMPPException e1) {
Log.error(e1);
}
}
}
});
mainPanel.add(leaveQueueButton, new GridBagConstraints(3, 4, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
mainPanel.setBackground(Color.white);
workgroupDialog.getContentPane().add(mainPanel);
workgroupDialog.pack();
GraphicUtils.centerWindowOnScreen(workgroupDialog);
workgroupDialog.setVisible(true);
workgroupDialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
if (workgroup.isInQueue()) {
try {
workgroup.departQueue();
}
catch (XMPPException e1) {
Log.error(e1);
}
}
}
});
SwingWorker worker = new SwingWorker() {
public Object construct() {
while (true) {
if (workgroup.isInQueue()) {
queuePostionLabel.setText("Current Position in Queue: " + workgroup.getQueuePosition());
queueWaitTime.setText("It is estimated your wait time to now be " + FormUtils.getTimeFromLong(workgroup.getQueueRemainingTime()));
}
else {
return true;
}
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
Log.error(e);
}
}
}
public void finished() {
workgroupDialog.setVisible(false);
if (invites.contains(workgroup.getWorkgroupJID())) {
invites.remove(workgroup.getWorkgroupJID());
}
else {
JOptionPane.showMessageDialog(SparkManager.getMainWindow(), "Unable to contact a member of the workgroup. Please try back later.", "No Answer", JOptionPane.INFORMATION_MESSAGE);
}
}
};
worker.start();
}
private class InviteListener implements RoomInvitationListener {
// Add own invitation listener
@Override
public boolean handleInvitation(final Connection conn, final String room, final String inviter, final String reason, final String password, final Message message) {
invites.add(inviter);
if (message.getExtension("workgroup", "http://jabber.org/protocol/workgroup") != null) {
String workgroupName = StringUtils.parseName(inviter);
GroupChatRoom groupChatRoom = ConferenceUtils.enterRoomOnSameThread(workgroupName, room, password);
int tabLocation = SparkManager.getChatManager().getChatContainer().indexOfComponent(groupChatRoom);
groupChatRoom.setTabIcon(FastpathRes.getImageIcon(FastpathRes.FASTPATH_IMAGE_16x16));
if (tabLocation != -1) {
SparkTab tab = SparkManager.getChatManager().getChatContainer().getTabAt(tabLocation);
tab.setIcon(FastpathRes.getImageIcon(FastpathRes.FASTPATH_IMAGE_16x16));
}
return true;
}
return false;
}
}
}