diff options
author | Kevin Smith <git@kismith.co.uk> | 2010-05-08 12:14:01 (GMT) |
---|---|---|
committer | Kevin Smith <git@kismith.co.uk> | 2010-05-13 12:29:20 (GMT) |
commit | 705bd7256fa4812045677743fc1e939ccfd66d05 (patch) | |
tree | 84502c2c6bd6bda1bc38e7fce59cc451e05b21c4 /Swift/Controllers | |
parent | 61078c4e4fd553bf952bae5c9d44da6cb96a3a70 (diff) | |
download | swift-contrib-705bd7256fa4812045677743fc1e939ccfd66d05.zip swift-contrib-705bd7256fa4812045677743fc1e939ccfd66d05.tar.bz2 |
List MUCs available on services.
Resolves: #276
Diffstat (limited to 'Swift/Controllers')
-rw-r--r-- | Swift/Controllers/Chat/MUCSearchController.cpp | 156 | ||||
-rw-r--r-- | Swift/Controllers/Chat/MUCSearchController.h | 108 | ||||
-rw-r--r-- | Swift/Controllers/MainController.cpp | 16 | ||||
-rw-r--r-- | Swift/Controllers/MainController.h | 6 | ||||
-rw-r--r-- | Swift/Controllers/SConscript | 3 | ||||
-rw-r--r-- | Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h | 15 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/MUCSearchWindow.h | 31 | ||||
-rw-r--r-- | Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h | 19 |
8 files changed, 347 insertions, 7 deletions
diff --git a/Swift/Controllers/Chat/MUCSearchController.cpp b/Swift/Controllers/Chat/MUCSearchController.cpp new file mode 100644 index 0000000..93d2087 --- /dev/null +++ b/Swift/Controllers/Chat/MUCSearchController.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swift/Controllers/Chat/MUCSearchController.h" + +#include <iostream> + +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> + +#include "Swiften/Queries/Requests/GetDiscoInfoRequest.h" +#include "Swiften/Queries/Requests/GetDiscoItemsRequest.h" + +#include "Swift/Controllers/UIEvents/UIEventStream.h" +#include "Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h" +#include "Swift/Controllers/UIInterfaces/MUCSearchWindow.h" +#include "Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h" + +namespace Swift { + +MUCSearchController::MUCSearchController(const JID& jid, UIEventStream* uiEventStream, MUCSearchWindowFactory* factory, IQRouter* iqRouter) : jid_(jid) { + iqRouter_ = iqRouter; + uiEventStream_ = uiEventStream; + uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&MUCSearchController::handleUIEvent, this, _1)); + window_ = NULL; + factory_ = factory; +} + +MUCSearchController::~MUCSearchController() { + delete window_; +} + +void MUCSearchController::handleUIEvent(boost::shared_ptr<UIEvent> event) { + boost::shared_ptr<RequestMUCSearchUIEvent> searchEvent = boost::dynamic_pointer_cast<RequestMUCSearchUIEvent>(event); + if (searchEvent) { + if (!window_) { + window_ = factory_->createMUCSearchWindow(uiEventStream_); + window_->onAddService.connect(boost::bind(&MUCSearchController::handleAddService, this, _1, true)); + handleAddService(JID(jid_.getDomain()), true); + } + window_->setMUC(""); + window_->setNick(jid_.getNode()); + window_->show(); + return; + } +} + +void MUCSearchController::handleAddService(const JID& jid, bool userTriggered) { + if (std::find(services_.begin(), services_.end(), jid) != services_.end()) { + if (!userTriggered) { + /* No infinite recursion. (Some buggy servers do infinitely deep disco of themselves)*/ + return; + } + } else if (userTriggered) { + services_.push_back(jid); + serviceDetails_[jid].setComplete(false); + refreshView(); + } + if (!jid.isValid()) { + //Set Window to say error this isn't valid + return; + } + boost::shared_ptr<GetDiscoInfoRequest> discoInfoRequest(new GetDiscoInfoRequest(jid, iqRouter_)); + discoInfoRequest->onResponse.connect(boost::bind(&MUCSearchController::handleDiscoInfoResponse, this, _1, _2, jid)); + discoInfoRequest->send(); +} + +void MUCSearchController::removeService(const JID& jid) { + serviceDetails_.erase(jid); + services_.erase(std::remove(services_.begin(), services_.end(), jid), services_.end()); + refreshView(); +} + +void MUCSearchController::handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, const boost::optional<ErrorPayload>& error, const JID& jid) { + if (error) { + handleDiscoError(jid, error.get()); + return; + } + boost::shared_ptr<GetDiscoItemsRequest> discoItemsRequest(new GetDiscoItemsRequest(jid, iqRouter_)); + bool mucService = false; + bool couldContainServices = false; + String name; + foreach (DiscoInfo::Identity identity, info->getIdentities()) { + if ((identity.getCategory() == "directory" + && identity.getType() == "chatroom") + || (identity.getCategory() == "conference" + && identity.getType() == "text")) { + mucService = true; + name = identity.getName(); + } + if (identity.getCategory() == "server") { + couldContainServices = true; + name = identity.getName(); + } + } + services_.erase(std::remove(services_.begin(), services_.end(), jid), services_.end()); /* Bring it back to the end on a refresh */ + services_.push_back(jid); + serviceDetails_[jid].setName(name); + serviceDetails_[jid].setJID(jid); + serviceDetails_[jid].setComplete(false); + + if (mucService) { + discoItemsRequest->onResponse.connect(boost::bind(&MUCSearchController::handleRoomsItemsResponse, this, _1, _2, jid)); + } else if (couldContainServices) { + discoItemsRequest->onResponse.connect(boost::bind(&MUCSearchController::handleServerItemsResponse, this, _1, _2, jid)); + } else { + removeService(jid); + return; + } + discoItemsRequest->send(); + refreshView(); +} + +void MUCSearchController::handleRoomsItemsResponse(boost::shared_ptr<DiscoItems> items, const boost::optional<ErrorPayload>& error, const JID& jid) { + if (error) { + handleDiscoError(jid, error.get()); + return; + } + serviceDetails_[jid].clearRooms(); + foreach (DiscoItems::Item item, items->getItems()) { + serviceDetails_[jid].addRoom(MUCService::MUCRoom(item.getJID().getNode(), item.getName(), -1)); + } + serviceDetails_[jid].setComplete(true); + refreshView(); +} + +void MUCSearchController::handleServerItemsResponse(boost::shared_ptr<DiscoItems> items, const boost::optional<ErrorPayload>& error, const JID& jid) { + if (error) { + handleDiscoError(jid, error.get()); + return; + } + if (jid.isValid()) { + removeService(jid); + } + foreach (DiscoItems::Item item, items->getItems()) { + handleAddService(item.getJID()); + } + refreshView(); +} + +void MUCSearchController::handleDiscoError(const JID& jid, const ErrorPayload& error) { + serviceDetails_[jid].setComplete(true); + serviceDetails_[jid].setError(error.getText()); +} + +void MUCSearchController::refreshView() { + window_->clearList(); + foreach (JID jid, services_) { + window_->addService(serviceDetails_[jid]); + } +} + +} diff --git a/Swift/Controllers/Chat/MUCSearchController.h b/Swift/Controllers/Chat/MUCSearchController.h new file mode 100644 index 0000000..6eba2a5 --- /dev/null +++ b/Swift/Controllers/Chat/MUCSearchController.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> +#include <map> + +#include <boost/shared_ptr.hpp> +#include <boost/signals.hpp> + +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" + +#include "Swift/Controllers/UIEvents/UIEvent.h" +#include "Swift/Controllers/Chat/MUCSearchController.h" +#include "Swiften/Elements/DiscoInfo.h" +#include "Swiften/Elements/DiscoItems.h" +#include "Swiften/Elements/ErrorPayload.h" + +namespace Swift { + class UIEventStream; + class MUCSearchWindow; + class MUCSearchWindowFactory; + class IQRouter; + + class MUCService { + public: + class MUCRoom { + public: + MUCRoom(const String& node, const String& name, int occupants) : node_(node), name_(name), occupants_(occupants) {} + String getNode() {return node_;} + String getName() {return name_;} + int getOccupantCount() {return occupants_;} + private: + String node_; + String name_; + int occupants_; + }; + + MUCService() {error_ = false; complete_ = false;} + + void setComplete(bool complete) { + complete_ = complete; + } + + void setName(const String& name) { + name_ = name; + } + + void setJID(const JID& jid) { + jid_ = jid; + } + + bool getComplete() const { + return complete_; + } + + JID getJID() const { + return jid_; + } + + String getName() const { + return name_; + } + + void setError(const String& errorText) {error_ = true; errorText_ = errorText;} + + void clearRooms() {rooms_.clear();} + + void addRoom(const MUCRoom& room) {rooms_.push_back(room);} + + std::vector<MUCRoom> getRooms() const {return rooms_;} + private: + String name_; + JID jid_; + std::vector<MUCRoom> rooms_; + bool complete_; + bool error_; + String errorText_; + }; + + class MUCSearchController { + public: + MUCSearchController(const JID& jid, UIEventStream* uiEventStream, MUCSearchWindowFactory* mucSearchWindowFactory, IQRouter* iqRouter); + ~MUCSearchController(); + private: + void handleUIEvent(boost::shared_ptr<UIEvent> event); + void handleAddService(const JID& jid, bool userTriggered=false); + void handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, const boost::optional<ErrorPayload>& error, const JID& jid); + void handleRoomsItemsResponse(boost::shared_ptr<DiscoItems> items, const boost::optional<ErrorPayload>& error, const JID& jid); + void handleServerItemsResponse(boost::shared_ptr<DiscoItems> items, const boost::optional<ErrorPayload>& error, const JID& jid); + void handleDiscoError(const JID& jid, const ErrorPayload& error); + void removeService(const JID& jid); + void refreshView(); + UIEventStream* uiEventStream_; + MUCSearchWindow* window_; + MUCSearchWindowFactory* factory_; + boost::bsignals::scoped_connection uiEventConnection_; + std::vector<JID> services_; + std::map<JID, MUCService> serviceDetails_; + IQRouter* iqRouter_; + JID jid_; + }; +} diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index e6dfe47..5be8e46 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -14,15 +14,16 @@ #include "Swiften/Application/Application.h" #include "Swiften/Application/ApplicationMessageDisplay.h" #include "Swift/Controllers/Chat/ChatController.h" -#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" +#include "Swift/Controllers/Chat/MUCSearchController.h" +//#include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" #include "Swift/Controllers/Chat/ChatsManager.h" #include "Swift/Controllers/EventController.h" #include "Swift/Controllers/EventWindowController.h" #include "Swift/Controllers/UIInterfaces/LoginWindow.h" #include "Swift/Controllers/UIInterfaces/LoginWindowFactory.h" -#include "Swift/Controllers/UIInterfaces/EventWindowFactory.h" +//#include "Swift/Controllers/UIInterfaces/EventWindowFactory.h" #include "Swift/Controllers/UIInterfaces/MainWindow.h" -#include "Swift/Controllers/UIInterfaces/MainWindowFactory.h" +//#include "Swift/Controllers/UIInterfaces/MainWindowFactory.h" #include "Swift/Controllers/Chat/MUCController.h" #include "Swift/Controllers/NickResolver.h" #include "Swift/Controllers/ProfileSettingsProvider.h" @@ -33,7 +34,7 @@ #include "Swift/Controllers/SystemTrayController.h" #include "Swift/Controllers/XMLConsoleController.h" #include "Swift/Controllers/XMPPRosterController.h" -#include "Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h" +//#include "Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h" #include "Swift/Controllers/UIEvents/UIEventStream.h" #include "Swiften/Base/foreach.h" #include "Swiften/Base/String.h" @@ -60,7 +61,7 @@ static const String CLIENT_VERSION = "0.3"; static const String CLIENT_NODE = "http://swift.im"; -MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency) +MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory, MUCSearchWindowFactory* mucSearchWindowFactory, bool useDelayForLatency) : timerFactory_(&boostIOServiceThread_.getIOService()), idleDetector_(&idleQuerier_, &timerFactory_, 100), chatWindowFactory_(chatWindowFactory), mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), settings_(settings), loginWindow_(NULL), useDelayForLatency_(useDelayForLatency) { application_ = application; presenceOracle_ = NULL; @@ -77,6 +78,7 @@ MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowF presenceSender_ = NULL; client_ = NULL; + mucSearchWindowFactory_ = mucSearchWindowFactory; eventWindowFactory_ = eventWindowFactory; chatListWindowFactory_ = chatListWindowFactory; uiEventStream_ = new UIEventStream(); @@ -155,6 +157,8 @@ void MainController::resetClient() { presenceSender_ = NULL; delete client_; client_ = NULL; + delete mucSearchController_; + mucSearchController_ = NULL; } @@ -203,6 +207,8 @@ void MainController::handleConnected() { discoResponder_->setDiscoInfo(discoInfo); discoResponder_->setDiscoInfo(capsInfo_->getNode() + "#" + capsInfo_->getVersion(), discoInfo); serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo()); + + mucSearchController_ = new MUCSearchController(jid_, uiEventStream_, mucSearchWindowFactory_, client_); } boost::shared_ptr<GetDiscoInfoRequest> discoInfoRequest(new GetDiscoInfoRequest(JID(), client_)); diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 5d3f998..63e77f2 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -58,10 +58,12 @@ namespace Swift { class XMLConsoleWidgetFactory; class EventWindowFactory; class EventWindowController; + class MUCSearchController; + class MUCSearchWindowFactory; class MainController { public: - MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory_, bool useDelayForLatency); + MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory_, MUCSearchWindowFactory* mucSearchWindowFactory, bool useDelayForLatency); ~MainController(); @@ -126,5 +128,7 @@ namespace Swift { ChatListWindowFactory* chatListWindowFactory_; boost::shared_ptr<ErrorEvent> lastDisconnectError_; bool useDelayForLatency_; + MUCSearchController* mucSearchController_; + MUCSearchWindowFactory* mucSearchWindowFactory_; }; } diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript index a7ddc79..eb63bed 100644 --- a/Swift/Controllers/SConscript +++ b/Swift/Controllers/SConscript @@ -21,11 +21,12 @@ if env["SCONS_STAGE"] == "build" : "Chat/ChatController.cpp", "Chat/ChatControllerBase.cpp", "Chat/ChatsManager.cpp", + "Chat/MUCController.cpp", + "Chat/MUCSearchController.cpp", "MainController.cpp", "NickResolver.cpp", "RosterController.cpp", "XMPPRosterController.cpp", - "Chat/MUCController.cpp", "EventController.cpp", "EventWindowController.cpp", "SoundEventController.cpp", diff --git a/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h b/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h new file mode 100644 index 0000000..623cd00 --- /dev/null +++ b/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swift/Controllers/UIEvents/UIEvent.h" + +namespace Swift { + class RequestMUCSearchUIEvent : public UIEvent { + + }; +} diff --git a/Swift/Controllers/UIInterfaces/MUCSearchWindow.h b/Swift/Controllers/UIInterfaces/MUCSearchWindow.h new file mode 100644 index 0000000..3114a5a --- /dev/null +++ b/Swift/Controllers/UIInterfaces/MUCSearchWindow.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/signals.hpp> + +#include "Swiften/Base/String.h" +#include "Swiften/JID/JID.h" + +#include "Swift/Controllers/Chat/MUCSearchController.h" + +namespace Swift { + + class MUCSearchWindow { + public: + virtual ~MUCSearchWindow() {}; + + virtual void setNick(const String& nick) = 0; + virtual void setMUC(const String& nick) = 0; + virtual void clearList() = 0; + virtual void addService(const MUCService& service) = 0; + + virtual void show() = 0; + + boost::signal<void (const JID&)> onAddService; + }; +} diff --git a/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h b/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h new file mode 100644 index 0000000..1f0bf90 --- /dev/null +++ b/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swift/Controllers/UIInterfaces/MUCSearchWindow.h" + +namespace Swift { + class UIEventStream; + class MUCSearchWindowFactory { + public: + virtual ~MUCSearchWindowFactory() {}; + + virtual MUCSearchWindow* createMUCSearchWindow(UIEventStream* eventStream) = 0; + }; +} |