From 004dfd8d4305b767b624be10072597ef3e311753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be> Date: Sun, 16 Jan 2011 20:56:10 +0100 Subject: Use a dedicated Join MUC dialog. diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 722b98f..b7e8432 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -9,15 +9,20 @@ #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" @@ -27,7 +32,30 @@ namespace Swift { typedef std::pair<JID, ChatController*> JIDChatControllerPair; typedef std::pair<JID, MUCController*> JIDMUCControllerPair; -ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager) : jid_(jid), useDelayForLatency_(useDelayForLatency), mucRegistry_(mucRegistry), entityCapsProvider_(entityCapsProvider), mucManager(mucManager) { +ChatsManager::ChatsManager( + JID jid, StanzaChannel* stanzaChannel, + IQRouter* iqRouter, + EventController* eventController, + ChatWindowFactory* chatWindowFactory, + JoinMUCWindowFactory* joinMUCWindowFactory, + NickResolver* nickResolver, + PresenceOracle* presenceOracle, + PresenceSender* presenceSender, + UIEventStream* uiEventStream, + ChatListWindowFactory* chatListWindowFactory, + bool useDelayForLatency, + TimerFactory* timerFactory, + MUCRegistry* mucRegistry, + EntityCapsProvider* entityCapsProvider, + MUCManager* mucManager, + MUCSearchWindowFactory* mucSearchWindowFactory, + SettingsProvider* settings) : + jid_(jid), + joinMUCWindowFactory_(joinMUCWindowFactory), + useDelayForLatency_(useDelayForLatency), + mucRegistry_(mucRegistry), + entityCapsProvider_(entityCapsProvider), + mucManager(mucManager) { timerFactory_ = timerFactory; eventController_ = eventController; stanzaChannel_ = stanzaChannel; @@ -43,10 +71,14 @@ ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRo presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1)); uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1)); chatListWindow_ = chatListWindowFactory->createChatListWindow(uiEventStream_); + joinMUCWindow_ = NULL; + mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, settings); + mucSearchController_->onMUCSelected.connect(boost::bind(&ChatsManager::handleMUCSelectedAfterSearch, this, _1)); setupBookmarks(); } ChatsManager::~ChatsManager() { + delete joinMUCWindow_; foreach (JIDChatControllerPair controllerPair, chatControllers_) { delete controllerPair.second; } @@ -54,6 +86,7 @@ ChatsManager::~ChatsManager() { delete controllerPair.second; } delete mucBookmarkManager_; + delete mucSearchController_; } void ChatsManager::setupBookmarks() { @@ -80,7 +113,7 @@ void ChatsManager::handleMUCBookmarkAdded(const MUCBookmark& bookmark) { std::map<JID, MUCController*>::iterator it = mucControllers_.find(bookmark.getRoom()); if (it == mucControllers_.end() && bookmark.getAutojoin()) { //FIXME: need vcard stuff here to get a nick - handleJoinMUCRequest(bookmark.getRoom(), bookmark.getNick()); + handleJoinMUCRequest(bookmark.getRoom(), bookmark.getNick(), false); } chatListWindow_->addMUCBookmark(bookmark); } @@ -106,11 +139,6 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) { handleChatRequest(chatEvent->getContact()); return; } - boost::shared_ptr<JoinMUCUIEvent> joinMUCEvent = boost::dynamic_pointer_cast<JoinMUCUIEvent>(event); - if (joinMUCEvent) { - handleJoinMUCRequest(joinMUCEvent->getJID(), joinMUCEvent->getNick()); - return; - } boost::shared_ptr<RemoveMUCBookmarkUIEvent> removeMUCBookmarkEvent = boost::dynamic_pointer_cast<RemoveMUCBookmarkUIEvent>(event); if (removeMUCBookmarkEvent) { mucBookmarkManager_->removeBookmark(removeMUCBookmarkEvent->getBookmark()); @@ -121,10 +149,23 @@ void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) { mucBookmarkManager_->addBookmark(addMUCBookmarkEvent->getBookmark()); return; } + boost::shared_ptr<EditMUCBookmarkUIEvent> editMUCBookmarkEvent = boost::dynamic_pointer_cast<EditMUCBookmarkUIEvent>(event); if (editMUCBookmarkEvent) { mucBookmarkManager_->replaceBookmark(editMUCBookmarkEvent->getOldBookmark(), editMUCBookmarkEvent->getNewBookmark()); - return; + } + else if (JoinMUCUIEvent::ref joinEvent = boost::dynamic_pointer_cast<JoinMUCUIEvent>(event)) { + handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getNick(), false); + } + else if (boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) { + if (!joinMUCWindow_) { + joinMUCWindow_ = joinMUCWindowFactory_->createJoinMUCWindow(); + joinMUCWindow_->onJoinMUC.connect(boost::bind(&ChatsManager::handleJoinMUCRequest, this, _1, _2, _3)); + joinMUCWindow_->onSearchMUC.connect(boost::bind(&ChatsManager::handleSearchMUCRequest, this)); + } + joinMUCWindow_->setMUC(""); + joinMUCWindow_->setNick(nickResolver_->jidToNick(jid_)); + joinMUCWindow_->show(); } } @@ -239,7 +280,16 @@ void ChatsManager::rebindControllerJID(const JID& from, const JID& to) { chatControllers_[to]->setToJID(to); } -void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<String>& nickMaybe) { +void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional<String>& nickMaybe, bool autoJoin) { + if (autoJoin) { + MUCBookmark bookmark(mucJID, mucJID.getNode()); + bookmark.setAutojoin(true); + if (nickMaybe) { + bookmark.setNick(*nickMaybe); + } + mucBookmarkManager_->addBookmark(bookmark); + } + std::map<JID, MUCController*>::iterator it = mucControllers_.find(mucJID); if (it != mucControllers_.end()) { it->second->rejoin(); @@ -254,6 +304,10 @@ void ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::optional mucControllers_[mucJID]->activateChatWindow(); } +void ChatsManager::handleSearchMUCRequest() { + mucSearchController_->openSearchWindow(); +} + void ChatsManager::handleIncomingMessage(boost::shared_ptr<Message> message) { JID jid = message->getFrom(); boost::shared_ptr<MessageEvent> event(new MessageEvent(message)); @@ -278,4 +332,11 @@ void ChatsManager::handleIncomingMessage(boost::shared_ptr<Message> message) { getChatControllerOrCreate(jid)->handleIncomingMessage(event); } +void ChatsManager::handleMUCSelectedAfterSearch(const JID& muc) { + if (joinMUCWindow_) { + joinMUCWindow_->setMUC(muc.toString()); + } +} + + } diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index 2b771eb..62b14d9 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -25,6 +25,8 @@ namespace Swift { class MUCController; class MUCManager; class ChatWindowFactory; + class JoinMUCWindow; + class JoinMUCWindowFactory; class NickResolver; class PresenceOracle; class AvatarManager; @@ -37,10 +39,13 @@ namespace Swift { class TimerFactory; class EntityCapsProvider; class DirectedPresenceSender; + class MUCSearchWindowFactory; + class SettingsProvider; + class MUCSearchController; class ChatsManager { public: - ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager); + ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, SettingsProvider* settings); virtual ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); void setOnline(bool enabled); @@ -48,7 +53,9 @@ namespace Swift { void handleIncomingMessage(boost::shared_ptr<Message> message); private: void handleChatRequest(const String& contact); - void handleJoinMUCRequest(const JID& muc, const boost::optional<String>& nick); + void handleJoinMUCRequest(const JID& muc, const boost::optional<String>& nick, bool autoJoin); + void handleSearchMUCRequest(); + void handleMUCSelectedAfterSearch(const JID&); void rebindControllerJID(const JID& from, const JID& to); void handlePresenceChange(boost::shared_ptr<Presence> newPresence); void handleUIEvent(boost::shared_ptr<UIEvent> event); @@ -68,6 +75,7 @@ namespace Swift { StanzaChannel* stanzaChannel_; IQRouter* iqRouter_; ChatWindowFactory* chatWindowFactory_; + JoinMUCWindowFactory* joinMUCWindowFactory_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; @@ -76,11 +84,13 @@ namespace Swift { MUCBookmarkManager* mucBookmarkManager_; boost::shared_ptr<DiscoInfo> serverDiscoInfo_; ChatListWindow* chatListWindow_; + JoinMUCWindow* joinMUCWindow_; boost::bsignals::scoped_connection uiEventConnection_; bool useDelayForLatency_; TimerFactory* timerFactory_; MUCRegistry* mucRegistry_; EntityCapsProvider* entityCapsProvider_; MUCManager* mucManager; + MUCSearchController* mucSearchController_; }; } diff --git a/Swift/Controllers/Chat/MUCSearchController.cpp b/Swift/Controllers/Chat/MUCSearchController.cpp index c254e51..c85f793 100644 --- a/Swift/Controllers/Chat/MUCSearchController.cpp +++ b/Swift/Controllers/Chat/MUCSearchController.cpp @@ -11,12 +11,9 @@ #include <boost/bind.hpp> #include <boost/shared_ptr.hpp> -#include <Swiften/Disco/GetDiscoInfoRequest.h> #include <Swiften/Disco/GetDiscoItemsRequest.h> - +#include <Swiften/Base/Log.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> #include <Swift/Controllers/DiscoServiceWalker.h> #include <Swiften/Client/NickResolver.h> @@ -25,57 +22,43 @@ namespace Swift { static const String SEARCHED_SERVICES = "searchedServices"; -MUCSearchController::MUCSearchController(const JID& jid, UIEventStream* uiEventStream, MUCSearchWindowFactory* factory, IQRouter* iqRouter, SettingsProvider* settings, NickResolver *nickResolver) : jid_(jid) { - iqRouter_ = iqRouter; - settings_ = settings; - uiEventStream_ = uiEventStream; - nickResolver_ = nickResolver; +MUCSearchController::MUCSearchController(const JID& jid, MUCSearchWindowFactory* factory, IQRouter* iqRouter, SettingsProvider* settings) : jid_(jid), factory_(factory), iqRouter_(iqRouter), settings_(settings), window_(NULL), walker_(NULL) { itemsInProgress_ = 0; - uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&MUCSearchController::handleUIEvent, this, _1)); - window_ = NULL; - factory_ = factory; - loadServices(); + loadSavedServices(); } MUCSearchController::~MUCSearchController() { - foreach (DiscoServiceWalker* walker, walksInProgress_) { - delete walker; - } + delete walker_; 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)); - window_->addSavedServices(savedServices_); - handleAddService(JID(jid_.getDomain())); - } - window_->setMUC(""); - window_->setNick(nickResolver_->jidToNick(jid_)); - window_->show(); - return; +void MUCSearchController::openSearchWindow() { + if (!window_) { + window_ = factory_->createMUCSearchWindow(); + window_->onSearchService.connect(boost::bind(&MUCSearchController::handleSearchService, this, _1)); + window_->onFinished.connect(boost::bind(&MUCSearchController::handleMUCSearchFinished, this, _1)); + window_->addSavedServices(savedServices_); + handleSearchService(JID(jid_.getDomain())); } + window_->show(); } -void MUCSearchController::loadServices() { +void MUCSearchController::loadSavedServices() { savedServices_.clear(); foreach (String stringItem, settings_->getStringSetting(SEARCHED_SERVICES).split('\n')) { savedServices_.push_back(JID(stringItem)); } } -void MUCSearchController::addAndSaveServices(const JID& jid) { +void MUCSearchController::addToSavedServices(const JID& jid) { savedServices_.erase(std::remove(savedServices_.begin(), savedServices_.end(), jid), savedServices_.end()); - savedServices_.push_back(jid); + savedServices_.push_front(jid); + String collapsed; - bool storeThis = savedServices_.size() < 15; + int i = 0; foreach (JID jidItem, savedServices_) { - if (!storeThis) { - storeThis = true; - continue; + if (i >= 15) { + break; } if (!collapsed.isEmpty()) { collapsed += "\n"; @@ -86,21 +69,32 @@ void MUCSearchController::addAndSaveServices(const JID& jid) { window_->addSavedServices(savedServices_); } -void MUCSearchController::handleAddService(const JID& jid) { +void MUCSearchController::handleSearchService(const JID& jid) { if (!jid.isValid()) { //Set Window to say error this isn't valid return; } - addAndSaveServices(jid); - services_.push_back(jid); - serviceDetails_[jid].setComplete(false); + addToSavedServices(jid); + + services_.clear(); + serviceDetails_.clear(); + window_->setSearchInProgress(true); refreshView(); - DiscoServiceWalker* walker = new DiscoServiceWalker(jid, iqRouter_); - walker->onServiceFound.connect(boost::bind(&MUCSearchController::handleDiscoServiceFound, this, _1, _2)); - walker->onWalkComplete.connect(boost::bind(&MUCSearchController::handleDiscoWalkFinished, this, walker)); - walksInProgress_.push_back(walker); - walker->beginWalk(); + + if (walker_) { + walker_->endWalk(); + walker_->onServiceFound.disconnect(boost::bind(&MUCSearchController::handleDiscoServiceFound, this, _1, _2)); + walker_->onWalkComplete.disconnect(boost::bind(&MUCSearchController::handleDiscoWalkFinished, this)); + delete walker_; + } + + SWIFT_LOG(debug) << "Starting walking MUC services" << std::endl; + itemsInProgress_ = 0; + walker_ = new DiscoServiceWalker(jid, iqRouter_); + walker_->onServiceFound.connect(boost::bind(&MUCSearchController::handleDiscoServiceFound, this, _1, _2)); + walker_->onWalkComplete.connect(boost::bind(&MUCSearchController::handleDiscoWalkFinished, this)); + walker_->beginWalk(); } void MUCSearchController::handleDiscoServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> info) { @@ -116,25 +110,27 @@ void MUCSearchController::handleDiscoServiceFound(const JID& jid, boost::shared_ } } if (isMUC) { - services_.erase(std::remove(services_.begin(), services_.end(), jid), services_.end()); /* Bring it back to the end on a refresh */ + SWIFT_LOG(debug) << "MUC Service found: " << jid << std::endl; + services_.erase(std::remove(services_.begin(), services_.end(), jid), services_.end()); services_.push_back(jid); serviceDetails_[jid].setName(name); serviceDetails_[jid].setJID(jid); serviceDetails_[jid].setComplete(false); itemsInProgress_++; + SWIFT_LOG(debug) << "Requesting items of " << jid << " (" << itemsInProgress_ << " item requests in progress)" << std::endl; GetDiscoItemsRequest::ref discoItemsRequest = GetDiscoItemsRequest::create(jid, iqRouter_); discoItemsRequest->onResponse.connect(boost::bind(&MUCSearchController::handleRoomsItemsResponse, this, _1, _2, jid)); discoItemsRequest->send(); - } else { + } + else { removeService(jid); } refreshView(); } -void MUCSearchController::handleDiscoWalkFinished(DiscoServiceWalker* walker) { - walksInProgress_.erase(std::remove(walksInProgress_.begin(), walksInProgress_.end(), walker), walksInProgress_.end()); +void MUCSearchController::handleDiscoWalkFinished() { + SWIFT_LOG(debug) << "MUC Walk finished" << std::endl; updateInProgressness(); - delete walker; } void MUCSearchController::removeService(const JID& jid) { @@ -145,6 +141,7 @@ void MUCSearchController::removeService(const JID& jid) { void MUCSearchController::handleRoomsItemsResponse(boost::shared_ptr<DiscoItems> items, ErrorPayload::ref error, const JID& jid) { itemsInProgress_--; + SWIFT_LOG(debug) << "Items received for " << jid << " (" << itemsInProgress_ << " item requests in progress)" << std::endl; updateInProgressness(); if (error) { handleDiscoError(jid, error); @@ -171,7 +168,13 @@ void MUCSearchController::refreshView() { } void MUCSearchController::updateInProgressness() { - window_->setSearchInProgress(walksInProgress_.size() + itemsInProgress_ > 0); + window_->setSearchInProgress((walker_ && walker_->isActive()) || itemsInProgress_ > 0); +} + +void MUCSearchController::handleMUCSearchFinished(const boost::optional<JID>& result) { + if (result) { + onMUCSelected(*result); + } } } diff --git a/Swift/Controllers/Chat/MUCSearchController.h b/Swift/Controllers/Chat/MUCSearchController.h index 6caee54..6d3afd1 100644 --- a/Swift/Controllers/Chat/MUCSearchController.h +++ b/Swift/Controllers/Chat/MUCSearchController.h @@ -88,32 +88,38 @@ namespace Swift { class MUCSearchController { public: - MUCSearchController(const JID& jid, UIEventStream* uiEventStream, MUCSearchWindowFactory* mucSearchWindowFactory, IQRouter* iqRouter, SettingsProvider* settings, NickResolver* nickResolver); + MUCSearchController(const JID& jid, MUCSearchWindowFactory* mucSearchWindowFactory, IQRouter* iqRouter, SettingsProvider* settings); ~MUCSearchController(); + + void openSearchWindow(); + + public: + boost::signal<void (const JID&)> onMUCSelected; + private: - void handleUIEvent(boost::shared_ptr<UIEvent> event); - void handleAddService(const JID& jid); + void handleSearchService(const JID& jid); void handleRoomsItemsResponse(boost::shared_ptr<DiscoItems> items, ErrorPayload::ref error, const JID& jid); void handleDiscoError(const JID& jid, ErrorPayload::ref error); void handleDiscoServiceFound(const JID&, boost::shared_ptr<DiscoInfo>); - void handleDiscoWalkFinished(DiscoServiceWalker* walker); + void handleDiscoWalkFinished(); + void handleMUCSearchFinished(const boost::optional<JID>& result); void removeService(const JID& jid); void refreshView(); - void loadServices(); - void addAndSaveServices(const JID& jid); + void loadSavedServices(); + void addToSavedServices(const JID& jid); void updateInProgressness(); - UIEventStream* uiEventStream_; - MUCSearchWindow* window_; + + private: + JID jid_; MUCSearchWindowFactory* factory_; + IQRouter* iqRouter_; SettingsProvider* settings_; - NickResolver* nickResolver_; - boost::bsignals::scoped_connection uiEventConnection_; - std::vector<JID> services_; - std::vector<JID> savedServices_; + MUCSearchWindow* window_; + DiscoServiceWalker* walker_; + std::list<JID> services_; + std::list<JID> savedServices_; std::map<JID, MUCService> serviceDetails_; std::vector<DiscoServiceWalker*> walksInProgress_; - IQRouter* iqRouter_; - JID jid_; int itemsInProgress_; }; } diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index 6d20f70..be262bc 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -11,8 +11,11 @@ #include "Swift/Controllers/Chat/ChatsManager.h" #include "Swift/Controllers/UIInterfaces/ChatWindow.h" +#include "Swift/Controllers/Settings/DummySettingsProvider.h" #include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" #include "Swift/Controllers/UIInterfaces/ChatListWindowFactory.h" +#include "Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h" +#include "Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h" #include "Swiften/Client/Client.h" #include "Swiften/Disco/EntityCapsManager.h" #include "Swiften/Disco/CapsProvider.h" @@ -68,6 +71,7 @@ public: capsProvider_ = new DummyCapsProvider(); eventController_ = new EventController(); chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>(); + joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>(); xmppRoster_ = new XMPPRosterImpl(); mucRegistry_ = new MUCRegistry(); nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_); @@ -79,8 +83,10 @@ public: uiEventStream_ = new UIEventStream(); entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_); chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>(); + mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>(); + settings_ = new DummySettingsProvider(); mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(NULL); - manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_); + manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, settings_); avatarManager_ = new NullAvatarManager(); manager_->setAvatarManager(avatarManager_); @@ -88,6 +94,7 @@ public: void tearDown() { //delete chatListWindowFactory_; + delete settings_; delete mocks_; delete avatarManager_; delete manager_; @@ -325,6 +332,7 @@ private: IQRouter* iqRouter_; EventController* eventController_; ChatWindowFactory* chatWindowFactory_; + JoinMUCWindowFactory* joinMUCWindowFactory_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; @@ -334,11 +342,13 @@ private: MockRepository* mocks_; UIEventStream* uiEventStream_; ChatListWindowFactory* chatListWindowFactory_; + MUCSearchWindowFactory* mucSearchWindowFactory_; MUCRegistry* mucRegistry_; DirectedPresenceSender* directedPresenceSender_; EntityCapsManager* entityCapsManager_; CapsProvider* capsProvider_; MUCManager* mucManager_; + DummySettingsProvider* settings_; }; CPPUNIT_TEST_SUITE_REGISTRATION(ChatsManagerTest); diff --git a/Swift/Controllers/DiscoServiceWalker.cpp b/Swift/Controllers/DiscoServiceWalker.cpp index 505acb4..15d2aaa 100644 --- a/Swift/Controllers/DiscoServiceWalker.cpp +++ b/Swift/Controllers/DiscoServiceWalker.cpp @@ -141,10 +141,12 @@ void DiscoServiceWalker::markNodeCompleted(const JID& jid) { servicesBeingSearched_.erase(jid); /* All results are in */ if (servicesBeingSearched_.size() == 0) { + active_ = false; onWalkComplete(); } /* Check if we're on a rampage */ - if (searchedServices_.size() >= maxSteps_) { + else if (searchedServices_.size() >= maxSteps_) { + active_ = false; onWalkComplete(); } } diff --git a/Swift/Controllers/DiscoServiceWalker.h b/Swift/Controllers/DiscoServiceWalker.h index 167174a..00e2436 100644 --- a/Swift/Controllers/DiscoServiceWalker.h +++ b/Swift/Controllers/DiscoServiceWalker.h @@ -41,6 +41,10 @@ namespace Swift { */ void endWalk(); + bool isActive() const { + return active_; + } + /** Emitted for each service found. */ boost::signal<void(const JID&, boost::shared_ptr<DiscoInfo>)> onServiceFound; diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index bc40f95..f07a964 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -98,7 +98,6 @@ MainController::MainController( rosterController_ = NULL; chatsManager_ = NULL; eventWindowController_ = NULL; - mucSearchController_ = NULL; userSearchControllerChat_ = NULL; userSearchControllerAdd_ = NULL; quitRequested_ = false; @@ -171,8 +170,6 @@ MainController::~MainController() { void MainController::resetClient() { resetCurrentError(); resetPendingReconnects(); - delete mucSearchController_; - mucSearchController_ = NULL; delete eventWindowController_; eventWindowController_ = NULL; delete chatsManager_; @@ -235,7 +232,7 @@ void MainController::handleConnected() { rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); - chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager()); + chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, settings_); client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1)); chatsManager_->setAvatarManager(client_->getAvatarManager()); @@ -251,7 +248,6 @@ void MainController::handleConnected() { client_->getDiscoManager()->setDiscoInfo(discoInfo); - mucSearchController_ = new MUCSearchController(jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), settings_, client_->getNickResolver()); userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, uiFactory_, client_->getIQRouter()); userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, uiFactory_, client_->getIQRouter()); } diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 900319e..a933a5a 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -139,7 +139,6 @@ namespace Swift { String certificateFile_; boost::shared_ptr<ErrorEvent> lastDisconnectError_; bool useDelayForLatency_; - MUCSearchController* mucSearchController_; UserSearchController* userSearchControllerChat_; UserSearchController* userSearchControllerAdd_; int timeBeforeNextReconnect_; diff --git a/Swift/Controllers/UIEvents/JoinMUCUIEvent.h b/Swift/Controllers/UIEvents/JoinMUCUIEvent.h index d294fe8..2a2cd96 100644 --- a/Swift/Controllers/UIEvents/JoinMUCUIEvent.h +++ b/Swift/Controllers/UIEvents/JoinMUCUIEvent.h @@ -7,6 +7,7 @@ #pragma once #include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> #include "Swiften/Base/String.h" #include "Swift/Controllers/UIEvents/UIEvent.h" @@ -14,6 +15,7 @@ namespace Swift { class JoinMUCUIEvent : public UIEvent { public: + typedef boost::shared_ptr<JoinMUCUIEvent> ref; JoinMUCUIEvent(const JID& jid, const boost::optional<String>& nick = boost::optional<String>()) : jid_(jid), nick_(nick) {}; boost::optional<String> getNick() {return nick_;}; JID getJID() {return jid_;}; diff --git a/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h b/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h new file mode 100644 index 0000000..1415140 --- /dev/null +++ b/Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <boost/optional.hpp> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/String.h> +#include <Swift/Controllers/UIEvents/UIEvent.h> + +namespace Swift { + class RequestJoinMUCUIEvent : public UIEvent { + public: + typedef boost::shared_ptr<RequestJoinMUCUIEvent> ref; + + RequestJoinMUCUIEvent() { + } + }; +} diff --git a/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h b/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h deleted file mode 100644 index 623cd00..0000000 --- a/Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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/JoinMUCWindow.h b/Swift/Controllers/UIInterfaces/JoinMUCWindow.h new file mode 100644 index 0000000..8cf712c --- /dev/null +++ b/Swift/Controllers/UIInterfaces/JoinMUCWindow.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <vector> + +#include <Swiften/Base/String.h> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + class JoinMUCWindow { + public: + virtual ~JoinMUCWindow() {}; + + virtual void setNick(const String& nick) = 0; + virtual void setMUC(const String& nick) = 0; + virtual void show() = 0; + + boost::signal<void (const JID& /* muc */, const String& /* nick */, bool /* autoJoin */)> onJoinMUC; + boost::signal<void ()> onSearchMUC; + }; +} diff --git a/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h b/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h new file mode 100644 index 0000000..9c8bd77 --- /dev/null +++ b/Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h> + +namespace Swift { + class JoinMUCWindowFactory { + public: + virtual ~JoinMUCWindowFactory() {}; + + virtual JoinMUCWindow* createJoinMUCWindow() = 0; + }; +} diff --git a/Swift/Controllers/UIInterfaces/MUCSearchWindow.h b/Swift/Controllers/UIInterfaces/MUCSearchWindow.h index 3c0ab12..ded2a0a 100644 --- a/Swift/Controllers/UIInterfaces/MUCSearchWindow.h +++ b/Swift/Controllers/UIInterfaces/MUCSearchWindow.h @@ -10,10 +10,10 @@ #include <vector> +#include <boost/optional.hpp> #include "Swiften/Base/String.h" #include "Swiften/JID/JID.h" - -#include "Swift/Controllers/Chat/MUCSearchController.h" +#include <Swift/Controllers/Chat/MUCSearchController.h> namespace Swift { @@ -21,15 +21,14 @@ namespace Swift { 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 addSavedServices(const std::vector<JID>& services) = 0; + virtual void addSavedServices(const std::list<JID>& services) = 0; virtual void setSearchInProgress(bool searching) = 0; virtual void show() = 0; - boost::signal<void (const JID&)> onAddService; + boost::signal<void (const JID&)> onSearchService; + boost::signal<void (const boost::optional<JID>&)> onFinished; }; } diff --git a/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h b/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h index 1f0bf90..d334dff 100644 --- a/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h +++ b/Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h @@ -14,6 +14,6 @@ namespace Swift { public: virtual ~MUCSearchWindowFactory() {}; - virtual MUCSearchWindow* createMUCSearchWindow(UIEventStream* eventStream) = 0; + virtual MUCSearchWindow* createMUCSearchWindow() = 0; }; } diff --git a/Swift/Controllers/UIInterfaces/UIFactory.h b/Swift/Controllers/UIInterfaces/UIFactory.h index acb7638..4783dc8 100644 --- a/Swift/Controllers/UIInterfaces/UIFactory.h +++ b/Swift/Controllers/UIInterfaces/UIFactory.h @@ -12,11 +12,21 @@ #include <Swift/Controllers/UIInterfaces/LoginWindowFactory.h> #include <Swift/Controllers/UIInterfaces/MainWindowFactory.h> #include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h> #include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h> #include <Swift/Controllers/UIInterfaces/XMLConsoleWidgetFactory.h> namespace Swift { - class UIFactory : public ChatListWindowFactory, public ChatWindowFactory, public EventWindowFactory, public LoginWindowFactory, public MainWindowFactory, public MUCSearchWindowFactory, public XMLConsoleWidgetFactory, public UserSearchWindowFactory { + class UIFactory : + public ChatListWindowFactory, + public ChatWindowFactory, + public EventWindowFactory, + public LoginWindowFactory, + public MainWindowFactory, + public MUCSearchWindowFactory, + public XMLConsoleWidgetFactory, + public UserSearchWindowFactory, + public JoinMUCWindowFactory { public: virtual ~UIFactory() {} }; diff --git a/Swift/QtUI/MUCSearch/MUCSearchEmptyItem.cpp b/Swift/QtUI/MUCSearch/MUCSearchEmptyItem.cpp new file mode 100644 index 0000000..b1b4175 --- /dev/null +++ b/Swift/QtUI/MUCSearch/MUCSearchEmptyItem.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/QtUI/MUCSearch/MUCSearchEmptyItem.h> + +#include <Swift/QtUI/MUCSearch/MUCSearchServiceItem.h> +#include <QFont> +#include <QColor> + +namespace Swift { +MUCSearchEmptyItem::MUCSearchEmptyItem(MUCSearchServiceItem* parent) : parent(parent) { + parent->addRoom(this); +} + +MUCSearchServiceItem* MUCSearchEmptyItem::getParent() { + return parent; +} + +QVariant MUCSearchEmptyItem::data(int role) { + switch (role) { + case Qt::DisplayRole: + return QVariant("No rooms found"); + case Qt::FontRole: { + QFont font; + font.setItalic(true); + return font; + } + case Qt::ForegroundRole: + return QColor(Qt::gray); + default: + return QVariant(); + } +} + +} diff --git a/Swift/QtUI/MUCSearch/MUCSearchEmptyItem.h b/Swift/QtUI/MUCSearch/MUCSearchEmptyItem.h new file mode 100644 index 0000000..d752ae3 --- /dev/null +++ b/Swift/QtUI/MUCSearch/MUCSearchEmptyItem.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swift/QtUI/MUCSearch/MUCSearchItem.h> + +namespace Swift { + class MUCSearchServiceItem; + + class MUCSearchEmptyItem : public MUCSearchItem { + public: + MUCSearchEmptyItem(MUCSearchServiceItem* parent); + + MUCSearchServiceItem* getParent(); + + QVariant data(int role); + + private: + MUCSearchServiceItem* parent; + }; +} diff --git a/Swift/QtUI/MUCSearch/MUCSearchModel.cpp b/Swift/QtUI/MUCSearch/MUCSearchModel.cpp index 2526039..c657190 100644 --- a/Swift/QtUI/MUCSearch/MUCSearchModel.cpp +++ b/Swift/QtUI/MUCSearch/MUCSearchModel.cpp @@ -5,6 +5,7 @@ */ #include "Swift/QtUI/MUCSearch/MUCSearchModel.h" +#include "Swift/QtUI/MUCSearch/MUCSearchEmptyItem.h" namespace Swift { @@ -39,7 +40,6 @@ QModelIndex MUCSearchModel::index(int row, int column, const QModelIndex & paren if (parent.isValid()) { MUCSearchServiceItem* parentItem = static_cast<MUCSearchServiceItem*>(parent.internalPointer()); return row < parentItem->rowCount() ? createIndex(row, column, parentItem->getItem(row)) : QModelIndex(); - } else { return row < services_.size() ? createIndex(row, column, services_[row]) : QModelIndex(); } @@ -55,10 +55,17 @@ QModelIndex MUCSearchModel::parent(const QModelIndex& index) const { if (!item) { return QModelIndex(); } - if (dynamic_cast<MUCSearchServiceItem*>(item)) { + else if (dynamic_cast<MUCSearchServiceItem*>(item)) { return QModelIndex(); } - MUCSearchServiceItem* parent = dynamic_cast<MUCSearchRoomItem*>(item)->getParent(); + + MUCSearchServiceItem* parent = NULL; + if (MUCSearchRoomItem* roomItem = dynamic_cast<MUCSearchRoomItem*>(item)) { + parent = roomItem->getParent(); + } + else if (MUCSearchEmptyItem* emptyItem = dynamic_cast<MUCSearchEmptyItem*>(item)) { + parent = emptyItem->getParent(); + } if (parent) { int row = services_.indexOf(parent); return createIndex(row, 1, parent); @@ -74,7 +81,8 @@ int MUCSearchModel::rowCount(const QModelIndex& parentIndex) const { } if (dynamic_cast<MUCSearchServiceItem*>(static_cast<MUCSearchItem*>(parentIndex.internalPointer()))) { return services_[parentIndex.row()]->rowCount(); - } else { + } + else { return 0; } } diff --git a/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h b/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h index 860792f..411727d 100644 --- a/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h +++ b/Swift/QtUI/MUCSearch/MUCSearchServiceItem.h @@ -15,9 +15,9 @@ namespace Swift { class MUCSearchServiceItem : public MUCSearchItem { public: MUCSearchServiceItem(const QString& jidString) : jidString_(jidString) {} - void addRoom(MUCSearchRoomItem* room) {rooms_.push_back(room);} + void addRoom(MUCSearchItem* room) {rooms_.push_back(room);} int rowCount() {return rooms_.count();} - MUCSearchRoomItem* getItem(int i) {return rooms_[i];} + MUCSearchItem* getItem(int i) {return rooms_[i];} QVariant data(int role) { switch (role) { case Qt::DisplayRole: return QVariant(jidString_); @@ -26,7 +26,7 @@ namespace Swift { } QString getHost() {return jidString_;} private: - QList<MUCSearchRoomItem*> rooms_; + QList<MUCSearchItem*> rooms_; QString jidString_; }; } diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp index 7d2caba..3bdc433 100644 --- a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp +++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp @@ -10,43 +10,42 @@ #include <QMovie> #include <QScrollBar> #include <QTimer> +#include <QPushButton> -#include "Swift/Controllers/UIEvents/UIEventStream.h" #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" #include "Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h" #include "Swift/QtUI/MUCSearch/MUCSearchModel.h" #include "Swift/QtUI/MUCSearch/MUCSearchDelegate.h" +#include "Swift/QtUI/MUCSearch/MUCSearchEmptyItem.h" #include "Swift/QtUI/QtSwiftUtil.h" namespace Swift { -QtMUCSearchWindow::QtMUCSearchWindow(UIEventStream* eventStream) { +QtMUCSearchWindow::QtMUCSearchWindow() { + ui_.setupUi(this); #ifndef Q_WS_MAC setWindowIcon(QIcon(":/logo-icon-16.png")); #endif - eventStream_ = eventStream; - setupUi(this); - showEmptyRooms_->hide(); - filterLabel_->hide(); - filter_->hide(); + setModal(true); + ui_.filter_->hide(); model_ = new MUCSearchModel(); delegate_ = new MUCSearchDelegate(); - results_->setModel(model_); - results_->setItemDelegate(delegate_); - results_->setHeaderHidden(true); -#ifdef SWIFT_PLATFORM_MACOSX - results_->setAlternatingRowColors(true); -#endif - connect(service_, SIGNAL(activated(const QString&)), this, SLOT(handleSearch(const QString&))); - connect(room_, SIGNAL(returnPressed()), this, SLOT(handleJoin())); - connect(nickName_, SIGNAL(returnPressed()), room_, SLOT(setFocus())); - connect(searchButton_, SIGNAL(clicked()), this, SLOT(handleSearch())); - connect(joinButton_, SIGNAL(clicked()), this, SLOT(handleJoin())); - connect(results_, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleSelected(const QModelIndex&))); - connect(results_, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleActivated(const QModelIndex&))); - throbber_ = new QLabel("Searching", results_); + ui_.results_->setModel(model_); + ui_.results_->setItemDelegate(delegate_); + ui_.results_->setHeaderHidden(true); + ui_.results_->setRootIsDecorated(true); + ui_.results_->setAnimated(true); + ui_.results_->setAlternatingRowColors(true); + connect(ui_.service_, SIGNAL(activated(const QString&)), this, SLOT(handleSearch(const QString&))); + connect(ui_.results_, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleActivated(const QModelIndex&))); + // Not using a button box, because i can't seem to be able to make the ok button non-default (on mac) + connect(ui_.okButton, SIGNAL(clicked()), this, SLOT(accept())); + connect(ui_.cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + throbber_ = new QLabel("Searching", ui_.results_); throbber_->setMovie(new QMovie(":/icons/throbber.gif", QByteArray(), throbber_)); throbber_->setToolTip("Searching"); + hasHadScrollBars_ = false; updateThrobberPosition(); setSearchInProgress(false); @@ -62,8 +61,8 @@ void QtMUCSearchWindow::resizeEvent(QResizeEvent* /*event*/) { void QtMUCSearchWindow::updateThrobberPosition() { bool isShown = throbber_->isVisible(); - int resultWidth = results_->width(); - int resultHeight = results_->height(); + int resultWidth = ui_.results_->width(); + int resultHeight = ui_.results_->height(); //throbberWidth = throbber_->movie()->scaledSize().width(); //throbberHeight = throbber_->movie()->scaledSize().height(); int throbberWidth = 16; /* This is nasty, but the above doesn't work! */ @@ -72,99 +71,43 @@ void QtMUCSearchWindow::updateThrobberPosition() { * because if you listen for the expanded/collapsed signals, you seem to get them before the scrollbars are updated. * This seems an acceptable workaround. */ - hasHadScrollBars_ |= results_->verticalScrollBar()->isVisible(); - int hMargin = hasHadScrollBars_ ? results_->verticalScrollBar()->width() + 2 : 2; + hasHadScrollBars_ |= ui_.results_->verticalScrollBar()->isVisible(); + int hMargin = hasHadScrollBars_ ? ui_.results_->verticalScrollBar()->width() + 2 : 2; int vMargin = 2; /* We don't get horizontal scrollbars */ throbber_->setGeometry(QRect(resultWidth - throbberWidth - hMargin, resultHeight - throbberHeight - vMargin, throbberWidth, throbberHeight)); /* include margins */ throbber_->setVisible(isShown); } -void QtMUCSearchWindow::addSavedServices(const std::vector<JID>& services) { - service_->clear(); - foreach (JID jid, services) { - service_->addItem(P2QSTRING(jid.toString())); +void QtMUCSearchWindow::addSavedServices(const std::list<JID>& services) { + ui_.service_->clear(); + foreach (const JID& jid, services) { + ui_.service_->addItem(P2QSTRING(jid.toString())); } - service_->clearEditText(); -} - -void QtMUCSearchWindow::handleActivated(const QModelIndex& index) { - if (!index.isValid()) { - return; + if (!services.empty()) { + ui_.service_->setEditText(P2QSTRING(services.begin()->toString())); } - MUCSearchRoomItem* roomItem = dynamic_cast<MUCSearchRoomItem*>(static_cast<MUCSearchItem*>(index.internalPointer())); - if (roomItem) { - handleSelected(index); - handleJoin(); + else { + ui_.service_->clearEditText(); } } -void QtMUCSearchWindow::handleSelected(const QModelIndex& current) { - if (!current.isValid()) { +void QtMUCSearchWindow::handleActivated(const QModelIndex& index) { + if (!index.isValid()) { return; - } - MUCSearchRoomItem* roomItem = dynamic_cast<MUCSearchRoomItem*>(static_cast<MUCSearchItem*>(current.internalPointer())); - if (roomItem) { - room_->setText(roomItem->getNode() + "@" + roomItem->getParent()->getHost()); } - -} - -void QtMUCSearchWindow::handleSearch(const QString& text) { - if (text.isEmpty()) { - return; + if (dynamic_cast<MUCSearchRoomItem*>(static_cast<MUCSearchItem*>(index.internalPointer()))) { + accept(); } - onAddService(JID(Q2PSTRING(text))); } void QtMUCSearchWindow::handleSearch() { - handleSearch(service_->currentText()); -} - - -void QtMUCSearchWindow::handleJoin() { - if (room_->text().isEmpty()) { - handleSelected(results_->currentIndex()); - } - if (room_->text().isEmpty()) { - return; - } - boost::optional<String> maybeNick; - if (!nickName_->text().isEmpty()) { - lastSetNick_ = Q2PSTRING(nickName_->text()); - maybeNick = lastSetNick_; - } - - JID room(Q2PSTRING(room_->text())); - if (joinAutomatically_->isChecked()) { - createAutoJoin(room, maybeNick); - } - eventStream_->send(boost::shared_ptr<UIEvent>(new JoinMUCUIEvent(room, maybeNick))); - hide(); + handleSearch(ui_.service_->currentText()); } -void QtMUCSearchWindow::createAutoJoin(const JID& room, boost::optional<String> passedNick) { - String nick = lastSetNick_; - if (passedNick) { - nick = passedNick.get(); +void QtMUCSearchWindow::handleSearch(const QString& service) { + if (!service.isEmpty()) { + onSearchService(JID(Q2PSTRING(service))); } - MUCBookmark bookmark(room, room.getNode()); - bookmark.setAutojoin(true); - if (!nick.isEmpty()) { - bookmark.setNick(nick); - } - //if (!password.isEmpty()) { - // bookmark.setPassword(password); - //} - eventStream_->send(boost::shared_ptr<UIEvent>(new AddMUCBookmarkUIEvent(bookmark))); -} - -void QtMUCSearchWindow::setNick(const String& nick) { - nickName_->setText(P2QSTRING(nick)); - lastSetNick_ = nick; -} - -void QtMUCSearchWindow::setMUC(const String& nick) { - room_->setText(P2QSTRING(nick)); } void QtMUCSearchWindow::show() { @@ -179,11 +122,16 @@ void QtMUCSearchWindow::clearList() { void QtMUCSearchWindow::addService(const MUCService& service) { updateThrobberPosition(); MUCSearchServiceItem* serviceItem = new MUCSearchServiceItem(P2QSTRING(service.getJID().toString())); - foreach (MUCService::MUCRoom room, service.getRooms()) { - new MUCSearchRoomItem(P2QSTRING(room.getNode()), serviceItem); + if (service.getRooms().size() > 0) { + foreach (MUCService::MUCRoom room, service.getRooms()) { + new MUCSearchRoomItem(P2QSTRING(room.getNode()), serviceItem); + } + } + else { + new MUCSearchEmptyItem(serviceItem); } model_->addService(serviceItem); - results_->expandAll(); + ui_.results_->expandAll(); } void QtMUCSearchWindow::setSearchInProgress(bool searching) { @@ -195,4 +143,24 @@ void QtMUCSearchWindow::setSearchInProgress(bool searching) { throbber_->setVisible(searching); } +void QtMUCSearchWindow::accept() { + QModelIndexList selection = ui_.results_->selectionModel()->selectedIndexes(); + if (selection.isEmpty()) { + onFinished(boost::optional<JID>()); + } + else { + QModelIndex selectedItem = selection[0]; + MUCSearchRoomItem* item = dynamic_cast<MUCSearchRoomItem*>(static_cast<MUCSearchItem*>(selectedItem.internalPointer())); + if (item) { + onFinished(JID(Q2PSTRING(item->getNode()), Q2PSTRING(item->getParent()->getHost()))); + } + } + QDialog::accept(); +} + +void QtMUCSearchWindow::reject() { + onFinished(boost::optional<JID>()); + QDialog::reject(); +} + } diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h index b8cf953..cb4585d 100644 --- a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h +++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h @@ -13,37 +13,36 @@ namespace Swift { class MUCSearchModel; class MUCSearchDelegate; - class UIEventStream; - class QtMUCSearchWindow : public QWidget, public MUCSearchWindow, private Ui::QtMUCSearchWindow { + + class QtMUCSearchWindow : public QDialog, public MUCSearchWindow { Q_OBJECT public: - QtMUCSearchWindow(UIEventStream* eventStream); + QtMUCSearchWindow(); virtual ~QtMUCSearchWindow(); - virtual void setNick(const String& nick); - virtual void setMUC(const String& nick); virtual void clearList(); virtual void addService(const MUCService& service); - virtual void addSavedServices(const std::vector<JID>& services); + virtual void addSavedServices(const std::list<JID>& services); virtual void setSearchInProgress(bool searching); virtual void show(); + virtual void accept(); + virtual void reject(); + protected: virtual void resizeEvent(QResizeEvent* event); + private slots: - void handleSearch(const QString& text); void handleSearch(); - void handleJoin(); - void handleSelected(const QModelIndex& current); + void handleSearch(const QString&); void handleActivated(const QModelIndex& index); void updateThrobberPosition(); + private: - void createAutoJoin(const JID& room, boost::optional<String> passedNick); + Ui::QtMUCSearchWindow ui_; MUCSearchModel* model_; MUCSearchDelegate* delegate_; - UIEventStream* eventStream_; QLabel* throbber_; - String lastSetNick_; bool hasHadScrollBars_; }; } diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui index ef2524b..f1a1fd5 100644 --- a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui +++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui @@ -1,212 +1,92 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>QtMUCSearchWindow</class> - <widget class="QWidget" name="QtMUCSearchWindow"> + <widget class="QDialog" name="QtMUCSearchWindow"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>523</width> - <height>531</height> + <height>368</height> </rect> </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> <property name="windowTitle"> - <string>Find Room</string> + <string>Dialog</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <item> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <property name="sizeConstraint"> - <enum>QLayout::SetDefaultConstraint</enum> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Service:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="service_"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>2</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="editable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLineEdit" name="filter_"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>1</horstretch> + <verstretch>0</verstretch> + </sizepolicy> </property> + <property name="text"> + <string/> + </property> + <property name="frame"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0" colspan="3"> + <widget class="QTreeView" name="results_"/> + </item> + <item row="2" column="0" colspan="3"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Available Rooms</string> - </property> - </widget> - </item> - <item> - <widget class="QTreeView" name="results_"/> - </item> - </layout> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout_2"> - <item> - <widget class="QLabel" name="label_5"> - <property name="text"> - <string>Your nickname:</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="nickName_"/> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Search another service:</string> - </property> - </widget> - </item> - <item> - <widget class="QComboBox" name="service_"> - <property name="editable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <spacer name="horizontalSpacer"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="searchButton_"> - <property name="text"> - <string>Search</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="filterLabel_"> - <property name="text"> - <string>Only show rooms matching:</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="filter_"/> - </item> - <item> - <widget class="QCheckBox" name="showEmptyRooms_"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>Show Empty Rooms</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>18</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Join Room Directly:</string> - </property> - </widget> - </item> - <item> - <widget class="QLineEdit" name="room_"/> - </item> - <item> - <widget class="QCheckBox" name="joinAutomatically_"> - <property name="text"> - <string>Join automatically in future</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> + <widget class="QPushButton" name="cancelButton"> + <property name="text"> + <string>Cancel</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="joinButton_"> - <property name="text"> - <string>Join Room</string> - </property> - </widget> - </item> - <item> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>40</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> + <widget class="QPushButton" name="okButton"> + <property name="text"> + <string>Ok</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + </widget> </item> </layout> </item> diff --git a/Swift/QtUI/QtJoinMUCWindow.cpp b/Swift/QtUI/QtJoinMUCWindow.cpp new file mode 100644 index 0000000..55b285b --- /dev/null +++ b/Swift/QtUI/QtJoinMUCWindow.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "QtJoinMUCWindow.h" +#include "QtSwiftUtil.h" + +namespace Swift { + +QtJoinMUCWindow::QtJoinMUCWindow() { + ui.setupUi(this); + connect(ui.room, SIGNAL(returnPressed()), this, SLOT(handleJoin())); + connect(ui.searchButton, SIGNAL(clicked()), this, SLOT(handleSearch())); + connect(ui.joinButton, SIGNAL(clicked()), this, SLOT(handleJoin())); +} + +void QtJoinMUCWindow::handleJoin() { + if (ui.room->text().isEmpty()) { + // TODO: Error + return; + } + if (ui.nickName->text().isEmpty()) { + // TODO: Error + return; + } + + lastSetNick = Q2PSTRING(ui.nickName->text()); + JID room(Q2PSTRING(ui.room->text())); + onJoinMUC(room, lastSetNick, ui.joinAutomatically->isChecked()); + hide(); +} + +void QtJoinMUCWindow::handleSearch() { + onSearchMUC(); +} + +void QtJoinMUCWindow::setNick(const String& nick) { + ui.nickName->setText(P2QSTRING(nick)); + lastSetNick = nick; +} + +void QtJoinMUCWindow::setMUC(const String& nick) { + ui.room->setText(P2QSTRING(nick)); +} + +void QtJoinMUCWindow::show() { + QWidget::show(); + QWidget::activateWindow(); +} + +} diff --git a/Swift/QtUI/QtJoinMUCWindow.h b/Swift/QtUI/QtJoinMUCWindow.h new file mode 100644 index 0000000..2d12319 --- /dev/null +++ b/Swift/QtUI/QtJoinMUCWindow.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 Remko Tronçon + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swiften/Base/String.h> +#include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h> +#include <Swift/QtUI/ui_QtJoinMUCWindow.h> + +namespace Swift { + class QtJoinMUCWindow : public QWidget, public JoinMUCWindow { + Q_OBJECT + public: + QtJoinMUCWindow(); + + virtual void setNick(const String& nick); + virtual void setMUC(const String& nick); + + virtual void show(); + + private slots: + void handleJoin(); + void handleSearch(); + + private: + Ui::QtJoinMUCWindow ui; + String lastSetNick; + }; +} diff --git a/Swift/QtUI/QtJoinMUCWindow.ui b/Swift/QtUI/QtJoinMUCWindow.ui new file mode 100644 index 0000000..2f3608a --- /dev/null +++ b/Swift/QtUI/QtJoinMUCWindow.ui @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>QtJoinMUCWindow</class> + <widget class="QWidget" name="QtJoinMUCWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>398</width> + <height>172</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Join Room</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Room:</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QToolButton" name="searchButton"> + <property name="text"> + <string>Search ...</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Nickname:</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2"> + <widget class="QLineEdit" name="nickName"/> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="room"> + <property name="text"> + <string/> + </property> + <property name="placeholderText"> + <string>swift@rooms.swift.im</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>36</height> + </size> + </property> + </spacer> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QCheckBox" name="joinAutomatically"> + <property name="text"> + <string>Join automatically in future</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="joinButton"> + <property name="text"> + <string>Join Room</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <tabstops> + <tabstop>room</tabstop> + <tabstop>nickName</tabstop> + <tabstop>joinAutomatically</tabstop> + <tabstop>joinButton</tabstop> + <tabstop>searchButton</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index 21d1474..0411c0b 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -8,6 +8,7 @@ #include <boost/optional.hpp> #include <boost/bind.hpp> +#include <boost/smart_ptr/make_shared.hpp> #include <QBoxLayout> #include <QComboBox> @@ -24,9 +25,9 @@ #include "QtSwiftUtil.h" #include "QtTabWidget.h" #include "Roster/QtTreeWidget.h" +#include "Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h" #include "Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h" #include "Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h" -#include "Swift/Controllers/UIEvents/RequestMUCSearchUIEvent.h" #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" #include "Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h" @@ -143,7 +144,7 @@ void QtMainWindow::handleSignOutAction() { } void QtMainWindow::handleJoinMUCAction() { - uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestMUCSearchUIEvent())); + uiEventStream_->send(boost::make_shared<RequestJoinMUCUIEvent>()); } void QtMainWindow::handleStatusChanged(StatusShow::Type showType, const QString &statusMessage) { diff --git a/Swift/QtUI/QtUIFactory.cpp b/Swift/QtUI/QtUIFactory.cpp index 25a508e..8cb9863 100644 --- a/Swift/QtUI/QtUIFactory.cpp +++ b/Swift/QtUI/QtUIFactory.cpp @@ -16,6 +16,7 @@ #include "QtSettingsProvider.h" #include "QtMainWindow.h" #include "QtChatWindow.h" +#include "QtJoinMUCWindow.h" #include "QtChatWindowFactory.h" #include "QtSwiftUtil.h" #include "MUCSearch/QtMUCSearchWindow.h" @@ -70,8 +71,8 @@ ChatListWindow* QtUIFactory::createChatListWindow(UIEventStream*) { return lastMainWindow->getChatListWindow(); } -MUCSearchWindow* QtUIFactory::createMUCSearchWindow(UIEventStream* eventStream) { - return new QtMUCSearchWindow(eventStream); +MUCSearchWindow* QtUIFactory::createMUCSearchWindow() { + return new QtMUCSearchWindow(); } ChatWindow* QtUIFactory::createChatWindow(const JID& contact, UIEventStream* eventStream) { @@ -82,4 +83,8 @@ UserSearchWindow* QtUIFactory::createUserSearchWindow(UserSearchWindow::Type typ return new QtUserSearchWindow(eventStream, type); }; +JoinMUCWindow* QtUIFactory::createJoinMUCWindow() { + return new QtJoinMUCWindow(); +} + } diff --git a/Swift/QtUI/QtUIFactory.h b/Swift/QtUI/QtUIFactory.h index 6ddc316..4d80338 100644 --- a/Swift/QtUI/QtUIFactory.h +++ b/Swift/QtUI/QtUIFactory.h @@ -31,9 +31,10 @@ namespace Swift { virtual LoginWindow* createLoginWindow(UIEventStream* eventStream); virtual EventWindow* createEventWindow(); virtual ChatListWindow* createChatListWindow(UIEventStream*); - virtual MUCSearchWindow* createMUCSearchWindow(UIEventStream* eventStream); + virtual MUCSearchWindow* createMUCSearchWindow(); virtual ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream); virtual UserSearchWindow* createUserSearchWindow(UserSearchWindow::Type type, UIEventStream* eventStream); + virtual JoinMUCWindow* createJoinMUCWindow(); private slots: void handleLoginWindowGeometryChanged(); diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index c0730dc..b0072a6 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -92,6 +92,7 @@ sources = [ "SystemMessageSnippet.cpp", "QtElidingLabel.cpp", "QtLineEdit.cpp", + "QtJoinMUCWindow.cpp", "Roster/RosterModel.cpp", "Roster/QtTreeWidget.cpp", # "Roster/QtTreeWidgetItem.cpp", @@ -110,6 +111,7 @@ sources = [ "MUCSearch/QtMUCSearchWindow.cpp", "MUCSearch/MUCSearchModel.cpp", "MUCSearch/MUCSearchRoomItem.cpp", + "MUCSearch/MUCSearchEmptyItem.cpp", "MUCSearch/MUCSearchDelegate.cpp", "UserSearch/QtUserSearchWindow.cpp", "UserSearch/UserSearchModel.cpp", @@ -147,6 +149,7 @@ myenv.Uic4("UserSearch/QtUserSearchFieldsPage.ui") myenv.Uic4("UserSearch/QtUserSearchResultsPage.ui") myenv.Uic4("QtAddContactDialog.ui") myenv.Uic4("QtBookmarkDetailWindow.ui") +myenv.Uic4("QtJoinMUCWindow.ui") myenv.Qrc("DefaultTheme.qrc") myenv.Qrc("Swift.qrc") -- cgit v0.10.2-6-g49f6