summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/Controllers/Chat/ChatsManager.cpp')
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp298
1 files changed, 261 insertions, 37 deletions
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 94d4b9a..47a65a8 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 Kevin Smith
+ * Copyright (c) 2010-2011 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
@@ -7,31 +7,40 @@
#include "Swift/Controllers/Chat/ChatsManager.h"
#include <boost/bind.hpp>
-
-#include "Swift/Controllers/Chat/ChatController.h"
-#include "Swift/Controllers/Chat/MUCSearchController.h"
-#include "Swift/Controllers/XMPPEvents/EventController.h"
-#include "Swift/Controllers/Chat/MUCController.h"
-#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h"
-#include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h"
-#include "Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h"
-#include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h"
-#include "Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h"
-#include "Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h"
-#include "Swift/Controllers/UIInterfaces/ChatListWindowFactory.h"
-#include "Swift/Controllers/UIInterfaces/JoinMUCWindow.h"
-#include "Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h"
-#include "Swiften/Presence/PresenceSender.h"
-#include "Swiften/Client/NickResolver.h"
-#include "Swiften/MUC/MUCManager.h"
-#include "Swiften/Elements/ChatState.h"
-#include "Swiften/MUC/MUCBookmarkManager.h"
+#include <boost/algorithm/string.hpp>
+
+#include <Swiften/Base/foreach.h>
+#include <Swift/Controllers/Chat/ChatController.h>
+#include <Swift/Controllers/Chat/ChatControllerBase.h>
+#include <Swift/Controllers/Chat/MUCSearchController.h>
+#include <Swift/Controllers/XMPPEvents/EventController.h>
+#include <Swift/Controllers/Chat/MUCController.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h>
+#include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h>
+#include <Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h>
+#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h>
+#include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h>
+#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h>
+#include <Swiften/Presence/PresenceSender.h>
+#include <Swiften/Client/NickResolver.h>
+#include <Swiften/MUC/MUCManager.h>
+#include <Swiften/Elements/ChatState.h>
+#include <Swiften/MUC/MUCBookmarkManager.h>
+#include <Swift/Controllers/FileTransfer/FileTransferController.h>
+#include <Swift/Controllers/FileTransfer/FileTransferOverview.h>
+#include <Swift/Controllers/ProfileSettingsProvider.h>
+#include <Swiften/Avatars/AvatarManager.h>
namespace Swift {
typedef std::pair<JID, ChatController*> JIDChatControllerPair;
typedef std::pair<JID, MUCController*> JIDMUCControllerPair;
+#define RECENT_CHATS "recent_chats"
+
ChatsManager::ChatsManager(
JID jid, StanzaChannel* stanzaChannel,
IQRouter* iqRouter,
@@ -49,13 +58,15 @@ ChatsManager::ChatsManager(
EntityCapsProvider* entityCapsProvider,
MUCManager* mucManager,
MUCSearchWindowFactory* mucSearchWindowFactory,
- SettingsProvider* settings) :
+ ProfileSettingsProvider* settings,
+ FileTransferOverview* ftOverview) :
jid_(jid),
joinMUCWindowFactory_(joinMUCWindowFactory),
useDelayForLatency_(useDelayForLatency),
mucRegistry_(mucRegistry),
entityCapsProvider_(entityCapsProvider),
- mucManager(mucManager) {
+ mucManager(mucManager),
+ ftOverview_(ftOverview) {
timerFactory_ = timerFactory;
eventController_ = eventController;
stanzaChannel_ = stanzaChannel;
@@ -68,13 +79,21 @@ ChatsManager::ChatsManager(
presenceSender_ = presenceSender;
uiEventStream_ = uiEventStream;
mucBookmarkManager_ = NULL;
+ profileSettings_ = settings;
presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1));
uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1));
+
chatListWindow_ = chatListWindowFactory->createChatListWindow(uiEventStream_);
+ chatListWindow_->onMUCBookmarkActivated.connect(boost::bind(&ChatsManager::handleMUCBookmarkActivated, this, _1));
+ chatListWindow_->onRecentActivated.connect(boost::bind(&ChatsManager::handleRecentActivated, this, _1));
+ chatListWindow_->onClearRecentsRequested.connect(boost::bind(&ChatsManager::handleClearRecentsRequested, this));
+
joinMUCWindow_ = NULL;
mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, settings);
mucSearchController_->onMUCSelected.connect(boost::bind(&ChatsManager::handleMUCSelectedAfterSearch, this, _1));
+ ftOverview_->onNewFileTransferController.connect(boost::bind(&ChatsManager::handleNewFileTransferController, this, _1));
setupBookmarks();
+ loadRecents();
}
ChatsManager::~ChatsManager() {
@@ -89,6 +108,72 @@ ChatsManager::~ChatsManager() {
delete mucSearchController_;
}
+void ChatsManager::saveRecents() {
+ std::string recents;
+ int i = 1;
+ foreach (ChatListWindow::Chat chat, recentChats_) {
+ std::vector<std::string> activity;
+ boost::split(activity, chat.activity, boost::is_any_of("\t\n"));
+ if (activity.empty()) {
+ /* Work around Boost bug https://svn.boost.org/trac/boost/ticket/4751 */
+ activity.push_back("");
+ }
+ std::string recent = chat.jid.toString() + "\t" + activity[0] + "\t" + (chat.isMUC ? "true" : "false") + "\t" + chat.nick;
+ recents += recent + "\n";
+ if (i++ > 25) {
+ break;
+ }
+ }
+ profileSettings_->storeString(RECENT_CHATS, recents);
+}
+
+void ChatsManager::handleClearRecentsRequested() {
+ recentChats_.clear();
+ saveRecents();
+ handleUnreadCountChanged(NULL);
+}
+
+void ChatsManager::loadRecents() {
+ std::string recentsString(profileSettings_->getStringSetting(RECENT_CHATS));
+ std::vector<std::string> recents;
+ boost::split(recents, recentsString, boost::is_any_of("\n"));
+ int i = 0;
+ foreach (std::string recentString, recents) {
+ if (i++ > 30) {
+ break;
+ }
+ std::vector<std::string> recent;
+ boost::split(recent, recentString, boost::is_any_of("\t"));
+ if (recent.size() < 4) {
+ continue;
+ }
+ JID jid(recent[0]);
+ if (!jid.isValid()) {
+ continue;
+ }
+ std::string activity(recent[1]);
+ bool isMUC = recent[2] == "true";
+ std::string nick(recent[3]);
+ StatusShow::Type type = StatusShow::None;
+ boost::filesystem::path path;
+ if (isMUC) {
+ if (mucControllers_.find(jid.toBare()) != mucControllers_.end()) {
+ type = StatusShow::Online;
+ }
+ } else {
+ if (avatarManager_) {
+ path = avatarManager_->getAvatarPath(jid);
+ }
+ Presence::ref presence = presenceOracle_->getHighestPriorityPresence(jid.toBare());
+ type = presence ? presence->getShow() : StatusShow::None;
+ }
+
+ ChatListWindow::Chat chat(jid, nickResolver_->jidToNick(jid), activity, 0, type, path, isMUC, nick);
+ prependRecent(chat);
+ }
+ handleUnreadCountChanged(NULL);
+}
+
void ChatsManager::setupBookmarks() {
if (!mucBookmarkManager_) {
mucBookmarkManager_ = new MUCBookmarkManager(iqRouter_);
@@ -98,7 +183,7 @@ void ChatsManager::setupBookmarks() {
if (chatListWindow_) {
chatListWindow_->setBookmarksEnabled(false);
- chatListWindow_->clear();
+ chatListWindow_->clearBookmarks();
}
}
}
@@ -122,10 +207,90 @@ void ChatsManager::handleMUCBookmarkRemoved(const MUCBookmark& bookmark) {
chatListWindow_->removeMUCBookmark(bookmark);
}
+ChatListWindow::Chat ChatsManager::createChatListChatItem(const JID& jid, const std::string& activity) {
+ int unreadCount = 0;
+ if (mucRegistry_->isMUC(jid)) {
+ MUCController* controller = mucControllers_[jid.toBare()];
+ StatusShow::Type type = StatusShow::None;
+ std::string nick = "";
+ if (controller) {
+ unreadCount = controller->getUnreadCount();
+ if (controller->isJoined()) {
+ type = StatusShow::Online;
+ }
+ nick = controller->getNick();
+ }
+ return ChatListWindow::Chat(jid, jid.toString(), activity, unreadCount, type, boost::filesystem::path(), true, nick);
+
+ } else {
+ ChatController* controller = getChatControllerIfExists(jid, false);
+ if (controller) {
+ unreadCount = controller->getUnreadCount();
+ }
+ JID bareishJID = mucRegistry_->isMUC(jid.toBare()) ? jid : jid.toBare();
+ Presence::ref presence = presenceOracle_->getHighestPriorityPresence(bareishJID);
+ StatusShow::Type type = presence ? presence->getShow() : StatusShow::None;
+ boost::filesystem::path avatarPath = avatarManager_ ? avatarManager_->getAvatarPath(bareishJID) : boost::filesystem::path();
+ return ChatListWindow::Chat(bareishJID, nickResolver_->jidToNick(bareishJID), activity, unreadCount, type, avatarPath, false);
+ }
+}
+
+void ChatsManager::handleChatActivity(const JID& jid, const std::string& activity, bool isMUC) {
+ if (mucRegistry_->isMUC(jid.toBare()) && !isMUC) {
+ /* Don't include PMs in MUC rooms.*/
+ return;
+ }
+ ChatListWindow::Chat chat = createChatListChatItem(jid, activity);
+ /* FIXME: handle nick changes */
+ appendRecent(chat);
+ handleUnreadCountChanged(NULL);
+ saveRecents();
+}
+
+void ChatsManager::handleUnreadCountChanged(ChatControllerBase* controller) {
+ int unreadTotal = 0;
+ bool controllerIsMUC = dynamic_cast<MUCController*>(controller);
+ bool isPM = controller && !controllerIsMUC && mucRegistry_->isMUC(controller->getToJID().toBare());
+ foreach (ChatListWindow::Chat& chatItem, recentChats_) {
+ bool match = false;
+ if (controller) {
+ /* Matching MUC item */
+ match |= chatItem.isMUC == controllerIsMUC && chatItem.jid.toBare() == controller->getToJID().toBare();
+ /* Matching PM */
+ match |= isPM && chatItem.jid == controller->getToJID();
+ /* Matching non-PM */
+ match |= !isPM && !controllerIsMUC && chatItem.jid.toBare() == controller->getToJID().toBare();
+ }
+ if (match) {
+ chatItem.setUnreadCount(controller->getUnreadCount());
+ }
+ unreadTotal += chatItem.unreadCount;
+ }
+ chatListWindow_->setRecents(recentChats_);
+ chatListWindow_->setUnreadCount(unreadTotal);
+}
+
+void ChatsManager::appendRecent(const ChatListWindow::Chat& chat) {
+ recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end());
+ recentChats_.push_front(chat);
+}
+
+void ChatsManager::prependRecent(const ChatListWindow::Chat& chat) {
+ recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end());
+ recentChats_.push_back(chat);
+}
+
void ChatsManager::handleUserLeftMUC(MUCController* mucController) {
std::map<JID, MUCController*>::iterator it;
- for (it = mucControllers_.begin(); it != mucControllers_.end(); it++) {
+ for (it = mucControllers_.begin(); it != mucControllers_.end(); ++it) {
if ((*it).second == mucController) {
+ foreach (ChatListWindow::Chat& chat, recentChats_) {
+ if (chat.isMUC && chat.jid == (*it).first) {
+ chat.statusType = StatusShow::None;
+ chatListWindow_->setRecents(recentChats_);
+ break;
+ }
+ }
mucControllers_.erase(it);
delete mucController;
return;
@@ -155,15 +320,15 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
mucBookmarkManager_->replaceBookmark(editMUCBookmarkEvent->getOldBookmark(), editMUCBookmarkEvent->getNewBookmark());
}
else if (JoinMUCUIEvent::ref joinEvent = boost::dynamic_pointer_cast<JoinMUCUIEvent>(event)) {
- handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getNick(), false);
+ handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getNick(), joinEvent->getShouldJoinAutomatically());
+ mucControllers_[joinEvent->getJID()]->activateChatWindow();
}
- else if (boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) {
+ else if (boost::shared_ptr<RequestJoinMUCUIEvent> joinEvent = boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) {
if (!joinMUCWindow_) {
- joinMUCWindow_ = joinMUCWindowFactory_->createJoinMUCWindow();
- joinMUCWindow_->onJoinMUC.connect(boost::bind(&ChatsManager::handleJoinMUCRequest, this, _1, _2, _3));
+ joinMUCWindow_ = joinMUCWindowFactory_->createJoinMUCWindow(uiEventStream_);
joinMUCWindow_->onSearchMUC.connect(boost::bind(&ChatsManager::handleSearchMUCRequest, this));
}
- joinMUCWindow_->setMUC("");
+ joinMUCWindow_->setMUC(joinEvent->getRoom());
joinMUCWindow_->setNick(nickResolver_->jidToNick(jid_));
joinMUCWindow_->show();
}
@@ -174,6 +339,16 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) {
*/
void ChatsManager::handlePresenceChange(boost::shared_ptr<Presence> newPresence) {
if (mucRegistry_->isMUC(newPresence->getFrom().toBare())) return;
+
+ foreach (ChatListWindow::Chat& chat, recentChats_) {
+ if (newPresence->getFrom().toBare() == chat.jid.toBare() && !chat.isMUC) {
+ Presence::ref presence = presenceOracle_->getHighestPriorityPresence(chat.jid.toBare());
+ chat.setStatusType(presence ? presence->getShow() : StatusShow::None);
+ chatListWindow_->setRecents(recentChats_);
+ break;
+ }
+ }
+
//if (newPresence->getType() != Presence::Unavailable) return;
JID fullJID(newPresence->getFrom());
std::map<JID, ChatController*>::iterator it = chatControllers_.find(fullJID);
@@ -185,7 +360,25 @@ void ChatsManager::handlePresenceChange(boost::shared_ptr<Presence> newPresence)
}
void ChatsManager::setAvatarManager(AvatarManager* avatarManager) {
+ if (avatarManager_) {
+ avatarManager_->onAvatarChanged.disconnect(boost::bind(&ChatsManager::handleAvatarChanged, this, _1));
+ }
avatarManager_ = avatarManager;
+ foreach (ChatListWindow::Chat& chat, recentChats_) {
+ if (!chat.isMUC) {
+ chat.setAvatarPath(avatarManager_->getAvatarPath(chat.jid));
+ }
+ }
+ avatarManager_->onAvatarChanged.connect(boost::bind(&ChatsManager::handleAvatarChanged, this, _1));
+}
+
+void ChatsManager::handleAvatarChanged(const JID& jid) {
+ foreach (ChatListWindow::Chat& chat, recentChats_) {
+ if (!chat.isMUC && jid.toBare() == chat.jid.toBare()) {
+ chat.setAvatarPath(avatarManager_->getAvatarPath(jid));
+ break;
+ }
+ }
}
void ChatsManager::setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info) {
@@ -244,6 +437,8 @@ ChatController* ChatsManager::createNewChatController(const JID& contact) {
ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_);
chatControllers_[contact] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
+ controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false));
+ controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller));
return controller;
}
@@ -252,7 +447,7 @@ ChatController* ChatsManager::getChatControllerOrCreate(const JID &contact) {
return controller ? controller : createNewChatController(contact);
}
-ChatController* ChatsManager::getChatControllerIfExists(const JID &contact) {
+ChatController* ChatsManager::getChatControllerIfExists(const JID &contact, bool rebindIfNeeded) {
if (chatControllers_.find(contact) == chatControllers_.end()) {
if (mucRegistry_->isMUC(contact.toBare())) {
return NULL;
@@ -264,8 +459,13 @@ ChatController* ChatsManager::getChatControllerIfExists(const JID &contact) {
} else {
foreach (JIDChatControllerPair pair, chatControllers_) {
if (pair.first.toBare() == contact.toBare()) {
- rebindControllerJID(pair.first, contact);
- return chatControllers_[contact];
+ if (rebindIfNeeded) {
+ rebindControllerJID(pair.first, contact);
+ return chatControllers_[contact];
+ } else {
+ return pair.second;
+ }
+
}
}
return NULL;
@@ -280,8 +480,8 @@ void ChatsManager::rebindControllerJID(const JID& from, const JID& to) {
chatControllers_[to]->setToJID(to);
}
-void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<std::string>& nickMaybe, bool autoJoin) {
- if (autoJoin) {
+void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<std::string>& nickMaybe, bool addAutoJoin) {
+ if (addAutoJoin) {
MUCBookmark bookmark(mucJID, mucJID.getNode());
bookmark.setAutojoin(true);
if (nickMaybe) {
@@ -296,12 +496,17 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional
} else {
std::string nick = nickMaybe ? nickMaybe.get() : jid_.getNode();
MUC::ref muc = mucManager->createMUC(mucJID);
- MUCController* controller = new MUCController(jid_, muc, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_);
+ MUCController* controller = new MUCController(jid_, muc, nick, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_);
mucControllers_[mucJID] = controller;
controller->setAvailableServerFeatures(serverDiscoInfo_);
controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller));
+ controller->onUserJoined.connect(boost::bind(&ChatsManager::handleChatActivity, this, mucJID.toBare(), "", true));
+ controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, mucJID.toBare(), _1, true));
+ controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller));
+ handleChatActivity(mucJID.toBare(), "", true);
}
- mucControllers_[mucJID]->activateChatWindow();
+
+ mucControllers_[mucJID]->showChatWindow();
}
void ChatsManager::handleSearchMUCRequest() {
@@ -311,7 +516,7 @@ void ChatsManager::handleSearchMUCRequest() {
void ChatsManager::handleIncomingMessage(boost::shared_ptr<Message> message) {
JID jid = message->getFrom();
boost::shared_ptr<MessageEvent> event(new MessageEvent(message));
- if (!event->isReadable() && !message->getPayload<ChatState>() && message->getSubject().empty()) {
+ if (!event->isReadable() && !message->getPayload<ChatState>() && !message->hasSubject()) {
return;
}
@@ -338,5 +543,24 @@ void ChatsManager::handleMUCSelectedAfterSearch(const JID& muc) {
}
}
+void ChatsManager::handleMUCBookmarkActivated(const MUCBookmark& mucBookmark) {
+ uiEventStream_->send(boost::make_shared<JoinMUCUIEvent>(mucBookmark.getRoom(), mucBookmark.getNick()));
+}
+
+void ChatsManager::handleNewFileTransferController(FileTransferController* ftc) {
+ ChatController* chatController = getChatControllerOrCreate(ftc->getOtherParty());
+ chatController->handleNewFileTransferController(ftc);
+ chatController->activateChatWindow();
+}
+
+void ChatsManager::handleRecentActivated(const ChatListWindow::Chat& chat) {
+ if (chat.isMUC) {
+ uiEventStream_->send(boost::make_shared<JoinMUCUIEvent>(chat.jid, chat.nick));
+ }
+ else {
+ uiEventStream_->send(boost::make_shared<RequestChatUIEvent>(chat.jid));
+ }
+}
+
}