/**
* $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.conferences;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.TimerTask;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import org.jivesoftware.resource.Res;
import org.jivesoftware.resource.SparkRes;
import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.ServiceDiscoveryManager;
import org.jivesoftware.smackx.bookmark.BookmarkManager;
import org.jivesoftware.smackx.bookmark.BookmarkedConference;
import org.jivesoftware.smackx.muc.InvitationListener;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.spark.ChatManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.spark.Workspace;
import org.jivesoftware.spark.plugin.ContextMenuListener;
import org.jivesoftware.spark.ui.ChatFrame;
import org.jivesoftware.spark.ui.ChatRoom;
import org.jivesoftware.spark.ui.ChatRoomButton;
import org.jivesoftware.spark.ui.ChatRoomClosingListener;
import org.jivesoftware.spark.ui.ChatRoomListener;
import org.jivesoftware.spark.ui.ChatRoomNotFoundException;
import org.jivesoftware.spark.ui.ContactGroup;
import org.jivesoftware.spark.ui.ContactItem;
import org.jivesoftware.spark.ui.ContactList;
import org.jivesoftware.spark.ui.PresenceListener;
import org.jivesoftware.spark.ui.rooms.ChatRoomImpl;
import org.jivesoftware.spark.ui.rooms.GroupChatRoom;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.SwingWorker;
import org.jivesoftware.spark.util.TaskEngine;
import org.jivesoftware.spark.util.UIComponentRegistry;
import org.jivesoftware.spark.util.log.Log;
import org.jivesoftware.sparkimpl.plugin.alerts.SparkToaster;
import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
/**
* Conference plugin is reponsible for the initial loading of MultiUser Chat support. To disable plugin,
* you can remove from the plugins.xml file located in the classpath of Communicator.
*/
public class ConferenceServices implements InvitationListener {
private static BookmarksUI bookmarksUI = new BookmarksUI(); //This variable shouldn't be null.
private static LocalPreferences _localPreferences = SettingsManager.getLocalPreferences();
public ConferenceServices() {
ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(SparkManager.getConnection());
boolean mucSupported = manager.includesFeature("http://jabber.org/protocol/muc");
if (mucSupported) {
// Add an invitation listener.
addInvitationListener();
addChatRoomListener();
addPopupListeners();
// Add Join Conference Button to ActionMenu
final JMenu actionsMenu = SparkManager.getMainWindow().getMenuByName(Res.getString("menuitem.actions"));
JMenuItem actionMenuItem = new JMenuItem(Res.getString("message.join.conference.room"), SparkRes.getImageIcon(SparkRes.CONFERENCE_IMAGE_16x16));
actionsMenu.add(actionMenuItem,1);
actionMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ConferenceRoomBrowser rooms = new ConferenceRoomBrowser(bookmarksUI, getDefaultServiceName());
rooms.invoke();
}
});
// Add Presence Listener to send directed presence to Group Chat Rooms.
PresenceListener presenceListener = new PresenceListener() {
public void presenceChanged(final Presence presence) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
for (ChatRoom room : SparkManager.getChatManager().getChatContainer().getChatRooms()) {
if (room instanceof GroupChatRoom) {
final Presence p = new Presence(presence.getType(), presence.getStatus(), presence.getPriority(), presence.getMode());
GroupChatRoom groupChatRoom = (GroupChatRoom)room;
String jid = groupChatRoom.getMultiUserChat().getRoom();
p.setTo(jid);
SparkManager.getConnection().sendPacket(p);
}
}
}
});
}
};
SparkManager.getSessionManager().addPresenceListener(presenceListener);
}
}
/**
* Adds an invitation listener to check for any MUC invites.
*/
private void addInvitationListener() {
MultiUserChat.addInvitationListener(SparkManager.getConnection(),this);
}
/**
* Persists bookmarked data, if any.
*/
public void shutdown() {
}
/**
* Load all bookmarked data.
*/
public void loadConferenceBookmarks() {
final TimerTask bookmarkLoader = new TimerTask(){
@Override
public void run() {
Collection<BookmarkedConference> bc = null;
while (bc == null) {
try {
BookmarkManager manager = BookmarkManager
.getBookmarkManager(SparkManager.getConnection());
bc = manager.getBookmarkedConferences();
} catch (XMPPException error) {
Log.error(error);
}
}
bookmarksUI.loadUI();
addBookmarksUI();
}
};
TaskEngine.getInstance().schedule(bookmarkLoader, 500);
}
protected void addBookmarksUI() {
final Workspace workspace = SparkManager.getWorkspace();
final boolean useTab = _localPreferences.isShowConferenceTab();
if (useTab) {
workspace.getWorkspacePane().addTab(Res.getString("tab.conferences"),
SparkRes.getImageIcon(SparkRes.CONFERENCE_IMAGE_16x16), bookmarksUI);
}
}
private void addChatRoomListener() {
ChatManager chatManager = SparkManager.getChatManager();
chatManager.addChatRoomListener(new ChatRoomListener() {
public void chatRoomOpened(final ChatRoom room) {
if (room instanceof ChatRoomImpl) {
final ChatRoomDecorator decorator = new ChatRoomDecorator(room);
decorator.decorate();
}
}
public void chatRoomLeft(ChatRoom room) {
}
public void chatRoomClosed(ChatRoom room) {
}
public void chatRoomActivated(ChatRoom room) {
}
public void userHasJoined(ChatRoom room, String userid) {
}
public void userHasLeft(ChatRoom room, String userid) {
}
});
}
public boolean canShutDown() {
return true;
}
public static String getDefaultServiceName() {
String serviceName = null;
Collection<String> services = bookmarksUI.getMucServices();
if (services != null) {
for (Object service : services) {
serviceName = (String) service;
break;
}
}
return serviceName;
}
private void addPopupListeners() {
final ContactList contactList = SparkManager.getWorkspace().getContactList();
// Add ContactList items.
final Action inviteAllAction = new AbstractAction() {
private static final long serialVersionUID = -7486282521151183678L;
public void actionPerformed(ActionEvent actionEvent) {
Collection<ContactItem> contacts = contactList.getActiveGroup().getContactItems();
startConference(contacts);
}
};
inviteAllAction.putValue(Action.NAME, Res.getString("menuitem.invite.group.to.conference"));
inviteAllAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.CONFERENCE_IMAGE_16x16));
final Action conferenceAction = new AbstractAction() {
private static final long serialVersionUID = 4724119680969496581L;
public void actionPerformed(ActionEvent actionEvent) {
Collection<ContactItem> contacts = contactList.getSelectedUsers();
startConference(contacts);
}
};
conferenceAction.putValue(Action.NAME, Res.getString("menuitem.start.a.conference"));
conferenceAction.putValue(Action.SMALL_ICON, SparkRes.getImageIcon(SparkRes.SMALL_WORKGROUP_QUEUE_IMAGE));
contactList.addContextMenuListener(new ContextMenuListener() {
public void poppingUp(Object component, JPopupMenu popup) {
Collection<ContactItem> col = contactList.getSelectedUsers();
if (component instanceof ContactGroup) {
popup.add(inviteAllAction);
}
else if (component instanceof Collection<?> && col.size() > 0) {
popup.add(conferenceAction);
}
}
public void poppingDown(JPopupMenu popup) {
}
public boolean handleDefaultAction(MouseEvent e) {
return false;
}
});
// Add to Actions Menu
final JMenu actionsMenu = SparkManager.getMainWindow().getMenuByName(Res.getString("menuitem.actions"));
actionsMenu.add(conferenceAction);
}
private void startConference(Collection<ContactItem> items) {
final ContactList contactList = SparkManager.getWorkspace().getContactList();
List<String> jids = new ArrayList<String>();
for (ContactItem item : items) {
ContactGroup contactGroup = contactList.getContactGroup(item.getGroupName());
contactGroup.clearSelection();
if (item.isAvailable()) {
jids.add(item.getJID());
}
}
String userName = StringUtils.parseName(SparkManager.getSessionManager().getJID());
final String roomName = userName + "_" + StringUtils.randomString(3);
String serviceName = getDefaultServiceName();
if (ModelUtil.hasLength(serviceName)) {
ConferenceUtils.inviteUsersToRoom(serviceName, roomName, jids, true);
}
}
protected BookmarkedConference getDefaultBookmark() {
BookmarkedConference bookmarkedConference = null;
try {
Collection<BookmarkedConference> bookmarkedConfs = ConferenceUtils.retrieveBookmarkedConferences();
String implicitBookmarkedJID = SettingsManager.getLocalPreferences().getDefaultBookmarkedConf();
if (bookmarkedConfs != null && !bookmarkedConfs.isEmpty()) {
// check if the "default" bookmarked conference is still in the bookmarks list:
if (implicitBookmarkedJID != null && implicitBookmarkedJID.trim().length() > 0) {
for (BookmarkedConference bc : bookmarkedConfs) {
if (implicitBookmarkedJID.equalsIgnoreCase(bc.getJid())) {
bookmarkedConference = bc;
break;
}
}
}
// if no match was found, or no "default" bookmark could be retrieved-use the
// first bookmark:
if (bookmarkedConference == null) {
bookmarkedConference = bookmarkedConfs.iterator().next();
}
}
return bookmarkedConference;
} catch (XMPPException ex) {
Log.warning("No default bookmark");
// no bookmark can be retrieved;
}
return null;
}
/**
* Returns the UI for the addition and removal of Conference bookmarks.
*
* @return the BookedMarkedConferences UI.
*/
public static BookmarksUI getBookmarkedConferences() {
return bookmarksUI;
}
private class ChatRoomDecorator implements ActionListener, ChatRoomClosingListener {
private ChatRoom chatRoom;
private ChatRoomButton inviteButton;
public ChatRoomDecorator(ChatRoom room) {
this.chatRoom = room;
chatRoom.addClosingListener(this);
}
public void decorate() {
// Add Conference Invite Button.
inviteButton = UIComponentRegistry.getButtonFactory().createInviteConferenceButton();
inviteButton.setToolTipText(Res.getString("title.invite.to.conference"));
chatRoom.addChatRoomButton(inviteButton);
inviteButton.addActionListener(this);
}
public void closing() {
inviteButton.removeActionListener(this);
chatRoom.removeClosingListener(this);
}
public void actionPerformed(ActionEvent e) {
String userName = StringUtils.parseName(SparkManager.getSessionManager().getJID());
final String roomName = userName + "_" + StringUtils.randomString(3);
final List<String> jids = new ArrayList<String>();
jids.add(((ChatRoomImpl)chatRoom).getParticipantJID());
final String serviceName = getDefaultServiceName();
if (serviceName != null) {
SwingWorker worker = new SwingWorker() {
public Object construct() {
try {
Thread.sleep(25);
}
catch (InterruptedException e1) {
Log.error(e1);
}
return "ok";
}
public void finished() {
try {
BookmarkedConference selectedBookmarkedConf = _localPreferences.isUseAdHocRoom() ? null : getDefaultBookmark();
if (selectedBookmarkedConf == null) {
ConferenceUtils.createPrivateConference(serviceName,
Res.getString("message.please.join.in.conference"), roomName, jids);
} else {
ConferenceUtils.joinConferenceOnSeperateThread(selectedBookmarkedConf.getName(),
selectedBookmarkedConf.getJid(), selectedBookmarkedConf.getPassword(),
Res.getString("message.please.join.in.conference"), jids);
}
}
catch (XMPPException e1) {
JOptionPane.showMessageDialog(chatRoom, ConferenceUtils.getReason(e1), Res.getString("title.error"), JOptionPane.ERROR_MESSAGE);
}
}
};
worker.start();
}
}
}
@Override
public void invitationReceived(final Connection conn, final String room, final String inviter, final String reason,
final String password, final Message message) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Collection<RoomInvitationListener> listeners = new ArrayList<RoomInvitationListener>(SparkManager
.getChatManager().getInvitationListeners());
for (RoomInvitationListener listener : listeners) {
boolean handle = listener.handleInvitation(conn, room, inviter, reason, password, message);
if (handle) {
return;
}
}
// Make sure the user is not already in the
// room.
try {
SparkManager.getChatManager().getChatContainer().getChatRoom(room);
return;
} catch (ChatRoomNotFoundException e) {
// Ignore :)
}
final GroupChatInvitationUI invitationUI = new GroupChatInvitationUI(room, inviter, password, reason);
String message = Res.getString("message.invite.to.groupchat", inviter);
String title = Res.getString("title.group.chat");
String bareJID = StringUtils.parseBareAddress(inviter);
if (_localPreferences.isAutoAcceptMucInvite()) {
ConferenceUtils.enterRoomOnSameThread(StringUtils.parseName(room), room, password);
GroupChatRoom chat = UIComponentRegistry.createGroupChatRoom(new MultiUserChat(SparkManager.getConnection(), room));
showToaster(message, title, chat);
return;
// Nothing to do here, we want to join the
// room, and stuff
}
try {
ChatRoom chatRoom = SparkManager.getChatManager().getChatContainer().getChatRoom(bareJID);
// If the ChatRoom exists, add an invitationUI.
chatRoom.getTranscriptWindow().addComponent(invitationUI);
// Notify user of incoming invitation.
chatRoom.increaseUnreadMessageCount();
chatRoom.scrollToBottom();
SparkManager.getChatManager().getChatContainer()
.fireNotifyOnMessage(chatRoom, true, message, title);
} catch (ChatRoomNotFoundException e) {
// If it doesn't exists. Create a new Group
// Chat Room
// Create the Group Chat Room
final MultiUserChat chat = new MultiUserChat(SparkManager.getConnection(), room);
GroupChatRoom groupChatRoom = UIComponentRegistry.createGroupChatRoom(chat);
showToaster(message, title, groupChatRoom);
groupChatRoom.getSplitPane().setDividerSize(5);
groupChatRoom.getVerticalSlipPane().setDividerLocation(0.6);
groupChatRoom.getSplitPane().setDividerLocation(0.6);
String roomName = StringUtils.parseName(room);
groupChatRoom.setTabTitle(roomName);
groupChatRoom.getToolBar().setVisible(true);
SparkManager.getChatManager().getChatContainer().addChatRoom(groupChatRoom);
groupChatRoom.getTranscriptWindow().addComponent(invitationUI);
// Notify user of incoming invitation.
groupChatRoom.increaseUnreadMessageCount();
groupChatRoom.scrollToBottom();
SparkManager.getChatManager().getChatContainer().fireNotifyOnMessage(groupChatRoom, true, message,
title);
}
// If no listeners handled the invitation,
// default to generic invite.
// new ConversationInvitation(conn, room,
// inviter, reason, password, message);
}
});
}
private void showToaster(String message, String title, GroupChatRoom groupChatRoom) {
if (_localPreferences.getShowToasterPopup()) {
SparkToaster toaster = new SparkToaster();
toaster.setCustomAction(new AbstractAction() {
private static final long serialVersionUID = -4546475740161533555L;
@Override
public void actionPerformed(ActionEvent e) {
ChatFrame chatFrame = SparkManager.getChatManager().getChatContainer().getChatFrame();
chatFrame.setState(Frame.NORMAL);
chatFrame.setVisible(true);
}
});
toaster.setDisplayTime(5000);
toaster.setBorder(BorderFactory.createBevelBorder(0));
toaster.setToasterHeight(150);
toaster.setToasterWidth(200);
toaster.setTitle(title);
toaster.showToaster(groupChatRoom.getTabIcon(), message);
}
}
}